some cleanup
[enigma2.git] / lib / gdi / font_arabic.cpp
1 /*
2  * This was taken from pango. 
3  * Modified for enigma by Felix Domke <tmbinc@gmx.net>.
4  * I removed support for vowels and ligatures. Sorry.
5  *
6  * Original header:
7  *
8  * This is part of Pango - Arabic shaping module 
9  *
10  * (C) 2000 Karl Koehler <koehler@or.uni-bonn.de>
11  * (C) 2001 Roozbeh Pournader <roozbeh@sharif.edu>
12  *
13  */
14
15 #include <vector>
16 #include <lib/base/eerror.h>
17
18 typedef struct
19 {
20         unsigned long basechar;
21         int count;
22         unsigned long charshape[4];
23 } shapestruct;
24
25 typedef struct
26 {
27         unsigned long basechar;
28         char numshapes;
29 } charstruct;
30
31 static void
32 charstruct_init (charstruct * s)
33 {
34   s->basechar = 0;
35   s->numshapes = 1;
36 }
37
38 #define connects_to_left(a)      ((a).numshapes > 2)
39
40 /* The Unicode order is always 'isolated, final, initial, medial'. */
41
42 /* *INDENT-OFF* */
43 static shapestruct chartable[] = {
44         {0x0621, 1, {0xFE80}}, /* HAMZA */
45         {0x0622, 2, {0xFE81, 0xFE82}}, /* ALEF WITH MADDA ABOVE */
46         {0x0623, 2, {0xFE83, 0xFE84}}, /* ALEF WITH HAMZA ABOVE */
47         {0x0624, 2, {0xFE85, 0xFE86}}, /* WAW WITH HAMZA ABOVE */
48         {0x0625, 2, {0xFE87, 0xFE88}}, /* ALEF WITH HAMZA BELOW */
49         {0x0626, 4, {0xFE89, 0xFE8A, 0xFE8B, 0xFE8C}}, /* YEH WITH HAMZA ABOVE */
50         {0x0627, 2, {0xFE8D, 0xFE8E}}, /* ALEF */
51         {0x0628, 4, {0xFE8F, 0xFE90, 0xFE91, 0xFE92}}, /* BEH */
52         {0x0629, 2, {0xFE93, 0xFE94}}, /* TEH MARBUTA */
53         {0x062A, 4, {0xFE95, 0xFE96, 0xFE97, 0xFE98}}, /* TEH */
54         {0x062B, 4, {0xFE99, 0xFE9A, 0xFE9B, 0xFE9C}}, /* THEH */
55         {0x062C, 4, {0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0}}, /* JEEM */
56         {0x062D, 4, {0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4}}, /* HAH */
57         {0x062E, 4, {0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8}}, /* KHAH */
58         {0x062F, 2, {0xFEA9, 0xFEAA}}, /* DAL */
59         {0x0630, 2, {0xFEAB, 0xFEAC}}, /* THAL */
60         {0x0631, 2, {0xFEAD, 0xFEAE}}, /* REH */
61         {0x0632, 2, {0xFEAF, 0xFEB0}}, /* ZAIN */
62         {0x0633, 4, {0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4}}, /* SEEN */
63         {0x0634, 4, {0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8}}, /* SHEEN */
64         {0x0635, 4, {0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC}}, /* SAD */
65         {0x0636, 4, {0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0}}, /* DAD */
66         {0x0637, 4, {0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4}}, /* TAH */
67         {0x0638, 4, {0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8}}, /* ZAH */
68         {0x0639, 4, {0xFEC9, 0xFECA, 0xFECB, 0xFECC}}, /* AIN */
69         {0x063A, 4, {0xFECD, 0xFECE, 0xFECF, 0xFED0}}, /* GHAIN */
70         {0x0640, 4, {0x0640, 0x0640, 0x0640, 0x0640}}, /* TATWEEL */
71         {0x0641, 4, {0xFED1, 0xFED2, 0xFED3, 0xFED4}}, /* FEH */
72         {0x0642, 4, {0xFED5, 0xFED6, 0xFED7, 0xFED8}}, /* QAF */
73         {0x0643, 4, {0xFED9, 0xFEDA, 0xFEDB, 0xFEDC}}, /* KAF */
74         {0x0644, 4, {0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0}}, /* LAM */
75         {0x0645, 4, {0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4}}, /* MEEM */
76         {0x0646, 4, {0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8}}, /* NOON */
77         {0x0647, 4, {0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC}}, /* HEH */
78         {0x0648, 2, {0xFEED, 0xFEEE}}, /* WAW */
79         {0x0649, 4, {0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9}}, /* ALEF MAKSURA */
80         {0x064A, 4, {0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4}}, /* YEH */
81         {0x0671, 2, {0xFB50, 0xFB51}}, /* ALEF WASLA */
82         {0x0679, 4, {0xFB66, 0xFB67, 0xFB68, 0xFB69}}, /* TTEH */
83         {0x067A, 4, {0xFB5E, 0xFB5F, 0xFB60, 0xFB61}}, /* TTEHEH */
84         {0x067B, 4, {0xFB52, 0xFB53, 0xFB54, 0xFB55}}, /* BEEH */
85         {0x067E, 4, {0xFB56, 0xFB57, 0xFB58, 0xFB59}}, /* PEH */
86         {0x067F, 4, {0xFB62, 0xFB63, 0xFB64, 0xFB65}}, /* TEHEH */
87         {0x0680, 4, {0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D}}, /* BEHEH */
88         {0x0683, 4, {0xFB76, 0xFB77, 0xFB78, 0xFB79}}, /* NYEH */
89         {0x0684, 4, {0xFB72, 0xFB73, 0xFB74, 0xFB75}}, /* DYEH */
90         {0x0686, 4, {0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D}}, /* TCHEH */
91         {0x0687, 4, {0xFB7E, 0xFB7F, 0xFB80, 0xFB81}}, /* TCHEHEH */
92         {0x0688, 2, {0xFB88, 0xFB89}}, /* DDAL */
93         {0x068C, 2, {0xFB84, 0xFB85}}, /* DAHAL */
94         {0x068D, 2, {0xFB82, 0xFB83}}, /* DDAHAL */
95         {0x068E, 2, {0xFB86, 0xFB87}}, /* DUL */
96         {0x0691, 2, {0xFB8C, 0xFB8D}}, /* RREH */
97         {0x0698, 2, {0xFB8A, 0xFB8B}}, /* JEH */
98         {0x06A4, 4, {0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D}}, /* VEH */
99         {0x06A6, 4, {0xFB6E, 0xFB6F, 0xFB70, 0xFB71}}, /* PEHEH */
100         {0x06A9, 4, {0xFB8E, 0xFB8F, 0xFB90, 0xFB91}}, /* KEHEH */
101         {0x06AD, 4, {0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6}}, /* NG */
102         {0x06AF, 4, {0xFB92, 0xFB93, 0xFB94, 0xFB95}}, /* GAF */
103         {0x06B1, 4, {0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D}}, /* NGOEH */
104         {0x06B3, 4, {0xFB96, 0xFB97, 0xFB98, 0xFB99}}, /* GUEH */
105         {0x06BB, 4, {0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3}}, /* RNOON */
106         {0x06BE, 4, {0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD}}, /* HEH DOACHASHMEE */
107         {0x06C0, 2, {0xFBA4, 0xFBA5}}, /* HEH WITH YEH ABOVE */
108         {0x06C1, 4, {0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9}}, /* HEH GOAL */
109         {0x06C5, 2, {0xFBE0, 0xFBE1}}, /* KIRGHIZ OE */
110         {0x06C6, 2, {0xFBD9, 0xFBDA}}, /* OE */
111         {0x06C7, 2, {0xFBD7, 0xFBD8}}, /* U */
112         {0x06C8, 2, {0xFBDB, 0xFBDC}}, /* YU */
113         {0x06C9, 2, {0xFBE2, 0xFBE3}}, /* KIRGHIZ YU */
114         {0x06CB, 2, {0xFBDE, 0xFBDF}}, /* VE */
115         {0x06CC, 4, {0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF}}, /* FARSI YEH */
116         {0x06D0, 4, {0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7}}, /* E */
117         {0x06D2, 2, {0xFBAE, 0xFBAF}}, /* YEH BARREE */
118         {0x06D3, 2, {0xFBB0, 0xFBB1}}, /* YEH BARREE WITH HAMZA ABOVE */
119 };
120
121 #define ALEF                                     0x0627
122 #define ALEFHAMZA                       0x0623
123 #define ALEFHAMZABELOW 0x0625
124 #define ALEFMADDA                       0x0622
125 #define LAM                                             0x0644
126 #define HAMZA                                   0x0621
127 #define TATWEEL                         0x0640
128 #define ZWJ                                             0x200D
129
130 #define HAMZAABOVE      0x0654
131 #define HAMZABELOW      0x0655
132
133 #define WAWHAMZA                0x0624
134 #define YEHHAMZA                0x0626
135 #define WAW                              0x0648
136 #define ALEFMAKSURA 0x0649
137 #define YEH                              0x064A
138 #define FARSIYEH                0x06CC
139
140 #define SHADDA                  0x0651
141 #define KASRA                    0x0650
142 #define FATHA                    0x064E
143 #define DAMMA                    0x064F
144 #define MADDA                    0x0653
145
146 #define LAM_ALEF                                         0xFEFB
147 #define LAM_ALEFHAMZA                   0xFEF7
148 #define LAM_ALEFHAMZABELOW 0xFEF9
149 #define LAM_ALEFMADDA                   0xFEF5
150
151 static short
152 shapecount (unsigned long s)
153 {
154   int l, r, m;
155   if ((s >= 0x0621) && (s <= 0x06D3))
156     {
157       l = 0;
158       r = sizeof (chartable) / sizeof (shapestruct);
159       while (l <= r)
160         {
161           m = (l + r) / 2;
162           if (s == chartable[m].basechar)
163             {
164               return chartable[m].count;
165             }
166           else if (s < chartable[m].basechar)
167             {
168               r = m - 1;
169             }
170           else
171             {
172               l = m + 1;
173             }
174         }
175     }
176   else if (s == ZWJ)
177     {
178       return 4;
179     }
180   return 1;
181 }
182
183 static unsigned long
184 charshape (unsigned long s, int which)
185 /* which 0=isolated 1=final 2=initial 3=medial */
186 {
187         int l, r, m;
188         if ((s >= 0x0621) && (s <= 0x06D3))
189                 {
190                         l = 0;
191                         r = sizeof (chartable) / sizeof (shapestruct);
192                         while (l <= r)
193                                 {
194                                         m = (l + r) / 2;
195                                         if (s == chartable[m].basechar)
196                                                 {
197                                                         return chartable[m].charshape[which];
198                                                 }
199                                         else if (s < chartable[m].basechar)
200                                                 {
201                                                         r = m - 1;
202                                                 }
203                                         else
204                                                 {
205                                                         l = m + 1;
206                                                 }
207                                 }
208                 }
209         else if ((s >= 0xFEF5) && (s <= 0xFEFB))
210                 {                                                                                                        /* Lam+Alef */
211                         return s + which;
212                 }
213
214         return s;
215 }
216
217 void
218 shape (std::vector<unsigned long> &string, const std::vector<unsigned long> &text)
219 {
220         string.reserve(text.size());
221
222         charstruct oldchar, curchar;
223         int which;
224         unsigned long nextletter;
225
226         charstruct_init (&oldchar);
227         charstruct_init (&curchar);
228         
229         for (std::vector<unsigned long>::const_iterator i(text.begin());
230                         i != text.end(); ++i)
231         {
232                 nextletter = *i;
233                 int nc = shapecount (nextletter);
234                 
235                 if (nc == 1)
236                         which = 0;                              /* final or isolated */
237                 else
238                         which = 2;                              /* medial or initial */
239                 if (connects_to_left (oldchar))
240                         which++;
241                 which = which % (curchar.numshapes);
242                 curchar.basechar = charshape (curchar.basechar, which);
243                         /* get rid of oldchar */
244                 if (oldchar.basechar)
245                         string.push_back(oldchar.basechar);
246                 oldchar = curchar;              /* new values in oldchar */
247
248                         /* init new curchar */
249                 charstruct_init (&curchar);
250                 curchar.basechar = nextletter;
251                 curchar.numshapes = nc;
252         }
253
254         /* Handle last char */
255         if (connects_to_left (oldchar))
256                 which = 1;
257         else
258                 which = 0;
259         which = which % (curchar.numshapes);
260         curchar.basechar = charshape (curchar.basechar, which);
261
262         if (oldchar.basechar != 0)
263                 string.push_back(oldchar.basechar);
264         if (curchar.basechar != 0)
265                 string.push_back(curchar.basechar);
266 }