diff options
| author | Kenichi Handa | 2010-07-12 14:25:46 +0900 |
|---|---|---|
| committer | Kenichi Handa | 2010-07-12 14:25:46 +0900 |
| commit | 6f2cdcd11202a6976a399bed4c071b9ac9ce254f (patch) | |
| tree | ca480f60a413349000296f91de2cff759fd98da5 | |
| parent | 2300368463c9719839a0289cd6dccaa93d3274cf (diff) | |
| download | emacs-6f2cdcd11202a6976a399bed4c071b9ac9ce254f.tar.gz emacs-6f2cdcd11202a6976a399bed4c071b9ac9ce254f.zip | |
Improve Hebrew rendering.
| -rw-r--r-- | lisp/ChangeLog | 8 | ||||
| -rw-r--r-- | lisp/language/hebrew.el | 178 | ||||
| -rw-r--r-- | src/ChangeLog | 3 | ||||
| -rw-r--r-- | src/Makefile.in | 4 |
4 files changed, 169 insertions, 24 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index e988b6bdef4..3d8648c86b6 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,11 @@ | |||
| 1 | 2010-07-12 Kenichi Handa <handa@m17n.org> | ||
| 2 | |||
| 3 | * language/hebrew.el: Remove no-byte-compile declaration. Change | ||
| 4 | coding: tag to utf-8. Register hebrew-shape-gstring in | ||
| 5 | composition-function-table for 3-character looking back. | ||
| 6 | (hebrew-font-get-precomposed): New function. | ||
| 7 | (hebrew-shape-gstring): Utilize precomposed glyphs if available. | ||
| 8 | |||
| 1 | 2010-07-11 Chong Yidong <cyd@stupidchicken.com> | 9 | 2010-07-11 Chong Yidong <cyd@stupidchicken.com> |
| 2 | 10 | ||
| 3 | * mouse.el (mouse-drag-track): Handle select-active-regions | 11 | * mouse.el (mouse-drag-track): Handle select-active-regions |
diff --git a/lisp/language/hebrew.el b/lisp/language/hebrew.el index f024251c60b..89a22d2d238 100644 --- a/lisp/language/hebrew.el +++ b/lisp/language/hebrew.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; hebrew.el --- support for Hebrew -*- coding: iso-2022-7bit; no-byte-compile: t -*- | 1 | ;;; hebrew.el --- support for Hebrew -*- coding: utf-8 -*- |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 | 3 | ;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 |
| 4 | ;; Free Software Foundation, Inc. | 4 | ;; Free Software Foundation, Inc. |
| @@ -59,7 +59,7 @@ | |||
| 59 | (nonascii-translation . iso-8859-8) | 59 | (nonascii-translation . iso-8859-8) |
| 60 | (input-method . "hebrew") | 60 | (input-method . "hebrew") |
| 61 | (unibyte-display . hebrew-iso-8bit) | 61 | (unibyte-display . hebrew-iso-8bit) |
| 62 | (sample-text . "Hebrew ,Hylem(B") | 62 | (sample-text . "Hebrew שלום") |
| 63 | (documentation . "Bidirectional editing is supported."))) | 63 | (documentation . "Bidirectional editing is supported."))) |
| 64 | 64 | ||
| 65 | (set-language-info-alist | 65 | (set-language-info-alist |
| @@ -85,33 +85,167 @@ Bidirectional editing is supported."))) | |||
| 85 | :mime-charset 'cp862) | 85 | :mime-charset 'cp862) |
| 86 | (define-coding-system-alias 'ibm862 'cp862) | 86 | (define-coding-system-alias 'ibm862 'cp862) |
| 87 | 87 | ||
| 88 | ;; Composition function for hebrew. | 88 | ;; Return a nested alist of Hebrew character sequences vs the |
| 89 | ;; corresponding glyph of FONT-OBJECT. | ||
| 90 | (defun hebrew-font-get-precomposed (font-object) | ||
| 91 | (let ((precomposed (font-get font-object 'hebrew-precomposed)) | ||
| 92 | ;; Vector of Hebrew precomposed charaters. | ||
| 93 | (chars [#xFB2A #xFB2B #xFB2C #xFB2D #xFB2E #xFB2F #xFB30 #xFB31 | ||
| 94 | #xFB32 #xFB33 #xFB34 #xFB35 #xFB36 #xFB38 #xFB39 #xFB3A | ||
| 95 | #xFB3B #xFB3C #xFB3E #xFB40 #xFB41 #xFB43 #xFB44 #xFB46 | ||
| 96 | #xFB47 #xFB48 #xFB49 #xFB4A #xFB4B #xFB4C #xFB4D #xFB4E]) | ||
| 97 | ;; Vector of decomposition character sequences corresponding | ||
| 98 | ;; to the above vector. | ||
| 99 | (decomposed | ||
| 100 | [[#x05E9 #x05C1] | ||
| 101 | [#x05E9 #x05C2] | ||
| 102 | [#x05E9 #x05BC #x05C1] | ||
| 103 | [#x05E9 #x05BC #x05C2] | ||
| 104 | [#x05D0 #x05B7] | ||
| 105 | [#x05D0 #x05B8] | ||
| 106 | [#x05D0 #x05BC] | ||
| 107 | [#x05D1 #x05BC] | ||
| 108 | [#x05D2 #x05BC] | ||
| 109 | [#x05D3 #x05BC] | ||
| 110 | [#x05D4 #x05BC] | ||
| 111 | [#x05D5 #x05BC] | ||
| 112 | [#x05D6 #x05BC] | ||
| 113 | [#x05D8 #x05BC] | ||
| 114 | [#x05D9 #x05BC] | ||
| 115 | [#x05DA #x05BC] | ||
| 116 | [#x05DB #x05BC] | ||
| 117 | [#x05DC #x05BC] | ||
| 118 | [#x05DE #x05BC] | ||
| 119 | [#x05E0 #x05BC] | ||
| 120 | [#x05E1 #x05BC] | ||
| 121 | [#x05E3 #x05BC] | ||
| 122 | [#x05E4 #x05BC] | ||
| 123 | [#x05E6 #x05BC] | ||
| 124 | [#x05E7 #x05BC] | ||
| 125 | [#x05E8 #x05BC] | ||
| 126 | [#x05E9 #x05BC] | ||
| 127 | [#x05EA #x05BC] | ||
| 128 | [#x05D5 #x05B9] | ||
| 129 | [#x05D1 #x05BF] | ||
| 130 | [#x05DB #x05BF] | ||
| 131 | [#x05E4 #x05BF]])) | ||
| 132 | (unless precomposed | ||
| 133 | (setq precomposed (list t)) | ||
| 134 | (let ((gvec (font-get-glyphs font-object 0 (length chars) chars))) | ||
| 135 | (dotimes (i (length chars)) | ||
| 136 | (if (aref gvec i) | ||
| 137 | (set-nested-alist (aref decomposed i) (aref gvec i) | ||
| 138 | precomposed)))) | ||
| 139 | ;; Cache the result in FONT-OBJECT's property. | ||
| 140 | (font-put font-object 'hebrew-precomposed precomposed)) | ||
| 141 | precomposed)) | ||
| 142 | |||
| 143 | ;; Composition function for hebrew. GSTRING is made of a Hebrew base | ||
| 144 | ;; character followed by Hebrew diacritical marks, or is made of | ||
| 145 | ;; single Hebrew diacritical mark. Adjust GSTRING to display that | ||
| 146 | ;; sequence properly. The basic strategy is: | ||
| 147 | ;; | ||
| 148 | ;; (1) If there's single diacritical, add padding space to the left | ||
| 149 | ;; and right of the glyph. | ||
| 150 | ;; | ||
| 151 | ;; (2) If the font has OpenType features for Hebrew, ask the OTF | ||
| 152 | ;; driver the whole work. | ||
| 153 | ;; | ||
| 154 | ;; (3) If the font has precomposed glyphs, use them as far as | ||
| 155 | ;; possible. Adjust the remaining glyphs artificially. | ||
| 156 | |||
| 89 | (defun hebrew-shape-gstring (gstring) | 157 | (defun hebrew-shape-gstring (gstring) |
| 90 | (setq gstring (font-shape-gstring gstring)) | 158 | (let* ((font (lgstring-font gstring)) |
| 91 | (let ((header (lgstring-header gstring)) | 159 | (otf (font-get font :otf)) |
| 92 | (nchars (lgstring-char-len gstring)) | 160 | (nchars (lgstring-char-len gstring)) |
| 93 | (nglyphs (lgstring-glyph-len gstring)) | 161 | header nglyphs base-width glyph precomposed val idx) |
| 94 | (base-width (lglyph-width (lgstring-glyph gstring 0)))) | 162 | (cond |
| 95 | (while (and (> nglyphs 1) | 163 | ((= nchars 1) |
| 96 | (not (lgstring-glyph gstring (1- nglyphs)))) | 164 | ;; Independent diacritical mark. Add padding space to left or |
| 97 | (setq nglyphs (1- nglyphs))) | 165 | ;; right so that the glyph doesn't overlap with the surrounding |
| 98 | (while (> nglyphs 1) | 166 | ;; chars. |
| 99 | (setq nglyphs (1- nglyphs)) | 167 | (setq glyph (lgstring-glyph gstring 0)) |
| 100 | (let* ((glyph (lgstring-glyph gstring nglyphs)) | 168 | (let ((width (lglyph-width glyph)) |
| 101 | (adjust (and glyph (lglyph-adjustment glyph)))) | 169 | bearing) |
| 102 | (if adjust | 170 | (if (< (setq bearing (lglyph-lbearing glyph)) 0) |
| 103 | (setq nglyphs 0) | 171 | (lglyph-set-adjustment glyph bearing 0 (- width bearing))) |
| 104 | (if (>= (lglyph-lbearing glyph) 0) | 172 | (if (> (setq bearing (lglyph-rbearing glyph)) width) |
| 105 | (lglyph-set-adjustment glyph (- base-width) 0 0)))))) | 173 | (lglyph-set-adjustment glyph 0 0 bearing)))) |
| 106 | gstring) | 174 | |
| 175 | ((or (assq 'hebr (car otf)) (assq 'hebr (cdr otf))) | ||
| 176 | ;; FONT has OpenType features for Hebrew. | ||
| 177 | (font-shape-gstring gstring)) | ||
| 178 | |||
| 179 | (t | ||
| 180 | ;; FONT doesn't have OpenType features for Hebrew. | ||
| 181 | ;; Try a precomposed glyph. | ||
| 182 | ;; Now GSTRING is in this form: | ||
| 183 | ;; [[FONT CHAR1 CHAR2 ... CHARn] nil GLYPH1 GLYPH2 ... GLYPHn nil ...] | ||
| 184 | (setq precomposed (hebrew-font-get-precomposed font) | ||
| 185 | header (lgstring-header gstring) | ||
| 186 | val (lookup-nested-alist header precomposed nil 1)) | ||
| 187 | (if (and (consp val) (vectorp (car val))) | ||
| 188 | ;; All characters can be displayed by a single precomposed glyph. | ||
| 189 | ;; Reform GSTRING to [HEADER nil PRECOMPOSED-GLYPH nil ...] | ||
| 190 | (let ((glyph (copy-sequence (car val)))) | ||
| 191 | (lglyph-set-from-to glyph 0 (1- nchars)) | ||
| 192 | (lgstring-set-glyph gstring 0 glyph) | ||
| 193 | (lgstring-set-glyph gstring 1 nil)) | ||
| 194 | (if (and (integerp val) (> val 2) | ||
| 195 | (setq glyph (lookup-nested-alist header precomposed val 1)) | ||
| 196 | (consp glyph) (vectorp (car glyph))) | ||
| 197 | ;; The first (1- VAL) characters can be displayed by a | ||
| 198 | ;; precomposed glyph. Provided that VAL is 3, the first | ||
| 199 | ;; two glyphs should be replaced by the precomposed glyph. | ||
| 200 | ;; In that case, reform GSTRING to: | ||
| 201 | ;; [HEADER nil PRECOMPOSED-GLYPH GLYPH3 ... GLYPHn nil ...] | ||
| 202 | (let* ((ncmp (1- val)) ; number of composed glyphs | ||
| 203 | (diff (1- ncmp))) ; number of reduced glyphs | ||
| 204 | (setq glyph (copy-sequence (car glyph))) | ||
| 205 | (lglyph-set-from-to glyph 0 (1- nchars)) | ||
| 206 | (lgstring-set-glyph gstring 0 glyph) | ||
| 207 | (setq idx ncmp) | ||
| 208 | (while (< idx nchars) | ||
| 209 | (setq glyph (lgstring-glyph gstring idx)) | ||
| 210 | (lglyph-set-from-to glyph 0 (1- nchars)) | ||
| 211 | (lgstring-set-glyph gstring (- idx diff) glyph) | ||
| 212 | (setq idx (1+ idx))) | ||
| 213 | (lgstring-set-glyph gstring (- idx diff) nil) | ||
| 214 | (setq idx (- ncmp diff) | ||
| 215 | nglyphs (- nchars diff))) | ||
| 216 | (setq glyph (lgstring-glyph gstring 0)) | ||
| 217 | (lglyph-set-from-to glyph 0 (1- nchars)) | ||
| 218 | (setq idx 1 nglyphs nchars)) | ||
| 219 | ;; Now IDX is an index to the first non-precomposed glyph. | ||
| 220 | ;; Adjust positions of the remaining glyphs artificially. | ||
| 221 | (setq base-width (lglyph-width (lgstring-glyph gstring 0))) | ||
| 222 | (while (< idx nglyphs) | ||
| 223 | (setq glyph (lgstring-glyph gstring idx)) | ||
| 224 | (lglyph-set-from-to glyph 0 (1- nchars)) | ||
| 225 | (if (>= (lglyph-lbearing glyph) (lglyph-width glyph)) | ||
| 226 | ;; It seems that this glyph is designed to be rendered | ||
| 227 | ;; before the base glyph. | ||
| 228 | (lglyph-set-adjustment glyph (- base-width) 0 0) | ||
| 229 | (if (>= (lglyph-lbearing glyph) 0) | ||
| 230 | ;; Align the horizontal center of this glyph to the | ||
| 231 | ;; horizontal center of the base glyph. | ||
| 232 | (let ((width (- (lglyph-rbearing glyph) | ||
| 233 | (lglyph-lbearing glyph)))) | ||
| 234 | (lglyph-set-adjustment glyph | ||
| 235 | (- (/ (- base-width width) 2) | ||
| 236 | (lglyph-lbearing glyph) | ||
| 237 | base-width) 0 0)))) | ||
| 238 | (setq idx (1+ idx)))))) | ||
| 239 | gstring)) | ||
| 107 | 240 | ||
| 108 | (let ((pattern1 "[\u05D0-\u05F2][\u0591-\u05BF\u05C1-\u05C5\u05C7]+") | 241 | (let ((pattern1 "[\u05D0-\u05F2][\u0591-\u05BF\u05C1-\u05C5\u05C7]+") |
| 109 | (pattern2 "[\u05D0-\u05F2]\u200D[\u0591-\u05BF\u05C1-\u05C5\u05C7]+")) | 242 | (pattern2 "[\u05D0-\u05F2]\u200D[\u0591-\u05BF\u05C1-\u05C5\u05C7]+")) |
| 110 | (set-char-table-range | 243 | (set-char-table-range |
| 111 | composition-function-table '(#x591 . #x5C7) | 244 | composition-function-table '(#x591 . #x5C7) |
| 112 | (list (vector pattern2 2 'hebrew-shape-gstring) | 245 | (list (vector pattern2 3 'hebrew-shape-gstring) |
| 246 | (vector pattern2 2 'hebrew-shape-gstring) | ||
| 113 | (vector pattern1 1 'hebrew-shape-gstring) | 247 | (vector pattern1 1 'hebrew-shape-gstring) |
| 114 | ["[\u0591-\u05C7]" 0 font-shape-gstring])) | 248 | [nil 0 hebrew-shape-gstring])) |
| 115 | (set-char-table-range | 249 | (set-char-table-range |
| 116 | composition-function-table #x5C0 nil) | 250 | composition-function-table #x5C0 nil) |
| 117 | (set-char-table-range | 251 | (set-char-table-range |
diff --git a/src/ChangeLog b/src/ChangeLog index 5acf42608e4..c7e5c5c3ef2 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,8 @@ | |||
| 1 | 2010-07-12 Kenichi Handa <handa@m17n.org> | 1 | 2010-07-12 Kenichi Handa <handa@m17n.org> |
| 2 | 2 | ||
| 3 | * Makefile.in (lisp): Change hebrew.el to hebrew.elc. | ||
| 4 | (shortlisp): Likewise. | ||
| 5 | |||
| 3 | * font.h (enum font_property_index): New member FONT_ENTITY_INDEX. | 6 | * font.h (enum font_property_index): New member FONT_ENTITY_INDEX. |
| 4 | 7 | ||
| 5 | * font.c (font_open_entity): Record ENTITY in FONT_OBJECT's slot | 8 | * font.c (font_open_entity): Record ENTITY in FONT_OBJECT's slot |
diff --git a/src/Makefile.in b/src/Makefile.in index 933ec98a8d5..6a60b1d1ffe 100644 --- a/src/Makefile.in +++ b/src/Makefile.in | |||
| @@ -426,7 +426,7 @@ lisp= \ | |||
| 426 | ${lispsource}language/slovak.el \ | 426 | ${lispsource}language/slovak.el \ |
| 427 | ${lispsource}language/romanian.el \ | 427 | ${lispsource}language/romanian.el \ |
| 428 | ${lispsource}language/greek.el \ | 428 | ${lispsource}language/greek.el \ |
| 429 | ${lispsource}language/hebrew.el \ | 429 | ${lispsource}language/hebrew.elc \ |
| 430 | ${lispsource}language/japanese.el \ | 430 | ${lispsource}language/japanese.el \ |
| 431 | ${lispsource}language/korean.el \ | 431 | ${lispsource}language/korean.el \ |
| 432 | ${lispsource}language/lao.el \ | 432 | ${lispsource}language/lao.el \ |
| @@ -517,7 +517,7 @@ shortlisp= \ | |||
| 517 | ../lisp/language/slovak.el \ | 517 | ../lisp/language/slovak.el \ |
| 518 | ../lisp/language/romanian.el \ | 518 | ../lisp/language/romanian.el \ |
| 519 | ../lisp/language/greek.el \ | 519 | ../lisp/language/greek.el \ |
| 520 | ../lisp/language/hebrew.el \ | 520 | ../lisp/language/hebrew.elc \ |
| 521 | ../lisp/language/japanese.el \ | 521 | ../lisp/language/japanese.el \ |
| 522 | ../lisp/language/korean.el \ | 522 | ../lisp/language/korean.el \ |
| 523 | ../lisp/language/lao.el \ | 523 | ../lisp/language/lao.el \ |