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