* nsterm.m (ns_draw_window_cursor): Draw BAR_CURSOR correct for R2L.
[bpt/emacs.git] / lisp / composite.el
CommitLineData
60370d40 1;;; composite.el --- support character composition
c674f351 2
409cc4a3 3;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
114f9c96 4;; 2008, 2009, 2010
ce03bf76
KH
5;; National Institute of Advanced Industrial Science and Technology (AIST)
6;; Registration Number H14PRO021
c674f351 7
c3fba29d
GM
8;; Author: Kenichi HANDA <handa@etl.go.jp>
9;; (according to ack.texi)
c674f351
KH
10;; Keywords: mule, multilingual, character composition
11
12;; This file is part of GNU Emacs.
13
eb3fa2cf 14;; GNU Emacs is free software: you can redistribute it and/or modify
c674f351 15;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
16;; the Free Software Foundation, either version 3 of the License, or
17;; (at your option) any later version.
c674f351
KH
18
19;; GNU Emacs is distributed in the hope that it will be useful,
20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22;; GNU General Public License for more details.
23
24;; You should have received a copy of the GNU General Public License
eb3fa2cf 25;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
c674f351 26
60370d40
PJ
27;;; Commentary:
28
c674f351
KH
29;;; Code:
30
07d7c3bd
JB
31(eval-when-compile (require 'cl))
32
c674f351
KH
33(defconst reference-point-alist
34 '((tl . 0) (tc . 1) (tr . 2)
35 (Bl . 3) (Bc . 4) (Br . 5)
36 (bl . 6) (bc . 7) (br . 8)
37 (cl . 9) (cc . 10) (cr . 11)
38 (top-left . 0) (top-center . 1) (top-right . 2)
39 (base-left . 3) (base-center . 4) (base-right . 5)
40 (bottom-left . 6) (bottom-center . 7) (bottom-right . 8)
41 (center-left . 9) (center-center . 10) (center-right . 11)
42 ;; For backward compatibility...
43 (ml . 3) (mc . 10) (mr . 5)
44 (mid-left . 3) (mid-center . 10) (mid-right . 5))
45 "Alist of symbols vs integer codes of glyph reference points.
46A glyph reference point symbol is to be used to specify a composition
1d1af02d 47rule in COMPONENTS argument to such functions as `compose-region'.
c674f351 48
4f27f7d2 49The meaning of glyph reference point codes is as follows:
c674f351
KH
50
51 0----1----2 <---- ascent 0:tl or top-left
52 | | 1:tc or top-center
53 | | 2:tr or top-right
54 | | 3:Bl or base-left 9:cl or center-left
55 9 10 11 <---- center 4:Bc or base-center 10:cc or center-center
56 | | 5:Br or base-right 11:cr or center-right
57 --3----4----5-- <-- baseline 6:bl or bottom-left
58 | | 7:bc or bottom-center
59 6----7----8 <---- descent 8:br or bottom-right
60
61Glyph reference point symbols are to be used to specify composition
62rule of the form \(GLOBAL-REF-POINT . NEW-REF-POINT), where
63GLOBAL-REF-POINT is a reference point in the overall glyphs already
64composed, and NEW-REF-POINT is a reference point in the new glyph to
65be added.
66
67For instance, if GLOBAL-REF-POINT is `br' (bottom-right) and
8f625692 68NEW-REF-POINT is `tc' (top-center), the overall glyph is updated as
c674f351
KH
69follows (the point `*' corresponds to both reference points):
70
71 +-------+--+ <--- new ascent
72 | | |
73 | global| |
74 | glyph | |
75 -- | | |-- <--- baseline \(doesn't change)
76 +----+--*--+
77 | | new |
78 | |glyph|
79 +----+-----+ <--- new descent
9c87e5c4
KH
80
81A composition rule may have the form \(GLOBAL-REF-POINT
07d7c3bd 82NEW-REF-POINT XOFF YOFF), where XOFF and YOFF specify how much
9c87e5c4
KH
83to shift NEW-REF-POINT from GLOBAL-REF-POINT. In this case, XOFF
84and YOFF are integers in the range -100..100 representing the
85shifting percentage against the font size.")
c674f351 86
c674f351 87
59a2dac0 88;;;###autoload
c674f351 89(defun encode-composition-rule (rule)
59a2dac0
KH
90 "Encode composition rule RULE into an integer value.
91RULE is a cons of global and new reference point symbols
2624e2ac 92\(see `reference-point-alist')."
59a2dac0
KH
93
94 ;; This must be compatible with C macro COMPOSITION_ENCODE_RULE
95 ;; defined in composite.h.
96
c674f351
KH
97 (if (and (integerp rule) (< rule 144))
98 ;; Already encoded.
99 rule
9c87e5c4
KH
100 (if (consp rule)
101 (let ((gref (car rule))
102 (nref (cdr rule))
103 xoff yoff)
104 (if (consp nref) ; (GREF NREF XOFF YOFF)
105 (progn
106 (setq xoff (nth 1 nref)
107 yoff (nth 2 nref)
108 nref (car nref))
109 (or (and (>= xoff -100) (<= xoff 100)
110 (>= yoff -100) (<= yoff 100))
ad1b4641 111 (error "Invalid composition rule: %s" rule))
9c87e5c4
KH
112 (setq xoff (+ xoff 128) yoff (+ yoff 128)))
113 ;; (GREF . NREF)
114 (setq xoff 0 yoff 0))
115 (or (integerp gref)
116 (setq gref (cdr (assq gref reference-point-alist))))
117 (or (integerp nref)
118 (setq nref (cdr (assq nref reference-point-alist))))
119 (or (and (>= gref 0) (< gref 12) (>= nref 0) (< nref 12))
120 (error "Invalid composition rule: %S" rule))
121 (logior (lsh xoff 16) (lsh yoff 8) (+ (* gref 12) nref)))
122 (error "Invalid composition rule: %S" rule))))
c674f351
KH
123
124;; Decode encoded composition rule RULE-CODE. The value is a cons of
125;; global and new reference point symbols.
126;; This must be compatible with C macro COMPOSITION_DECODE_RULE
127;; defined in composite.h.
128
129(defun decode-composition-rule (rule-code)
9c87e5c4 130 (or (and (natnump rule-code) (< rule-code #x1000000))
c674f351 131 (error "Invalid encoded composition rule: %S" rule-code))
9c87e5c4
KH
132 (let ((xoff (lsh rule-code -16))
133 (yoff (logand (lsh rule-code -8) #xFF))
134 gref nref)
135 (setq rule-code (logand rule-code #xFF)
136 gref (car (rassq (/ rule-code 12) reference-point-alist))
137 nref (car (rassq (% rule-code 12) reference-point-alist)))
c674f351
KH
138 (or (and gref (symbolp gref) nref (symbolp nref))
139 (error "Invalid composition rule code: %S" rule-code))
9c87e5c4
KH
140 (if (and (= xoff 0) (= yoff 0))
141 (cons gref nref)
142 (setq xoff (- xoff 128) yoff (- yoff 128))
143 (list gref xoff yoff nref))))
c674f351
KH
144
145;; Encode composition rules in composition components COMPONENTS. The
146;; value is a copy of COMPONENTS, where composition rules (cons of
147;; global and new glyph reference point symbols) are replaced with
148;; encoded composition rules. Optional 2nd argument NOCOPY non-nil
149;; means don't make a copy but modify COMPONENTS directly.
150
151(defun encode-composition-components (components &optional nocopy)
152 (or nocopy
153 (setq components (copy-sequence components)))
154 (if (vectorp components)
155 (let ((len (length components))
156 (i 1))
157 (while (< i len)
158 (aset components i
159 (encode-composition-rule (aref components i)))
160 (setq i (+ i 2))))
161 (let ((tail (cdr components)))
162 (while tail
163 (setcar tail
164 (encode-composition-rule (car tail)))
165 (setq tail (nthcdr 2 tail)))))
166 components)
167
168;; Decode composition rule codes in composition components COMPONENTS.
169;; The value is a copy of COMPONENTS, where composition rule codes are
170;; replaced with composition rules (cons of global and new glyph
171;; reference point symbols). Optional 2nd argument NOCOPY non-nil
172;; means don't make a copy but modify COMPONENTS directly.
173;; It is assumed that COMPONENTS is a vector and is for rule-base
174;; composition, thus (2N+1)th elements are rule codes.
175
176(defun decode-composition-components (components &optional nocopy)
177 (or nocopy
178 (setq components (copy-sequence components)))
179 (let ((len (length components))
180 (i 1))
181 (while (< i len)
182 (aset components i
183 (decode-composition-rule (aref components i)))
184 (setq i (+ i 2))))
185 components)
186
c674f351
KH
187(defun compose-region (start end &optional components modification-func)
188 "Compose characters in the current region.
189
b6cac59c
KH
190Characters are composed relatively, i.e. composed by overstriking
191or stacking depending on ascent, descent and other metrics of
192glyphs.
193
194For instance, if the region has three characters \"XYZ\", X is
195regarded as BASE glyph, and Y is displayed:
196 (1) above BASE if Y's descent value is not positive
197 (2) below BASE if Y's ascent value is not positive
198 (3) on BASE (i.e. at the BASE position) otherwise
199and Z is displayed with the same rule while regarding the whole
200XY glyphs as BASE.
c9f60860 201
c674f351
KH
202When called from a program, expects these four arguments.
203
204First two arguments START and END are positions (integers or markers)
205specifying the region.
206
1d1af02d
DL
207Optional 3rd argument COMPONENTS, if non-nil, is a character, a string
208or a vector or list of integers and rules.
c674f351
KH
209
210If it is a character, it is an alternate character to display instead
211of the text in the region.
212
c0cd1255
KH
213If it is a string, the elements are alternate characters. In
214this case, TAB element has a special meaning. If the first
215characer is TAB, the glyphs are displayed with left padding space
216so that no pixel overlaps with the previous column. If the last
4f27f7d2 217character is TAB, the glyphs are displayed with right padding
c0cd1255 218space so that no pixel overlaps with the following column.
c674f351
KH
219
220If it is a vector or list, it is a sequence of alternate characters and
221composition rules, where (2N)th elements are characters and (2N+1)th
222elements are composition rules to specify how to compose (2N+2)th
223elements with previously composed N glyphs.
224
225A composition rule is a cons of global and new glyph reference point
226symbols. See the documentation of `reference-point-alist' for more
4f27f7d2 227details.
c674f351
KH
228
229Optional 4th argument MODIFICATION-FUNC is a function to call to
230adjust the composition when it gets invalid because of a change of
231text in the composition."
232 (interactive "r")
233 (let ((modified-p (buffer-modified-p))
09d52401 234 (inhibit-read-only t))
c674f351
KH
235 (if (or (vectorp components) (listp components))
236 (setq components (encode-composition-components components)))
237 (compose-region-internal start end components modification-func)
6b61353c 238 (restore-buffer-modified-p modified-p)))
c674f351 239
c674f351
KH
240(defun decompose-region (start end)
241 "Decompose text in the current region.
242
243When called from a program, expects two arguments,
244positions (integers or markers) specifying the region."
245 (interactive "r")
246 (let ((modified-p (buffer-modified-p))
09d52401 247 (inhibit-read-only t))
c674f351 248 (remove-text-properties start end '(composition nil))
09d52401 249 (restore-buffer-modified-p modified-p)))
c674f351 250
c674f351
KH
251(defun compose-string (string &optional start end components modification-func)
252 "Compose characters in string STRING.
253
c1750694 254The return value is STRING with the `composition' property put on all
c674f351
KH
255the characters in it.
256
257Optional 2nd and 3rd arguments START and END specify the range of
c1750694 258STRING to be composed. They default to the beginning and the end of
c674f351
KH
259STRING respectively.
260
261Optional 4th argument COMPONENTS, if non-nil, is a character or a
262sequence (vector, list, or string) of integers. See the function
263`compose-region' for more detail.
264
265Optional 5th argument MODIFICATION-FUNC is a function to call to
266adjust the composition when it gets invalid because of a change of
267text in the composition."
268 (if (or (vectorp components) (listp components))
269 (setq components (encode-composition-components components)))
270 (or start (setq start 0))
271 (or end (setq end (length string)))
272 (compose-string-internal string start end components modification-func)
273 string)
274
c674f351
KH
275(defun decompose-string (string)
276 "Return STRING where `composition' property is removed."
277 (remove-text-properties 0 (length string) '(composition nil) string)
278 string)
279
c674f351
KH
280(defun compose-chars (&rest args)
281 "Return a string from arguments in which all characters are composed.
282For relative composition, arguments are characters.
283For rule-based composition, Mth \(where M is odd) arguments are
284characters, and Nth \(where N is even) arguments are composition rules.
285A composition rule is a cons of glyph reference points of the form
286\(GLOBAL-REF-POINT . NEW-REF-POINT). See the documentation of
287`reference-point-alist' for more detail."
288 (let (str components)
289 (if (consp (car (cdr args)))
290 ;; Rule-base composition.
291 (let ((len (length args))
292 (tail (encode-composition-components args 'nocopy)))
293
294 (while tail
295 (setq str (cons (car tail) str))
296 (setq tail (nthcdr 2 tail)))
297 (setq str (concat (nreverse str))
298 components args))
299 ;; Relative composition.
300 (setq str (concat args)))
301 (compose-string-internal str 0 (length str) components)))
302
c674f351 303(defun find-composition (pos &optional limit string detail-p)
9a6eb156 304 "Return information about a composition at or near buffer position POS.
c674f351
KH
305
306If the character at POS has `composition' property, the value is a list
9a6eb156 307\(FROM TO VALID-P).
c674f351
KH
308
309FROM and TO specify the range of text that has the same `composition'
8b1c87bf 310property, VALID-P is t if this composition is valid, and nil if not.
c674f351
KH
311
312If there's no composition at POS, and the optional 2nd argument LIMIT
9a6eb156 313is non-nil, search for a composition toward the position given by LIMIT.
c674f351
KH
314
315If no composition is found, return nil.
316
317Optional 3rd argument STRING, if non-nil, is a string to look for a
318composition in; nil means the current buffer.
319
320If a valid composition is found and the optional 4th argument DETAIL-P
9a6eb156
EZ
321is non-nil, the return value is a list of the form
322
323 (FROM TO COMPONENTS RELATIVE-P MOD-FUNC WIDTH)
c674f351
KH
324
325COMPONENTS is a vector of integers, the meaning depends on RELATIVE-P.
326
327RELATIVE-P is t if the composition method is relative, else nil.
328
329If RELATIVE-P is t, COMPONENTS is a vector of characters to be
330composed. If RELATIVE-P is nil, COMPONENTS is a vector of characters
331and composition rules as described in `compose-region'.
332
333MOD-FUNC is a modification function of the composition.
334
8b1c87bf
KH
335WIDTH is a number of columns the composition occupies on the screen.
336
d21133bc 337When Automatic Composition mode is on, this function also finds a
8b1c87bf
KH
338chunk of text that is automatically composed. If such a chunk is
339found closer to POS than the position that has `composition'
9a6eb156
EZ
340property, the value is a list of FROM, TO, and a glyph-string
341that specifies how the chunk is to be composed. See the function
342`composition-get-gstring' for the format of the glyph-string."
c674f351 343 (let ((result (find-composition-internal pos limit string detail-p)))
8b1c87bf 344 (if (and detail-p (> (length result) 3) (nth 2 result) (not (nth 3 result)))
c674f351
KH
345 ;; This is a valid rule-base composition.
346 (decode-composition-components (nth 2 result) 'nocopy))
347 result))
348
349\f
7141ee65 350(defun compose-chars-after (pos &optional limit object)
c674f351
KH
351 "Compose characters in current buffer after position POS.
352
67125135
KH
353It looks up the char-table `composition-function-table' (which
354see) by a character at POS, and compose characters after POS
355according to the contents of `composition-function-table'.
356
357Optional 2nd arg LIMIT, if non-nil, limits characters to compose.
c674f351 358
7141ee65 359Optional 3rd arg OBJECT, if non-nil, is a string that contains the
1d1af02d 360text to compose. In that case, POS and LIMIT index into the string.
7141ee65 361
c674f351
KH
362This function is the default value of `compose-chars-after-function'."
363 (let ((tail (aref composition-function-table (char-after pos)))
67125135
KH
364 (font-obj (and (display-multi-font-p)
365 (and (not (stringp object))
366 (font-at pos (selected-window)))))
c674f351 367 pattern func result)
67125135
KH
368 (or limit
369 (setq limit (if (stringp object) (length object) (point-max))))
d04effb3 370 (when (and font-obj tail)
339cebdc
KH
371 (save-match-data
372 (save-excursion
67125135
KH
373 (while tail
374 (if (functionp (car tail))
375 (setq pattern nil func (car tail))
376 (setq pattern (car (car tail))
377 func (cdr (car tail))))
339cebdc 378 (goto-char pos)
67125135
KH
379 (if pattern
380 (if (and (if (stringp object)
381 (eq (string-match pattern object) 0)
382 (looking-at pattern))
383 (<= (match-end 0) limit))
384 (setq result
385 (funcall func pos (match-end 0) font-obj object)))
386 (setq result (funcall func pos limit font-obj object)))
387 (if result (setq tail nil))))))
388 result))
c674f351 389
c674f351
KH
390(defun compose-last-chars (args)
391 "Compose last characters.
3b923ad8
KH
392The argument is a parameterized event of the form
393 \(compose-last-chars N COMPONENTS),
394where N is the number of characters before point to compose,
395COMPONENTS, if non-nil, is the same as the argument to `compose-region'
396\(which see). If it is nil, `compose-chars-after' is called,
2624e2ac 397and that function finds a proper rule to compose the target characters.
c674f351
KH
398This function is intended to be used from input methods.
399The global keymap binds special event `compose-last-chars' to this
3b923ad8 400function. Input method may generate an event (compose-last-chars N COMPONENTS)
2624e2ac 401after a sequence of character events."
c674f351
KH
402 (interactive "e")
403 (let ((chars (nth 1 args)))
404 (if (and (numberp chars)
405 (>= (- (point) (point-min)) chars))
3b923ad8
KH
406 (if (nth 2 args)
407 (compose-region (- (point) chars) (point) (nth 2 args))
408 (compose-chars-after (- (point) chars) (point))))))
c674f351 409
68fbe650 410(global-set-key [compose-last-chars] 'compose-last-chars)
c674f351
KH
411
412\f
68fbe650
KH
413;;; Automatic character composition.
414
68fbe650
KH
415;; Copied from font-lock.el.
416(eval-when-compile
68fbe650
KH
417 ;; Borrowed from lazy-lock.el.
418 ;; We use this to preserve or protect things when modifying text properties.
419 (defmacro save-buffer-state (varlist &rest body)
420 "Bind variables according to VARLIST and eval BODY restoring buffer state."
ba8972b6
KH
421 `(let* ,(append varlist
422 '((modified (buffer-modified-p)) (buffer-undo-list t)
423 (inhibit-read-only t) (inhibit-point-motion-hooks t)
424 (inhibit-modification-hooks t)
425 deactivate-mark buffer-file-name buffer-file-truename))
426 ,@body
427 (unless modified
428 (restore-buffer-modified-p nil))))
1d1af02d 429 ;; Fixme: This makes bootstrapping fail with this error.
ba8972b6
KH
430 ;; Symbol's function definition is void: eval-defun
431 ;;(def-edebug-spec save-buffer-state let)
432 )
68fbe650 433
02bf0a0a
KH
434(put 'save-buffer-state 'lisp-indent-function 1)
435
473ccad0
KH
436;; These macros must match with C macros LGSTRING_XXX and LGLYPH_XXX in font.h
437(defsubst lgstring-header (gstring) (aref gstring 0))
438(defsubst lgstring-set-header (gstring header) (aset gstring 0 header))
439(defsubst lgstring-font (gstring) (aref (lgstring-header gstring) 0))
440(defsubst lgstring-char (gstring i) (aref (lgstring-header gstring) (1+ i)))
441(defsubst lgstring-char-len (gstring) (1- (length (lgstring-header gstring))))
442(defsubst lgstring-shaped-p (gstring) (aref gstring 1))
443(defsubst lgstring-set-id (gstring id) (aset gstring 1 id))
444(defsubst lgstring-glyph (gstring i) (aref gstring (+ i 2)))
445(defsubst lgstring-glyph-len (gstring) (- (length gstring) 2))
446(defsubst lgstring-set-glyph (gstring i glyph) (aset gstring (+ i 2) glyph))
447
448(defsubst lglyph-from (glyph) (aref glyph 0))
449(defsubst lglyph-to (glyph) (aref glyph 1))
450(defsubst lglyph-char (glyph) (aref glyph 2))
451(defsubst lglyph-code (glyph) (aref glyph 3))
452(defsubst lglyph-width (glyph) (aref glyph 4))
453(defsubst lglyph-lbearing (glyph) (aref glyph 5))
454(defsubst lglyph-rbearing (glyph) (aref glyph 6))
455(defsubst lglyph-ascent (glyph) (aref glyph 7))
456(defsubst lglyph-descent (glyph) (aref glyph 8))
457(defsubst lglyph-adjustment (glyph) (aref glyph 9))
458
459(defsubst lglyph-set-from-to (glyph from to)
460 (progn (aset glyph 0 from) (aset glyph 1 to)))
461(defsubst lglyph-set-char (glyph char) (aset glyph 2 char))
b23dc424 462(defsubst lglyph-set-code (glyph code) (aset glyph 3 code))
473ccad0
KH
463(defsubst lglyph-set-width (glyph width) (aset glyph 4 width))
464(defsubst lglyph-set-adjustment (glyph &optional xoff yoff wadjust)
465 (aset glyph 9 (vector (or xoff 0) (or yoff 0) (or wadjust 0))))
466
467(defsubst lglyph-copy (glyph) (copy-sequence glyph))
468
469(defun lgstring-insert-glyph (gstring idx glyph)
470 (let ((nglyphs (lgstring-glyph-len gstring))
471 (i idx) g)
472 (while (and (< i nglyphs) (setq g (lgstring-glyph gstring i)))
473 (setq i (1+ i)))
474 (if (= i nglyphs)
475 (setq gstring (vconcat gstring (vector glyph)))
476 (if (< (1+ i) nglyphs)
477 (lgstring-set-glyph gstring (1+ i) nil)))
478 (while (> i idx)
479 (lgstring-set-glyph gstring i (lgstring-glyph gstring (1- i)))
480 (setq i (1- i)))
481 (lgstring-set-glyph gstring i glyph)
482 gstring))
483
484(defun compose-glyph-string (gstring from to)
485 (let ((glyph (lgstring-glyph gstring from))
486 from-pos to-pos
487 ascent descent lbearing rbearing)
488 (setq from-pos (lglyph-from glyph)
489 to-pos (lglyph-to (lgstring-glyph gstring (1- to))))
490 (lglyph-set-from-to glyph from-pos to-pos)
491 (setq from (1+ from))
492 (while (and (< from to)
493 (setq glyph (lgstring-glyph gstring from)))
494 (lglyph-set-from-to glyph from-pos to-pos)
495 (let ((xoff (if (<= (lglyph-rbearing glyph) 0) 0
496 (- (lglyph-width glyph)))))
497 (lglyph-set-adjustment glyph xoff 0 0))
498 (setq from (1+ from)))
499 gstring))
500
501(defun compose-glyph-string-relative (gstring from to &optional gap)
502 (let ((font-object (lgstring-font gstring))
503 (glyph (lgstring-glyph gstring from))
504 from-pos to-pos
505 ascent descent lbearing rbearing)
506 (if gap
507 (setq gap (floor (* (font-get font-object :size) gap)))
508 (setq gap 0))
509 (setq from-pos (lglyph-from glyph)
510 to-pos (lglyph-to (lgstring-glyph gstring (1- to)))
511 ascent (lglyph-ascent glyph)
512 descent (lglyph-descent glyph))
513 (lglyph-set-from-to glyph from-pos to-pos)
514 (setq from (1+ from))
515 (while (< from to)
516 (setq glyph (lgstring-glyph gstring from))
517 (lglyph-set-from-to glyph from-pos to-pos)
518 (let ((this-ascent (lglyph-ascent glyph))
519 (this-descent (lglyph-descent glyph))
520 xoff yoff wadjust)
521 (setq xoff (if (<= (lglyph-rbearing glyph) 0) 0
522 (- (lglyph-width glyph))))
523 (if (> this-ascent 0)
524 (if (< this-descent 0)
525 (setq yoff (- 0 ascent gap this-descent)
526 ascent (+ ascent gap this-ascent this-descent))
527 (setq yoff 0))
528 (setq yoff (+ descent gap this-ascent)
529 descent (+ descent gap this-ascent this-descent)))
530 (if (or (/= xoff 0) (/= yoff 0))
531 (lglyph-set-adjustment glyph xoff yoff 0)))
532 (setq from (1+ from)))
533 gstring))
534
535(defun compose-gstring-for-graphic (gstring)
536 "Compose glyph-string GSTRING for graphic display.
2833d915 537Combining characters are composed with the preceding base
473ccad0 538character. If the preceding character is not a base character,
2833d915 539each combining character is composed as a spacing character by
473ccad0
KH
540a padding space before and/or after the character.
541
07d7c3bd 542All non-spacing characters have this function in
473ccad0
KH
543`composition-function-table' unless overwritten."
544 (let* ((header (lgstring-header gstring))
545 (nchars (lgstring-char-len gstring))
546 (nglyphs (lgstring-glyph-len gstring))
547 (glyph (lgstring-glyph gstring 0)))
548 (cond
549 ;; A non-spacing character not following a proper base character.
550 ((= nchars 1)
551 (let ((lbearing (lglyph-lbearing glyph))
552 (rbearing (lglyph-rbearing glyph))
553 (width (lglyph-width glyph))
554 xoff wadjust)
555 (if (< lbearing 0)
556 (setq xoff (- lbearing))
557 (setq xoff 0 lbearing 0))
558 (if (< rbearing width)
559 (setq rbearing width))
560 (lglyph-set-adjustment glyph xoff 0 (- rbearing lbearing))
561 gstring))
562
563 ;; This sequence doesn't start with a proper base character.
564 ((memq (get-char-code-property (lgstring-char gstring 0)
565 'general-category)
566 '(Mn Mc Me Zs Zl Zp Cc Cf Cs))
567 nil)
568
569 ;; A base character and the following non-spacing characters.
570 (t
571 (let ((gstr (font-shape-gstring gstring)))
572 (if (and gstr
573 (> (lglyph-to (lgstring-glyph gstr 0)) 0))
574 gstr
575 ;; The shaper of the font couldn't shape the gstring.
576 ;; Shape them according to canonical-combining-class.
577 (lgstring-set-id gstring nil)
578 (let* ((width (lglyph-width glyph))
579 (ascent (lglyph-ascent glyph))
580 (descent (lglyph-descent glyph))
581 (rbearing (lglyph-rbearing glyph))
582 (lbearing (lglyph-lbearing glyph))
583 (center (/ (+ lbearing rbearing) 2))
584 (gap (round (* (font-get (lgstring-font gstring) :size) 0.1)))
585 xoff yoff)
586 (dotimes (i nchars)
587 (setq glyph (lgstring-glyph gstring i))
588 (when (> i 0)
589 (let* ((class (get-char-code-property
590 (lglyph-char glyph) 'canonical-combining-class))
591 (lb (lglyph-lbearing glyph))
592 (rb (lglyph-rbearing glyph))
593 (as (lglyph-ascent glyph))
594 (de (lglyph-descent glyph))
595 (ce (/ (+ lb rb) 2))
596 xoff yoff)
c0a839ae
KH
597 (when (and class (>= class 200) (<= class 240))
598 (setq xoff 0 yoff 0)
599 (cond
600 ((= class 200)
601 (setq xoff (- lbearing ce)
602 yoff (if (> as 0) 0 (+ descent as))))
603 ((= class 202)
604 (if (> as 0) (setq as 0))
605 (setq xoff (- center ce)
606 yoff (if (> as 0) 0 (+ descent as))))
607 ((= class 204)
608 (if (> as 0) (setq as 0))
609 (setq xoff (- rbearing ce)
610 yoff (if (> as 0) 0 (+ descent as))))
611 ((= class 208)
612 (setq xoff (- lbearing rb)))
613 ((= class 210)
614 (setq xoff (- rbearing lb)))
615 ((= class 212)
616 (setq xoff (- lbearing ce)
617 yoff (if (>= de 0) 0 (- (- ascent) de))))
618 ((= class 214)
619 (setq xoff (- center ce)
620 yoff (if (>= de 0) 0 (- (- ascent) de))))
621 ((= class 216)
622 (setq xoff (- rbearing ce)
623 yoff (if (>= de 0) 0 (- (- ascent) de))))
624 ((= class 218)
625 (setq xoff (- lbearing ce)
626 yoff (if (> as 0) 0 (+ descent as gap))))
627 ((= class 220)
628 (setq xoff (- center ce)
629 yoff (if (> as 0) 0 (+ descent as gap))))
630 ((= class 222)
631 (setq xoff (- rbearing ce)
632 yoff (if (> as 0) 0 (+ descent as gap))))
633 ((= class 224)
634 (setq xoff (- lbearing rb)))
635 ((= class 226)
636 (setq xoff (- rbearing lb)))
637 ((= class 228)
638 (setq xoff (- lbearing ce)
639 yoff (if (>= de 0) 0 (- (- ascent) de gap))))
640 ((= class 230)
641 (setq xoff (- center ce)
642 yoff (if (>= de 0) 0 (- (- ascent) de gap))))
643 ((= class 232)
644 (setq xoff (- rbearing ce)
645 yoff (if (>= de 0) 0 (- (+ ascent de) gap)))))
646 (lglyph-set-adjustment glyph (- xoff width) yoff)
647 (setq lb (+ lb xoff)
648 rb (+ lb xoff)
649 as (- as yoff)
650 de (+ de yoff)))
651 (if (< ascent as)
652 (setq ascent as))
653 (if (< descent de)
654 (setq descent de))))))
473ccad0
KH
655 (let ((i 0))
656 (while (and (< i nglyphs) (setq glyph (lgstring-glyph gstring i)))
657 (lglyph-set-from-to glyph 0 (1- nchars))
658 (setq i (1+ i))))
659 gstring))))))
660
6d341a2a 661(let ((elt `([,(purecopy "\\c.\\c^+") 1 compose-gstring-for-graphic]
473ccad0
KH
662 [nil 0 compose-gstring-for-graphic])))
663 (map-char-table
664 #'(lambda (key val)
2833d915 665 (if (memq val '(Mn Mc Me))
473ccad0 666 (set-char-table-range composition-function-table key elt)))
2833d915 667 unicode-category-table))
473ccad0
KH
668
669(defun compose-gstring-for-terminal (gstring)
670 "Compose glyph string GSTRING for terminal display.
671Non-spacing characters are composed with the preceding base
672character. If the preceding character is not a base character,
673each non-spacing character is composed as a spacing character by
07d7c3bd 674prepending a space before it."
473ccad0
KH
675 (let* ((header (lgstring-header gstring))
676 (nchars (lgstring-char-len gstring))
677 (nglyphs (lgstring-glyph-len gstring))
678 (i 0)
8da43785 679 (coding (lgstring-font gstring))
473ccad0
KH
680 glyph)
681 (while (and (< i nglyphs)
682 (setq glyph (lgstring-glyph gstring i)))
8da43785 683 (if (not (char-charset (lglyph-char glyph) coding))
473ccad0 684 (progn
8da43785
KH
685 ;; As the terminal doesn't support this glyph, return a
686 ;; gstring in which each glyph is its own graphme-cluster
687 ;; of width 1..
688 (setq i 0)
689 (while (and (< i nglyphs)
690 (setq glyph (lgstring-glyph gstring i)))
691 (if (< (lglyph-width glyph) 1)
692 (lglyph-set-width glyph 1))
693 (lglyph-set-from-to glyph i i)
694 (setq i (1+ i))))
695 (if (= (lglyph-width glyph) 0)
b8321d86
KH
696 (if (eq (get-char-code-property (lglyph-char glyph)
697 'general-category)
698 'Cf)
699 (progn
700 ;; Compose by replacing with a space.
701 (lglyph-set-char glyph 32)
702 (lglyph-set-width glyph 1)
703 (setq i (1+ i)))
8da43785
KH
704 ;; Compose by prepending a space.
705 (setq gstring (lgstring-insert-glyph gstring i
706 (lglyph-copy glyph))
707 nglyphs (lgstring-glyph-len gstring))
708 (setq glyph (lgstring-glyph gstring i))
709 (lglyph-set-char glyph 32)
710 (lglyph-set-width glyph 1)
711 (setq i (+ 2)))
712 (let ((from (lglyph-from glyph))
713 (to (lglyph-to glyph))
714 (j (1+ i)))
715 (while (and (< j nglyphs)
716 (setq glyph (lgstring-glyph gstring j))
717 (char-charset (lglyph-char glyph) coding)
718 (= (lglyph-width glyph) 0))
719 (setq to (lglyph-to glyph)
720 j (1+ j)))
721 (while (< i j)
722 (setq glyph (lgstring-glyph gstring i))
723 (lglyph-set-from-to glyph from to)
724 (setq i (1+ i)))))))
473ccad0
KH
725 gstring))
726
727
728(defun auto-compose-chars (func from to font-object string)
729 "Compose the characters at FROM by FUNC.
730FUNC is called with one argument GSTRING which is built for characters
731in the region FROM (inclusive) and TO (exclusive).
732
733If the character are composed on a graphic display, FONT-OBJECT
1ce3d35b 734is a font to use. Otherwise, FONT-OBJECT is nil, and the function
473ccad0
KH
735`compose-gstring-for-terminal' is used instead of FUNC.
736
00ddf712
KH
737If STRING is non-nil, it is a string, and FROM and TO are indices
738into the string. In that case, compose characters in the string.
68fbe650 739
473ccad0
KH
740The value is a gstring containing information for shaping the characters.
741
68fbe650 742This function is the default value of `auto-composition-function' (which see)."
473ccad0
KH
743 (let ((gstring (composition-get-gstring from to font-object string)))
744 (if (lgstring-shaped-p gstring)
745 gstring
8da43785 746 (or (fontp font-object 'font-object)
473ccad0
KH
747 (setq func 'compose-gstring-for-terminal))
748 (funcall func gstring))))
68fbe650 749
d9a7c140
KH
750(put 'auto-composition-mode 'permanent-local t)
751
37707939 752(make-variable-buffer-local 'auto-composition-function)
d9a7c140 753(setq-default auto-composition-function 'auto-compose-chars)
37707939 754
16d58d04 755;;;###autoload
56eb0904 756(define-minor-mode auto-composition-mode
ad1b4641
GM
757 "Toggle Auto Composition mode.
758With ARG, turn Auto Composition mode off if and only if ARG is a non-positive
759number; if ARG is nil, toggle Auto Composition mode; anything else turns Auto
760Composition on.
37707939
KH
761
762When Auto Composition is enabled, text characters are automatically composed
763by functions registered in `composition-function-table' (which see).
764
ad1b4641 765You can use `global-auto-composition-mode' to turn on
56eb0904 766Auto Composition mode in all buffers (this is the default).")
37707939 767
16d58d04 768;;;###autoload
f44379e7 769(define-minor-mode global-auto-composition-mode
d9a7c140
KH
770 "Toggle Auto-Composition mode in every possible buffer.
771With prefix arg, turn Global-Auto-Composition mode on if and only if arg
772is positive.
773See `auto-composition-mode' for more information on Auto-Composition mode."
f44379e7
SM
774 :variable (default-value 'auto-composition-mode))
775
a485d4f7 776(defalias 'toggle-auto-composition 'auto-composition-mode)
bd4a85b9 777
c674f351 778\f
09d52401
SM
779;; The following codes are only for backward compatibility with Emacs
780;; 20.4 and earlier.
c674f351 781
c674f351
KH
782(defun decompose-composite-char (char &optional type with-composition-rule)
783 "Convert CHAR to string.
c674f351
KH
784
785If optional 2nd arg TYPE is non-nil, it is `string', `list', or
1ea62389
JB
786`vector'. In this case, CHAR is converted to string, list of CHAR, or
787vector of CHAR respectively.
788Optional 3rd arg WITH-COMPOSITION-RULE is ignored."
c674f351
KH
789 (cond ((or (null type) (eq type 'string)) (char-to-string char))
790 ((eq type 'list) (list char))
791 (t (vector char))))
792
8d787845
KH
793(make-obsolete 'decompose-composite-char 'char-to-string "21.1")
794
c674f351 795\f
6b61353c 796
09d52401 797;; arch-tag: ee703d77-1723-45d4-a31f-e9f0f867aa33
c674f351 798;;; composite.el ends here