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