34117732a1a71f178adf5e5dfe82377b55de9aef
[bpt/emacs.git] / lisp / language / devan-util.el
1 ;;; devan-util.el --- Support for composing Devanagari characters
2
3 ;; Copyright (C) 2001 Free Software Foundation, Inc.
4
5 ;; Maintainer: KAWABATA, Taichi <batta@beige.ocn.ne.jp>
6 ;; Keywords: multilingual, Devanagari
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;; Created: Feb. 17. 2001
26
27 ;;; Commentary:
28
29 ;; This file provides character(Unicode) to glyph(CDAC) conversion and
30 ;; composition of Devanagari script characters.
31
32 ;;; Code:
33
34 ;;;###autoload
35
36 ;; Devanagari Composable Pattern
37 ;; C .. Consonants
38 ;; V .. Vowel
39 ;; H .. Halant
40 ;; M .. Matra
41 ;; V .. Vowel
42 ;; A .. Anuswar
43 ;; D .. Chandrabindu
44 ;; (N .. Zerowidth Non Joiner)
45 ;; (J .. Zerowidth Joiner. )
46 ;; 1. vowel
47 ;; V(A/D)?
48 ;; 2. syllable : maximum of 5 consecutive consonants. (e.g. kartsnya)
49 ;; ((CH)?(CH)?(CH)?CH)?C(MA?|D|H)?
50
51 (defconst devanagari-consonant
52 "[\e$,15U\e(B-\e$,15y68\e(B-\e$,16?\e(B]")
53
54 (defconst devanagari-composable-pattern
55 (concat
56 "\\([\e$,15E\e(B-\e$,15T6@6A\e(B][\e$,15A5B\e(B]?\\)\\|\e$,15C\e(B"
57 "\\|\\("
58 "\\(?:\\(?:[\e$,15U\e(B-\e$,15y68\e(B-\e$,16?\e(B]\e$,16-\e(B\\)?\\(?:[\e$,15U\e(B-\e$,15y68\e(B-\e$,16?\e(B]\e$,16-\e(B\\)?\\(?:[\e$,15U\e(B-\e$,15y68\e(B-\e$,16?\e(B]\e$,16-\e(B\\)?[\e$,15U\e(B-\e$,15y68\e(B-\e$,16?\e(B]\e$,16-\e(B\\)?"
59 "[\e$,15U\e(B-\e$,15y68\e(B-\e$,16?\e(B]\\(?:\e$,16-\e(B\\|[\e$,15~\e(B-\e$,16-6B6C\e(B]?[\e$,15B5A\e(B]?\\)?"
60 "\\)")
61 "Regexp matching a composable sequence of Devanagari characters.")
62
63 (defun devanagari-compose-region (from to)
64 (interactive "r")
65 (save-excursion
66 (save-restriction
67 (narrow-to-region from to)
68 (goto-char (point-min))
69 (while (re-search-forward devanagari-composable-pattern nil t)
70 (devanagari-compose-syllable-region (match-beginning 0)
71 (match-end 0))))))
72 (defun devanagari-compose-string (string)
73 (with-temp-buffer
74 (insert (decompose-string string))
75 (devanagari-compose-region (point-min) (point-max))
76 (buffer-string)))
77
78 (defun range (from to)
79 "Make the list of the integers of range FROM to TO."
80 (let (result)
81 (while (<= from to) (setq result (cons to result) to (1- to))) result))
82
83 (defun regexp-of-hashtbl-keys (hashtbl)
84 "Returns the regular expression of hashtable keys."
85 (let ((max-specpdl-size 1000))
86 (regexp-opt
87 (sort
88 (let (dummy)
89 (maphash (function (lambda (key val) (setq dummy (cons key dummy)))) hashtbl)
90 dummy)
91 (function (lambda (x y) (> (length x) (length y))))))))
92
93 (defun devanagari-composition-function (from to pattern &optional string)
94 "Compose Devanagari characters in REGION, or STRING if specified.
95 Assume that the REGION or STRING must fully match the composable
96 PATTERN regexp."
97 (if string (devanagari-compose-syllable-string string)
98 (devanagari-compose-syllable-region from to))
99 (- to from))
100
101 ;; Register a function to compose Devanagari characters.
102 (mapc
103 (function (lambda (ucs)
104 (aset composition-function-table (decode-char 'ucs ucs)
105 (list (cons devanagari-composable-pattern
106 'devanagari-composition-function)))))
107 (nconc '(#x0903) (range #x0905 #x0939) (range #x0958 #x0961)))
108
109 ;; Notes on conversion steps.
110
111 ;; 1. chars to glyphs
112 ;;
113 ;; Rules will not be applied to the halant appeared at the end of the
114 ;; text. Also, the preceding/following "r" will be treated as special case.
115
116 ;; 2. glyphs reordering.
117 ;;
118 ;; The glyphs are split by halant, and each glyph groups are
119 ;; re-ordered in the following order.
120 ;;
121 ;; Note that `consonant-glyph' mentioned here does not contain the
122 ;; vertical bar (right modifier) attached at the right of the
123 ;; consonant.
124 ;;
125 ;; If the glyph-group contains right modifier,
126 ;; (1) consonant-glyphs/vowels, with nukta sign
127 ;; (2) spacing
128 ;; (3) right modifier (may be matra)
129 ;; (4) top matra
130 ;; (5) preceding "r"
131 ;; (6) anuswar
132 ;; (7) following "r"
133 ;; (8) bottom matra or halant.
134 ;;
135 ;; Otherwise,
136 ;; (1) consonant-glyph/vowels, with nukta sign
137 ;; (3) left matra
138 ;; (4) top matra
139 ;; (5) preceding "r"
140 ;; (6) anuswar
141 ;; (7) following "r"
142 ;; (8) bottom matra or halant.
143 ;; (2) spacing
144
145 ;; 3. glyph to glyph
146 ;;
147 ;; For better display, some glyph display would be tuned.
148
149 ;; 4. Composition.
150 ;;
151 ;; left modifiers will be attached at the left.
152 ;; others will be attached right.
153
154 ;; Problem::
155 ;; Can we generalize this methods to other Indian scripts?
156
157 (defvar dev-char-glyph
158 '(("\e$,15E\e(B" . "\e$,4 K\e(B")
159 ("\e$,15F\e(B" . "\e$,4 K\")\e(B")
160 ("\e$,15~\e(B" . "\e$,4\")\e(B")
161 ("\e$,15G\e(B" . "\e$,4 \\e(B")
162 ("\e$,15\7f\e(B" . "\e$,4\"*\e(B")
163 ("\e$,15\7f5A\e(B" . "\e$,4\"*\e(B\\e$,4\"&\e(B")
164 ("\e$,15H\e(B" . "\e$,4 \"'\e(B")
165 ("\e$,15H5A\e(B" . "\e$,4 \"'\"&\e(B")
166 ("\e$,16 \e(B" . "\e$,4\"2\e(B")
167 ("\e$,16 5A\e(B" . "\e$,4\"2\"&\e(B")
168 ("\e$,15I\e(B" . "\e$,4 ]\e(B")
169 ("\e$,16!\e(B" . "\e$,4\"6\e(B")
170 ("\e$,15J\e(B" . "\e$,4 ^\"P\e(B")
171 ("\e$,16"\e(B" . "\e$,4\":\e(B")
172 ("\e$,15K\e(B" . "\e$,4 `\"Q\e(B")
173 ("\e$,16#\e(B" . "\e$,4\">\e(B")
174 ;;("\e$,15L\e(B" . nil) ; not implemented.
175 ("\e$,16$\e(B" . "\e$,4\"?\e(B")
176 ("\e$,15M\e(B" . "\e$,4 b\"L\e(B")
177 ("\e$,15M5A\e(B" . "\e$,4 b\"$\e(B")
178 ("\e$,15M5B\e(B" . "\e$,4 b\"$\e(B")
179 ("\e$,16%\e(B" . "\\e$,4\"L\e(B")
180 ("\e$,15N\e(B" . "\e$,4 b\"@\e(B")
181 ("\e$,15N5A\e(B" . "\e$,4 b\"@\"&\e(B")
182 ("\e$,16&\e(B" . "\\e$,4\"@\e(B")
183 ("\e$,16&5A\e(B" . "\\e$,4\"@\e(B\\e$,4\"&\e(B")
184 ("\e$,15O\e(B" . "\e$,4 b\e(B")
185 ("\e$,16'\e(B" . "\\e$,4\"D\e(B")
186 ("\e$,16'5A\e(B" . "\\e$,4\"D\e(B\\e$,4\"&\e(B")
187 ("\e$,15P\e(B" . "\e$,4 b\"D\e(B")
188 ("\e$,15P5A\e(B" . "\e$,4 b\"D\"&\e(B")
189 ("\e$,16(\e(B" . "\\e$,4\"H\e(B")
190 ("\e$,16(5A\e(B" . "\\e$,4\"H\e(B\\e$,4\"&\e(B")
191 ("\e$,15Q\e(B" . "\e$,4 K\")\"L\e(B") ;; special rule for reodering.
192 ("\e$,15Q5A\e(B" . "\e$,4 K\")\"$\e(B")
193 ("\e$,15Q5B\e(B" . "\e$,4 K\")\"$\e(B")
194 ("\e$,16)\e(B" . "\\e$,4\")\"L\e(B")
195 ("\e$,16)5A\e(B" . "\\e$,4\")\"$\e(B")
196 ("\e$,16)5B\e(B" . "\\e$,4\")\"$\e(B")
197 ("\e$,15R\e(B" . "\e$,4 K\")\"@\e(B")
198 ("\e$,15R5A\e(B" . "\e$,4 K\")\"@\"&\e(B")
199 ("\e$,16*\e(B" . "\\e$,4\")\"@\e(B")
200 ("\e$,16*5A\e(B" . "\\e$,4\")\"@\"&\e(B")
201 ("\e$,15S\e(B" . "\e$,4 K\")\"D\e(B")
202 ("\e$,15S5A\e(B" . "\e$,4 K\")\"D\"&\e(B")
203 ("\e$,16+\e(B" . "\\e$,4\")\"D\e(B")
204 ("\e$,16+5A\e(B" . "\\e$,4\")\"D\"&\e(B")
205 ("\e$,15T\e(B" . "\e$,4 K\")\"H\e(B")
206 ("\e$,15T5A\e(B" . "\e$,4 K\")\"H\"&\e(B")
207 ("\e$,16,\e(B" . "\\e$,4\")\"H\e(B")
208 ("\e$,16,5A\e(B" . "\\e$,4\")\"H\"&\e(B")
209 ("\e$,16@\e(B" . "\e$,4 a\"Q\e(B")
210 ;;("\e$,16B\e(B" . nil)
211 ;;("\e$,16A\e(B" . nil)
212 ;;("\e$,16C\e(B" . nil)
213
214 ;; GRUTTALS
215 ("\e$,15U\e(B" . "\e$,4 e\"R\e(B")
216 ("\e$,15U6-\e(B" . "\e$,4 c\e(B")
217 ("\e$,15U6-5p\e(B" . "\e$,4 g\"R\e(B")
218 ("\e$,15U6-5d\e(B" . "\e$,4 h\"R\e(B")
219 ("\e$,15U6-5w\e(B" . "\e$,4 i\")\e(B")
220 ("\e$,15U6-5w6-\e(B" . "\e$,4 i\e(B")
221
222 ("\e$,15V\e(B" . "\e$,4 j\")\e(B")
223 ("\e$,15V6-\e(B" . "\e$,4 j\e(B")
224 ("\e$,15V6-5p\e(B" . "\e$,4 l\")\e(B")
225 ("\e$,15V6-5p6-\e(B" . "\e$,4 l\e(B")
226
227 ("\e$,15W\e(B" . "\e$,4 m\")\e(B")
228 ("\e$,15W6-\e(B" . "\e$,4 m\e(B")
229 ("\e$,15W6-5p\e(B" . "\e$,4 o\")\e(B")
230 ("\e$,15W6-5p6-\e(B" . "\e$,4 o\e(B")
231
232 ("\e$,15X\e(B" . "\e$,4 p\")\e(B")
233 ("\e$,15X6-\e(B" . "\e$,4 p\e(B")
234 ("\e$,15X6-5p\e(B" . "\e$,4 q\")\e(B")
235 ("\e$,15X6-5p6-\e(B" . "\e$,4 q\e(B")
236
237 ("\e$,15Y\e(B" . "\e$,4 r\"S\e(B")
238 ;; PALATALS
239 ("\e$,15Z\e(B" . "\e$,4 s\")\e(B")
240 ("\e$,15Z6-\e(B" . "\e$,4 s\e(B")
241 ("\e$,15Z6-5p\e(B" . "\e$,4 t\")\e(B")
242 ("\e$,15Z6-5p6-\e(B" . "\e$,4 t\e(B")
243
244 ("\e$,15[\e(B" . "\e$,4 u\"T\e(B")
245
246 ("\e$,15\\e(B" . "\e$,4 v\")\e(B")
247 ("\e$,15\6-\e(B" . "\e$,4 v\e(B")
248 ("\e$,15\6-5p\e(B" . "\e$,4 x\")\e(B")
249 ("\e$,15\6-5p6-\e(B" . "\e$,4 x\e(B")
250 ("\e$,15\6-5^\e(B" . "\e$,4 y\")\e(B")
251 ("\e$,15\6-5^6-\e(B" . "\e$,4 y\e(B")
252
253 ("\e$,15]\e(B" . "\e$,4 z\")\e(B")
254 ("\e$,15]6-\e(B" . "\e$,4 z\e(B")
255 ("\e$,15]6-5p\e(B" . "\e$,4 {\")\e(B")
256 ("\e$,15]6-5p6-\e(B" . "\e$,4 {\e(B")
257
258 ("\e$,15^\e(B" . "\e$,4 |\")\e(B")
259 ("\e$,15^6-\e(B" . "\e$,4 |\e(B")
260 ;; CEREBRALS
261 ("\e$,15_\e(B" . "\e$,4 }\"U\e(B")
262 ("\e$,15_6-5_\e(B" . "\e$,4 ~\"U\e(B")
263 ("\e$,15_6-5`\e(B" . "\e$,4 \7f\"U\e(B")
264
265 ("\e$,15`\e(B" . "\e$,4! \"V\e(B")
266 ("\e$,15`6-5`\e(B" . "\e$,4!!\"V\e(B")
267
268 ("\e$,15a\e(B" . "\e$,4!\"\"W\e(B")
269 ("\e$,15a6-5a\e(B" . "\e$,4!$\"W\e(B")
270 ("\e$,15a6-5b\e(B" . "\e$,4!%\"W\e(B")
271
272 ("\e$,15b\e(B" . "\e$,4!&\"X\e(B")
273
274 ("\e$,15c\e(B" . "\e$,4!(\")\e(B")
275 ("\e$,15c6-\e(B" . "\e$,4!(\e(B")
276 ;; DENTALS
277 ("\e$,15d\e(B" . "\e$,4!)\")\e(B")
278 ("\e$,15d6-\e(B" . "\e$,4!)\e(B")
279 ("\e$,15d6-5p\e(B" . "\e$,4!*\")\e(B")
280 ("\e$,15d6-5p6-\e(B" . "\e$,4!*\e(B")
281 ("\e$,15d6-5d\e(B" . "\e$,4!+\")\e(B")
282 ("\e$,15d6-5d6-\e(B" . "\e$,4!+\e(B")
283
284 ("\e$,15e\e(B" . "\e$,4!,\")\e(B")
285 ("\e$,15e6-\e(B" . "\e$,4!,\e(B")
286 ("\e$,15e6-5p\e(B" . "\e$,4!-\")\e(B")
287 ("\e$,15e6-5p6-\e(B" . "\e$,4!-\e(B")
288
289 ("\e$,15f\e(B" . "\e$,4!.\"Y\e(B")
290 ("\e$,15f6#\e(B" . "\e$,4!/\"Y\e(B")
291 ("\e$,15f6-5p\e(B" . "\e$,4!0\"Y\e(B")
292 ("\e$,15f6-5f\e(B" . "\e$,4!1\"Y\e(B")
293 ("\e$,15f6-5g\e(B" . "\e$,4!2\"Y\e(B")
294 ("\e$,15f6-5n\e(B" . "\e$,4!3\e(B")
295 ("\e$,15f6-5o\e(B" . "\e$,4!4\e(B")
296 ("\e$,15f6-5u\e(B" . "\e$,4!5\"Y\e(B")
297
298 ("\e$,15g\e(B" . "\e$,4!6\")\e(B")
299 ("\e$,15g6-\e(B" . "\e$,4!6\e(B")
300 ("\e$,15g6-5p\e(B" . "\e$,4!7\")\e(B")
301 ("\e$,15g6-5p6-\e(B" . "\e$,4!7\e(B")
302
303 ("\e$,15h\e(B" . "\e$,4!8\")\e(B")
304 ("\e$,15h6-\e(B" . "\e$,4!8\e(B")
305 ("\e$,15h6-5p\e(B" . "\e$,4!9\")\e(B")
306 ("\e$,15h6-5p6-\e(B" . "\e$,4!9\")\e(B")
307 ("\e$,15h6-5h\e(B" . "\e$,4!:\")\e(B")
308 ("\e$,15h6-5h6-\e(B" . "\e$,4!:\e(B")
309
310 ("\e$,15i\e(B" . "\e$,4!8"#")\e(B")
311 ;; LABIALS
312 ("\e$,15j\e(B" . "\e$,4!;\")\e(B")
313 ("\e$,15j6-\e(B" . "\e$,4!;\e(B")
314 ("\e$,15j6-5p\e(B" . "\e$,4!<\")\e(B")
315 ("\e$,15j6-5p6-\e(B" . "\e$,4!<\e(B")
316
317 ("\e$,15k\e(B" . "\e$,4!a\"[\e(B")
318 ("\e$,15k6-\e(B" . "\e$,4!=\e(B")
319 ("\e$,15k6-5p\e(B" . "\e$,4!c\"[\e(B")
320
321 ("\e$,15l\e(B" . "\e$,4!d\")\e(B")
322 ("\e$,15l6-\e(B" . "\e$,4!d\e(B")
323 ("\e$,15l6-5p\e(B" . "\e$,4!e\")\e(B")
324 ("\e$,15l6-5p6-\e(B" . "\e$,4!e\e(B")
325
326 ("\e$,15m\e(B" . "\e$,4!f\")\e(B")
327 ("\e$,15m6-\e(B" . "\e$,4!f\e(B")
328 ("\e$,15m6-5p\e(B" . "\e$,4!g\")\e(B")
329 ("\e$,15m6-5p6-\e(B" . "\e$,4!g\e(B")
330
331 ("\e$,15n\e(B" . "\e$,4!h\")\e(B")
332 ("\e$,15n6-\e(B" . "\e$,4!h\e(B")
333 ("\e$,15n6-5p\e(B" . "\e$,4!i\")\e(B")
334 ("\e$,15n6-5p6-\e(B" . "\e$,4!i\e(B")
335 ;; SEMIVOWELS
336 ("\e$,15o\e(B" . "\e$,4!j\")\e(B")
337 ("\e$,15o6-\e(B" . "\e$,4!j\e(B")
338 ("\e$,15o6-5p\e(B" . "\e$,4!k\")\e(B")
339 ("\e$,15o6-5p6-\e(B" . "\e$,4!k\e(B")
340 ("\e$,16-5o\e(B" . "\e$,4!l\e(B") ;; when every ohter lig. fails.
341
342 ("\e$,15p\e(B" . "\e$,4!n\"W\e(B")
343 ;; ("\e$,15p6-\e(B" . "\\e$,4"'\e(B") ;; special case. only the topmost pos.
344 ("\e$,15q\e(B" . "\e$,4!n"#"W\e(B")
345 ("\e$,15q6-\e(B" . "\e$,4!m\e(B") ;; IS 13194 speical rule.
346 ("\e$,15p6!\e(B" . "\e$,4!o\"[\e(B")
347 ("\e$,15p6"\e(B" . "\e$,4!p\"\\e(B")
348
349 ("\e$,15r\e(B" . "\e$,4!q\")\e(B")
350 ("\e$,15r6-\e(B" . "\e$,4!q\e(B")
351 ("\e$,15s\e(B" . "\e$,4!s\e(B")
352 ("\e$,15s6-\e(B" . "\e$,4!r\e(B")
353 ("\e$,15t\e(B" . "\e$,4!s\"#\e(B")
354 ("\e$,15t6-\e(B" . "\e$,4!r\"#\e(B")
355
356 ("\e$,15u\e(B" . "\e$,4!t\")\e(B")
357 ("\e$,15u6-\e(B" . "\e$,4!t\e(B")
358 ("\e$,15u6-5p\e(B" . "\e$,4!u\")\e(B")
359 ("\e$,15u6-5p6-\e(B" . "\e$,4!u\e(B")
360 ;; SIBILANTS
361 ("\e$,15v\e(B" . "\e$,4!v\")\e(B")
362 ("\e$,15v6-\e(B" . "\e$,4!v\e(B")
363 ("\e$,15v6-5u\e(B" . "\e$,4!w\")\e(B")
364 ("\e$,15v6-5u6-\e(B" . "\e$,4!w\e(B")
365 ("\e$,15v6-5p\e(B" . "\e$,4!x\")\e(B")
366 ("\e$,15v6-5p6-\e(B" . "\e$,4!x\e(B")
367
368 ("\e$,15w\e(B" . "\e$,4!y\")\e(B")
369 ("\e$,15w6-\e(B" . "\e$,4!y\e(B")
370 ("\e$,15x\e(B" . "\e$,4!z\")\e(B")
371 ("\e$,15x6-\e(B" . "\e$,4!z\e(B")
372 ("\e$,15x6-5p\e(B" . "\e$,4!{\")\e(B")
373 ("\e$,15x6-5p6-\e(B" . "\e$,4!{\e(B")
374
375 ("\e$,15y\e(B" . "\e$,4!}\e(B")
376 ("\e$,15y6-\e(B" . "\e$,4!|\e(B")
377 ("\e$,15y6#\e(B" . "\e$,4!~\e(B")
378 ("\e$,15y6-5p\e(B" . "\e$,4!\7f\e(B")
379 ("\e$,15y6-5n\e(B" . "\e$,4\" \e(B")
380 ("\e$,15y6-5o\e(B" . "\e$,4\"!\e(B")
381 ;; NUKTAS
382 ("\e$,168\e(B" . "\e$,4 f"R"S\e(B")
383 ("\e$,1686-\e(B" . "\e$,4 d\e(B")
384 ("\e$,169\e(B" . "\e$,4 k\")\e(B")
385 ("\e$,1696-\e(B" . "\e$,4 k\e(B")
386 ("\e$,16:\e(B" . "\e$,4 n\")\e(B")
387 ("\e$,16:6-\e(B" . "\e$,4 n\e(B")
388 ("\e$,16;\e(B" . "\e$,4 w\")\e(B")
389 ("\e$,16;6-\e(B" . "\e$,4 w\e(B")
390 ("\e$,16<\e(B" . "\e$,4!#\"W\e(B")
391 ("\e$,16=\e(B" . "\e$,4!'\"X\e(B")
392 ("\e$,16>\e(B" . "\e$,4!b\"[\e(B")
393 ("\e$,16>6-\e(B" . "\e$,4!>\e(B")
394 ("\e$,16?\e(B" . "\e$,4!j"#")\e(B")
395 ;; misc modifiers.
396 ("\e$,15A\e(B" . "\\e$,4\"$\e(B")
397 ("\e$,15B\e(B" . "\\e$,4\"&\e(B")
398 ("\e$,15C\e(B" . "\e$,4 F\e(B")
399 ("\e$,15|\e(B" . "\e$,4\"#\e(B")
400 ("\e$,15}\e(B" . "\e$,4 E\e(B")
401 ("\e$,16-\e(B" . "\e$,4\"\"\e(B")
402 ("\e$,16-5p\e(B" . "\e$,4\"%\e(B") ;; following "r"
403 ;; ("\e$,160\e(B" . "\e$,4 D\e(B")
404 ;; ("\e$,16D\e(B" . "\e$,4 J\e(B")
405 ;; ("\e$,16F\e(B" . "")
406 ;; ("\e$,16G\e(B" . "")
407 ;; ("\e$,16H\e(B" . "")
408 ;; ("\e$,16I\e(B" . "")
409 ;; ("\e$,16J\e(B" . "")
410 ;; ("\e$,16K\e(B" . "")
411 ;; ("\e$,16L\e(B" . "")
412 ;; ("\e$,16M\e(B" . "")
413 ;; ("\e$,16N\e(B" . "")
414 ;; ("\e$,16O\e(B" . "")
415 )
416 "Devanagari characters to glyphs conversion table.
417 Default value contains only the basic rules. You may add your own
418 preferred rule from the sanskrit fonts." )
419
420 (defvar dev-char-glyph-hash
421 (let* ((hash (makehash 'equal)))
422 (mapc (function (lambda (x) (puthash (car x) (cdr x) hash)))
423 dev-char-glyph)
424 hash))
425
426 (defvar dev-char-glyph-regexp
427 (regexp-of-hashtbl-keys dev-char-glyph-hash))
428
429 ;; glyph-to-glyph conversion table.
430 ;; it is supposed that glyphs are ordered in
431 ;; [consonant/nukta] - [matra/halant] - [preceding-r] - [anuswar].
432
433 (defvar dev-glyph-glyph
434 '(("\\e$,4\"'\e(B\\e$,4\"&\e(B" . "\\e$,4\"(\e(B")
435 ("\\e$,4\"'\e(B\\e$,4\"$\e(B" . "\\e$,4\"(\e(B")
436 ("\e$,4\"*\e(B\\e$,4\"&\e(B" . "\e$,4\"+\e(B")
437 ("\e$,4\"*\e(B\\e$,4\"'\e(B" . "\e$,4\",\e(B")
438 ("\e$,4\"*\e(B\\e$,4\"'\e(B\\e$,4\"&\e(B" . "\e$,4\"-\e(B")
439 ("\e$,4\"2\e(B\\e$,4\"&\e(B" . "\e$,4\"3\e(B")
440 ("\e$,4\"2\e(B\\e$,4\"'\e(B" . "\e$,4\"4\e(B")
441 ("\e$,4\"2\e(B\\e$,4\"'\e(B\\e$,4\"&\e(B" . "\e$,4\"5\e(B")
442 ("\e$,4\"#\e(B\\e$,4\"6\e(B" . "\e$,4\"7\e(B")
443 ("\e$,4\"%\e(B\\e$,4\"6\e(B" . "\e$,4\"8\e(B")
444 ;;("\e$,4\"6\e(B" . "\e$,4\"9\e(B")
445 ("\e$,4\"#\e(B\\e$,4\":\e(B" . "\e$,4\";\e(B")
446 ("\e$,4\"%\e(B\\e$,4\":\e(B" . "\e$,4\"<\e(B")
447 ;;("\e$,4\":\e(B" . "\e$,4\"=\e(B")
448 ("\\e$,4\"@\e(B\\e$,4\"&\e(B" . "\\e$,4\"A\e(B")
449 ("\\e$,4\"@\e(B\\e$,4\"'\e(B" . "\\e$,4\"B\e(B")
450 ("\\e$,4\"@\e(B\\e$,4\"'\e(B\\e$,4\"&\e(B" . "\\e$,4\"C\e(B")
451 ("\\e$,4\"D\e(B\\e$,4\"&\e(B" . "\\e$,4\"E\e(B")
452 ("\\e$,4\"D\e(B\\e$,4\"'\e(B" . "\\e$,4\"F\e(B")
453 ("\\e$,4\"D\e(B\\e$,4\"'\e(B\\e$,4\"&\e(B" . "\\e$,4\"G\e(B")
454 ("\\e$,4\"H\e(B\\e$,4\"&\e(B" . "\\e$,4\"I\e(B")
455 ("\\e$,4\"H\e(B\\e$,4\"'\e(B" . "\\e$,4\"J\e(B")
456 ("\\e$,4\"H\e(B\\e$,4\"'\e(B\\e$,4\"&\e(B" . "\\e$,4\"K\e(B")
457 ("\\e$,4\"L\e(B\\e$,4\"&\e(B" . "\\e$,4\"M\e(B")
458 ("\\e$,4\"L\e(B\\e$,4\"'\e(B" . "\\e$,4\"N\e(B")
459 ("\\e$,4\"L\e(B\\e$,4\"'\e(B\\e$,4\"&\e(B" . "\\e$,4\"O\e(B")
460 ))
461 (defvar dev-glyph-glyph-hash
462 (let* ((hash (makehash 'equal)))
463 (mapc (function (lambda (x) (puthash (car x) (cdr x) hash)))
464 dev-glyph-glyph)
465 hash))
466 (defvar dev-glyph-glyph-regexp
467 (regexp-of-hashtbl-keys dev-glyph-glyph-hash))
468
469
470 ;; yet another glyph-to-glyph conversions.
471 (defvar dev-glyph-glyph-2
472 '(("\e$,4\"*\e(B" . "\e$,4\".\e(B")
473 ("\e$,4\"+\e(B" . "\e$,4\"/\e(B")
474 ("\e$,4\",\e(B" . "\e$,4\"0\e(B")
475 ("\e$,4\"-\e(B" . "\e$,4\"1\e(B")))
476 (defvar dev-glyph-glyph-2-hash
477 (let* ((hash (makehash 'equal)))
478 (mapc (function (lambda (x) (puthash (car x) (cdr x) hash)))
479 dev-glyph-glyph-2)
480 hash))
481 (defvar dev-glyph-glyph-2-regexp
482 (regexp-of-hashtbl-keys dev-glyph-glyph-2-hash))
483
484
485 (defun dev-charseq (from &optional to)
486 (if (null to) (setq to from))
487 (mapcar (function (lambda (x) (indian-glyph-char x 'devanagari)))
488 (range from to)))
489
490 (defvar dev-glyph-cvn
491 (append
492 (dev-charseq #x2b)
493 (dev-charseq #x3c #xc1)
494 (dev-charseq #xc3))
495 "Devanagari Consonants/Vowels/Nukta Glyphs")
496
497 (defvar dev-glyph-space
498 (dev-charseq #xf0 #xfe)
499 "Devanagari Spacing Glyphs")
500
501 (defvar dev-glyph-right-modifier
502 (append
503 (dev-charseq #xc9)
504 (dev-charseq #xd2 #xd5))
505 "Devanagari Modifiers attached at the right side.")
506
507 (defvar dev-glyph-right-modifier-regexp
508 (concat "[" dev-glyph-right-modifier "]"))
509
510 (defvar dev-glyph-left-matra
511 (dev-charseq #xca #xd1)
512 "Devanagari Matras attached at the left side.")
513
514 (defvar dev-glyph-top-matra
515 (dev-charseq #xe0 #xef)
516 "Devanagari Matras attached at the top side.")
517
518 (defvar dev-glyph-bottom-modifier
519 (append
520 (dev-charseq #xd6 #xdf)
521 (dev-charseq #xc2))
522 "Devanagari Modifiers attached at the bottom.")
523
524 (defvar dev-glyph-order
525 `((,dev-glyph-cvn . 1)
526 (,dev-glyph-space . 2)
527 (,dev-glyph-right-modifier . 3)
528 (,dev-glyph-left-matra . 3) ;; processed by reference point.
529 (,dev-glyph-top-matra . 4)
530 (,(dev-charseq #xc7 #xc8) . 5)
531 (,(dev-charseq #xc6) . 6)
532 (,(dev-charseq #xc5) . 7)
533 (,dev-glyph-bottom-modifier . 8)))
534
535 (mapc
536 (function (lambda (x)
537 (mapc
538 (function (lambda (y)
539 (put-char-code-property y 'composition-order (cdr x))))
540 (car x))))
541 dev-glyph-order)
542
543 (mapc
544 (function (lambda (x)
545 (put-char-code-property x 'reference-point '(3 . 5))))
546 dev-glyph-left-matra)
547
548 (defun devanagari-compose-syllable-string (string)
549 (with-temp-buffer
550 (insert (decompose-string string))
551 (devanagari-compose-syllable-region (point-min) (point-max))
552 (buffer-string)))
553
554 (defun devanagari-compose-syllable-region (from to)
555 "Compose devanagari syllable in region FROM to TO."
556 (let ((glyph-str nil) (cons-num 0) glyph-str-list
557 (last-halant nil) (preceding-r nil) (last-modifier nil)
558 (last-char (char-before to)) match-str
559 glyph-block split-pos)
560 (save-excursion
561 (save-restriction
562 ;;; *** char-to-glyph conversion ***
563 ;; Special rule 1. -- Last halant must be preserved.
564 (if (eq last-char ?\e$,16-\e(B)
565 (progn
566 (setq last-halant t)
567 (narrow-to-region from (1- to)))
568 (narrow-to-region from to)
569 ;; note if the last char is modifier.
570 (if (or (eq last-char ?\e$,15A\e(B) (eq last-char ?\e$,15B\e(B))
571 (setq last-modifier t)))
572 (goto-char (point-min))
573 ;; Special rule 2. -- preceding "r halant" must be modifier.
574 (when (looking-at "\e$,15p6-\e(B.")
575 (setq preceding-r t)
576 (goto-char (+ 2 (point))))
577 ;; translate the rest characters into glyphs
578 (while (re-search-forward dev-char-glyph-regexp nil t)
579 (setq match-str (match-string 0))
580 (setq glyph-str
581 (concat glyph-str
582 (gethash match-str dev-char-glyph-hash)))
583 ;; count the number of consonant-glyhs.
584 (if (string-match devanagari-consonant match-str)
585 (setq cons-num (1+ cons-num))))
586 ;; preceding-r must be attached before the anuswar if exists.
587 (if preceding-r
588 (if last-modifier
589 (setq glyph-str (concat (substring glyph-str 0 -1)
590 "\e$,4\"'\e(B" (substring glyph-str -1)))
591 (setq glyph-str (concat glyph-str "\e$,4\"'\e(B"))))
592 (if last-halant (setq glyph-str (concat glyph-str "\e$,4\"\"\e(B")))
593 ;;; *** glyph-to-glyph conversion ***
594 (when (string-match dev-glyph-glyph-regexp glyph-str)
595 (setq glyph-str
596 (replace-match (gethash (match-string 0 glyph-str)
597 dev-glyph-glyph-hash)
598 nil t glyph-str))
599 (if (and (> cons-num 1)
600 (string-match dev-glyph-glyph-2-regexp glyph-str))
601 (setq glyph-str
602 (replace-match (gethash (match-string 0 glyph-str)
603 dev-glyph-glyph-2-hash)
604 nil t glyph-str))))
605 ;;; *** glyph reordering ***
606 (while (setq split-pos (string-match "\e$,4\"\"\e(B\\|.$" glyph-str))
607 (setq glyph-block (substring glyph-str 0 (1+ split-pos)))
608 (setq glyph-str (substring glyph-str (1+ split-pos)))
609 (setq
610 glyph-block
611 (if (string-match dev-glyph-right-modifier-regexp glyph-block)
612 (sort (string-to-list glyph-block)
613 (function (lambda (x y)
614 (< (get-char-code-property x 'composition-order)
615 (get-char-code-property y 'composition-order)))))
616 (sort (string-to-list glyph-block)
617 (function (lambda (x y)
618 (let ((xo (get-char-code-property x 'composition-order))
619 (yo (get-char-code-property y 'composition-order)))
620 (if (= xo 2) nil (if (= yo 2) t (< xo yo)))))))))
621 (setq glyph-str-list (nconc glyph-str-list glyph-block)))
622 ;; concatenate and attach reference-points.
623 (setq glyph-str
624 (cdr
625 (apply
626 'nconc
627 (mapcar
628 (function (lambda (x)
629 (list
630 (or (get-char-code-property x 'reference-point)
631 '(5 . 3) ;; default reference point.
632 )
633 x)))
634 glyph-str-list))))))
635 (compose-region from to glyph-str)))
636
637 (provide 'devan-util)