i Changes to support cursive letter forms. It works, but I've
[WebKit-https.git] / WebKit / Misc.subproj / WebUnicode.m
1 /*      
2         WebUnicode.m
3         Copyright 2001, 2002, Apple Computer, Inc.
4 */
5 #import <WebKit/WebUnicode.h>
6 #import <WebCore/WebCoreUnicode.h>
7
8
9 static int _unicodeDigitValue(UniChar c)
10 {
11     const char *dec_row = decimal_info[WK_ROW(c)];
12     if( !dec_row )
13         return -1;
14     return dec_row[WK_CELL(c)];
15 }
16
17 static WebCoreUnicodeCategory _unicodeCategory(UniChar c)
18 {
19     return (WebCoreUnicodeCategory)(unicode_info[WK_ROW(c)][WK_CELL(c)]);
20 }
21
22 static WebCoreUnicodeDirection _unicodeDirection(UniChar c)
23 {
24     const unsigned char *rowp = direction_info[WK_ROW(c)];
25     
26     if(!rowp) 
27         return DirectionL;
28     return (WebCoreUnicodeDirection) ( *(rowp+WK_CELL(c)) &0x1f );
29 }
30
31 static WebCoreUnicodeJoining _unicodeJoining(UniChar c)
32 {
33     const unsigned char *rowp = direction_info[WK_ROW(c)];
34     if ( !rowp )
35         return JoiningOther;
36     return (WebCoreUnicodeJoining) ((*(rowp+WK_CELL(c)) >> 5) &0x3);
37 }
38
39 static WebCoreUnicodeDecomposition _unicodeDecompositionTag(UniChar c)
40 {
41     const unsigned short *r = decomposition_info[WK_ROW(c)];
42     if(!r)
43         return DecompositionSingle;
44
45     unsigned short pos = r[WK_CELL(c)];
46     if(!pos)
47         return DecompositionSingle;
48
49     return (WebCoreUnicodeDecomposition) decomposition_map[pos];
50 }
51
52 static bool _unicodeMirrored(UniChar c)
53 {
54     const unsigned char *rowp = direction_info[WK_ROW(c)];
55     if ( !rowp )
56         return FALSE;
57     return *(rowp+WK_CELL(c))>128;
58 }
59
60 static UniChar _unicodeMirroredChar(UniChar c)
61 {
62     if(!_unicodeMirrored(c))
63         return c;
64
65     int i;
66     for (i = 0; i < symmetricPairsSize; i ++) {
67         if (symmetricPairs[i] == c)
68           return symmetricPairs[(i%2) ? (i-1) : (i+1)];
69     }
70     return c;
71 }
72
73 static WebCoreUnicodeCombiningClass _unicodeCombiningClass (UniChar c)
74 {
75     const unsigned char *rowp = combining_info[WK_ROW(c)];
76     if ( !rowp )
77         return 0;
78     return *(rowp+WK_CELL(c));
79 }
80
81 static UniChar _unicodeLower(UniChar c)
82 {
83     if ( _unicodeCategory(c) != Letter_Uppercase )
84         return c;
85     unsigned short lower = *( case_info[WK_ROW(c)] + WK_CELL(c) );
86     if ( lower == 0 )
87         return c;
88     return lower;
89 }
90
91 static UniChar _unicodeUpper(UniChar c)
92 {
93     if ( _unicodeCategory(c) != Letter_Lowercase )
94         return c;
95     unsigned short upper = *(case_info[WK_ROW(c)]+WK_CELL(c));
96     if ( upper == 0 )
97         return c;
98     return upper;
99 }
100
101 static bool _unicodeIsMark(UniChar c)
102 {
103     WebCoreUnicodeCategory category = _unicodeDigitValue(c);
104     return category >= Mark_NonSpacing && category <= Mark_Enclosing;
105 }
106
107 void WebKitInitializeUnicode(void)
108 {
109     WebCoreUnicodeDigitValueFunction = _unicodeDigitValue;
110     WebCoreUnicodeCategoryFunction = _unicodeCategory;
111     WebCoreUnicodeDirectionFunction = _unicodeDirection;
112     WebCoreUnicodeJoiningFunction = _unicodeJoining;
113     WebCoreUnicodeDecompositionTagFunction = _unicodeDecompositionTag;
114     WebCoreUnicodeMirroredFunction = _unicodeMirrored;
115     WebCoreUnicodeMirroredCharFunction = _unicodeMirroredChar;
116     WebCoreUnicodeCombiningClassFunction = _unicodeCombiningClass;
117     WebCoreUnicodeLowerFunction = _unicodeLower;
118     WebCoreUnicodeUpperFunction = _unicodeUpper;
119 }
120
121 // The unicode to unicode shaping codec.
122 // does only presentation forms B at the moment, but that should be enough for
123 // simple display
124 static const ushort arabicUnicodeMapping[256][2] = {
125     // base of shaped forms, and number-1 of them ( 0 for non shaping,
126     // 1 for right binding and 3 for dual binding
127
128     // These are just the glyphs available in Unicode,
129     // some characters are in R class, but have no glyphs in Unicode.
130
131     { 0x0600, 0 }, // 0x0600
132     { 0x0601, 0 }, // 0x0601
133     { 0x0602, 0 }, // 0x0602
134     { 0x0603, 0 }, // 0x0603
135     { 0x0604, 0 }, // 0x0604
136     { 0x0605, 0 }, // 0x0605
137     { 0x0606, 0 }, // 0x0606
138     { 0x0607, 0 }, // 0x0607
139     { 0x0608, 0 }, // 0x0608
140     { 0x0609, 0 }, // 0x0609
141     { 0x060A, 0 }, // 0x060A
142     { 0x060B, 0 }, // 0x060B
143     { 0x060C, 0 }, // 0x060C
144     { 0x060D, 0 }, // 0x060D
145     { 0x060E, 0 }, // 0x060E
146     { 0x060F, 0 }, // 0x060F
147
148     { 0x0610, 0 }, // 0x0610
149     { 0x0611, 0 }, // 0x0611
150     { 0x0612, 0 }, // 0x0612
151     { 0x0613, 0 }, // 0x0613
152     { 0x0614, 0 }, // 0x0614
153     { 0x0615, 0 }, // 0x0615
154     { 0x0616, 0 }, // 0x0616
155     { 0x0617, 0 }, // 0x0617
156     { 0x0618, 0 }, // 0x0618
157     { 0x0619, 0 }, // 0x0619
158     { 0x061A, 0 }, // 0x061A
159     { 0x061B, 0 }, // 0x061B
160     { 0x061C, 0 }, // 0x061C
161     { 0x061D, 0 }, // 0x061D
162     { 0x061E, 0 }, // 0x061E
163     { 0x061F, 0 }, // 0x061F
164
165     { 0x0620, 0 }, // 0x0620
166     { 0xFE80, 0 }, // 0x0621            HAMZA
167     { 0xFE81, 1 }, // 0x0622    R       ALEF WITH MADDA ABOVE
168     { 0xFE83, 1 }, // 0x0623    R       ALEF WITH HAMZA ABOVE
169     { 0xFE85, 1 }, // 0x0624    R       WAW WITH HAMZA ABOVE
170     { 0xFE87, 1 }, // 0x0625    R       ALEF WITH HAMZA BELOW
171     { 0xFE89, 3 }, // 0x0626    D       YEH WITH HAMZA ABOVE
172     { 0xFE8D, 1 }, // 0x0627    R       ALEF
173     { 0xFE8F, 3 }, // 0x0628    D       BEH
174     { 0xFE93, 1 }, // 0x0629    R       TEH MARBUTA
175     { 0xFE95, 3 }, // 0x062A    D       TEH
176     { 0xFE99, 3 }, // 0x062B    D       THEH
177     { 0xFE9D, 3 }, // 0x062C    D       JEEM
178     { 0xFEA1, 3 }, // 0x062D    D       HAH
179     { 0xFEA5, 3 }, // 0x062E    D       KHAH
180     { 0xFEA9, 1 }, // 0x062F    R       DAL
181
182     { 0xFEAB, 1 }, // 0x0630    R       THAL
183     { 0xFEAD, 1 }, // 0x0631    R       REH
184     { 0xFEAF, 1 }, // 0x0632    R       ZAIN
185     { 0xFEB1, 3 }, // 0x0633    D       SEEN
186     { 0xFEB5, 3 }, // 0x0634    D       SHEEN
187     { 0xFEB9, 3 }, // 0x0635    D       SAD
188     { 0xFEBD, 3 }, // 0x0636    D       DAD
189     { 0xFEC1, 3 }, // 0x0637    D       TAH
190     { 0xFEC5, 3 }, // 0x0638    D       ZAH
191     { 0xFEC9, 3 }, // 0x0639    D       AIN
192     { 0xFECD, 3 }, // 0x063A    D       GHAIN
193     { 0x063B, 0 }, // 0x063B
194     { 0x063C, 0 }, // 0x063C
195     { 0x063D, 0 }, // 0x063D
196     { 0x063E, 0 }, // 0x063E
197     { 0x063F, 0 }, // 0x063F
198
199     { 0x0640, 0 }, // 0x0640    C       TATWEEL // ### Join Causing, only one glyph
200     { 0xFED1, 3 }, // 0x0641    D       FEH
201     { 0xFED5, 3 }, // 0x0642    D       QAF
202     { 0xFED9, 3 }, // 0x0643    D       KAF
203     { 0xFEDD, 3 }, // 0x0644    D       LAM
204     { 0xFEE1, 3 }, // 0x0645    D       MEEM
205     { 0xFEE5, 3 }, // 0x0646    D       NOON
206     { 0xFEE9, 3 }, // 0x0647    D       HEH
207     { 0xFEED, 1 }, // 0x0648    R       WAW
208     { 0x0649, 0 }, // 0x0649            ALEF MAKSURA // ### Dual, glyphs not consecutive, handle in code.
209     { 0xFEF1, 3 }, // 0x064A    D       YEH
210     { 0x064B, 0 }, // 0x064B
211     { 0x064C, 0 }, // 0x064C
212     { 0x064D, 0 }, // 0x064D
213     { 0x064E, 0 }, // 0x064E
214     { 0x064F, 0 }, // 0x064F
215
216     { 0x0650, 0 }, // 0x0650
217     { 0x0651, 0 }, // 0x0651
218     { 0x0652, 0 }, // 0x0652
219     { 0x0653, 0 }, // 0x0653
220     { 0x0654, 0 }, // 0x0654
221     { 0x0655, 0 }, // 0x0655
222     { 0x0656, 0 }, // 0x0656
223     { 0x0657, 0 }, // 0x0657
224     { 0x0658, 0 }, // 0x0658
225     { 0x0659, 0 }, // 0x0659
226     { 0x065A, 0 }, // 0x065A
227     { 0x065B, 0 }, // 0x065B
228     { 0x065C, 0 }, // 0x065C
229     { 0x065D, 0 }, // 0x065D
230     { 0x065E, 0 }, // 0x065E
231     { 0x065F, 0 }, // 0x065F
232
233     { 0x0660, 0 }, // 0x0660
234     { 0x0661, 0 }, // 0x0661
235     { 0x0662, 0 }, // 0x0662
236     { 0x0663, 0 }, // 0x0663
237     { 0x0664, 0 }, // 0x0664
238     { 0x0665, 0 }, // 0x0665
239     { 0x0666, 0 }, // 0x0666
240     { 0x0667, 0 }, // 0x0667
241     { 0x0668, 0 }, // 0x0668
242     { 0x0669, 0 }, // 0x0669
243     { 0x066A, 0 }, // 0x066A
244     { 0x066B, 0 }, // 0x066B
245     { 0x066C, 0 }, // 0x066C
246     { 0x066D, 0 }, // 0x066D
247     { 0x066E, 0 }, // 0x066E
248     { 0x066F, 0 }, // 0x066F
249
250     { 0x0670, 0 }, // 0x0670
251     { 0xFB50, 1 }, // 0x0671    R       ALEF WASLA
252     { 0x0672, 0 }, // 0x0672
253     { 0x0673, 0 }, // 0x0673
254     { 0x0674, 0 }, // 0x0674
255     { 0x0675, 0 }, // 0x0675
256     { 0x0676, 0 }, // 0x0676
257     { 0x0677, 0 }, // 0x0677
258     { 0x0678, 0 }, // 0x0678
259     { 0xFB66, 3 }, // 0x0679    D       TTEH
260     { 0xFB5E, 3 }, // 0x067A    D       TTEHEH
261     { 0xFB52, 3 }, // 0x067B    D       BEEH
262     { 0x067C, 0 }, // 0x067C
263     { 0x067D, 0 }, // 0x067D
264     { 0xFB56, 3 }, // 0x067E    D       PEH
265     { 0xFB62, 3 }, // 0x067F    D       TEHEH
266
267     { 0xFB5A, 3 }, // 0x0680    D       BEHEH
268     { 0x0681, 0 }, // 0x0681
269     { 0x0682, 0 }, // 0x0682
270     { 0xFB76, 3 }, // 0x0683    D       NYEH
271     { 0xFB72, 3 }, // 0x0684    D       DYEH
272     { 0x0685, 0 }, // 0x0685
273     { 0xFB7A, 3 }, // 0x0686    D       TCHEH
274     { 0xFB7E, 3 }, // 0x0687    D       TCHEHEH
275     { 0xFB88, 1 }, // 0x0688    R       DDAL
276     { 0x0689, 0 }, // 0x0689
277     { 0x068A, 0 }, // 0x068A
278     { 0x068B, 0 }, // 0x068B
279     { 0xFB84, 1 }, // 0x068C    R       DAHAL
280     { 0xFB82, 1 }, // 0x068D    R       DDAHAL
281     { 0xFB86, 1 }, // 0x068E    R       DUL
282     { 0x068F, 0 }, // 0x068F
283
284     { 0x0690, 0 }, // 0x0690
285     { 0xFB8C, 1 }, // 0x0691    R       RREH
286     { 0x0692, 0 }, // 0x0692
287     { 0x0693, 0 }, // 0x0693
288     { 0x0694, 0 }, // 0x0694
289     { 0x0695, 0 }, // 0x0695
290     { 0x0696, 0 }, // 0x0696
291     { 0x0697, 0 }, // 0x0697
292     { 0xFB8A, 1 }, // 0x0698    R       JEH
293     { 0x0699, 0 }, // 0x0699
294     { 0x069A, 0 }, // 0x069A
295     { 0x069B, 0 }, // 0x069B
296     { 0x069C, 0 }, // 0x069C
297     { 0x069D, 0 }, // 0x069D
298     { 0x069E, 0 }, // 0x069E
299     { 0x069F, 0 }, // 0x069F
300
301     { 0x06A0, 0 }, // 0x06A0
302     { 0x06A1, 0 }, // 0x06A1
303     { 0x06A2, 0 }, // 0x06A2
304     { 0x06A3, 0 }, // 0x06A3
305     { 0xFB6A, 3 }, // 0x06A4    D       VEH
306     { 0x06A5, 0 }, // 0x06A5
307     { 0xFB6E, 3 }, // 0x06A6    D       PEHEH
308     { 0x06A7, 0 }, // 0x06A7
309     { 0x06A8, 0 }, // 0x06A8
310     { 0xFB8E, 3 }, // 0x06A9    D       KEHEH
311     { 0x06AA, 0 }, // 0x06AA
312     { 0x06AB, 0 }, // 0x06AB
313     { 0x06AC, 0 }, // 0x06AC
314     { 0xFBD3, 3 }, // 0x06AD    D       NG
315     { 0x06AE, 0 }, // 0x06AE
316     { 0xFB92, 3 }, // 0x06AF    D       GAF
317
318     { 0x06B0, 0 }, // 0x06B0
319     { 0xFB9A, 3 }, // 0x06B1    D       NGOEH
320     { 0x06B2, 0 }, // 0x06B2
321     { 0xFB96, 3 }, // 0x06B3    D       GUEH
322     { 0x06B4, 0 }, // 0x06B4
323     { 0x06B5, 0 }, // 0x06B5
324     { 0x06B6, 0 }, // 0x06B6
325     { 0x06B7, 0 }, // 0x06B7
326     { 0x06B8, 0 }, // 0x06B8
327     { 0x06B9, 0 }, // 0x06B9
328     { 0x06BA, 0 }, // 0x06BA
329     { 0xFBA0, 3 }, // 0x06BB    D       RNOON
330     { 0x06BC, 0 }, // 0x06BC
331     { 0x06BD, 0 }, // 0x06BD
332     { 0xFBAA, 3 }, // 0x06BE    D       HEH DOACHASHMEE
333     { 0x06BF, 0 }, // 0x06BF
334
335     { 0xFBA4, 1 }, // 0x06C0    R       HEH WITH YEH ABOVE
336     { 0xFBA6, 3 }, // 0x06C1    D       HEH GOAL
337     { 0x06C2, 0 }, // 0x06C2
338     { 0x06C3, 0 }, // 0x06C3
339     { 0x06C4, 0 }, // 0x06C4
340     { 0xFBE0, 1 }, // 0x06C5    R       KIRGHIZ OE
341     { 0xFBD9, 1 }, // 0x06C6    R       OE
342     { 0xFBD7, 1 }, // 0x06C7    R       U
343     { 0xFBDB, 1 }, // 0x06C8    R       YU
344     { 0xFBE2, 1 }, // 0x06C9    R       KIRGHIZ YU
345     { 0x06CA, 0 }, // 0x06CA
346     { 0xFBDE, 1 }, // 0x06CB    R       VE
347     { 0xFBFC, 3 }, // 0x06CC    D       FARSI YEH
348     { 0x06CD, 0 }, // 0x06CD
349     { 0x06CE, 0 }, // 0x06CE
350     { 0x06CF, 0 }, // 0x06CF
351
352     { 0xFBE4, 3 }, // 0x06D0    D       E
353     { 0x06D1, 0 }, // 0x06D1
354     { 0xFBAE, 1 }, // 0x06D2    R       YEH BARREE
355     { 0xFBB0, 1 }, // 0x06D3    R       YEH BARREE WITH HAMZA ABOVE
356     { 0x06D4, 0 }, // 0x06D4
357     { 0x06D5, 0 }, // 0x06D5
358     { 0x06D6, 0 }, // 0x06D6
359     { 0x06D7, 0 }, // 0x06D7
360     { 0x06D8, 0 }, // 0x06D8
361     { 0x06D9, 0 }, // 0x06D9
362     { 0x06DA, 0 }, // 0x06DA
363     { 0x06DB, 0 }, // 0x06DB
364     { 0x06DC, 0 }, // 0x06DC
365     { 0x06DD, 0 }, // 0x06DD
366     { 0x06DE, 0 }, // 0x06DE
367     { 0x06DF, 0 }, // 0x06DF
368
369     { 0x06E0, 0 }, // 0x06E0
370     { 0x06E1, 0 }, // 0x06E1
371     { 0x06E2, 0 }, // 0x06E2
372     { 0x06E3, 0 }, // 0x06E3
373     { 0x06E4, 0 }, // 0x06E4
374     { 0x06E5, 0 }, // 0x06E5
375     { 0x06E6, 0 }, // 0x06E6
376     { 0x06E7, 0 }, // 0x06E7
377     { 0x06E8, 0 }, // 0x06E8
378     { 0x06E9, 0 }, // 0x06E9
379     { 0x06EA, 0 }, // 0x06EA
380     { 0x06EB, 0 }, // 0x06EB
381     { 0x06EC, 0 }, // 0x06EC
382     { 0x06ED, 0 }, // 0x06ED
383     { 0x06EE, 0 }, // 0x06EE
384     { 0x06EF, 0 }, // 0x06EF
385
386     { 0x06F0, 0 }, // 0x06F0
387     { 0x06F1, 0 }, // 0x06F1
388     { 0x06F2, 0 }, // 0x06F2
389     { 0x06F3, 0 }, // 0x06F3
390     { 0x06F4, 0 }, // 0x06F4
391     { 0x06F5, 0 }, // 0x06F5
392     { 0x06F6, 0 }, // 0x06F6
393     { 0x06F7, 0 }, // 0x06F7
394     { 0x06F8, 0 }, // 0x06F8
395     { 0x06F9, 0 }, // 0x06F9
396     { 0x06FA, 0 }, // 0x06FA
397     { 0x06FB, 0 }, // 0x06FB
398     { 0x06FC, 0 }, // 0x06FC
399     { 0x06FD, 0 }, // 0x06FD
400     { 0x06FE, 0 }, // 0x06FE
401     { 0x06FF, 0 }  // 0x06FF
402 };
403
404 // the arabicUnicodeMapping does not work for U+0649 ALEF MAKSURA, this table does
405 static const ushort alefMaksura[4] = {0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9};
406
407 // this is a bit tricky. Alef always binds to the right, so the second parameter descibing the shape
408 // of the lam can be either initial of medial. So initial maps to the isolated form of the ligature,
409 // medial to the final form
410 static const ushort arabicUnicodeLamAlefMapping[6][4] = {
411     { 0xfffd, 0xfffd, 0xfef5, 0xfef6 }, // 0x622        R       Alef with Madda above
412     { 0xfffd, 0xfffd, 0xfef7, 0xfef8 }, // 0x623        R       Alef with Hamza above
413     { 0xfffd, 0xfffd, 0xfffd, 0xfffd }, // 0x624        // Just to fill the table ;-)
414     { 0xfffd, 0xfffd, 0xfef9, 0xfefa }, // 0x625        R       Alef with Hamza below
415     { 0xfffd, 0xfffd, 0xfffd, 0xfffd }, // 0x626        // Just to fill the table ;-)
416     { 0xfffd, 0xfffd, 0xfefb, 0xfefc }  // 0x627        R       Alef
417 };
418
419 static inline int getShape( UniChar cell, int shape)
420 {
421     // the arabicUnicodeMapping does not work for U+0649 ALEF MAKSURA, handle this here
422     uint ch = ( cell != 0x49 ) ? arabicUnicodeMapping[cell][0] + shape
423                                : alefMaksura[shape] ;
424     return ch;
425 }
426
427 enum CursiveShape {
428     XIsolated,
429     XFinal,
430     XInitial,
431     XMedial
432 };
433
434 UniChar replacementUniChar = 0xfffd;
435
436 static inline UniChar *prevChar( UniChar *str, int stringLength, int pos )
437 {
438     pos--;
439     UniChar *ch = str + pos;
440     while( pos > -1 ) {
441         if( !_unicodeIsMark(*ch) )
442             return ch;
443         pos--;
444         ch--;
445     }
446     return &replacementUniChar;
447 }
448
449 static inline UniChar *nextChar( UniChar *str, int stringLength, int pos)
450 {
451     pos++;
452     int len = stringLength;
453     UniChar *ch = str + pos;
454     while( pos < len ) {
455         //qDebug("rightChar: %d isLetter=%d, joining=%d", pos, ch.isLetter(), ch.joining());
456         if( !_unicodeIsMark(*ch) )
457             return ch;
458         // assume it's a transparent char, this might not be 100% correct
459         pos++;
460         ch++;
461     }
462     return &replacementUniChar;
463 }
464
465 static inline bool prevLogicalCharJoins( UniChar *str, int stringLength, int pos)
466 {
467     return ( _unicodeJoining(*nextChar( str, stringLength, pos )) != JoiningOther );
468 }
469
470 static inline bool nextLogicalCharJoins( UniChar *str, int stringLength, int pos)
471 {
472     int join = _unicodeJoining(*prevChar( str, stringLength, pos ));
473     return ( join == JoiningDual || join == JoiningCausing );
474 }
475
476 static int glyphVariantLogical( UniChar *str, int stringLength, int pos)
477 {
478     // ignores L1 - L3, ligatures are job of the codec
479     int joining = _unicodeJoining(str[pos]);
480     //qDebug("checking %x, joining=%d", str[pos].unicode(), joining);
481     switch ( joining ) {
482         case JoiningOther:
483         case JoiningCausing:
484             // these don't change shape
485             return XIsolated;
486         case JoiningRight:
487             // only rule R2 applies
488             return ( nextLogicalCharJoins( str, stringLength, pos ) ) ? XFinal : XIsolated;
489         case JoiningDual: {
490             bool right = nextLogicalCharJoins( str, stringLength, pos );
491             bool left = prevLogicalCharJoins( str, stringLength, pos );
492             //qDebug("dual: right=%d, left=%d", right, left);
493             return ( right ) ? ( left ? XMedial : XFinal ) : ( left ? XInitial : XIsolated );
494         }
495     }
496     return XIsolated;
497 }
498
499 static UniChar *shapeBuffer;
500 static int shapeBufSize = 0;
501
502 #define LTR 0
503 #define RTL 1
504
505
506 UniChar *shapedString(UniChar *uc, int stringLength, int from, int len, int dir, int *lengthOut)
507 {
508     if( len < 0 ) {
509         len = stringLength - from;
510     } else if( len == 0 ) {
511         return 0;
512     }
513
514     // we have to ignore NSMs at the beginning and add at the end.
515     int num = stringLength - from - len;
516     UniChar *ch = uc + from + len;
517     while ( num > 0 && _unicodeCombiningClass(*ch) != 0 ) {
518         ch++;
519         num--;
520         len++;
521     }
522     ch = uc + from;
523     while ( len > 0 && _unicodeCombiningClass(*ch) != 0 ) {
524         ch++;
525         len--;
526         from++;
527     }
528     if ( len == 0 )
529         return 0;
530
531     if( !shapeBuffer || len > shapeBufSize ) {
532         if( shapeBuffer )
533             free( (void *) shapeBuffer );
534         shapeBuffer = (UniChar *) malloc( len*sizeof( UniChar ) );
535         shapeBufSize = len;
536     }
537
538     int lenOut = 0;
539     UniChar *data = shapeBuffer;
540     if ( dir == RTL )
541         ch += len - 1;
542     int i;
543     for (i = 0; i < len; i++ ) {
544         UniChar r = WK_ROW(*ch);
545         UniChar c = WK_CELL(*ch);
546         if ( r != 0x06 ) {
547             if ( r == 0x20 ) {
548                 // remove ZWJ and ZWNJ
549                 switch ( c ) {
550                     case 0x0C: // ZERO WIDTH NONJOINER
551                     case 0x0D: // ZERO WIDTH JOINER
552                         goto skip;
553                     default:
554                         break;
555                 }
556             }
557             if ( dir == RTL && _unicodeMirrored(*ch) )
558                 *data = _unicodeMirroredChar(*ch);
559             else
560                 *data = *ch;
561             data++;
562             lenOut++;
563         } else {
564             int pos = i + from;
565             if ( dir == RTL )
566                 pos = from + len - 1 - i;
567             int shape = glyphVariantLogical( uc, stringLength, pos );
568             //qDebug("mapping U+%x to shape %d glyph=0x%x", ch->unicode(), shape, arabicUnicodeMapping[ch->cell()][shape]);
569             // take care of lam-alef ligatures (lam right of alef)
570             ushort map;
571             switch ( c ) {
572                 case 0x44: { // lam
573                     UniChar *pch = nextChar( uc, stringLength, pos );
574                     if ( WK_ROW(*pch) == 0x06 ) {
575                         switch ( WK_CELL(*pch) ) {
576                             case 0x22:
577                             case 0x23:
578                             case 0x25:
579                             case 0x27:
580                                 //qDebug(" lam of lam-alef ligature");
581                                 map = arabicUnicodeLamAlefMapping[WK_CELL(*pch) - 0x22][shape];
582                                 goto next;
583                             default:
584                                 break;
585                         }
586                     }
587                     break;
588                 }
589                 case 0x22: // alef with madda
590                 case 0x23: // alef with hamza above
591                 case 0x25: // alef with hamza below
592                 case 0x27: // alef
593                     if ( *prevChar( uc, stringLength, pos ) == 0x0644 ) {
594                         // have a lam alef ligature
595                         //qDebug(" alef of lam-alef ligature");
596                         goto skip;
597                     }
598                 default:
599                     break;
600             }
601             map = getShape( c, shape );
602         next:
603             *data = map;
604             data++;
605             lenOut++;
606         }
607     skip:
608         if ( dir == RTL )
609             ch--;
610         else
611             ch++;
612     }
613
614 //    if ( dir == QPainter::Auto && !uc.simpleText() ) {
615 //      return bidiReorderString( QConstString( shapeBuffer, lenOut ).string() );
616 //    }
617     if ( dir == RTL ) {
618         // reverses the non spacing marks to be again after the base char
619         UniChar *s = shapeBuffer;
620         int i = 0;
621         while ( i < lenOut ) {
622             if ( _unicodeCombiningClass(*s) != 0 ) {
623                 // non spacing marks
624                 int clen = 1;
625                 UniChar *ch = s;
626                 do {
627                     ch++;
628                     clen++;
629                 } while ( _unicodeCombiningClass(*ch) != 0 );
630
631                 int j = 0;
632                 UniChar *cp = s;
633                 while ( j < clen/2 ) {
634                     UniChar tmp = *cp;
635                     *cp = *ch;
636                     *ch = tmp;
637                     cp++;
638                     ch--;
639                     j++;
640                 }
641                 s += clen;
642                 i += clen;
643             } else {
644                 s++;
645                 i++;
646             }
647         }
648     }
649
650 //    return QConstString( shapeBuffer, lenOut ).string();
651     *lengthOut = lenOut;
652     return shapeBuffer;
653 }