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