2 /* Copyright (C) 2002 Nadim Shaikli (arabeyes.org) */
3 /* This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * A place holder for when fribidi finally implements character
22 * shaping/joining. This shaping/joining is a must for a variety of
23 * Bidi'ed languages such as Arabic, Farsi, as well as all the Syriacs
24 * (Urdu, Sindhi, Pashto, Kurdish, Baluchi, Kashmiri, Kazakh, Berber,
25 * Uighur, Kirghiz, etc).
35 /* ---------------------------- included header files ---------------------- */
39 /* ---------------------------- local types -------------------------------- */
41 typedef struct char_shaped
45 /* The various Arabic shaped permutations */
52 typedef struct char_shaped_comb
54 /* The Arabic exceptions - 2chars ==> 1char */
57 FriBidiChar comb_isolated
;
58 FriBidiChar comb_joined
;
61 /* ---------------------------- static variables --------------------------- */
63 static const char_shaped_t shaped_table
[] =
66 { 0x0621, 0xFE80, 0x0000, 0x0000, 0x0000, }, /* HAMZA */
67 { 0x0622, 0xFE81, 0x0000, 0x0000, 0xFE82, }, /* ALEF_MADDA */
68 { 0x0623, 0xFE83, 0x0000, 0x0000, 0xFE84, }, /* ALEF_HAMZA_ABOVE */
69 { 0x0624, 0xFE85, 0x0000, 0x0000, 0xFE86, }, /* WAW_HAMZA */
70 { 0x0625, 0xFE87, 0x0000, 0x0000, 0xFE88, }, /* ALEF_HAMZA_BELOW */
71 { 0x0626, 0xFE89, 0xFE8B, 0xFE8C, 0xFE8A, }, /* YEH_HAMZA */
72 { 0x0627, 0xFE8D, 0x0000, 0x0000, 0xFE8E, }, /* ALEF */
73 { 0x0628, 0xFE8F, 0xFE91, 0xFE92, 0xFE90, }, /* BEH */
74 { 0x0629, 0xFE93, 0x0000, 0x0000, 0xFE94, }, /* TEH_MARBUTA */
75 { 0x062A, 0xFE95, 0xFE97, 0xFE98, 0xFE96, }, /* TEH */
76 { 0x062B, 0xFE99, 0xFE9B, 0xFE9C, 0xFE9A, }, /* THEH */
77 { 0x062C, 0xFE9D, 0xFE9F, 0xFEA0, 0xFE9E, }, /* JEEM */
78 { 0x062D, 0xFEA1, 0xFEA3, 0xFEA4, 0xFEA2, }, /* HAH */
79 { 0x062E, 0xFEA5, 0xFEA7, 0xFEA8, 0xFEA6, }, /* KHAH */
80 { 0x062F, 0xFEA9, 0x0000, 0x0000, 0xFEAA, }, /* DAL */
81 { 0x0630, 0xFEAB, 0x0000, 0x0000, 0xFEAC, }, /* THAL */
82 { 0x0631, 0xFEAD, 0x0000, 0x0000, 0xFEAE, }, /* REH */
83 { 0x0632, 0xFEAF, 0x0000, 0x0000, 0xFEB0, }, /* ZAIN */
84 { 0x0633, 0xFEB1, 0xFEB3, 0xFEB4, 0xFEB2, }, /* SEEN */
85 { 0x0634, 0xFEB5, 0xFEB7, 0xFEB8, 0xFEB6, }, /* SHEEN */
86 { 0x0635, 0xFEB9, 0xFEBB, 0xFEBC, 0xFEBA, }, /* SAD */
87 { 0x0636, 0xFEBD, 0xFEBF, 0xFEC0, 0xFEBE, }, /* DAD */
88 { 0x0637, 0xFEC1, 0xFEC3, 0xFEC4, 0xFEC2, }, /* TAH */
89 { 0x0638, 0xFEC5, 0xFEC7, 0xFEC8, 0xFEC6, }, /* ZAH */
90 { 0x0639, 0xFEC9, 0xFECB, 0xFECC, 0xFECA, }, /* AIN */
91 { 0x063A, 0xFECD, 0xFECF, 0xFED0, 0xFECE, }, /* GHAIN */
92 { 0x0640, 0x0640, 0x0640, 0x0640, 0x0640, }, /* TATWEEL */
93 { 0x0641, 0xFED1, 0xFED3, 0xFED4, 0xFED2, }, /* FEH */
94 { 0x0642, 0xFED5, 0xFED7, 0xFED8, 0xFED6, }, /* QAF */
95 { 0x0643, 0xFED9, 0xFEDB, 0xFEDC, 0xFEDA, }, /* KAF */
96 { 0x0644, 0xFEDD, 0xFEDF, 0xFEE0, 0xFEDE, }, /* LAM */
97 { 0x0645, 0xFEE1, 0xFEE3, 0xFEE4, 0xFEE2, }, /* MEEM */
98 { 0x0646, 0xFEE5, 0xFEE7, 0xFEE8, 0xFEE6, }, /* NOON */
99 { 0x0647, 0xFEE9, 0xFEEB, 0xFEEC, 0xFEEA, }, /* HEH */
100 { 0x0648, 0xFEED, 0x0000, 0x0000, 0xFEEE, }, /* WAW */
101 { 0x0649, 0xFEEF, 0xFBE8, 0xFBE9, 0xFEF0, }, /* ALEF_MAKSURA */
102 { 0x064A, 0xFEF1, 0xFEF3, 0xFEF4, 0xFEF2, }, /* YEH */
103 { 0x0671, 0xFB50, 0x0000, 0x0000, 0xFB51, },
104 { 0x0679, 0xFB66, 0xFB68, 0xFB69, 0xFB67, },
105 { 0x067A, 0xFB5E, 0xFB60, 0xFB61, 0xFB5F, },
106 { 0x067B, 0xFB52, 0xFB54, 0xFB55, 0xFB53, },
107 { 0x067E, 0xFB56, 0xFB58, 0xFB59, 0xFB57, },
108 { 0x067F, 0xFB62, 0xFB64, 0xFB65, 0xFB63, },
109 { 0x0680, 0xFB5A, 0xFB5C, 0xFB5D, 0xFB5B, },
110 { 0x0683, 0xFB76, 0xFB78, 0xFB79, 0xFB77, },
111 { 0x0684, 0xFB72, 0xFB74, 0xFB75, 0xFB73, },
112 { 0x0686, 0xFB7A, 0xFB7C, 0xFB7D, 0xFB7B, },
113 { 0x0687, 0xFB7E, 0xFB80, 0xFB81, 0xFB7F, },
114 { 0x0688, 0xFB88, 0x0000, 0x0000, 0xFB89, },
115 { 0x068C, 0xFB84, 0x0000, 0x0000, 0xFB85, },
116 { 0x068D, 0xFB82, 0x0000, 0x0000, 0xFB83, },
117 { 0x068E, 0xFB86, 0x0000, 0x0000, 0xFB87, },
118 { 0x0691, 0xFB8C, 0x0000, 0x0000, 0xFB8D, },
119 { 0x0698, 0xFB8A, 0x0000, 0x0000, 0xFB8B, },
120 { 0x06A4, 0xFB6A, 0xFB6C, 0xFB6D, 0xFB6B, },
121 { 0x06A6, 0xFB6E, 0xFB70, 0xFB71, 0xFB6F, },
122 { 0x06A9, 0xFB8E, 0xFB90, 0xFB91, 0xFB8F, },
123 { 0x06AD, 0xFBD3, 0xFBD5, 0xFBD6, 0xFBD4, },
124 { 0x06AF, 0xFB92, 0xFB94, 0xFB95, 0xFB93, },
125 { 0x06B1, 0xFB9A, 0xFB9C, 0xFB9D, 0xFB9B, },
126 { 0x06B3, 0xFB96, 0xFB98, 0xFB99, 0xFB97, },
127 { 0x06BB, 0xFBA0, 0xFBA2, 0xFBA3, 0xFBA1, },
128 { 0x06BE, 0xFBAA, 0xFBAC, 0xFBAD, 0xFBAB, },
129 { 0x06C0, 0xFBA4, 0x0000, 0x0000, 0xFBA5, },
130 { 0x06C1, 0xFBA6, 0xFBA8, 0xFBA9, 0xFBA7, },
131 { 0x06C5, 0xFBE0, 0x0000, 0x0000, 0xFBE1, },
132 { 0x06C6, 0xFBD9, 0x0000, 0x0000, 0xFBDA, },
133 { 0x06C7, 0xFBD7, 0x0000, 0x0000, 0xFBD8, },
134 { 0x06C8, 0xFBDB, 0x0000, 0x0000, 0xFBDC, },
135 { 0x06C9, 0xFBE2, 0x0000, 0x0000, 0xFBE3, },
136 { 0x06CB, 0xFBDE, 0x0000, 0x0000, 0xFBDF, },
137 { 0x06CC, 0xFBFC, 0xFBFE, 0xFBFF, 0xFBFD, },
138 { 0x06D0, 0xFBE4, 0xFBE6, 0xFBE7, 0xFBE5, },
139 { 0x06D2, 0xFBAE, 0x0000, 0x0000, 0xFBAF, },
140 { 0x06D3, 0xFBB0, 0x0000, 0x0000, 0xFBB1, },
141 /* special treatment for ligatures from combining phase */
142 { 0xFEF5, 0xFEF5, 0x0000, 0x0000, 0xFEF6, }, /* LAM_ALEF_MADDA */
143 { 0xFEF7, 0xFEF7, 0x0000, 0x0000, 0xFEF8, }, /* LAM_ALEF_HAMZA_ABOVE */
144 { 0xFEF9, 0xFEF9, 0x0000, 0x0000, 0xFEFA, }, /* LAM_ALEF_HAMZA_BELOW */
145 { 0xFEFB, 0xFEFB, 0x0000, 0x0000, 0xFEFC, }, /* LAM_ALEF */
148 static const char_shaped_comb_t shaped_comb_table
[] =
150 { 0x0644, 0x0622, 0xFEF5, 0xFEF6, }, /* LAM_ALEF_MADDA */
151 { 0x0644, 0x0623, 0xFEF7, 0xFEF8, }, /* LAM_ALEF_HAMZA_ABOVE */
152 { 0x0644, 0x0625, 0xFEF9, 0xFEFA, }, /* LAM_ALEF_HAMZA_BELOW */
153 { 0x0644, 0x0627, 0xFEFB, 0xFEFC, }, /* LAM_ALEF */
156 /* -------------------------- local functions ------------------------------ */
158 static const char_shaped_t
*
159 get_shaped_entry(FriBidiChar ch
)
164 table_size
= sizeof(shaped_table
) / sizeof(shaped_table
[0]);
166 for (count
= 0; count
< table_size
; count
++)
168 if (shaped_table
[count
].base
== ch
)
170 return &shaped_table
[count
];
177 /* ------------------------- interface functions --------------------------- */
181 FriBidiChar
*str_visual
, int str_len
)
183 int i
; /* counter of the input string */
184 int len
; /* counter and the final length of the shaped string */
185 FriBidiChar
*orig_str
;
186 const char_shaped_t
**list
;
187 const char_shaped_t
*prev
;
188 const char_shaped_t
*curr
;
189 const char_shaped_t
*next
;
191 list
= (const char_shaped_t
**)safemalloc(
192 (str_len
+ 2) * sizeof(char_shaped_t
*));
194 orig_str
= (FriBidiChar
*)safemalloc(
195 (str_len
+ 1) * sizeof(FriBidiChar
));
201 /* Populate with existent shaped characters */
202 for (i
= 0; i
< str_len
; i
++)
204 list
[i
] = get_shaped_entry(str_visual
[i
]);
210 /* Store-off non-shaped characters; start with a clean slate */
211 memcpy(orig_str
, str_visual
, (str_len
* sizeof(str_visual
[0])));
212 memset(str_visual
, 0, (str_len
* sizeof(str_visual
[0])));
214 /* Traverse the line & build new content */
215 for (i
= 0, len
= 0; i
<= str_len
- 1; i
++, len
++)
217 /* Get previous, current, and next characters */
222 /* Process current mapped characters */
229 if (!prev
->initial
|| !prev
->medial
)
238 str_visual
[len
] = curr
->medial
?
245 str_visual
[len
] = curr
->initial
?
254 if (!prev
->initial
|| !prev
->medial
)
261 str_visual
[len
] = curr
->final
?
268 str_visual
[len
] = curr
->isolated
;
274 str_visual
[len
] = orig_str
[i
];
281 /* return the length of the new string */
285 #endif /* HAVE_BIDI */