* net/browse-url.el (browse-url): Identify alist with "consp and
[bpt/emacs.git] / src / composite.c
CommitLineData
ca4c9455 1/* Composite sequence support.
aaef169d 2 Copyright (C) 2001, 2002, 2003, 2004, 2005,
76b6f707
GM
3 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
ce03bf76
KH
5 National Institute of Advanced Industrial Science and Technology (AIST)
6 Registration Number H14PRO021
f30d8d94 7 Copyright (C) 2003, 2006
1527c36e
KH
8 National Institute of Advanced Industrial Science and Technology (AIST)
9 Registration Number H13PRO009
ca4c9455
KH
10
11This file is part of GNU Emacs.
12
9ec0b715 13GNU Emacs is free software: you can redistribute it and/or modify
ca4c9455 14it under the terms of the GNU General Public License as published by
9ec0b715
GM
15the Free Software Foundation, either version 3 of the License, or
16(at your option) any later version.
ca4c9455
KH
17
18GNU Emacs is distributed in the hope that it will be useful,
19but WITHOUT ANY WARRANTY; without even the implied warranty of
20MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21GNU General Public License for more details.
22
23You should have received a copy of the GNU General Public License
9ec0b715 24along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
ca4c9455
KH
25
26#include <config.h>
27#include "lisp.h"
28#include "buffer.h"
1527c36e 29#include "character.h"
f5199465 30#include "coding.h"
ca4c9455 31#include "intervals.h"
58753d74
KH
32#include "window.h"
33#include "frame.h"
34#include "dispextern.h"
35#include "font.h"
f5199465
KH
36#include "termhooks.h"
37
ca4c9455
KH
38
39/* Emacs uses special text property `composition' to support character
40 composition. A sequence of characters that have the same (i.e. eq)
41 `composition' property value is treated as a single composite
42 sequence (we call it just `composition' here after). Characters in
43 a composition are all composed somehow on the screen.
44
45 The property value has this form when the composition is made:
46 ((LENGTH . COMPONENTS) . MODIFICATION-FUNC)
47 then turns to this form:
48 (COMPOSITION-ID . (LENGTH COMPONENTS-VEC . MODIFICATION-FUNC))
49 when the composition is registered in composition_hash_table and
50 composition_table. These rather peculiar structures were designed
51 to make it easy to distinguish them quickly (we can do that by
52 checking only the first element) and to extract LENGTH (from the
53 former form) and COMPOSITION-ID (from the latter form).
54
55 We register a composition when it is displayed, or when the width
56 is required (for instance, to calculate columns).
57
58 LENGTH -- Length of the composition. This information is used to
59 check the validity of the composition.
60
61 COMPONENTS -- Character, string, vector, list, or nil.
62
63 If it is nil, characters in the text are composed relatively
64 according to their metrics in font glyphs.
65
66 If it is a character or a string, the character or characters
67 in the string are composed relatively.
68
69 If it is a vector or list of integers, the element is a
70 character or an encoded composition rule. The characters are
71 composed according to the rules. (2N)th elements are
72 characters to be composed and (2N+1)th elements are
73 composition rules to tell how to compose (2N+2)th element with
74 the previously composed 2N glyphs.
75
76 COMPONENTS-VEC -- Vector of integers. In relative composition, the
77 elements are characters to be composed. In rule-base
78 composition, the elements are characters or encoded
79 composition rules.
80
81 MODIFICATION-FUNC -- If non nil, it is a function to call when the
82 composition gets invalid after a modification in a buffer. If
83 it is nil, a function in `composition-function-table' of the
84 first character in the sequence is called.
85
86 COMPOSITION-ID --Identification number of the composition. It is
87 used as an index to composition_table for the composition.
88
89 When Emacs has to display a composition or has to know its
90 displaying width, the function get_composition_id is called. It
91 returns COMPOSITION-ID so that the caller can access the
92 information about the composition through composition_table. If a
93 COMPOSITION-ID has not yet been assigned to the composition,
94 get_composition_id checks the validity of `composition' property,
95 and, if valid, assigns a new ID, registers the information in
96 composition_hash_table and composition_table, and changes the form
97 of the property value. If the property is invalid, return -1
98 without changing the property value.
99
100 We use two tables to keep information about composition;
101 composition_hash_table and composition_table.
102
103 The former is a hash table in which keys are COMPONENTS-VECs and
104 values are the corresponding COMPOSITION-IDs. This hash table is
4abc7470 105 weak, but as each key (COMPONENTS-VEC) is also kept as a value of the
ca4c9455 106 `composition' property, it won't be collected as garbage until all
4abc7470 107 bits of text that have the same COMPONENTS-VEC are deleted.
ca4c9455
KH
108
109 The latter is a table of pointers to `struct composition' indexed
4abc7470 110 by COMPOSITION-ID. This structure keeps the other information (see
ca4c9455
KH
111 composite.h).
112
113 In general, a text property holds information about individual
114 characters. But, a `composition' property holds information about
4abc7470 115 a sequence of characters (in this sense, it is like the `intangible'
ca4c9455 116 property). That means that we should not share the property value
4abc7470 117 in adjacent compositions -- we can't distinguish them if they have the
ca4c9455
KH
118 same property. So, after any changes, we call
119 `update_compositions' and change a property of one of adjacent
120 compositions to a copy of it. This function also runs a proper
121 composition modification function to make a composition that gets
122 invalid by the change valid again.
123
4abc7470 124 As the value of the `composition' property holds information about a
ca4c9455 125 specific range of text, the value gets invalid if we change the
4abc7470 126 text in the range. We treat the `composition' property as always
ca4c9455
KH
127 rear-nonsticky (currently by setting default-text-properties to
128 (rear-nonsticky (composition))) and we never make properties of
129 adjacent compositions identical. Thus, any such changes make the
4abc7470 130 range just shorter. So, we can check the validity of the `composition'
ca4c9455
KH
131 property by comparing LENGTH information with the actual length of
132 the composition.
133
134*/
135
136
137Lisp_Object Qcomposition;
138
139/* Table of pointers to the structure `composition' indexed by
140 COMPOSITION-ID. This structure is for storing information about
141 each composition except for COMPONENTS-VEC. */
142struct composition **composition_table;
143
144/* The current size of `composition_table'. */
145static int composition_table_size;
146
147/* Number of compositions currently made. */
148int n_compositions;
149
150/* Hash table for compositions. The key is COMPONENTS-VEC of
151 `composition' property. The value is the corresponding
152 COMPOSITION-ID. */
153Lisp_Object composition_hash_table;
154
155/* Function to call to adjust composition. */
156Lisp_Object Vcompose_chars_after_function;
157
f96ba4c1
KH
158Lisp_Object Qauto_composed;
159Lisp_Object Vauto_composition_function;
160Lisp_Object Qauto_composition_function;
58753d74 161Lisp_Object Vcomposition_function_table;
40add26d 162
895416e3
KH
163/* Maxinum number of characters to lookback to check
164 auto-composition. */
165#define MAX_AUTO_COMPOSITION_LOOKBACK 3
166
ea058d2c
DL
167EXFUN (Fremove_list_of_text_properties, 4);
168
ca4c9455
KH
169/* Temporary variable used in macros COMPOSITION_XXX. */
170Lisp_Object composition_temp;
f30d8d94 171
ca4c9455 172\f
ca4c9455
KH
173/* Return COMPOSITION-ID of a composition at buffer position
174 CHARPOS/BYTEPOS and length NCHARS. The `composition' property of
175 the sequence is PROP. STRING, if non-nil, is a string that
176 contains the composition instead of the current buffer.
177
178 If the composition is invalid, return -1. */
179
180int
181get_composition_id (charpos, bytepos, nchars, prop, string)
182 int charpos, bytepos, nchars;
183 Lisp_Object prop, string;
184{
185 Lisp_Object id, length, components, key, *key_contents;
186 int glyph_len;
187 struct Lisp_Hash_Table *hash_table = XHASH_TABLE (composition_hash_table);
188 int hash_index;
189 unsigned hash_code;
190 struct composition *cmp;
191 int i, ch;
192
193 /* PROP should be
194 Form-A: ((LENGTH . COMPONENTS) . MODIFICATION-FUNC)
195 or
196 Form-B: (COMPOSITION-ID . (LENGTH COMPONENTS-VEC . MODIFICATION-FUNC))
197 */
198 if (nchars == 0 || !CONSP (prop))
199 goto invalid_composition;
200
201 id = XCAR (prop);
202 if (INTEGERP (id))
203 {
204 /* PROP should be Form-B. */
205 if (XINT (id) < 0 || XINT (id) >= n_compositions)
206 goto invalid_composition;
207 return XINT (id);
208 }
209
210 /* PROP should be Form-A.
211 Thus, ID should be (LENGTH . COMPONENTS). */
212 if (!CONSP (id))
213 goto invalid_composition;
214 length = XCAR (id);
215 if (!INTEGERP (length) || XINT (length) != nchars)
216 goto invalid_composition;
217
218 components = XCDR (id);
219
220 /* Check if the same composition has already been registered or not
221 by consulting composition_hash_table. The key for this table is
222 COMPONENTS (converted to a vector COMPONENTS-VEC) or, if it is
223 nil, vector of characters in the composition range. */
224 if (INTEGERP (components))
225 key = Fmake_vector (make_number (1), components);
226 else if (STRINGP (components) || CONSP (components))
227 key = Fvconcat (1, &components);
228 else if (VECTORP (components))
229 key = components;
230 else if (NILP (components))
231 {
232 key = Fmake_vector (make_number (nchars), Qnil);
233 if (STRINGP (string))
234 for (i = 0; i < nchars; i++)
235 {
236 FETCH_STRING_CHAR_ADVANCE (ch, string, charpos, bytepos);
237 XVECTOR (key)->contents[i] = make_number (ch);
238 }
239 else
240 for (i = 0; i < nchars; i++)
241 {
242 FETCH_CHAR_ADVANCE (ch, charpos, bytepos);
243 XVECTOR (key)->contents[i] = make_number (ch);
244 }
245 }
246 else
247 goto invalid_composition;
248
249 hash_index = hash_lookup (hash_table, key, &hash_code);
250 if (hash_index >= 0)
251 {
252 /* We have already registered the same composition. Change PROP
253 from Form-A above to Form-B while replacing COMPONENTS with
254 COMPONENTS-VEC stored in the hash table. We can directly
255 modify the cons cell of PROP because it is not shared. */
256 key = HASH_KEY (hash_table, hash_index);
257 id = HASH_VALUE (hash_table, hash_index);
f3fbd155
KR
258 XSETCAR (prop, id);
259 XSETCDR (prop, Fcons (make_number (nchars), Fcons (key, XCDR (prop))));
ca4c9455
KH
260 return XINT (id);
261 }
262
263 /* This composition is a new one. We must register it. */
177c0ea7 264
ca4c9455
KH
265 /* Check if we have sufficient memory to store this information. */
266 if (composition_table_size == 0)
267 {
268 composition_table_size = 256;
269 composition_table
270 = (struct composition **) xmalloc (sizeof (composition_table[0])
271 * composition_table_size);
272 }
273 else if (composition_table_size <= n_compositions)
274 {
275 composition_table_size += 256;
276 composition_table
277 = (struct composition **) xrealloc (composition_table,
278 sizeof (composition_table[0])
279 * composition_table_size);
280 }
281
282 key_contents = XVECTOR (key)->contents;
283
284 /* Check if the contents of COMPONENTS are valid if COMPONENTS is a
285 vector or a list. It should be a sequence of:
286 char1 rule1 char2 rule2 char3 ... ruleN charN+1 */
f30d8d94 287
dd5e1ed4 288 if (VECTORP (components)
f30d8d94
KH
289 && ASIZE (components) >= 2
290 && VECTORP (AREF (components, 0)))
291 {
292 /* COMPONENTS is a glyph-string. */
293 int len = ASIZE (key);
294
295 for (i = 1; i < len; i++)
296 if (! VECTORP (AREF (key, i)))
297 goto invalid_composition;
298 }
dd5e1ed4 299 else if (VECTORP (components) || CONSP (components))
ca4c9455
KH
300 {
301 int len = XVECTOR (key)->size;
302
303 /* The number of elements should be odd. */
304 if ((len % 2) == 0)
305 goto invalid_composition;
306 /* All elements should be integers (character or encoded
307 composition rule). */
308 for (i = 0; i < len; i++)
309 {
310 if (!INTEGERP (key_contents[i]))
311 goto invalid_composition;
312 }
313 }
314
315 /* Change PROP from Form-A above to Form-B. We can directly modify
316 the cons cell of PROP because it is not shared. */
317 XSETFASTINT (id, n_compositions);
f3fbd155
KR
318 XSETCAR (prop, id);
319 XSETCDR (prop, Fcons (make_number (nchars), Fcons (key, XCDR (prop))));
ca4c9455
KH
320
321 /* Register the composition in composition_hash_table. */
322 hash_index = hash_put (hash_table, key, id, hash_code);
323
324 /* Register the composition in composition_table. */
325 cmp = (struct composition *) xmalloc (sizeof (struct composition));
326
327 cmp->method = (NILP (components)
328 ? COMPOSITION_RELATIVE
329 : ((INTEGERP (components) || STRINGP (components))
330 ? COMPOSITION_WITH_ALTCHARS
331 : COMPOSITION_WITH_RULE_ALTCHARS));
332 cmp->hash_index = hash_index;
333 glyph_len = (cmp->method == COMPOSITION_WITH_RULE_ALTCHARS
334 ? (XVECTOR (key)->size + 1) / 2
335 : XVECTOR (key)->size);
336 cmp->glyph_len = glyph_len;
337 cmp->offsets = (short *) xmalloc (sizeof (short) * glyph_len * 2);
338 cmp->font = NULL;
339
58753d74 340 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
ca4c9455
KH
341 {
342 /* Relative composition. */
343 cmp->width = 0;
344 for (i = 0; i < glyph_len; i++)
345 {
346 int this_width;
347 ch = XINT (key_contents[i]);
8e86803c 348 this_width = (ch == '\t' ? 1 : CHAR_WIDTH (ch));
ca4c9455
KH
349 if (cmp->width < this_width)
350 cmp->width = this_width;
351 }
352 }
353 else
354 {
355 /* Rule-base composition. */
356 float leftmost = 0.0, rightmost;
357
358 ch = XINT (key_contents[0]);
69df789a 359 rightmost = ch != '\t' ? CHAR_WIDTH (ch) : 1;
ca4c9455
KH
360
361 for (i = 1; i < glyph_len; i += 2)
362 {
464f8566 363 int rule, gref, nref, xoff, yoff;
ca4c9455
KH
364 int this_width;
365 float this_left;
366
367 rule = XINT (key_contents[i]);
368 ch = XINT (key_contents[i + 1]);
69df789a 369 this_width = ch != '\t' ? CHAR_WIDTH (ch) : 1;
ca4c9455
KH
370
371 /* A composition rule is specified by an integer value
372 that encodes global and new reference points (GREF and
373 NREF). GREF and NREF are specified by numbers as
374 below:
375 0---1---2 -- ascent
376 | |
377 | |
378 | |
379 9--10--11 -- center
380 | |
381 ---3---4---5--- baseline
382 | |
383 6---7---8 -- descent
384 */
464f8566 385 COMPOSITION_DECODE_RULE (rule, gref, nref, xoff, yoff);
ca4c9455
KH
386 this_left = (leftmost
387 + (gref % 3) * (rightmost - leftmost) / 2.0
388 - (nref % 3) * this_width / 2.0);
389
390 if (this_left < leftmost)
391 leftmost = this_left;
392 if (this_left + this_width > rightmost)
393 rightmost = this_left + this_width;
394 }
395
396 cmp->width = rightmost - leftmost;
397 if (cmp->width < (rightmost - leftmost))
398 /* To get a ceiling integer value. */
399 cmp->width++;
400 }
401
402 composition_table[n_compositions] = cmp;
403
404 return n_compositions++;
405
406 invalid_composition:
407 /* Would it be better to remove this `composition' property? */
408 return -1;
409}
410
411\f
90b3fe91
KH
412/* Find a static composition at or nearest to position POS of OBJECT
413 (buffer or string).
ca4c9455
KH
414
415 OBJECT defaults to the current buffer. If there's a composition at
416 POS, set *START and *END to the start and end of the sequence,
417 *PROP to the `composition' property, and return 1.
418
419 If there's no composition at POS and LIMIT is negative, return 0.
420
421 Otherwise, search for a composition forward (LIMIT > POS) or
422 backward (LIMIT < POS). In this case, LIMIT bounds the search.
423
424 If a composition is found, set *START, *END, and *PROP as above,
425 and return 1, else return 0.
426
427 This doesn't check the validity of composition. */
428
429int
430find_composition (pos, limit, start, end, prop, object)
aaefca97
DL
431 int pos, limit;
432 EMACS_INT *start, *end;
ca4c9455
KH
433 Lisp_Object *prop, object;
434{
435 Lisp_Object val;
436
437 if (get_property_and_range (pos, Qcomposition, prop, start, end, object))
438 return 1;
439
440 if (limit < 0 || limit == pos)
441 return 0;
442
443 if (limit > pos) /* search forward */
d279f620
KH
444 {
445 val = Fnext_single_property_change (make_number (pos), Qcomposition,
446 object, make_number (limit));
447 pos = XINT (val);
448 if (pos == limit)
449 return 0;
450 }
ca4c9455 451 else /* search backward */
d279f620
KH
452 {
453 if (get_property_and_range (pos - 1, Qcomposition, prop, start, end,
454 object))
455 return 1;
456 val = Fprevious_single_property_change (make_number (pos), Qcomposition,
457 object, make_number (limit));
458 pos = XINT (val);
459 if (pos == limit)
460 return 0;
461 pos--;
462 }
ca4c9455
KH
463 get_property_and_range (pos, Qcomposition, prop, start, end, object);
464 return 1;
465}
466
467/* Run a proper function to adjust the composition sitting between
468 FROM and TO with property PROP. */
469
470static void
471run_composition_function (from, to, prop)
472 int from, to;
473 Lisp_Object prop;
474{
7d019510 475 Lisp_Object func;
aaefca97 476 EMACS_INT start, end;
ca4c9455
KH
477
478 func = COMPOSITION_MODIFICATION_FUNC (prop);
479 /* If an invalid composition precedes or follows, try to make them
480 valid too. */
481 if (from > BEGV
482 && find_composition (from - 1, -1, &start, &end, &prop, Qnil)
483 && !COMPOSITION_VALID_P (start, end, prop))
484 from = start;
485 if (to < ZV
486 && find_composition (to, -1, &start, &end, &prop, Qnil)
487 && !COMPOSITION_VALID_P (start, end, prop))
488 to = end;
775b3d2d 489 if (!NILP (Ffboundp (func)))
ca4c9455 490 call2 (func, make_number (from), make_number (to));
ca4c9455
KH
491}
492
493/* Make invalid compositions adjacent to or inside FROM and TO valid.
494 CHECK_MASK is bitwise `or' of mask bits defined by macros
495 CHECK_XXX (see the comment in composite.h).
496
b418f8a6 497 It also resets the text-property `auto-composed' to a proper region
f96ba4c1
KH
498 so that automatic character composition works correctly later while
499 displaying the region.
8f924df7 500
ca4c9455
KH
501 This function is called when a buffer text is changed. If the
502 change is deletion, FROM == TO. Otherwise, FROM < TO. */
503
504void
505update_compositions (from, to, check_mask)
aaefca97
DL
506 EMACS_INT from, to;
507 int check_mask;
ca4c9455 508{
7d019510 509 Lisp_Object prop;
aaefca97 510 EMACS_INT start, end;
f96ba4c1
KH
511 /* The beginning and end of the region to set the property
512 `auto-composed' to nil. */
aaefca97 513 EMACS_INT min_pos = from, max_pos = to;
ca4c9455 514
6c1aa7f1
GM
515 if (inhibit_modification_hooks)
516 return;
177c0ea7 517
d3f40cbd
KH
518 /* If FROM and TO are not in a valid range, do nothing. */
519 if (! (BEGV <= from && from <= to && to <= ZV))
520 return;
521
ca4c9455
KH
522 if (check_mask & CHECK_HEAD)
523 {
524 /* FROM should be at composition boundary. But, insertion or
525 deletion will make two compositions adjacent and
526 indistinguishable when they have same (eq) property. To
527 avoid it, in such a case, we change the property of the
528 latter to the copy of it. */
529 if (from > BEGV
553d3164
KH
530 && find_composition (from - 1, -1, &start, &end, &prop, Qnil)
531 && COMPOSITION_VALID_P (start, end, prop))
ca4c9455 532 {
f96ba4c1
KH
533 min_pos = start;
534 if (end > to)
535 max_pos = end;
ca4c9455
KH
536 if (from < end)
537 Fput_text_property (make_number (from), make_number (end),
538 Qcomposition,
539 Fcons (XCAR (prop), XCDR (prop)), Qnil);
540 run_composition_function (start, end, prop);
541 from = end;
542 }
dd33cc56 543 else if (from < ZV
553d3164 544 && find_composition (from, -1, &start, &from, &prop, Qnil)
9657d668 545 && COMPOSITION_VALID_P (start, from, prop))
f96ba4c1
KH
546 {
547 if (from > to)
548 max_pos = from;
549 run_composition_function (start, from, prop);
550 }
ca4c9455
KH
551 }
552
553 if (check_mask & CHECK_INSIDE)
554 {
555 /* In this case, we are sure that (check & CHECK_TAIL) is also
556 nonzero. Thus, here we should check only compositions before
557 (to - 1). */
558 while (from < to - 1
559 && find_composition (from, to, &start, &from, &prop, Qnil)
9657d668 560 && COMPOSITION_VALID_P (start, from, prop)
ca4c9455
KH
561 && from < to - 1)
562 run_composition_function (start, from, prop);
563 }
564
565 if (check_mask & CHECK_TAIL)
566 {
567 if (from < to
553d3164
KH
568 && find_composition (to - 1, -1, &start, &end, &prop, Qnil)
569 && COMPOSITION_VALID_P (start, end, prop))
ca4c9455
KH
570 {
571 /* TO should be also at composition boundary. But,
572 insertion or deletion will make two compositions adjacent
573 and indistinguishable when they have same (eq) property.
574 To avoid it, in such a case, we change the property of
575 the former to the copy of it. */
576 if (to < end)
f96ba4c1
KH
577 {
578 Fput_text_property (make_number (start), make_number (to),
579 Qcomposition,
580 Fcons (XCAR (prop), XCDR (prop)), Qnil);
581 max_pos = end;
582 }
ca4c9455
KH
583 run_composition_function (start, end, prop);
584 }
585 else if (to < ZV
553d3164
KH
586 && find_composition (to, -1, &start, &end, &prop, Qnil)
587 && COMPOSITION_VALID_P (start, end, prop))
f96ba4c1
KH
588 {
589 run_composition_function (start, end, prop);
590 max_pos = end;
591 }
ca4c9455 592 }
f96ba4c1 593 if (min_pos < max_pos)
9d440521
KH
594 {
595 int count = SPECPDL_INDEX ();
596
597 specbind (Qinhibit_read_only, Qt);
598 specbind (Qinhibit_modification_hooks, Qt);
599 specbind (Qinhibit_point_motion_hooks, Qt);
600 Fremove_list_of_text_properties (make_number (min_pos),
601 make_number (max_pos),
602 Fcons (Qauto_composed, Qnil), Qnil);
603 unbind_to (count, Qnil);
604 }
ca4c9455
KH
605}
606
c1361885
KH
607
608/* Modify composition property values in LIST destructively. LIST is
609 a list as returned from text_property_list. Change values to the
610 top-level copies of them so that none of them are `eq'. */
611
612void
613make_composition_value_copy (list)
614 Lisp_Object list;
615{
616 Lisp_Object plist, val;
617
618 for (; CONSP (list); list = XCDR (list))
619 {
620 plist = XCAR (XCDR (XCDR (XCAR (list))));
621 while (CONSP (plist) && CONSP (XCDR (plist)))
622 {
623 if (EQ (XCAR (plist), Qcomposition)
624 && (val = XCAR (XCDR (plist)), CONSP (val)))
f3fbd155 625 XSETCAR (XCDR (plist), Fcons (XCAR (val), XCDR (val)));
c1361885
KH
626 plist = XCDR (XCDR (plist));
627 }
628 }
629}
630
631
ca4c9455
KH
632/* Make text in the region between START and END a composition that
633 has COMPONENTS and MODIFICATION-FUNC.
634
635 If STRING is non-nil, then operate on characters contained between
636 indices START and END in STRING. */
637
638void
639compose_text (start, end, components, modification_func, string)
640 int start, end;
641 Lisp_Object components, modification_func, string;
642{
643 Lisp_Object prop;
644
645 prop = Fcons (Fcons (make_number (end - start), components),
646 modification_func);
647 Fput_text_property (make_number (start), make_number (end),
648 Qcomposition, prop, string);
649}
58753d74
KH
650
651
652static Lisp_Object autocmp_chars P_ ((Lisp_Object, EMACS_INT, EMACS_INT,
653 EMACS_INT, struct window *,
654 struct face *, Lisp_Object));
655
656\f
657/* Lisp glyph-string handlers */
658
659/* Hash table for automatic composition. The key is a header of a
660 lgstring (Lispy glyph-string), and the value is a body of a
661 lgstring. */
662
663static Lisp_Object gstring_hash_table;
664
665static Lisp_Object gstring_lookup_cache P_ ((Lisp_Object));
666
667static Lisp_Object
668gstring_lookup_cache (header)
669 Lisp_Object header;
670{
671 struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
672 int i = hash_lookup (h, header, NULL);
673
674 return (i >= 0 ? HASH_VALUE (h, i) : Qnil);
675}
676
677Lisp_Object
678composition_gstring_put_cache (gstring, len)
679 Lisp_Object gstring;
680 int len;
681{
682 struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
683 unsigned hash;
684 Lisp_Object header, copy;
685 int i;
686
687 header = LGSTRING_HEADER (gstring);
688 hash = h->hashfn (h, header);
689 if (len < 0)
690 {
691 len = LGSTRING_GLYPH_LEN (gstring);
692 for (i = 0; i < len; i++)
693 if (NILP (LGSTRING_GLYPH (gstring, i)))
694 break;
695 len = i;
696 }
087e2ea9 697
58753d74
KH
698 copy = Fmake_vector (make_number (len + 2), Qnil);
699 LGSTRING_SET_HEADER (copy, Fcopy_sequence (header));
700 for (i = 0; i < len; i++)
701 LGSTRING_SET_GLYPH (copy, i, Fcopy_sequence (LGSTRING_GLYPH (gstring, i)));
702 i = hash_put (h, LGSTRING_HEADER (copy), copy, hash);
703 LGSTRING_SET_ID (copy, make_number (i));
704 return copy;
705}
706
707Lisp_Object
708composition_gstring_from_id (id)
709 int id;
710{
711 struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
712
713 return HASH_VALUE (h, id);
714}
715
716static Lisp_Object fill_gstring_header P_ ((Lisp_Object, Lisp_Object,
717 Lisp_Object, Lisp_Object,
718 Lisp_Object));
719
720int
721composition_gstring_p (gstring)
722 Lisp_Object gstring;
723{
724 Lisp_Object header;
725 int i;
726
727 if (! VECTORP (gstring) || ASIZE (gstring) < 2)
728 return 0;
729 header = LGSTRING_HEADER (gstring);
730 if (! VECTORP (header) || ASIZE (header) < 2)
731 return 0;
732 if (! NILP (LGSTRING_FONT (gstring))
f5199465
KH
733 && (! FONT_OBJECT_P (LGSTRING_FONT (gstring))
734 && ! CODING_SYSTEM_P (LGSTRING_FONT (gstring))))
58753d74
KH
735 return 0;
736 for (i = 1; i < ASIZE (LGSTRING_HEADER (gstring)); i++)
737 if (! NATNUMP (AREF (LGSTRING_HEADER (gstring), i)))
738 return 0;
739 if (! NILP (LGSTRING_ID (gstring)) && ! NATNUMP (LGSTRING_ID (gstring)))
740 return 0;
741 for (i = 0; i < LGSTRING_GLYPH_LEN (gstring); i++)
742 {
743 Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
744 if (NILP (glyph))
745 break;
746 if (! VECTORP (glyph) || ASIZE (glyph) != LGLYPH_SIZE)
747 return 0;
748 }
749 return 1;
750}
751
752int
753composition_gstring_width (gstring, from, to, metrics)
754 Lisp_Object gstring;
755 int from, to;
756 struct font_metrics *metrics;
757{
758 Lisp_Object *glyph;
759 int width = 0;
760
761 if (metrics)
762 {
763 Lisp_Object font_object = LGSTRING_FONT (gstring);
58753d74 764
f5199465
KH
765 if (FONT_OBJECT_P (font_object))
766 {
767 struct font *font = XFONT_OBJECT (font_object);
768
769 metrics->ascent = font->ascent;
770 metrics->descent = font->descent;
771 }
772 else
773 {
774 metrics->ascent = 1;
775 metrics->descent = 0;
776 }
58753d74
KH
777 metrics->width = metrics->lbearing = metrics->rbearing = 0;
778 }
779 for (glyph = &LGSTRING_GLYPH (gstring, from); from < to; from++, glyph++)
780 {
781 int x;
782
783 if (NILP (LGLYPH_ADJUSTMENT (*glyph)))
784 width += LGLYPH_WIDTH (*glyph);
785 else
786 width += LGLYPH_WADJUST (*glyph);
787 if (metrics)
788 {
789 x = metrics->width + LGLYPH_LBEARING (*glyph) + LGLYPH_XOFF (*glyph);
790 if (metrics->lbearing > x)
791 metrics->lbearing = x;
792 x = metrics->width + LGLYPH_RBEARING (*glyph) + LGLYPH_XOFF (*glyph);
793 if (metrics->rbearing < x)
794 metrics->rbearing = x;
795 metrics->width = width;
796 x = LGLYPH_ASCENT (*glyph) - LGLYPH_YOFF (*glyph);
797 if (metrics->ascent < x)
798 metrics->ascent = x;
895416e3 799 x = LGLYPH_DESCENT (*glyph) + LGLYPH_YOFF (*glyph);
58753d74
KH
800 if (metrics->descent < x)
801 metrics->descent = x;
802 }
803 }
804 return width;
805}
806
807
808static Lisp_Object gstring_work;
809static Lisp_Object gstring_work_headers;
810
811static Lisp_Object
812fill_gstring_header (header, start, end, font_object, string)
813 Lisp_Object header, start, end, font_object, string;
814{
815 EMACS_INT from, to, from_byte;
816 EMACS_INT len, i;
817
818 if (NILP (string))
819 {
820 if (NILP (current_buffer->enable_multibyte_characters))
821 error ("Attempt to shape unibyte text");
822 validate_region (&start, &end);
823 from = XFASTINT (start);
824 to = XFASTINT (end);
825 from_byte = CHAR_TO_BYTE (from);
826 }
827 else
828 {
829 CHECK_STRING (string);
793ffee8 830 if (! STRING_MULTIBYTE (string))
58753d74 831 error ("Attempt to shape unibyte text");
ea8ba975 832 /* FROM and TO are checked by the caller. */
58753d74 833 from = XINT (start);
58753d74
KH
834 to = XINT (end);
835 if (from < 0 || from > to || to > SCHARS (string))
836 args_out_of_range_3 (string, start, end);
837 from_byte = string_char_to_byte (string, from);
838 }
839
840 len = to - from;
841 if (len == 0)
842 error ("Attempt to shape zero-length text");
843 if (VECTORP (header))
844 {
845 if (ASIZE (header) != len + 1)
846 args_out_of_range (header, make_number (len + 1));
847 }
848 else
849 {
850 if (len <= 8)
851 header = AREF (gstring_work_headers, len - 1);
852 else
853 header = Fmake_vector (make_number (len + 1), Qnil);
854 }
855
856 ASET (header, 0, font_object);
857 for (i = 0; i < len; i++)
858 {
859 int c;
860
861 if (NILP (string))
862 FETCH_CHAR_ADVANCE_NO_CHECK (c, from, from_byte);
863 else
864 FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string, from, from_byte);
865 ASET (header, i + 1, make_number (c));
866 }
867 return header;
868}
869
870extern void font_fill_lglyph_metrics P_ ((Lisp_Object, Lisp_Object));
871
872static void
873fill_gstring_body (gstring)
874 Lisp_Object gstring;
875{
876 Lisp_Object font_object = LGSTRING_FONT (gstring);
877 Lisp_Object header = AREF (gstring, 0);
878 EMACS_INT len = LGSTRING_CHAR_LEN (gstring);
879 EMACS_INT i;
880
881 for (i = 0; i < len; i++)
882 {
883 Lisp_Object g = LGSTRING_GLYPH (gstring, i);
77fa4db2 884 EMACS_INT c = XINT (AREF (header, i + 1));
58753d74
KH
885
886 if (NILP (g))
887 {
888 g = LGLYPH_NEW ();
889 LGSTRING_SET_GLYPH (gstring, i, g);
890 }
891 LGLYPH_SET_FROM (g, i);
892 LGLYPH_SET_TO (g, i);
893 LGLYPH_SET_CHAR (g, c);
f5199465 894 if (FONT_OBJECT_P (font_object))
58753d74
KH
895 {
896 font_fill_lglyph_metrics (g, font_object);
897 }
898 else
899 {
900 int width = XFASTINT (CHAR_TABLE_REF (Vchar_width_table, c));
901
902 LGLYPH_SET_CODE (g, c);
903 LGLYPH_SET_LBEARING (g, 0);
904 LGLYPH_SET_RBEARING (g, width);
905 LGLYPH_SET_WIDTH (g, width);
906 LGLYPH_SET_ASCENT (g, 1);
907 LGLYPH_SET_DESCENT (g, 0);
908 }
909 LGLYPH_SET_ADJUSTMENT (g, Qnil);
910 }
911 if (i < LGSTRING_GLYPH_LEN (gstring))
912 LGSTRING_SET_GLYPH (gstring, i, Qnil);
913}
914
58753d74
KH
915
916/* Try to compose the characters at CHARPOS according to CFT_ELEMENT
087e2ea9 917 which is an element of composition-function-table (which see).
58753d74
KH
918 LIMIT limits the characters to compose. STRING, if not nil, is a
919 target string. WIN is a window where the characters are being
920 displayed. */
921
922static Lisp_Object
923autocmp_chars (cft_element, charpos, bytepos, limit, win, face, string)
924 Lisp_Object cft_element;
925 EMACS_INT charpos, bytepos, limit;
926 struct window *win;
927 struct face *face;
928 Lisp_Object string;
929{
930 int count = SPECPDL_INDEX ();
931 FRAME_PTR f = XFRAME (win->frame);
932 Lisp_Object pos = make_number (charpos);
933 EMACS_INT pt = PT, pt_byte = PT_BYTE;
90b3fe91 934 int lookback;
087e2ea9 935
58753d74 936 record_unwind_save_match_data ();
90b3fe91 937 for (lookback = -1; CONSP (cft_element); cft_element = XCDR (cft_element))
58753d74
KH
938 {
939 Lisp_Object elt = XCAR (cft_element);
940 Lisp_Object re;
941 Lisp_Object font_object = Qnil, gstring;
895416e3 942 EMACS_INT len, to;
58753d74
KH
943
944 if (! VECTORP (elt) || ASIZE (elt) != 3)
945 continue;
90b3fe91 946 if (lookback < 0)
895416e3
KH
947 {
948 lookback = XFASTINT (AREF (elt, 1));
949 if (limit > charpos + MAX_COMPOSITION_COMPONENTS)
950 limit = charpos + MAX_COMPOSITION_COMPONENTS;
951 }
90b3fe91
KH
952 else if (lookback != XFASTINT (AREF (elt, 1)))
953 break;
58753d74 954 re = AREF (elt, 0);
895416e3
KH
955 if (NILP (re))
956 len = 1;
957 else if ((len = fast_looking_at (re, charpos, bytepos, limit, -1, string))
958 > 0)
58753d74 959 {
895416e3
KH
960 if (NILP (string))
961 len = BYTE_TO_CHAR (bytepos + len) - charpos;
962 else
963 len = string_byte_to_char (string, bytepos + len) - charpos;
964 }
965 if (len > 0)
966 {
967 limit = to = charpos + len;
58753d74
KH
968#ifdef HAVE_WINDOW_SYSTEM
969 if (FRAME_WINDOW_P (f))
970 {
971 font_object = font_range (charpos, &to, win, face, string);
895416e3
KH
972 if (! FONT_OBJECT_P (font_object)
973 || (! NILP (re)
974 && to < limit
975 && (fast_looking_at (re, charpos, bytepos, to, -1, string) <= 0)))
58753d74
KH
976 {
977 if (NILP (string))
978 TEMP_SET_PT_BOTH (pt, pt_byte);
979 return unbind_to (count, Qnil);
980 }
981 }
f5199465 982 else
58753d74 983#endif /* not HAVE_WINDOW_SYSTEM */
f5199465 984 font_object = win->frame;
58753d74
KH
985 gstring = Fcomposition_get_gstring (pos, make_number (to),
986 font_object, string);
987 if (NILP (LGSTRING_ID (gstring)))
988 {
989 Lisp_Object args[6];
990
991 args[0] = Vauto_composition_function;
992 args[1] = AREF (elt, 2);
993 args[2] = pos;
994 args[3] = make_number (to);
995 args[4] = font_object;
996 args[5] = string;
997 gstring = safe_call (6, args);
998 }
999 if (NILP (string))
1000 TEMP_SET_PT_BOTH (pt, pt_byte);
1001 return unbind_to (count, gstring);
1002 }
1003 }
1004 if (NILP (string))
1005 TEMP_SET_PT_BOTH (pt, pt_byte);
1006 return unbind_to (count, Qnil);
1007}
1008
1009
1010/* Update cmp_it->stop_pos to the next position after CHARPOS (and
1011 BYTEPOS) where character composition may happen. If BYTEPOS is
1012 negative, compoute it. If it is a static composition, set
1013 cmp_it->ch to -1. Otherwise, set cmp_it->ch to the character that
1014 triggers a automatic composition. */
1015
1016void
1017composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string)
1018 struct composition_it *cmp_it;
1019 EMACS_INT charpos, bytepos, endpos;
1020 Lisp_Object string;
1021{
1022 EMACS_INT start, end, c;
1023 Lisp_Object prop, val;
3ffdafce
KH
1024 /* This is from forward_to_next_line_start in xdisp.c. */
1025 const int MAX_NEWLINE_DISTANCE = 500;
58753d74 1026
3ffdafce
KH
1027 if (endpos > charpos + MAX_NEWLINE_DISTANCE)
1028 endpos = charpos + MAX_NEWLINE_DISTANCE;
58753d74 1029 cmp_it->stop_pos = endpos;
053ca52b 1030 cmp_it->id = -1;
44566dc7 1031 cmp_it->ch = -2;
58753d74
KH
1032 if (find_composition (charpos, endpos, &start, &end, &prop, string)
1033 && COMPOSITION_VALID_P (start, end, prop))
1034 {
1035 cmp_it->stop_pos = endpos = start;
1036 cmp_it->ch = -1;
1037 }
f5199465
KH
1038 if (NILP (string) && PT > charpos && PT < endpos)
1039 cmp_it->stop_pos = PT;
58753d74
KH
1040 if (NILP (current_buffer->enable_multibyte_characters)
1041 || ! FUNCTIONP (Vauto_composition_function))
1042 return;
1043 if (bytepos < 0)
1044 {
1045 if (STRINGP (string))
1046 bytepos = string_char_to_byte (string, charpos);
1047 else
1048 bytepos = CHAR_TO_BYTE (charpos);
1049 }
1050
1051 start = charpos;
1052 while (charpos < endpos)
1053 {
1054 if (STRINGP (string))
1055 FETCH_STRING_CHAR_ADVANCE (c, string, charpos, bytepos);
1056 else
1057 FETCH_CHAR_ADVANCE (c, charpos, bytepos);
3ffdafce 1058 if (c == '\n')
ea8ba975
KH
1059 {
1060 cmp_it->ch = -2;
1061 break;
1062 }
58753d74
KH
1063 val = CHAR_TABLE_REF (Vcomposition_function_table, c);
1064 if (! NILP (val))
1065 {
1066 Lisp_Object elt;
1067
1068 for (; CONSP (val); val = XCDR (val))
1069 {
1070 elt = XCAR (val);
1071 if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1))
1072 && charpos - 1 - XFASTINT (AREF (elt, 1)) >= start)
1073 break;
1074 }
1075 if (CONSP (val))
1076 {
90b3fe91
KH
1077 cmp_it->lookback = XFASTINT (AREF (elt, 1));
1078 cmp_it->stop_pos = charpos - 1 - cmp_it->lookback;
58753d74 1079 cmp_it->ch = c;
44566dc7 1080 return;
58753d74
KH
1081 }
1082 }
1083 }
44566dc7 1084 cmp_it->stop_pos = charpos;
58753d74
KH
1085}
1086
1087/* Check if the character at CHARPOS (and BYTEPOS) is composed
22e33406 1088 (possibly with the following characters) on window W. ENDPOS limits
58753d74
KH
1089 characters to be composed. FACE, in non-NULL, is a base face of
1090 the character. If STRING is not nil, it is a string containing the
1091 character to check, and CHARPOS and BYTEPOS are indices in the
1092 string. In that case, FACE must not be NULL.
1093
1094 If the character is composed, setup members of CMP_IT (id, nglyphs,
1095 and from), and return 1. Otherwise, update CMP_IT->stop_pos, and
1096 return 0. */
1097
1098int
1099composition_reseat_it (cmp_it, charpos, bytepos, endpos, w, face, string)
1100 struct composition_it *cmp_it;
1101 EMACS_INT charpos, bytepos, endpos;
1102 struct window *w;
1103 struct face *face;
1104 Lisp_Object string;
1105{
3ffdafce
KH
1106 if (cmp_it->ch == -2)
1107 {
1108 composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string);
1109 if (cmp_it->ch == -2)
1110 return 0;
1111 }
1112
58753d74
KH
1113 if (cmp_it->ch < 0)
1114 {
1115 /* We are looking at a static composition. */
1116 EMACS_INT start, end;
1117 Lisp_Object prop;
1118
1119 find_composition (charpos, -1, &start, &end, &prop, string);
1120 cmp_it->id = get_composition_id (charpos, bytepos, end - start,
1121 prop, string);
1122 if (cmp_it->id < 0)
1123 goto no_composition;
1124 cmp_it->nchars = end - start;
1125 cmp_it->nglyphs = composition_table[cmp_it->id]->glyph_len;
1126 }
29fb7306 1127 else if (w)
58753d74 1128 {
90b3fe91 1129 Lisp_Object val, elt;
58753d74
KH
1130 int i;
1131
1132 val = CHAR_TABLE_REF (Vcomposition_function_table, cmp_it->ch);
90b3fe91
KH
1133 for (; CONSP (val); val = XCDR (val))
1134 {
1135 elt = XCAR (val);
1136 if (cmp_it->lookback == XFASTINT (AREF (elt, 1)))
1137 break;
1138 }
58753d74
KH
1139 if (NILP (val))
1140 goto no_composition;
90b3fe91 1141
58753d74
KH
1142 val = autocmp_chars (val, charpos, bytepos, endpos, w, face, string);
1143 if (! composition_gstring_p (val))
1144 goto no_composition;
1145 if (NILP (LGSTRING_ID (val)))
1146 val = composition_gstring_put_cache (val, -1);
1147 cmp_it->id = XINT (LGSTRING_ID (val));
1148 for (i = 0; i < LGSTRING_GLYPH_LEN (val); i++)
1149 if (NILP (LGSTRING_GLYPH (val, i)))
1150 break;
1151 cmp_it->nglyphs = i;
1152 }
29fb7306
KH
1153 else
1154 goto no_composition;
58753d74
KH
1155 cmp_it->from = 0;
1156 return 1;
1157
1158 no_composition:
1159 charpos++;
1160 if (STRINGP (string))
1161 bytepos += MULTIBYTE_LENGTH_NO_CHECK (SDATA (string) + bytepos);
1162 else
1163 INC_POS (bytepos);
1164 composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string);
1165 return 0;
1166}
1167
1168int
1169composition_update_it (cmp_it, charpos, bytepos, string)
1170 struct composition_it *cmp_it;
1171 EMACS_INT charpos, bytepos;
1172 Lisp_Object string;
1173{
1174 int i, c;
1175
1176 if (cmp_it->ch < 0)
1177 {
1178 struct composition *cmp = composition_table[cmp_it->id];
1179
1180 cmp_it->to = cmp_it->nglyphs;
1181 if (cmp_it->nglyphs == 0)
1182 c = -1;
1183 else
1184 {
1185 for (i = 0; i < cmp->glyph_len; i++)
1186 if ((c = COMPOSITION_GLYPH (cmp, i)) != '\t')
1187 break;
1188 if (c == '\t')
1189 c = ' ';
1190 }
1191 cmp_it->width = cmp->width;
1192 }
1193 else
1194 {
1195 Lisp_Object gstring = composition_gstring_from_id (cmp_it->id);
1196
1197 if (cmp_it->nglyphs == 0)
1198 {
1199 c = -1;
1200 cmp_it->nchars = LGSTRING_CHAR_LEN (gstring);
1201 cmp_it->width = 0;
1202 }
1203 else
1204 {
1205 Lisp_Object glyph = LGSTRING_GLYPH (gstring, cmp_it->from);
1206 int from = LGLYPH_FROM (glyph);
1207
c7c7a80c 1208 c = XINT (LGSTRING_CHAR (gstring, from));
58753d74
KH
1209 cmp_it->nchars = LGLYPH_TO (glyph) - from + 1;
1210 cmp_it->width = (LGLYPH_WIDTH (glyph) > 0
1211 ? CHAR_WIDTH (LGLYPH_CHAR (glyph)) : 0);
1212 for (cmp_it->to = cmp_it->from + 1; cmp_it->to < cmp_it->nglyphs;
1213 cmp_it->to++)
1214 {
1215 glyph = LGSTRING_GLYPH (gstring, cmp_it->to);
1216 if (LGLYPH_FROM (glyph) != from)
1217 break;
1218 if (LGLYPH_WIDTH (glyph) > 0)
1219 cmp_it->width += CHAR_WIDTH (LGLYPH_CHAR (glyph));
1220 }
1221 }
1222 }
1223
1224 charpos += cmp_it->nchars;
1225 if (STRINGP (string))
1226 cmp_it->nbytes = string_char_to_byte (string, charpos) - bytepos;
1227 else
1228 cmp_it->nbytes = CHAR_TO_BYTE (charpos) - bytepos;
1229 return c;
1230}
1231
1232
90b3fe91
KH
1233struct position_record
1234{
1235 EMACS_INT pos, pos_byte;
1236 unsigned char *p;
1237};
1238
1239/* Update the members of POSTION to the next character boundary. */
1240#define FORWARD_CHAR(POSITION, STOP) \
1241 do { \
90b3fe91 1242 (POSITION).pos++; \
900c4486
KH
1243 if ((POSITION).pos == (STOP)) \
1244 { \
1245 (POSITION).p = GAP_END_ADDR; \
1246 (POSITION).pos_byte = GPT_BYTE; \
1247 } \
1248 else \
1249 { \
900c4486 1250 (POSITION).pos_byte += BYTES_BY_CHAR_HEAD (*((POSITION).p)); \
d45a49e3 1251 (POSITION).p += BYTES_BY_CHAR_HEAD (*((POSITION).p)); \
900c4486 1252 } \
90b3fe91
KH
1253 } while (0)
1254
1255/* Update the members of POSTION to the previous character boundary. */
1256#define BACKWARD_CHAR(POSITION, STOP) \
1257 do { \
1258 if ((POSITION).pos == STOP) \
1259 (POSITION).p = GPT_ADDR; \
1260 do { \
1261 (POSITION).pos_byte--; \
1262 (POSITION).p--; \
1263 } while (! CHAR_HEAD_P (*((POSITION).p))); \
1264 (POSITION).pos--; \
1265 } while (0)
1266
1267static Lisp_Object _work_val;
1268static int _work_char;
1269
1270/* 1 iff the character C is composable. */
1271#define CHAR_COMPOSABLE_P(C) \
1272 (_work_val = CHAR_TABLE_REF (Vunicode_category_table, (C)), \
1273 (SYMBOLP (_work_val) \
1274 && (_work_char = SDATA (SYMBOL_NAME (_work_val))[0]) != 'C' \
1275 && _work_char != 'Z'))
1276
1277/* This is like find_composition, but find an automatic composition
1278 instead. If found, set *GSTRING to the glyph-string representing
1279 the composition, and return 1. Otherwise, return 0. */
1280
1281static int
1282find_automatic_composition (pos, limit, start, end, gstring, string)
1283 EMACS_INT pos, limit, *start, *end;
1284 Lisp_Object *gstring, string;
1285{
1286 EMACS_INT head, tail, stop;
895416e3
KH
1287 /* Limit to check a composition after POS. */
1288 EMACS_INT fore_check_limit;
90b3fe91
KH
1289 struct position_record orig, cur, check, prev;
1290 Lisp_Object check_val, val, elt;
1291 int check_lookback;
1292 int c;
29fb7306 1293 Lisp_Object window;
90b3fe91
KH
1294 struct window *w;
1295
3eda4b19 1296 window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
29fb7306
KH
1297 if (NILP (window))
1298 return 0;
1299 w = XWINDOW (window);
1300
90b3fe91
KH
1301 orig.pos = pos;
1302 if (NILP (string))
1303 {
1304 head = BEGV, tail = ZV, stop = GPT;
1305 orig.pos_byte = CHAR_TO_BYTE (orig.pos);
1306 orig.p = BYTE_POS_ADDR (orig.pos_byte);
1307 }
1308 else
1309 {
1310 head = 0, tail = SCHARS (string), stop = -1;
1311 orig.pos_byte = string_char_to_byte (string, orig.pos);
1312 orig.p = SDATA (string) + orig.pos_byte;
1313 }
1314 if (limit < pos)
895416e3 1315 fore_check_limit = min (tail, pos + MAX_AUTO_COMPOSITION_LOOKBACK);
90b3fe91 1316 else
895416e3 1317 fore_check_limit = min (tail, limit + MAX_AUTO_COMPOSITION_LOOKBACK);
90b3fe91
KH
1318 cur = orig;
1319
1320 retry:
1321 check_val = Qnil;
895416e3 1322 /* At first, check if POS is composable. */
90b3fe91
KH
1323 c = STRING_CHAR (cur.p, 0);
1324 if (! CHAR_COMPOSABLE_P (c))
1325 {
1326 if (limit < 0)
1327 return 0;
1328 if (limit >= cur.pos)
1329 goto search_forward;
1330 }
1331 else
1332 {
1333 val = CHAR_TABLE_REF (Vcomposition_function_table, c);
1334 if (! NILP (val))
1335 check_val = val, check = cur;
1336 else
895416e3 1337 while (cur.pos + 1 < fore_check_limit)
90b3fe91 1338 {
895416e3
KH
1339 EMACS_INT b, e;
1340
90b3fe91 1341 FORWARD_CHAR (cur, stop);
895416e3
KH
1342 if (get_property_and_range (cur.pos, Qcomposition, &val, &b, &e,
1343 Qnil)
1344 && COMPOSITION_VALID_P (b, e, val))
1345 {
1346 fore_check_limit = cur.pos;
1347 break;
1348 }
90b3fe91
KH
1349 c = STRING_CHAR (cur.p, 0);
1350 if (! CHAR_COMPOSABLE_P (c))
1351 break;
1352 val = CHAR_TABLE_REF (Vcomposition_function_table, c);
1353 if (NILP (val))
1354 continue;
1355 check_val = val, check = cur;
1356 break;
1357 }
1358 cur = orig;
1359 }
1360 /* Rewind back to the position where we can safely search forward
1361 for compositions. */
1362 while (cur.pos > head)
1363 {
895416e3
KH
1364 EMACS_INT b, e;
1365
90b3fe91 1366 BACKWARD_CHAR (cur, stop);
895416e3
KH
1367 if (get_property_and_range (cur.pos, Qcomposition, &val, &b, &e, Qnil)
1368 && COMPOSITION_VALID_P (b, e, val))
1369 break;
90b3fe91
KH
1370 c = STRING_CHAR (cur.p, 0);
1371 if (! CHAR_COMPOSABLE_P (c))
1372 break;
1373 val = CHAR_TABLE_REF (Vcomposition_function_table, c);
1374 if (! NILP (val))
1375 check_val = val, check = cur;
1376 }
1377 prev = cur;
1378 /* Now search forward. */
087e2ea9 1379 search_forward:
90b3fe91
KH
1380 *gstring = Qnil;
1381 if (! NILP (check_val) || limit >= orig.pos)
1382 {
1383 if (NILP (check_val))
1384 cur = orig;
1385 else
1386 cur = check;
895416e3 1387 while (cur.pos < fore_check_limit)
90b3fe91
KH
1388 {
1389 int need_adjustment = 0;
1390
1391 if (NILP (check_val))
1392 {
1393 c = STRING_CHAR (cur.p, 0);
1394 check_val = CHAR_TABLE_REF (Vcomposition_function_table, c);
1395 }
1396 for (; CONSP (check_val); check_val = XCDR (check_val))
1397 {
1398 elt = XCAR (check_val);
1399 if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1))
1400 && cur.pos - XFASTINT (AREF (elt, 1)) >= head)
1401 {
1402 check.pos = cur.pos - XFASTINT (AREF (elt, 1));
1403 if (check.pos == cur.pos)
1404 check.pos_byte = cur.pos_byte;
1405 else
1406 check.pos_byte = CHAR_TO_BYTE (check.pos);
1407 val = autocmp_chars (check_val, check.pos, check.pos_byte,
1408 tail, w, NULL, string);
1409 need_adjustment = 1;
1410 if (! NILP (val))
1411 {
1412 *gstring = val;
1413 *start = check.pos;
1414 *end = check.pos + LGSTRING_CHAR_LEN (*gstring);
1415 if (*start <= orig.pos ? *end > orig.pos
1416 : limit >= orig.pos)
1417 return 1;
1418 cur.pos = *end;
1419 cur.pos_byte = CHAR_TO_BYTE (cur.pos);
1420 break;
1421 }
1422 }
1423 }
1424 if (need_adjustment)
1425 {
1426 /* As we have called Lisp, there's a possibilily that
1427 buffer/string is relocated. */
1428 if (NILP (string))
1429 cur.p = BYTE_POS_ADDR (cur.pos_byte);
1430 else
1431 cur.p = SDATA (string) + cur.pos_byte;
1432 }
1433 if (! CONSP (check_val))
1434 FORWARD_CHAR (cur, stop);
1435 check_val = Qnil;
1436 }
1437 }
1438 if (! NILP (*gstring))
1439 return (limit >= 0 || (*start <= orig.pos && *end > orig.pos));
1440 if (limit >= 0 && limit < orig.pos && prev.pos > head)
1441 {
1442 cur = prev;
1443 BACKWARD_CHAR (cur, stop);
1444 orig = cur;
895416e3 1445 fore_check_limit = orig.pos;
90b3fe91
KH
1446 goto retry;
1447 }
1448 return 0;
1449}
1450
58753d74
KH
1451int
1452composition_adjust_point (last_pt)
1453 EMACS_INT last_pt;
1454{
58753d74 1455 EMACS_INT charpos, bytepos, startpos, beg, end, pos;
90b3fe91
KH
1456 Lisp_Object val;
1457 int i;
58753d74
KH
1458
1459 if (PT == BEGV || PT == ZV)
1460 return PT;
1461
90b3fe91 1462 /* At first check the static composition. */
58753d74 1463 if (get_property_and_range (PT, Qcomposition, &val, &beg, &end, Qnil)
895416e3
KH
1464 && COMPOSITION_VALID_P (beg, end, val))
1465 {
1466 if (beg < PT /* && end > PT <- It's always the case. */
1467 && (last_pt <= beg || last_pt >= end))
1468 return (PT < last_pt ? beg : end);
1469 return PT;
1470 }
58753d74
KH
1471
1472 if (NILP (current_buffer->enable_multibyte_characters)
1473 || ! FUNCTIONP (Vauto_composition_function))
1474 return PT;
1475
90b3fe91 1476 /* Next check the automatic composition. */
939c679e 1477 if (! find_automatic_composition (PT, (EMACS_INT) -1, &beg, &end, &val, Qnil)
90b3fe91 1478 || beg == PT)
58753d74 1479 return PT;
90b3fe91 1480 for (i = 0; i < LGSTRING_GLYPH_LEN (val); i++)
58753d74 1481 {
90b3fe91 1482 Lisp_Object glyph = LGSTRING_GLYPH (val, i);
58753d74 1483
90b3fe91
KH
1484 if (NILP (glyph))
1485 break;
1486 if (beg + LGLYPH_FROM (glyph) == PT)
1487 return PT;
1488 if (beg + LGLYPH_TO (glyph) >= PT)
1489 return (PT < last_pt
1490 ? beg + LGLYPH_FROM (glyph)
1491 : beg + LGLYPH_TO (glyph) + 1);
58753d74
KH
1492 }
1493 return PT;
1494}
1495
1496DEFUN ("composition-get-gstring", Fcomposition_get_gstring,
1497 Scomposition_get_gstring, 4, 4, 0,
1498 doc: /* Return a glyph-string for characters between FROM and TO.
9d751859 1499If the glyph string is for graphic display, FONT-OBJECT must be
58753d74 1500a font-object to use for those characters.
f5199465
KH
1501Otherwise (for terminal display), FONT-OBJECT must be a terminal ID, a
1502frame, or nil for the selected frame's terminal device.
58753d74
KH
1503
1504If the optional 4th argument STRING is not nil, it is a string
1505containing the target characters between indices FROM and TO.
1506
9d751859
EZ
1507A glyph-string is a vector containing information about how to display
1508a specific character sequence. The format is:
58753d74
KH
1509 [HEADER ID GLYPH ...]
1510
1511HEADER is a vector of this form:
1512 [FONT-OBJECT CHAR ...]
1513where
1514 FONT-OBJECT is a font-object for all glyphs in the glyph-string,
f5199465 1515 or the terminal coding system of the specified terminal.
58753d74
KH
1516 CHARs are characters to be composed by GLYPHs.
1517
1518ID is an identification number of the glyph-string. It may be nil if
1519not yet shaped.
1520
9d751859 1521GLYPH is a vector whose elements have this form:
58753d74
KH
1522 [ FROM-IDX TO-IDX C CODE WIDTH LBEARING RBEARING ASCENT DESCENT
1523 [ [X-OFF Y-OFF WADJUST] | nil] ]
1524where
1525 FROM-IDX and TO-IDX are used internally and should not be touched.
1526 C is the character of the glyph.
1527 CODE is the glyph-code of C in FONT-OBJECT.
1528 WIDTH thru DESCENT are the metrics (in pixels) of the glyph.
9d751859 1529 X-OFF and Y-OFF are offsets to the base position for the glyph.
58753d74
KH
1530 WADJUST is the adjustment to the normal width of the glyph.
1531
9d751859
EZ
1532If GLYPH is nil, the remaining elements of the glyph-string vector
1533should be ignored. */)
58753d74
KH
1534 (from, to, font_object, string)
1535 Lisp_Object font_object, from, to, string;
1536{
1537 Lisp_Object gstring, header;
46f905e1 1538 EMACS_INT frompos, topos;
58753d74 1539
ea8ba975
KH
1540 CHECK_NATNUM (from);
1541 CHECK_NATNUM (to);
895416e3
KH
1542 if (XINT (to) > XINT (from) + MAX_COMPOSITION_COMPONENTS)
1543 to = make_number (XINT (from) + MAX_COMPOSITION_COMPONENTS);
f5199465
KH
1544 if (! FONT_OBJECT_P (font_object))
1545 {
1546 struct coding_system *coding;
1547 struct terminal *terminal = get_terminal (font_object, 1);
1548
1549 coding = ((TERMINAL_TERMINAL_CODING (terminal)->common_flags
1550 & CODING_REQUIRE_ENCODING_MASK)
1551 ? TERMINAL_TERMINAL_CODING (terminal) : &safe_terminal_coding);
1552 font_object = CODING_ID_NAME (coding->id);
1553 }
1554
58753d74
KH
1555 header = fill_gstring_header (Qnil, from, to, font_object, string);
1556 gstring = gstring_lookup_cache (header);
1557 if (! NILP (gstring))
1558 return gstring;
46f905e1 1559
ea8ba975
KH
1560 frompos = XINT (from);
1561 topos = XINT (to);
46f905e1
SM
1562 if (LGSTRING_GLYPH_LEN (gstring_work) < topos - frompos)
1563 gstring_work = Fmake_vector (make_number (topos - frompos + 2), Qnil);
58753d74
KH
1564 LGSTRING_SET_HEADER (gstring_work, header);
1565 LGSTRING_SET_ID (gstring_work, Qnil);
1566 fill_gstring_body (gstring_work);
1567 return gstring_work;
1568}
1569
ca4c9455
KH
1570\f
1571/* Emacs Lisp APIs. */
1572
1573DEFUN ("compose-region-internal", Fcompose_region_internal,
1574 Scompose_region_internal, 2, 4, 0,
335c5470
PJ
1575 doc: /* Internal use only.
1576
1577Compose text in the region between START and END.
1578Optional 3rd and 4th arguments are COMPONENTS and MODIFICATION-FUNC
9d751859 1579for the composition. See `compose-region' for more details. */)
d562f8ab
JB
1580 (start, end, components, modification_func)
1581 Lisp_Object start, end, components, modification_func;
ca4c9455
KH
1582{
1583 validate_region (&start, &end);
1584 if (!NILP (components)
1585 && !INTEGERP (components)
1586 && !CONSP (components)
1587 && !STRINGP (components))
b7826503 1588 CHECK_VECTOR (components);
ca4c9455 1589
d562f8ab 1590 compose_text (XINT (start), XINT (end), components, modification_func, Qnil);
ca4c9455
KH
1591 return Qnil;
1592}
1593
1594DEFUN ("compose-string-internal", Fcompose_string_internal,
1595 Scompose_string_internal, 3, 5, 0,
335c5470
PJ
1596 doc: /* Internal use only.
1597
1598Compose text between indices START and END of STRING.
1599Optional 4th and 5th arguments are COMPONENTS and MODIFICATION-FUNC
9d751859 1600for the composition. See `compose-string' for more details. */)
d562f8ab
JB
1601 (string, start, end, components, modification_func)
1602 Lisp_Object string, start, end, components, modification_func;
ca4c9455 1603{
b7826503
PJ
1604 CHECK_STRING (string);
1605 CHECK_NUMBER (start);
1606 CHECK_NUMBER (end);
ca4c9455
KH
1607
1608 if (XINT (start) < 0 ||
1609 XINT (start) > XINT (end)
d5db4077 1610 || XINT (end) > SCHARS (string))
ca4c9455
KH
1611 args_out_of_range (start, end);
1612
d562f8ab 1613 compose_text (XINT (start), XINT (end), components, modification_func, string);
ca4c9455
KH
1614 return string;
1615}
1616
1617DEFUN ("find-composition-internal", Ffind_composition_internal,
177c0ea7 1618 Sfind_composition_internal, 4, 4, 0,
335c5470
PJ
1619 doc: /* Internal use only.
1620
1621Return information about composition at or nearest to position POS.
9d751859 1622See `find-composition' for more details. */)
335c5470 1623 (pos, limit, string, detail_p)
ca4c9455
KH
1624 Lisp_Object pos, limit, string, detail_p;
1625{
90b3fe91
KH
1626 Lisp_Object prop, tail, gstring;
1627 EMACS_INT start, end, from, to;
ca4c9455
KH
1628 int id;
1629
b7826503 1630 CHECK_NUMBER_COERCE_MARKER (pos);
90b3fe91 1631 from = XINT (pos);
ca4c9455
KH
1632 if (!NILP (limit))
1633 {
b7826503 1634 CHECK_NUMBER_COERCE_MARKER (limit);
90b3fe91 1635 to = XINT (limit);
ca4c9455
KH
1636 }
1637 else
90b3fe91 1638 to = -1;
177c0ea7 1639
ca4c9455 1640 if (!NILP (string))
e3b3e327 1641 {
b7826503 1642 CHECK_STRING (string);
d5db4077 1643 if (XINT (pos) < 0 || XINT (pos) > SCHARS (string))
e3b3e327
GM
1644 args_out_of_range (string, pos);
1645 }
1646 else
1647 {
fa9090b8 1648 if (XINT (pos) < BEGV || XINT (pos) > ZV)
e3b3e327
GM
1649 args_out_of_range (Fcurrent_buffer (), pos);
1650 }
ca4c9455 1651
90b3fe91
KH
1652 if (!find_composition (from, to, &start, &end, &prop, string))
1653 {
1654 if (!NILP (current_buffer->enable_multibyte_characters)
1655 && FUNCTIONP (Vauto_composition_function)
1656 && find_automatic_composition (from, to, &start, &end, &gstring,
1657 string))
1658 return list3 (make_number (start), make_number (end), gstring);
1659 return Qnil;
1660 }
1661 if ((end <= XINT (pos) || start > XINT (pos)))
1662 {
1663 EMACS_INT s, e;
1664
1665 if (find_automatic_composition (from, to, &s, &e, &gstring, string)
1666 && (e <= XINT (pos) ? e > end : s < start))
1667 return list3 (make_number (start), make_number (end), gstring);
1668 }
ca4c9455
KH
1669 if (!COMPOSITION_VALID_P (start, end, prop))
1670 return Fcons (make_number (start), Fcons (make_number (end),
1671 Fcons (Qnil, Qnil)));
1672 if (NILP (detail_p))
1673 return Fcons (make_number (start), Fcons (make_number (end),
1674 Fcons (Qt, Qnil)));
1675
1676 if (COMPOSITION_REGISTERD_P (prop))
1677 id = COMPOSITION_ID (prop);
1678 else
1679 {
1680 int start_byte = (NILP (string)
1681 ? CHAR_TO_BYTE (start)
1682 : string_char_to_byte (string, start));
1683 id = get_composition_id (start, start_byte, end - start, prop, string);
1684 }
1685
1686 if (id >= 0)
1687 {
1688 Lisp_Object components, relative_p, mod_func;
1689 enum composition_method method = COMPOSITION_METHOD (prop);
1690 int width = composition_table[id]->width;
1691
1692 components = Fcopy_sequence (COMPOSITION_COMPONENTS (prop));
1693 relative_p = (method == COMPOSITION_WITH_RULE_ALTCHARS
1694 ? Qnil : Qt);
1695 mod_func = COMPOSITION_MODIFICATION_FUNC (prop);
1696 tail = Fcons (components,
1697 Fcons (relative_p,
1698 Fcons (mod_func,
1699 Fcons (make_number (width), Qnil))));
1700 }
1701 else
1702 tail = Qnil;
1703
1704 return Fcons (make_number (start), Fcons (make_number (end), tail));
1705}
1706
1707\f
1708void
1709syms_of_composite ()
1710{
58753d74
KH
1711 int i;
1712
ca4c9455
KH
1713 Qcomposition = intern ("composition");
1714 staticpro (&Qcomposition);
1715
58753d74 1716 /* Make a hash table for static composition. */
ca4c9455 1717 {
09654086 1718 Lisp_Object args[6];
ca4c9455 1719 extern Lisp_Object QCsize;
177c0ea7 1720
ca4c9455
KH
1721 args[0] = QCtest;
1722 args[1] = Qequal;
1723 args[2] = QCweakness;
dc47eccc 1724 /* We used to make the hash table weak so that unreferenced
ca101cff 1725 compositions can be garbage-collected. But, usually once
dc47eccc
KH
1726 created compositions are repeatedly used in an Emacs session,
1727 and thus it's not worth to save memory in such a way. So, we
1728 make the table not weak. */
6a83ee8a 1729 args[3] = Qnil;
ca4c9455
KH
1730 args[4] = QCsize;
1731 args[5] = make_number (311);
09654086 1732 composition_hash_table = Fmake_hash_table (6, args);
ca4c9455
KH
1733 staticpro (&composition_hash_table);
1734 }
1735
58753d74
KH
1736 /* Make a hash table for glyph-string. */
1737 {
1738 Lisp_Object args[6];
1739 extern Lisp_Object QCsize;
1740
1741 args[0] = QCtest;
1742 args[1] = Qequal;
1743 args[2] = QCweakness;
1744 args[3] = Qnil;
1745 args[4] = QCsize;
1746 args[5] = make_number (311);
1747 gstring_hash_table = Fmake_hash_table (6, args);
1748 staticpro (&gstring_hash_table);
1749 }
1750
1751 staticpro (&gstring_work_headers);
1752 gstring_work_headers = Fmake_vector (make_number (8), Qnil);
1753 for (i = 0; i < 8; i++)
1754 ASET (gstring_work_headers, i, Fmake_vector (make_number (i + 2), Qnil));
1755 staticpro (&gstring_work);
1756 gstring_work = Fmake_vector (make_number (10), Qnil);
1757
ca4c9455
KH
1758 /* Text property `composition' should be nonsticky by default. */
1759 Vtext_property_default_nonsticky
1760 = Fcons (Fcons (Qcomposition, Qt), Vtext_property_default_nonsticky);
1761
1762 DEFVAR_LISP ("compose-chars-after-function", &Vcompose_chars_after_function,
335c5470
PJ
1763 doc: /* Function to adjust composition of buffer text.
1764
9d751859
EZ
1765This function is called with three arguments: FROM, TO, and OBJECT.
1766FROM and TO specify the range of text whose composition should be
335c5470
PJ
1767adjusted. OBJECT, if non-nil, is a string that contains the text.
1768
1769This function is called after a text with `composition' property is
1770inserted or deleted to keep `composition' property of buffer text
1771valid.
1772
1773The default value is the function `compose-chars-after'. */);
ca4c9455
KH
1774 Vcompose_chars_after_function = intern ("compose-chars-after");
1775
f96ba4c1
KH
1776 Qauto_composed = intern ("auto-composed");
1777 staticpro (&Qauto_composed);
40add26d 1778
f96ba4c1
KH
1779 Qauto_composition_function = intern ("auto-composition-function");
1780 staticpro (&Qauto_composition_function);
40add26d 1781
f96ba4c1
KH
1782 DEFVAR_LISP ("auto-composition-function", &Vauto_composition_function,
1783 doc: /* Function to call to compose characters automatically.
9d751859 1784This function is called from the display routine with four arguments:
ddc872ba 1785FROM, TO, WINDOW, and STRING.
335c5470 1786
ddc872ba
KH
1787If STRING is nil, the function must compose characters in the region
1788between FROM and TO in the current buffer.
335c5470 1789
ddc872ba
KH
1790Otherwise, STRING is a string, and FROM and TO are indices into the
1791string. In this case, the function must compose characters in the
1792string. */);
f96ba4c1 1793 Vauto_composition_function = Qnil;
40add26d 1794
58753d74 1795 DEFVAR_LISP ("composition-function-table", &Vcomposition_function_table,
9d751859 1796 doc: /* Char-table of functions for automatic character composition.
58753d74
KH
1797For each character that has to be composed automatically with
1798preceding and/or following characters, this char-table contains
1799a function to call to compose that character.
1800
1801The element at index C in the table, if non-nil, is a list of
1802this form: ([PATTERN PREV-CHARS FUNC] ...)
1803
9d751859 1804PATTERN is a regular expression which C and the surrounding
58753d74
KH
1805characters must match.
1806
895416e3
KH
1807PREV-CHARS is a non-negative integer (less than 4) specifying how many
1808characters before C to check the matching with PATTERN. If it is 0,
1809PATTERN must match C and the following characters. If it is 1,
1810PATTERN must match a character before C and the following characters.
58753d74
KH
1811
1812If PREV-CHARS is 0, PATTERN can be nil, which means that the
1813single character C should be composed.
1814
1815FUNC is a function to return a glyph-string representing a
9d751859 1816composition of the characters that match PATTERN. It is
58753d74
KH
1817called with one argument GSTRING.
1818
1819GSTRING is a template of a glyph-string to return. It is already
1820filled with a proper header for the characters to compose, and
1821glyphs corresponding to those characters one by one. The
9d751859 1822function must return a new glyph-string with the same header as
58753d74
KH
1823GSTRING, or modify GSTRING itself and return it.
1824
1825See also the documentation of `auto-composition-mode'. */);
1826 Vcomposition_function_table = Fmake_char_table (Qnil, Qnil);
1827
ca4c9455
KH
1828 defsubr (&Scompose_region_internal);
1829 defsubr (&Scompose_string_internal);
1830 defsubr (&Sfind_composition_internal);
58753d74 1831 defsubr (&Scomposition_get_gstring);
ca4c9455 1832}
ee6f9c59
KH
1833
1834/* arch-tag: 79cefaf8-ca48-4eed-97e5-d5afb290d272
1835 (do not change this comment) */