diff options
| author | Kenichi Handa | 2008-08-29 07:53:27 +0000 |
|---|---|---|
| committer | Kenichi Handa | 2008-08-29 07:53:27 +0000 |
| commit | 58753d746d131ad0595730e76e9c66e9db5fc5f9 (patch) | |
| tree | 1fe81e721171030018e54e4e60854bc9017ad47a /src | |
| parent | c3b57f2354e9f7f4be46bda9e5111582d2aa324c (diff) | |
| download | emacs-58753d746d131ad0595730e76e9c66e9db5fc5f9.tar.gz emacs-58753d746d131ad0595730e76e9c66e9db5fc5f9.zip | |
Include window.h, frame.h, dispextern.h font.h.
(Vcomposition_function_table)
(get_composition_id): Don't handle COMPOSITION_WITH_GLYPH_STRING.
(gstring_hash_table, gstring_work, gstring_work_headers): New
variables.
(gstring_lookup_cache, composition_gstring_put_cache)
(composition_gstring_from_id, composition_gstring_p)
(composition_gstring_width, fill_gstring_header)
(fill_gstring_body, autocmp_chars, composition_compute_stop_pos)
(composition_reseat_it, composition_update_it)
(composition_adjust_point, Fcomposition_get_gstring): New
functions.
(syms_of_composite): Initialize gstring_hash_table, gstrint_work,
and gstring_work_headers. DEFVAR_LISP composition-function-table.
Defsubr compostion_get_gstring.
Diffstat (limited to 'src')
| -rw-r--r-- | src/composite.c | 776 |
1 files changed, 764 insertions, 12 deletions
diff --git a/src/composite.c b/src/composite.c index e0ac92ee20e..1e19033b5a4 100644 --- a/src/composite.c +++ b/src/composite.c | |||
| @@ -28,6 +28,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 28 | #include "buffer.h" | 28 | #include "buffer.h" |
| 29 | #include "character.h" | 29 | #include "character.h" |
| 30 | #include "intervals.h" | 30 | #include "intervals.h" |
| 31 | #include "window.h" | ||
| 32 | #include "frame.h" | ||
| 33 | #include "dispextern.h" | ||
| 34 | #include "font.h" | ||
| 31 | 35 | ||
| 32 | /* Emacs uses special text property `composition' to support character | 36 | /* Emacs uses special text property `composition' to support character |
| 33 | composition. A sequence of characters that have the same (i.e. eq) | 37 | composition. A sequence of characters that have the same (i.e. eq) |
| @@ -151,6 +155,7 @@ Lisp_Object Vcompose_chars_after_function; | |||
| 151 | Lisp_Object Qauto_composed; | 155 | Lisp_Object Qauto_composed; |
| 152 | Lisp_Object Vauto_composition_function; | 156 | Lisp_Object Vauto_composition_function; |
| 153 | Lisp_Object Qauto_composition_function; | 157 | Lisp_Object Qauto_composition_function; |
| 158 | Lisp_Object Vcomposition_function_table; | ||
| 154 | 159 | ||
| 155 | EXFUN (Fremove_list_of_text_properties, 4); | 160 | EXFUN (Fremove_list_of_text_properties, 4); |
| 156 | 161 | ||
| @@ -317,10 +322,6 @@ get_composition_id (charpos, bytepos, nchars, prop, string) | |||
| 317 | : ((INTEGERP (components) || STRINGP (components)) | 322 | : ((INTEGERP (components) || STRINGP (components)) |
| 318 | ? COMPOSITION_WITH_ALTCHARS | 323 | ? COMPOSITION_WITH_ALTCHARS |
| 319 | : COMPOSITION_WITH_RULE_ALTCHARS)); | 324 | : COMPOSITION_WITH_RULE_ALTCHARS)); |
| 320 | if (cmp->method == COMPOSITION_WITH_RULE_ALTCHARS | ||
| 321 | && VECTORP (components) | ||
| 322 | && ! INTEGERP (AREF (components, 0))) | ||
| 323 | cmp->method = COMPOSITION_WITH_GLYPH_STRING; | ||
| 324 | cmp->hash_index = hash_index; | 325 | cmp->hash_index = hash_index; |
| 325 | glyph_len = (cmp->method == COMPOSITION_WITH_RULE_ALTCHARS | 326 | glyph_len = (cmp->method == COMPOSITION_WITH_RULE_ALTCHARS |
| 326 | ? (XVECTOR (key)->size + 1) / 2 | 327 | ? (XVECTOR (key)->size + 1) / 2 |
| @@ -329,13 +330,7 @@ get_composition_id (charpos, bytepos, nchars, prop, string) | |||
| 329 | cmp->offsets = (short *) xmalloc (sizeof (short) * glyph_len * 2); | 330 | cmp->offsets = (short *) xmalloc (sizeof (short) * glyph_len * 2); |
| 330 | cmp->font = NULL; | 331 | cmp->font = NULL; |
| 331 | 332 | ||
| 332 | /* Calculate the width of overall glyphs of the composition. */ | 333 | if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS) |
| 333 | if (cmp->method == COMPOSITION_WITH_GLYPH_STRING) | ||
| 334 | { | ||
| 335 | cmp->width = 1; /* Should be fixed later. */ | ||
| 336 | cmp->glyph_len--; | ||
| 337 | } | ||
| 338 | else if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS) | ||
| 339 | { | 334 | { |
| 340 | /* Relative composition. */ | 335 | /* Relative composition. */ |
| 341 | cmp->width = 0; | 336 | cmp->width = 0; |
| @@ -645,6 +640,705 @@ compose_text (start, end, components, modification_func, string) | |||
| 645 | Fput_text_property (make_number (start), make_number (end), | 640 | Fput_text_property (make_number (start), make_number (end), |
| 646 | Qcomposition, prop, string); | 641 | Qcomposition, prop, string); |
| 647 | } | 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 | |||
| 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 | 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 | |||
| 920 | record_unwind_save_match_data (); | ||
| 921 | for (; CONSP (cft_element); cft_element = XCDR (cft_element)) | ||
| 922 | { | ||
| 923 | Lisp_Object elt = XCAR (cft_element); | ||
| 924 | Lisp_Object re; | ||
| 925 | Lisp_Object font_object = Qnil, gstring; | ||
| 926 | EMACS_INT to; | ||
| 927 | |||
| 928 | if (! VECTORP (elt) || ASIZE (elt) != 3) | ||
| 929 | continue; | ||
| 930 | re = AREF (elt, 0); | ||
| 931 | if (NILP (string)) | ||
| 932 | TEMP_SET_PT_BOTH (charpos, bytepos); | ||
| 933 | if (NILP (re) | ||
| 934 | || (STRINGP (re) | ||
| 935 | && (STRINGP (string) | ||
| 936 | ? EQ (Fstring_match (re, string, pos), pos) | ||
| 937 | : (! NILP (Fre_search_forward (re, make_number (limit), Qt, Qnil)) | ||
| 938 | && EQ (Fmatch_beginning (make_number (0)), pos))))) | ||
| 939 | { | ||
| 940 | to = (NILP (re) ? charpos + 1 : XINT (Fmatch_end (make_number (0)))); | ||
| 941 | #ifdef HAVE_WINDOW_SYSTEM | ||
| 942 | if (FRAME_WINDOW_P (f)) | ||
| 943 | { | ||
| 944 | font_object = font_range (charpos, &to, win, face, string); | ||
| 945 | if (! FONT_OBJECT_P (font_object)) | ||
| 946 | { | ||
| 947 | if (NILP (string)) | ||
| 948 | TEMP_SET_PT_BOTH (pt, pt_byte); | ||
| 949 | return unbind_to (count, Qnil); | ||
| 950 | } | ||
| 951 | } | ||
| 952 | #endif /* not HAVE_WINDOW_SYSTEM */ | ||
| 953 | gstring = Fcomposition_get_gstring (pos, make_number (to), | ||
| 954 | font_object, string); | ||
| 955 | if (NILP (LGSTRING_ID (gstring))) | ||
| 956 | { | ||
| 957 | Lisp_Object args[6]; | ||
| 958 | |||
| 959 | args[0] = Vauto_composition_function; | ||
| 960 | args[1] = AREF (elt, 2); | ||
| 961 | args[2] = pos; | ||
| 962 | args[3] = make_number (to); | ||
| 963 | args[4] = font_object; | ||
| 964 | args[5] = string; | ||
| 965 | gstring = safe_call (6, args); | ||
| 966 | } | ||
| 967 | if (NILP (string)) | ||
| 968 | TEMP_SET_PT_BOTH (pt, pt_byte); | ||
| 969 | return unbind_to (count, gstring); | ||
| 970 | } | ||
| 971 | } | ||
| 972 | if (NILP (string)) | ||
| 973 | TEMP_SET_PT_BOTH (pt, pt_byte); | ||
| 974 | return unbind_to (count, Qnil); | ||
| 975 | } | ||
| 976 | |||
| 977 | |||
| 978 | /* Update cmp_it->stop_pos to the next position after CHARPOS (and | ||
| 979 | BYTEPOS) where character composition may happen. If BYTEPOS is | ||
| 980 | negative, compoute it. If it is a static composition, set | ||
| 981 | cmp_it->ch to -1. Otherwise, set cmp_it->ch to the character that | ||
| 982 | triggers a automatic composition. */ | ||
| 983 | |||
| 984 | void | ||
| 985 | composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string) | ||
| 986 | struct composition_it *cmp_it; | ||
| 987 | EMACS_INT charpos, bytepos, endpos; | ||
| 988 | Lisp_Object string; | ||
| 989 | { | ||
| 990 | EMACS_INT start, end, c; | ||
| 991 | Lisp_Object prop, val; | ||
| 992 | |||
| 993 | cmp_it->stop_pos = endpos; | ||
| 994 | if (find_composition (charpos, endpos, &start, &end, &prop, string) | ||
| 995 | && COMPOSITION_VALID_P (start, end, prop)) | ||
| 996 | { | ||
| 997 | cmp_it->stop_pos = endpos = start; | ||
| 998 | cmp_it->ch = -1; | ||
| 999 | } | ||
| 1000 | if (NILP (current_buffer->enable_multibyte_characters) | ||
| 1001 | || ! FUNCTIONP (Vauto_composition_function)) | ||
| 1002 | return; | ||
| 1003 | if (bytepos < 0) | ||
| 1004 | { | ||
| 1005 | if (STRINGP (string)) | ||
| 1006 | bytepos = string_char_to_byte (string, charpos); | ||
| 1007 | else | ||
| 1008 | bytepos = CHAR_TO_BYTE (charpos); | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | start = charpos; | ||
| 1012 | while (charpos < endpos) | ||
| 1013 | { | ||
| 1014 | if (STRINGP (string)) | ||
| 1015 | FETCH_STRING_CHAR_ADVANCE (c, string, charpos, bytepos); | ||
| 1016 | else | ||
| 1017 | FETCH_CHAR_ADVANCE (c, charpos, bytepos); | ||
| 1018 | val = CHAR_TABLE_REF (Vcomposition_function_table, c); | ||
| 1019 | if (! NILP (val)) | ||
| 1020 | { | ||
| 1021 | Lisp_Object elt; | ||
| 1022 | |||
| 1023 | for (; CONSP (val); val = XCDR (val)) | ||
| 1024 | { | ||
| 1025 | elt = XCAR (val); | ||
| 1026 | if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1)) | ||
| 1027 | && charpos - 1 - XFASTINT (AREF (elt, 1)) >= start) | ||
| 1028 | break; | ||
| 1029 | } | ||
| 1030 | if (CONSP (val)) | ||
| 1031 | { | ||
| 1032 | cmp_it->stop_pos = charpos - 1 - XFASTINT (AREF (elt, 1)); | ||
| 1033 | cmp_it->ch = c; | ||
| 1034 | break; | ||
| 1035 | } | ||
| 1036 | } | ||
| 1037 | } | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | /* Check if the character at CHARPOS (and BYTEPOS) is composed | ||
| 1041 | (possibly with the following charaters) on window W. ENDPOS limits | ||
| 1042 | characters to be composed. FACE, in non-NULL, is a base face of | ||
| 1043 | the character. If STRING is not nil, it is a string containing the | ||
| 1044 | character to check, and CHARPOS and BYTEPOS are indices in the | ||
| 1045 | string. In that case, FACE must not be NULL. | ||
| 1046 | |||
| 1047 | If the character is composed, setup members of CMP_IT (id, nglyphs, | ||
| 1048 | and from), and return 1. Otherwise, update CMP_IT->stop_pos, and | ||
| 1049 | return 0. */ | ||
| 1050 | |||
| 1051 | int | ||
| 1052 | composition_reseat_it (cmp_it, charpos, bytepos, endpos, w, face, string) | ||
| 1053 | struct composition_it *cmp_it; | ||
| 1054 | EMACS_INT charpos, bytepos, endpos; | ||
| 1055 | struct window *w; | ||
| 1056 | struct face *face; | ||
| 1057 | Lisp_Object string; | ||
| 1058 | { | ||
| 1059 | if (cmp_it->ch < 0) | ||
| 1060 | { | ||
| 1061 | /* We are looking at a static composition. */ | ||
| 1062 | EMACS_INT start, end; | ||
| 1063 | Lisp_Object prop; | ||
| 1064 | |||
| 1065 | find_composition (charpos, -1, &start, &end, &prop, string); | ||
| 1066 | cmp_it->id = get_composition_id (charpos, bytepos, end - start, | ||
| 1067 | prop, string); | ||
| 1068 | if (cmp_it->id < 0) | ||
| 1069 | goto no_composition; | ||
| 1070 | cmp_it->nchars = end - start; | ||
| 1071 | cmp_it->nglyphs = composition_table[cmp_it->id]->glyph_len; | ||
| 1072 | } | ||
| 1073 | else | ||
| 1074 | { | ||
| 1075 | Lisp_Object val; | ||
| 1076 | int i; | ||
| 1077 | |||
| 1078 | val = CHAR_TABLE_REF (Vcomposition_function_table, cmp_it->ch); | ||
| 1079 | if (NILP (val)) | ||
| 1080 | goto no_composition; | ||
| 1081 | val = autocmp_chars (val, charpos, bytepos, endpos, w, face, string); | ||
| 1082 | if (! composition_gstring_p (val)) | ||
| 1083 | goto no_composition; | ||
| 1084 | if (NILP (LGSTRING_ID (val))) | ||
| 1085 | val = composition_gstring_put_cache (val, -1); | ||
| 1086 | cmp_it->id = XINT (LGSTRING_ID (val)); | ||
| 1087 | for (i = 0; i < LGSTRING_GLYPH_LEN (val); i++) | ||
| 1088 | if (NILP (LGSTRING_GLYPH (val, i))) | ||
| 1089 | break; | ||
| 1090 | cmp_it->nglyphs = i; | ||
| 1091 | } | ||
| 1092 | cmp_it->from = 0; | ||
| 1093 | return 1; | ||
| 1094 | |||
| 1095 | no_composition: | ||
| 1096 | charpos++; | ||
| 1097 | if (STRINGP (string)) | ||
| 1098 | bytepos += MULTIBYTE_LENGTH_NO_CHECK (SDATA (string) + bytepos); | ||
| 1099 | else | ||
| 1100 | INC_POS (bytepos); | ||
| 1101 | composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string); | ||
| 1102 | return 0; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | int | ||
| 1106 | composition_update_it (cmp_it, charpos, bytepos, string) | ||
| 1107 | struct composition_it *cmp_it; | ||
| 1108 | EMACS_INT charpos, bytepos; | ||
| 1109 | Lisp_Object string; | ||
| 1110 | { | ||
| 1111 | int i, c; | ||
| 1112 | |||
| 1113 | if (cmp_it->ch < 0) | ||
| 1114 | { | ||
| 1115 | struct composition *cmp = composition_table[cmp_it->id]; | ||
| 1116 | |||
| 1117 | cmp_it->to = cmp_it->nglyphs; | ||
| 1118 | if (cmp_it->nglyphs == 0) | ||
| 1119 | c = -1; | ||
| 1120 | else | ||
| 1121 | { | ||
| 1122 | for (i = 0; i < cmp->glyph_len; i++) | ||
| 1123 | if ((c = COMPOSITION_GLYPH (cmp, i)) != '\t') | ||
| 1124 | break; | ||
| 1125 | if (c == '\t') | ||
| 1126 | c = ' '; | ||
| 1127 | } | ||
| 1128 | cmp_it->width = cmp->width; | ||
| 1129 | } | ||
| 1130 | else | ||
| 1131 | { | ||
| 1132 | Lisp_Object gstring = composition_gstring_from_id (cmp_it->id); | ||
| 1133 | |||
| 1134 | if (cmp_it->nglyphs == 0) | ||
| 1135 | { | ||
| 1136 | c = -1; | ||
| 1137 | cmp_it->nchars = LGSTRING_CHAR_LEN (gstring); | ||
| 1138 | cmp_it->width = 0; | ||
| 1139 | } | ||
| 1140 | else | ||
| 1141 | { | ||
| 1142 | Lisp_Object glyph = LGSTRING_GLYPH (gstring, cmp_it->from); | ||
| 1143 | int from = LGLYPH_FROM (glyph); | ||
| 1144 | |||
| 1145 | c = LGSTRING_CHAR (gstring, from); | ||
| 1146 | cmp_it->nchars = LGLYPH_TO (glyph) - from + 1; | ||
| 1147 | cmp_it->width = (LGLYPH_WIDTH (glyph) > 0 | ||
| 1148 | ? CHAR_WIDTH (LGLYPH_CHAR (glyph)) : 0); | ||
| 1149 | for (cmp_it->to = cmp_it->from + 1; cmp_it->to < cmp_it->nglyphs; | ||
| 1150 | cmp_it->to++) | ||
| 1151 | { | ||
| 1152 | glyph = LGSTRING_GLYPH (gstring, cmp_it->to); | ||
| 1153 | if (LGLYPH_FROM (glyph) != from) | ||
| 1154 | break; | ||
| 1155 | if (LGLYPH_WIDTH (glyph) > 0) | ||
| 1156 | cmp_it->width += CHAR_WIDTH (LGLYPH_CHAR (glyph)); | ||
| 1157 | } | ||
| 1158 | } | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | charpos += cmp_it->nchars; | ||
| 1162 | if (STRINGP (string)) | ||
| 1163 | cmp_it->nbytes = string_char_to_byte (string, charpos) - bytepos; | ||
| 1164 | else | ||
| 1165 | cmp_it->nbytes = CHAR_TO_BYTE (charpos) - bytepos; | ||
| 1166 | return c; | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | |||
| 1170 | int | ||
| 1171 | composition_adjust_point (last_pt) | ||
| 1172 | EMACS_INT last_pt; | ||
| 1173 | { | ||
| 1174 | /* Now check the automatic composition. */ | ||
| 1175 | EMACS_INT charpos, bytepos, startpos, beg, end, pos; | ||
| 1176 | Lisp_Object val, cat; | ||
| 1177 | EMACS_INT limit; | ||
| 1178 | int c; | ||
| 1179 | |||
| 1180 | if (PT == BEGV || PT == ZV) | ||
| 1181 | return PT; | ||
| 1182 | |||
| 1183 | if (get_property_and_range (PT, Qcomposition, &val, &beg, &end, Qnil) | ||
| 1184 | && COMPOSITION_VALID_P (beg, end, val) | ||
| 1185 | && beg < PT /* && end > PT <- It's always the case. */ | ||
| 1186 | && (last_pt <= beg || last_pt >= end)) | ||
| 1187 | return (PT < last_pt ? beg : end); | ||
| 1188 | |||
| 1189 | if (NILP (current_buffer->enable_multibyte_characters) | ||
| 1190 | || ! FUNCTIONP (Vauto_composition_function)) | ||
| 1191 | return PT; | ||
| 1192 | |||
| 1193 | c = FETCH_MULTIBYTE_CHAR (PT_BYTE); | ||
| 1194 | cat = CHAR_TABLE_REF (Vunicode_category_table, c); | ||
| 1195 | if (SYMBOLP (cat) | ||
| 1196 | && ((c = SDATA (SYMBOL_NAME (cat))[0]) == 'C' || c == 'Z')) | ||
| 1197 | /* A control character is never composed. */ | ||
| 1198 | return PT; | ||
| 1199 | |||
| 1200 | charpos = PT; | ||
| 1201 | bytepos = PT_BYTE; | ||
| 1202 | limit = (last_pt < PT ? last_pt : BEGV); | ||
| 1203 | do { | ||
| 1204 | DEC_BOTH (charpos, bytepos); | ||
| 1205 | c = FETCH_MULTIBYTE_CHAR (bytepos); | ||
| 1206 | cat = CHAR_TABLE_REF (Vunicode_category_table, c); | ||
| 1207 | if (SYMBOLP (cat) | ||
| 1208 | && ((c = SDATA (SYMBOL_NAME (cat))[0]) == 'C' || c == 'Z')) | ||
| 1209 | { | ||
| 1210 | INC_BOTH (charpos, bytepos); | ||
| 1211 | break; | ||
| 1212 | } | ||
| 1213 | } while (charpos > limit); | ||
| 1214 | |||
| 1215 | |||
| 1216 | limit = (last_pt < PT ? ZV : last_pt); | ||
| 1217 | if (limit > PT + 3) | ||
| 1218 | limit = PT + 3; | ||
| 1219 | startpos = charpos; | ||
| 1220 | while (charpos < limit) | ||
| 1221 | { | ||
| 1222 | c = FETCH_MULTIBYTE_CHAR (bytepos); | ||
| 1223 | if (charpos > PT) | ||
| 1224 | { | ||
| 1225 | int ch; | ||
| 1226 | |||
| 1227 | cat = CHAR_TABLE_REF (Vunicode_category_table, c); | ||
| 1228 | if (SYMBOLP (cat) | ||
| 1229 | && ((ch = SDATA (SYMBOL_NAME (cat))[0]) == 'C' || ch == 'Z')) | ||
| 1230 | return PT; | ||
| 1231 | } | ||
| 1232 | val = CHAR_TABLE_REF (Vcomposition_function_table, c); | ||
| 1233 | if (! CONSP (val)) | ||
| 1234 | { | ||
| 1235 | INC_BOTH (charpos, bytepos); | ||
| 1236 | continue; | ||
| 1237 | } | ||
| 1238 | for (; CONSP (val); val = XCDR (val)) | ||
| 1239 | { | ||
| 1240 | Lisp_Object elt = XCAR (val); | ||
| 1241 | |||
| 1242 | if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1)) | ||
| 1243 | && (pos = charpos - XFASTINT (AREF (elt, 1))) < PT | ||
| 1244 | && pos >= startpos) | ||
| 1245 | { | ||
| 1246 | Lisp_Object gstring; | ||
| 1247 | EMACS_INT pos_byte; | ||
| 1248 | |||
| 1249 | if (XFASTINT (AREF (elt, 1)) == 0) | ||
| 1250 | pos_byte = bytepos; | ||
| 1251 | else | ||
| 1252 | pos_byte = CHAR_TO_BYTE (pos); | ||
| 1253 | gstring = autocmp_chars (val, pos, pos_byte, Z, | ||
| 1254 | XWINDOW (selected_window), NULL, Qnil); | ||
| 1255 | if (composition_gstring_p (gstring)) | ||
| 1256 | { | ||
| 1257 | if (pos + LGSTRING_CHAR_LEN (gstring) > PT) | ||
| 1258 | { | ||
| 1259 | int i; | ||
| 1260 | |||
| 1261 | for (i = 0; i < LGSTRING_GLYPH_LEN (gstring); i++) | ||
| 1262 | { | ||
| 1263 | Lisp_Object glyph = LGSTRING_GLYPH (gstring, i); | ||
| 1264 | |||
| 1265 | if (NILP (glyph)) | ||
| 1266 | break; | ||
| 1267 | if (pos + LGLYPH_FROM (glyph) == PT) | ||
| 1268 | return PT; | ||
| 1269 | if (pos + LGLYPH_TO (glyph) + 1 > PT) | ||
| 1270 | return (PT < last_pt | ||
| 1271 | ? pos + LGLYPH_FROM (glyph) | ||
| 1272 | : pos + LGLYPH_TO (glyph) + 1); | ||
| 1273 | } | ||
| 1274 | return PT; | ||
| 1275 | } | ||
| 1276 | charpos = startpos = pos + LGSTRING_CHAR_LEN (gstring); | ||
| 1277 | bytepos = CHAR_TO_BYTE (charpos); | ||
| 1278 | break; | ||
| 1279 | } | ||
| 1280 | } | ||
| 1281 | } | ||
| 1282 | if (! CONSP (val)) | ||
| 1283 | INC_BOTH (charpos, bytepos); | ||
| 1284 | } | ||
| 1285 | return PT; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | DEFUN ("composition-get-gstring", Fcomposition_get_gstring, | ||
| 1289 | Scomposition_get_gstring, 4, 4, 0, | ||
| 1290 | doc: /* Return a glyph-string for characters between FROM and TO. | ||
| 1291 | If the glhph string is for graphic display, FONT-OBJECT must be | ||
| 1292 | a font-object to use for those characters. | ||
| 1293 | Otherwise (for terminal display), FONT-OBJECT must be nil. | ||
| 1294 | |||
| 1295 | If the optional 4th argument STRING is not nil, it is a string | ||
| 1296 | containing the target characters between indices FROM and TO. | ||
| 1297 | |||
| 1298 | A glhph-string is a vector containing information about how to display | ||
| 1299 | specific character sequence. The format is: | ||
| 1300 | [HEADER ID GLYPH ...] | ||
| 1301 | |||
| 1302 | HEADER is a vector of this form: | ||
| 1303 | [FONT-OBJECT CHAR ...] | ||
| 1304 | where | ||
| 1305 | FONT-OBJECT is a font-object for all glyphs in the glyph-string, | ||
| 1306 | or nil if not yet decided. | ||
| 1307 | CHARs are characters to be composed by GLYPHs. | ||
| 1308 | |||
| 1309 | ID is an identification number of the glyph-string. It may be nil if | ||
| 1310 | not yet shaped. | ||
| 1311 | |||
| 1312 | GLYPH is a vector whose elements has this form: | ||
| 1313 | [ FROM-IDX TO-IDX C CODE WIDTH LBEARING RBEARING ASCENT DESCENT | ||
| 1314 | [ [X-OFF Y-OFF WADJUST] | nil] ] | ||
| 1315 | where | ||
| 1316 | FROM-IDX and TO-IDX are used internally and should not be touched. | ||
| 1317 | C is the character of the glyph. | ||
| 1318 | CODE is the glyph-code of C in FONT-OBJECT. | ||
| 1319 | WIDTH thru DESCENT are the metrics (in pixels) of the glyph. | ||
| 1320 | X-OFF and Y-OFF are offests to the base position for the glyph. | ||
| 1321 | WADJUST is the adjustment to the normal width of the glyph. | ||
| 1322 | |||
| 1323 | If GLYPH is nil, the remaining elements of the glhph-string vector | ||
| 1324 | must be ignore. */) | ||
| 1325 | (from, to, font_object, string) | ||
| 1326 | Lisp_Object font_object, from, to, string; | ||
| 1327 | { | ||
| 1328 | Lisp_Object gstring, header; | ||
| 1329 | |||
| 1330 | if (! NILP (font_object)) | ||
| 1331 | CHECK_FONT_OBJECT (font_object); | ||
| 1332 | header = fill_gstring_header (Qnil, from, to, font_object, string); | ||
| 1333 | gstring = gstring_lookup_cache (header); | ||
| 1334 | if (! NILP (gstring)) | ||
| 1335 | return gstring; | ||
| 1336 | LGSTRING_SET_HEADER (gstring_work, header); | ||
| 1337 | LGSTRING_SET_ID (gstring_work, Qnil); | ||
| 1338 | fill_gstring_body (gstring_work); | ||
| 1339 | return gstring_work; | ||
| 1340 | } | ||
| 1341 | |||
| 648 | 1342 | ||
| 649 | /* Emacs Lisp APIs. */ | 1343 | /* Emacs Lisp APIs. */ |
| 650 | 1344 | ||
| @@ -771,10 +1465,12 @@ See `find-composition' for more detail. */) | |||
| 771 | void | 1465 | void |
| 772 | syms_of_composite () | 1466 | syms_of_composite () |
| 773 | { | 1467 | { |
| 1468 | int i; | ||
| 1469 | |||
| 774 | Qcomposition = intern ("composition"); | 1470 | Qcomposition = intern ("composition"); |
| 775 | staticpro (&Qcomposition); | 1471 | staticpro (&Qcomposition); |
| 776 | 1472 | ||
| 777 | /* Make a hash table for composition. */ | 1473 | /* Make a hash table for static composition. */ |
| 778 | { | 1474 | { |
| 779 | Lisp_Object args[6]; | 1475 | Lisp_Object args[6]; |
| 780 | extern Lisp_Object QCsize; | 1476 | extern Lisp_Object QCsize; |
| @@ -794,6 +1490,28 @@ syms_of_composite () | |||
| 794 | staticpro (&composition_hash_table); | 1490 | staticpro (&composition_hash_table); |
| 795 | } | 1491 | } |
| 796 | 1492 | ||
| 1493 | /* Make a hash table for glyph-string. */ | ||
| 1494 | { | ||
| 1495 | Lisp_Object args[6]; | ||
| 1496 | extern Lisp_Object QCsize; | ||
| 1497 | |||
| 1498 | args[0] = QCtest; | ||
| 1499 | args[1] = Qequal; | ||
| 1500 | args[2] = QCweakness; | ||
| 1501 | args[3] = Qnil; | ||
| 1502 | args[4] = QCsize; | ||
| 1503 | args[5] = make_number (311); | ||
| 1504 | gstring_hash_table = Fmake_hash_table (6, args); | ||
| 1505 | staticpro (&gstring_hash_table); | ||
| 1506 | } | ||
| 1507 | |||
| 1508 | staticpro (&gstring_work_headers); | ||
| 1509 | gstring_work_headers = Fmake_vector (make_number (8), Qnil); | ||
| 1510 | for (i = 0; i < 8; i++) | ||
| 1511 | ASET (gstring_work_headers, i, Fmake_vector (make_number (i + 2), Qnil)); | ||
| 1512 | staticpro (&gstring_work); | ||
| 1513 | gstring_work = Fmake_vector (make_number (10), Qnil); | ||
| 1514 | |||
| 797 | /* Text property `composition' should be nonsticky by default. */ | 1515 | /* Text property `composition' should be nonsticky by default. */ |
| 798 | Vtext_property_default_nonsticky | 1516 | Vtext_property_default_nonsticky |
| 799 | = Fcons (Fcons (Qcomposition, Qt), Vtext_property_default_nonsticky); | 1517 | = Fcons (Fcons (Qcomposition, Qt), Vtext_property_default_nonsticky); |
| @@ -831,9 +1549,43 @@ string. In this case, the function must compose characters in the | |||
| 831 | string. */); | 1549 | string. */); |
| 832 | Vauto_composition_function = Qnil; | 1550 | Vauto_composition_function = Qnil; |
| 833 | 1551 | ||
| 1552 | DEFVAR_LISP ("composition-function-table", &Vcomposition_function_table, | ||
| 1553 | doc: /* Char-able of functions for automatic character composition. | ||
| 1554 | For each character that has to be composed automatically with | ||
| 1555 | preceding and/or following characters, this char-table contains | ||
| 1556 | a function to call to compose that character. | ||
| 1557 | |||
| 1558 | The element at index C in the table, if non-nil, is a list of | ||
| 1559 | this form: ([PATTERN PREV-CHARS FUNC] ...) | ||
| 1560 | |||
| 1561 | PATTERN is a regular expression with which C and the surrounding | ||
| 1562 | characters must match. | ||
| 1563 | |||
| 1564 | PREV-CHARS is a number of characters before C to check the | ||
| 1565 | matching with PATTERN. If it is 0, PATTERN must match with C and | ||
| 1566 | the following characters. If it is 1, PATTERN must match with a | ||
| 1567 | character before C and the following characters. | ||
| 1568 | |||
| 1569 | If PREV-CHARS is 0, PATTERN can be nil, which means that the | ||
| 1570 | single character C should be composed. | ||
| 1571 | |||
| 1572 | FUNC is a function to return a glyph-string representing a | ||
| 1573 | composition of the characters matching with PATTERN. It is | ||
| 1574 | called with one argument GSTRING. | ||
| 1575 | |||
| 1576 | GSTRING is a template of a glyph-string to return. It is already | ||
| 1577 | filled with a proper header for the characters to compose, and | ||
| 1578 | glyphs corresponding to those characters one by one. The | ||
| 1579 | function must return a new glyph-string of the same header as | ||
| 1580 | GSTRING, or modify GSTRING itself and return it. | ||
| 1581 | |||
| 1582 | See also the documentation of `auto-composition-mode'. */); | ||
| 1583 | Vcomposition_function_table = Fmake_char_table (Qnil, Qnil); | ||
| 1584 | |||
| 834 | defsubr (&Scompose_region_internal); | 1585 | defsubr (&Scompose_region_internal); |
| 835 | defsubr (&Scompose_string_internal); | 1586 | defsubr (&Scompose_string_internal); |
| 836 | defsubr (&Sfind_composition_internal); | 1587 | defsubr (&Sfind_composition_internal); |
| 1588 | defsubr (&Scomposition_get_gstring); | ||
| 837 | } | 1589 | } |
| 838 | 1590 | ||
| 839 | /* arch-tag: 79cefaf8-ca48-4eed-97e5-d5afb290d272 | 1591 | /* arch-tag: 79cefaf8-ca48-4eed-97e5-d5afb290d272 |