-(defvar composition-function-table
- (make-char-table nil)
- "Char table of functions for automatic character composition.
-For each character that has to be composed automatically with
-preceding and/or following characters, this char table contains
-a function to call to compose that character.
-
-An element, if non-nil, is FUNC or an alist of PATTERNs vs FUNCs,
-where PATTERNs are regular expressions and FUNCs are functions.
-If the element is FUNC, FUNC itself determines the region to
-compose.
-
-Each function is called with 4 arguments, FROM, TO, FONT-OBJECT,
-and STRING.
-
-If STRING is nil, FROM and TO are positions specifying the region
-matching with PATTERN in the current buffer, and the function has
-to compose character in that region (possibly with characters
-preceding FROM). FONT-OBJECT may be nil if not
-available (e.g. for the case of terminal). The return value of
-the function is the end position where characters are composed,
-or nil if no composition is made.
-
-Otherwise, STRING is a string, and FROM and TO are indices into
-the string. In this case, the function has to compose a
-character in the string. The others are the same as above.
-
-See also the documentation of `auto-composition-mode'.")
-
-;; Copied from font-lock.el.
-(eval-when-compile
- ;; Borrowed from lazy-lock.el.
- ;; We use this to preserve or protect things when modifying text properties.
- (defmacro save-buffer-state (varlist &rest body)
- "Bind variables according to VARLIST and eval BODY restoring buffer state."
- `(let* ,(append varlist
- '((modified (buffer-modified-p)) (buffer-undo-list t)
- (inhibit-read-only t) (inhibit-point-motion-hooks t)
- (inhibit-modification-hooks t)
- deactivate-mark buffer-file-name buffer-file-truename))
- ,@body
- (unless modified
- (restore-buffer-modified-p nil))))
- ;; Fixme: This makes bootstrapping fail with this error.
- ;; Symbol's function definition is void: eval-defun
- ;;(def-edebug-spec save-buffer-state let)
- )
-
-(put 'save-buffer-state 'lisp-indent-function 1)
-
-(defun terminal-composition-function (from to font-object string)
- "General composition function used on terminal.
-Non-spacing characters are composed with the preceding spacing
-character. All non-spacing characters has this function in
-`terminal-composition-function-table'."
- (let ((pos (1+ from)))
- (if string
- (progn
- (while (and (< pos to)
- (= (aref char-width-table (aref string pos)) 0))
- (setq pos (1+ pos)))
- (if (> from 0)
- (compose-string string (1- from) pos)
- (compose-string string from pos
- (concat " " (buffer-substring from pos)))))
- (while (and (< pos to)
- (= (aref char-width-table (char-after pos)) 0))
- (setq pos (1+ pos)))
- (if (> from (point-min))
- (compose-region (1- from) pos (buffer-substring from pos))
- (compose-region from pos
- (concat " " (buffer-substring from pos)))))
- pos))
-
-(defvar terminal-composition-function-table
- (let ((table (make-char-table nil)))
+;; These macros must match with C macros LGSTRING_XXX and LGLYPH_XXX in font.h
+(defsubst lgstring-header (gstring) (aref gstring 0))
+(defsubst lgstring-set-header (gstring header) (aset gstring 0 header))
+(defsubst lgstring-font (gstring) (aref (lgstring-header gstring) 0))
+(defsubst lgstring-char (gstring i) (aref (lgstring-header gstring) (1+ i)))
+(defsubst lgstring-char-len (gstring) (1- (length (lgstring-header gstring))))
+(defsubst lgstring-shaped-p (gstring) (aref gstring 1))
+(defsubst lgstring-set-id (gstring id) (aset gstring 1 id))
+(defsubst lgstring-glyph (gstring i) (aref gstring (+ i 2)))
+(defsubst lgstring-glyph-len (gstring) (- (length gstring) 2))
+(defsubst lgstring-set-glyph (gstring i glyph) (aset gstring (+ i 2) glyph))
+
+(defsubst lglyph-from (glyph) (aref glyph 0))
+(defsubst lglyph-to (glyph) (aref glyph 1))
+(defsubst lglyph-char (glyph) (aref glyph 2))
+(defsubst lglyph-code (glyph) (aref glyph 3))
+(defsubst lglyph-width (glyph) (aref glyph 4))
+(defsubst lglyph-lbearing (glyph) (aref glyph 5))
+(defsubst lglyph-rbearing (glyph) (aref glyph 6))
+(defsubst lglyph-ascent (glyph) (aref glyph 7))
+(defsubst lglyph-descent (glyph) (aref glyph 8))
+(defsubst lglyph-adjustment (glyph) (aref glyph 9))
+
+(defsubst lglyph-set-from-to (glyph from to)
+ (progn (aset glyph 0 from) (aset glyph 1 to)))
+(defsubst lglyph-set-char (glyph char) (aset glyph 2 char))
+(defsubst lglyph-set-code (glyph code) (aset glyph 3 code))
+(defsubst lglyph-set-width (glyph width) (aset glyph 4 width))
+(defsubst lglyph-set-adjustment (glyph &optional xoff yoff wadjust)
+ (aset glyph 9 (vector (or xoff 0) (or yoff 0) (or wadjust 0))))
+
+(defsubst lglyph-copy (glyph) (copy-sequence glyph))
+
+(defun lgstring-insert-glyph (gstring idx glyph)
+ (let ((nglyphs (lgstring-glyph-len gstring))
+ (i idx))
+ (while (and (< i nglyphs) (lgstring-glyph gstring i))
+ (setq i (1+ i)))
+ (if (= i nglyphs)
+ (setq gstring (vconcat gstring (vector glyph)))
+ (if (< (1+ i) nglyphs)
+ (lgstring-set-glyph gstring (1+ i) nil)))
+ (while (> i idx)
+ (lgstring-set-glyph gstring i (lgstring-glyph gstring (1- i)))
+ (setq i (1- i)))
+ (lgstring-set-glyph gstring i glyph)
+ gstring))
+
+(defun compose-glyph-string (gstring from to)
+ (let ((glyph (lgstring-glyph gstring from))
+ from-pos to-pos)
+ (setq from-pos (lglyph-from glyph)
+ to-pos (lglyph-to (lgstring-glyph gstring (1- to))))
+ (lglyph-set-from-to glyph from-pos to-pos)
+ (setq from (1+ from))
+ (while (and (< from to)
+ (setq glyph (lgstring-glyph gstring from)))
+ (lglyph-set-from-to glyph from-pos to-pos)
+ (let ((xoff (if (<= (lglyph-rbearing glyph) 0) 0
+ (- (lglyph-width glyph)))))
+ (lglyph-set-adjustment glyph xoff 0 0))
+ (setq from (1+ from)))
+ gstring))
+
+(defun compose-glyph-string-relative (gstring from to &optional gap)
+ (let ((font-object (lgstring-font gstring))
+ (glyph (lgstring-glyph gstring from))
+ from-pos to-pos
+ ascent descent)
+ (if gap
+ (setq gap (floor (* (font-get font-object :size) gap)))
+ (setq gap 0))
+ (setq from-pos (lglyph-from glyph)
+ to-pos (lglyph-to (lgstring-glyph gstring (1- to)))
+ ascent (lglyph-ascent glyph)
+ descent (lglyph-descent glyph))
+ (lglyph-set-from-to glyph from-pos to-pos)
+ (setq from (1+ from))
+ (while (< from to)
+ (setq glyph (lgstring-glyph gstring from))
+ (lglyph-set-from-to glyph from-pos to-pos)
+ (let ((this-ascent (lglyph-ascent glyph))
+ (this-descent (lglyph-descent glyph))
+ xoff yoff)
+ (setq xoff (if (<= (lglyph-rbearing glyph) 0) 0
+ (- (lglyph-width glyph))))
+ (if (> this-ascent 0)
+ (if (< this-descent 0)
+ (setq yoff (- 0 ascent gap this-descent)
+ ascent (+ ascent gap this-ascent this-descent))
+ (setq yoff 0))
+ (setq yoff (+ descent gap this-ascent)
+ descent (+ descent gap this-ascent this-descent)))
+ (if (or (/= xoff 0) (/= yoff 0))
+ (lglyph-set-adjustment glyph xoff yoff 0)))
+ (setq from (1+ from)))
+ gstring))
+
+(defun compose-gstring-for-graphic (gstring)
+ "Compose glyph-string GSTRING for graphic display.
+Combining characters are composed with the preceding base
+character. If the preceding character is not a base character,
+each combining character is composed as a spacing character by
+a padding space before and/or after the character.
+
+All non-spacing characters have this function in
+`composition-function-table' unless overwritten."
+ (let ((nchars (lgstring-char-len gstring))
+ (nglyphs (lgstring-glyph-len gstring))
+ (glyph (lgstring-glyph gstring 0)))
+ (cond
+ ;; A non-spacing character not following a proper base character.
+ ((= nchars 1)
+ (let ((lbearing (lglyph-lbearing glyph))
+ (rbearing (lglyph-rbearing glyph))
+ (width (lglyph-width glyph))
+ xoff)
+ (if (< lbearing 0)
+ (setq xoff (- lbearing))
+ (setq xoff 0 lbearing 0))
+ (if (< rbearing width)
+ (setq rbearing width))
+ (lglyph-set-adjustment glyph xoff 0 (- rbearing lbearing))
+ gstring))
+
+ ;; This sequence doesn't start with a proper base character.
+ ((memq (get-char-code-property (lgstring-char gstring 0)
+ 'general-category)
+ '(Mn Mc Me Zs Zl Zp Cc Cf Cs))
+ nil)
+
+ ;; A base character and the following non-spacing characters.
+ (t
+ (let ((gstr (font-shape-gstring gstring)))
+ (if (and gstr
+ (> (lglyph-to (lgstring-glyph gstr 0)) 0))
+ gstr
+ ;; The shaper of the font couldn't shape the gstring.
+ ;; Shape them according to canonical-combining-class.
+ (lgstring-set-id gstring nil)
+ (let* ((width (lglyph-width glyph))
+ (ascent (lglyph-ascent glyph))
+ (descent (lglyph-descent glyph))
+ (rbearing (lglyph-rbearing glyph))
+ (lbearing (lglyph-lbearing glyph))
+ (center (/ (+ lbearing rbearing) 2))
+ ;; Artificial vertical gap between the glyphs.
+ (gap (round (* (font-get (lgstring-font gstring) :size) 0.1))))
+ (if (= gap 0)
+ ;; Assure at least 1 pixel vertical gap.
+ (setq gap 1))
+ (dotimes (i nchars)
+ (setq glyph (lgstring-glyph gstring i))
+ (when (> i 0)
+ (let* ((class (get-char-code-property
+ (lglyph-char glyph) 'canonical-combining-class))
+ (lb (lglyph-lbearing glyph))
+ (rb (lglyph-rbearing glyph))
+ (as (lglyph-ascent glyph))
+ (de (lglyph-descent glyph))
+ (ce (/ (+ lb rb) 2))
+ (w (lglyph-width glyph))
+ xoff yoff)
+ (cond
+ ((and class (>= class 200) (<= class 240))
+ (setq xoff 0 yoff 0)
+ (cond
+ ((= class 200)
+ (setq xoff (- lbearing ce)
+ yoff (if (> as 0) 0 (+ descent as))))
+ ((= class 202)
+ (if (> as 0) (setq as 0))
+ (setq xoff (- center ce)
+ yoff (if (> as 0) 0 (+ descent as))))
+ ((= class 204)
+ (if (> as 0) (setq as 0))
+ (setq xoff (- rbearing ce)
+ yoff (if (> as 0) 0 (+ descent as))))
+ ((= class 208)
+ (setq xoff (- lbearing rb)))
+ ((= class 210)
+ (setq xoff (- rbearing lb)))
+ ((= class 212)
+ (setq xoff (- lbearing ce)
+ yoff (if (>= de 0) 0 (- (- ascent) de))))
+ ((= class 214)
+ (setq xoff (- center ce)
+ yoff (if (>= de 0) 0 (- (- ascent) de))))
+ ((= class 216)
+ (setq xoff (- rbearing ce)
+ yoff (if (>= de 0) 0 (- (- ascent) de))))
+ ((= class 218)
+ (setq xoff (- lbearing ce)
+ yoff (if (> as 0) 0 (+ descent as gap))))
+ ((= class 220)
+ (setq xoff (- center ce)
+ yoff (if (> as 0) 0 (+ descent as gap))))
+ ((= class 222)
+ (setq xoff (- rbearing ce)
+ yoff (if (> as 0) 0 (+ descent as gap))))
+ ((= class 224)
+ (setq xoff (- lbearing rb)))
+ ((= class 226)
+ (setq xoff (- rbearing lb)))
+ ((= class 228)
+ (setq xoff (- lbearing ce)
+ yoff (if (>= de 0) 0 (- (- ascent) de gap))))
+ ((= class 230)
+ (setq xoff (- center ce)
+ yoff (if (>= de 0) 0 (- (- ascent) de gap))))
+ ((= class 232)
+ (setq xoff (- rbearing ce)
+ yoff (if (>= de 0) 0 (- (+ ascent de) gap)))))
+ (lglyph-set-adjustment glyph (- xoff width) yoff)
+ (setq lb (+ lb xoff)
+ rb (+ lb xoff)
+ as (- as yoff)
+ de (+ de yoff)))
+ ((and (= class 0)
+ (eq (get-char-code-property (lglyph-char glyph)
+ 'general-category) 'Me))
+ ;; Artificially laying out glyphs in an enclosing
+ ;; mark is difficult. All we can do is to adjust
+ ;; the x-offset and width of the base glyph to
+ ;; align it at the center of the glyph of the
+ ;; enclosing mark hoping that the enclosing mark
+ ;; is big enough. We also have to adjust the
+ ;; x-offset and width of the mark ifself properly
+ ;; depending on how the glyph is designed.
+
+ ;; (non-spacing or not). For instance, when we
+ ;; have these glyphs:
+ ;; X position |
+ ;; base: <-*-> lbearing=0 rbearing=5 width=5
+ ;; mark: <----------.> lb=-11 rb=2 w=0
+ ;; we get a correct layout by moving them as this:
+ ;; base: <-*-> XOFF=4 WAD=9
+ ;; mark: <----------.> xoff=2 wad=4
+ ;; we have moved the base to the left by 4-pixel
+ ;; and make its width 9-pixel, then move the mark
+ ;; to the left 2-pixel and make its width 4-pixel.
+ (let* (;; Adjustment for the base glyph
+ (XOFF (/ (- rb lb width) 2))
+ (WAD (+ width XOFF))
+ ;; Adjustment for the enclosing mark glyph
+ (xoff (- (+ lb WAD)))
+ (wad (- rb lb WAD)))
+ (lglyph-set-adjustment glyph xoff 0 wad)
+ (setq glyph (lgstring-glyph gstring 0))
+ (lglyph-set-adjustment glyph XOFF 0 WAD))))
+ (if (< ascent as)
+ (setq ascent as))
+ (if (< descent de)
+ (setq descent de))))))
+ (let ((i 0))
+ (while (and (< i nglyphs) (setq glyph (lgstring-glyph gstring i)))
+ (lglyph-set-from-to glyph 0 (1- nchars))
+ (setq i (1+ i))))
+ gstring))))))
+
+(defun compose-gstring-for-dotted-circle (gstring)
+ (let* ((dc (lgstring-glyph gstring 0)) ; glyph of dotted-circle
+ (dc-id (lglyph-code dc))
+ (fc (lgstring-glyph gstring 1)) ; glyph of the following char
+ (fc-id (lglyph-code fc))
+ (gstr (and nil (font-shape-gstring gstring))))
+ (if (and gstr
+ (or (= (lgstring-glyph-len gstr) 1)
+ (and (= (lgstring-glyph-len gstr) 2)
+ (= (lglyph-to (lgstring-glyph gstr 0))
+ (lglyph-to (lgstring-glyph gstr 1))))))
+ ;; It seems that font-shape-gstring has composed glyphs.
+ gstr
+ ;; Artificially compose the following glyph with the preceding
+ ;; dotted-circle.
+ (setq dc (lgstring-glyph gstring 0)
+ fc (lgstring-glyph gstring 1))
+ (let ((dc-width (lglyph-width dc))
+ (fc-width (- (lglyph-rbearing fc) (lglyph-lbearing fc)))
+ (from (lglyph-from dc))
+ (to (lglyph-to fc))
+ (xoff 0) (yoff 0) (width 0))
+ (if (and (< (lglyph-descent fc) 0)
+ (> (lglyph-ascent dc) (- (lglyph-descent fc))))
+ ;; Set YOFF so that the following glyph is put on top of
+ ;; the dotted-circle.
+ (setq yoff (- (- (lglyph-descent fc)) (lglyph-ascent dc))))
+ (if (> (lglyph-width fc) 0)
+ (setq xoff (- (lglyph-rbearing fc))))
+ (if (< dc-width fc-width)
+ ;; The following glyph is wider, but we don't know how to
+ ;; align both glyphs. So, try the easiet method;
+ ;; i.e. align left edges of the glyphs.
+ (setq xoff (- xoff (- dc-width) (- (lglyph-lbearing fc )))
+ width (- fc-width dc-width)))
+ (if (or (/= xoff 0) (/= yoff 0) (/= width 0) (/= (lglyph-width fc) 0))
+ (lglyph-set-adjustment fc xoff yoff width))
+ (lglyph-set-from-to dc from to)
+ (lglyph-set-from-to fc from to))
+ (if (> (lgstring-glyph-len gstring) 2)
+ (lgstring-set-glyph gstring 2 nil))
+ gstring)))
+
+;; Allow for bootstrapping without uni-*.el.
+(when unicode-category-table
+ (let ((elt `([,(purecopy "\\c.\\c^+") 1 compose-gstring-for-graphic]
+ [nil 0 compose-gstring-for-graphic])))