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