15569331642446be05292e3e1f8a51218827168cdclaireho/*
25569331642446be05292e3e1f8a51218827168cdclaireho * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
35569331642446be05292e3e1f8a51218827168cdclaireho *
45569331642446be05292e3e1f8a51218827168cdclaireho * This is part of HarfBuzz, an OpenType Layout engine library.
55569331642446be05292e3e1f8a51218827168cdclaireho *
65569331642446be05292e3e1f8a51218827168cdclaireho * Permission is hereby granted, without written agreement and without
75569331642446be05292e3e1f8a51218827168cdclaireho * license or royalty fees, to use, copy, modify, and distribute this
85569331642446be05292e3e1f8a51218827168cdclaireho * software and its documentation for any purpose, provided that the
95569331642446be05292e3e1f8a51218827168cdclaireho * above copyright notice and the following two paragraphs appear in
105569331642446be05292e3e1f8a51218827168cdclaireho * all copies of this software.
115569331642446be05292e3e1f8a51218827168cdclaireho *
125569331642446be05292e3e1f8a51218827168cdclaireho * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
135569331642446be05292e3e1f8a51218827168cdclaireho * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
145569331642446be05292e3e1f8a51218827168cdclaireho * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
155569331642446be05292e3e1f8a51218827168cdclaireho * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
165569331642446be05292e3e1f8a51218827168cdclaireho * DAMAGE.
175569331642446be05292e3e1f8a51218827168cdclaireho *
185569331642446be05292e3e1f8a51218827168cdclaireho * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
195569331642446be05292e3e1f8a51218827168cdclaireho * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
205569331642446be05292e3e1f8a51218827168cdclaireho * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
215569331642446be05292e3e1f8a51218827168cdclaireho * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
225569331642446be05292e3e1f8a51218827168cdclaireho * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
235569331642446be05292e3e1f8a51218827168cdclaireho */
245569331642446be05292e3e1f8a51218827168cdclaireho
255569331642446be05292e3e1f8a51218827168cdclaireho#include "harfbuzz-shaper.h"
265569331642446be05292e3e1f8a51218827168cdclaireho#include "harfbuzz-shaper-private.h"
275569331642446be05292e3e1f8a51218827168cdclaireho
285569331642446be05292e3e1f8a51218827168cdclaireho#include <assert.h>
295569331642446be05292e3e1f8a51218827168cdclaireho
305569331642446be05292e3e1f8a51218827168cdclairehostatic const HB_UChar16 ReplacementCharacter = 0xfffd;
315569331642446be05292e3e1f8a51218827168cdclaireho
325569331642446be05292e3e1f8a51218827168cdclairehotypedef struct {
335569331642446be05292e3e1f8a51218827168cdclaireho    unsigned char shape;
345569331642446be05292e3e1f8a51218827168cdclaireho    unsigned char justification;
355569331642446be05292e3e1f8a51218827168cdclaireho} HB_ArabicProperties;
365569331642446be05292e3e1f8a51218827168cdclaireho
375569331642446be05292e3e1f8a51218827168cdclairehotypedef enum {
385569331642446be05292e3e1f8a51218827168cdclaireho    XIsolated,
395569331642446be05292e3e1f8a51218827168cdclaireho    XFinal,
405569331642446be05292e3e1f8a51218827168cdclaireho    XInitial,
415569331642446be05292e3e1f8a51218827168cdclaireho    XMedial,
425569331642446be05292e3e1f8a51218827168cdclaireho    /* intermediate state */
435569331642446be05292e3e1f8a51218827168cdclaireho    XCausing
445569331642446be05292e3e1f8a51218827168cdclaireho} ArabicShape;
455569331642446be05292e3e1f8a51218827168cdclaireho
465569331642446be05292e3e1f8a51218827168cdclaireho/*
475569331642446be05292e3e1f8a51218827168cdclaireho// these groups correspond to the groups defined in the Unicode standard.
485569331642446be05292e3e1f8a51218827168cdclaireho// Some of these groups are equal with regards to both joining and line breaking behaviour,
495569331642446be05292e3e1f8a51218827168cdclaireho// and thus have the same enum value
505569331642446be05292e3e1f8a51218827168cdclaireho//
515569331642446be05292e3e1f8a51218827168cdclaireho// I'm not sure the mapping of syriac to arabic enums is correct with regards to justification, but as
525569331642446be05292e3e1f8a51218827168cdclaireho// I couldn't find any better document I'll hope for the best.
535569331642446be05292e3e1f8a51218827168cdclaireho*/
545569331642446be05292e3e1f8a51218827168cdclairehotypedef enum {
555569331642446be05292e3e1f8a51218827168cdclaireho    /* NonJoining */
565569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone,
575569331642446be05292e3e1f8a51218827168cdclaireho    ArabicSpace,
585569331642446be05292e3e1f8a51218827168cdclaireho    /* Transparent */
595569331642446be05292e3e1f8a51218827168cdclaireho    Transparent,
605569331642446be05292e3e1f8a51218827168cdclaireho    /* Causing */
615569331642446be05292e3e1f8a51218827168cdclaireho    Center,
625569331642446be05292e3e1f8a51218827168cdclaireho    Kashida,
635569331642446be05292e3e1f8a51218827168cdclaireho
645569331642446be05292e3e1f8a51218827168cdclaireho    /* Arabic */
655569331642446be05292e3e1f8a51218827168cdclaireho    /* Dual */
665569331642446be05292e3e1f8a51218827168cdclaireho    Beh,
675569331642446be05292e3e1f8a51218827168cdclaireho    Noon,
685569331642446be05292e3e1f8a51218827168cdclaireho    Meem = Noon,
695569331642446be05292e3e1f8a51218827168cdclaireho    Heh = Noon,
705569331642446be05292e3e1f8a51218827168cdclaireho    KnottedHeh = Noon,
715569331642446be05292e3e1f8a51218827168cdclaireho    HehGoal = Noon,
725569331642446be05292e3e1f8a51218827168cdclaireho    SwashKaf = Noon,
735569331642446be05292e3e1f8a51218827168cdclaireho    Yeh,
745569331642446be05292e3e1f8a51218827168cdclaireho    Hah,
755569331642446be05292e3e1f8a51218827168cdclaireho    Seen,
765569331642446be05292e3e1f8a51218827168cdclaireho    Sad = Seen,
775569331642446be05292e3e1f8a51218827168cdclaireho    Tah,
785569331642446be05292e3e1f8a51218827168cdclaireho    Kaf = Tah,
795569331642446be05292e3e1f8a51218827168cdclaireho    Gaf = Tah,
805569331642446be05292e3e1f8a51218827168cdclaireho    Lam = Tah,
815569331642446be05292e3e1f8a51218827168cdclaireho    Ain,
825569331642446be05292e3e1f8a51218827168cdclaireho    Feh = Ain,
835569331642446be05292e3e1f8a51218827168cdclaireho    Qaf = Ain,
845569331642446be05292e3e1f8a51218827168cdclaireho    /* Right */
855569331642446be05292e3e1f8a51218827168cdclaireho    Alef,
865569331642446be05292e3e1f8a51218827168cdclaireho    Waw,
875569331642446be05292e3e1f8a51218827168cdclaireho    Dal,
885569331642446be05292e3e1f8a51218827168cdclaireho    TehMarbuta = Dal,
895569331642446be05292e3e1f8a51218827168cdclaireho    Reh,
905569331642446be05292e3e1f8a51218827168cdclaireho    HamzaOnHehGoal,
915569331642446be05292e3e1f8a51218827168cdclaireho    YehWithTail = HamzaOnHehGoal,
925569331642446be05292e3e1f8a51218827168cdclaireho    YehBarre = HamzaOnHehGoal,
935569331642446be05292e3e1f8a51218827168cdclaireho
945569331642446be05292e3e1f8a51218827168cdclaireho    /* Syriac */
955569331642446be05292e3e1f8a51218827168cdclaireho    /* Dual */
965569331642446be05292e3e1f8a51218827168cdclaireho    Beth = Beh,
975569331642446be05292e3e1f8a51218827168cdclaireho    Gamal = Ain,
985569331642446be05292e3e1f8a51218827168cdclaireho    Heth = Noon,
995569331642446be05292e3e1f8a51218827168cdclaireho    Teth = Hah,
1005569331642446be05292e3e1f8a51218827168cdclaireho    Yudh = Noon,
1015569331642446be05292e3e1f8a51218827168cdclaireho    Kaph = Noon,
1025569331642446be05292e3e1f8a51218827168cdclaireho    Lamadh = Lam,
1035569331642446be05292e3e1f8a51218827168cdclaireho    Mim = Noon,
1045569331642446be05292e3e1f8a51218827168cdclaireho    Nun = Noon,
1055569331642446be05292e3e1f8a51218827168cdclaireho    Semakh = Noon,
1065569331642446be05292e3e1f8a51218827168cdclaireho    FinalSemakh = Noon,
1075569331642446be05292e3e1f8a51218827168cdclaireho    SyriacE = Ain,
1085569331642446be05292e3e1f8a51218827168cdclaireho    Pe = Ain,
1095569331642446be05292e3e1f8a51218827168cdclaireho    ReversedPe = Hah,
1105569331642446be05292e3e1f8a51218827168cdclaireho    Qaph = Noon,
1115569331642446be05292e3e1f8a51218827168cdclaireho    Shin = Noon,
1125569331642446be05292e3e1f8a51218827168cdclaireho    Fe = Ain,
1135569331642446be05292e3e1f8a51218827168cdclaireho
1145569331642446be05292e3e1f8a51218827168cdclaireho    /* Right */
1155569331642446be05292e3e1f8a51218827168cdclaireho    Alaph = Alef,
1165569331642446be05292e3e1f8a51218827168cdclaireho    Dalath = Dal,
1175569331642446be05292e3e1f8a51218827168cdclaireho    He = Dal,
1185569331642446be05292e3e1f8a51218827168cdclaireho    SyriacWaw = Waw,
1195569331642446be05292e3e1f8a51218827168cdclaireho    Zain = Alef,
1205569331642446be05292e3e1f8a51218827168cdclaireho    YudhHe = Waw,
1215569331642446be05292e3e1f8a51218827168cdclaireho    Sadhe = HamzaOnHehGoal,
1225569331642446be05292e3e1f8a51218827168cdclaireho    Taw = Dal,
1235569331642446be05292e3e1f8a51218827168cdclaireho
1245569331642446be05292e3e1f8a51218827168cdclaireho    /* Compiler bug? Otherwise ArabicGroupsEnd would be equal to Dal + 1. */
1255569331642446be05292e3e1f8a51218827168cdclaireho    Dummy = HamzaOnHehGoal,
1265569331642446be05292e3e1f8a51218827168cdclaireho    ArabicGroupsEnd
1275569331642446be05292e3e1f8a51218827168cdclaireho} ArabicGroup;
1285569331642446be05292e3e1f8a51218827168cdclaireho
1295569331642446be05292e3e1f8a51218827168cdclairehostatic const unsigned char arabic_group[0x150] = {
1305569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
1315569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
1325569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
1335569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
1345569331642446be05292e3e1f8a51218827168cdclaireho
1355569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, Transparent,
1365569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, ArabicNone, ArabicNone,
1375569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
1385569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
1395569331642446be05292e3e1f8a51218827168cdclaireho
1405569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, Alef, Alef,
1415569331642446be05292e3e1f8a51218827168cdclaireho    Waw, Alef, Yeh, Alef,
1425569331642446be05292e3e1f8a51218827168cdclaireho    Beh, TehMarbuta, Beh, Beh,
1435569331642446be05292e3e1f8a51218827168cdclaireho    Hah, Hah, Hah, Dal,
1445569331642446be05292e3e1f8a51218827168cdclaireho
1455569331642446be05292e3e1f8a51218827168cdclaireho    Dal, Reh, Reh, Seen,
1465569331642446be05292e3e1f8a51218827168cdclaireho    Seen, Sad, Sad, Tah,
1475569331642446be05292e3e1f8a51218827168cdclaireho    Tah, Ain, Ain, ArabicNone,
1485569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
1495569331642446be05292e3e1f8a51218827168cdclaireho
1505569331642446be05292e3e1f8a51218827168cdclaireho    /* 0x640 */
1515569331642446be05292e3e1f8a51218827168cdclaireho    Kashida, Feh, Qaf, Kaf,
1525569331642446be05292e3e1f8a51218827168cdclaireho    Lam, Meem, Noon, Heh,
1535569331642446be05292e3e1f8a51218827168cdclaireho    Waw, Yeh, Yeh, Transparent,
1545569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, Transparent,
1555569331642446be05292e3e1f8a51218827168cdclaireho
1565569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, Transparent,
1575569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, Transparent,
1585569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, ArabicNone, ArabicNone, ArabicNone,
1595569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
1605569331642446be05292e3e1f8a51218827168cdclaireho
1615569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
1625569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
1635569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
1645569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, Beh, Qaf,
1655569331642446be05292e3e1f8a51218827168cdclaireho
1665569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Alef, Alef, Alef,
1675569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, Alef, Waw, Waw,
1685569331642446be05292e3e1f8a51218827168cdclaireho    Yeh, Beh, Beh, Beh,
1695569331642446be05292e3e1f8a51218827168cdclaireho    Beh, Beh, Beh, Beh,
1705569331642446be05292e3e1f8a51218827168cdclaireho
1715569331642446be05292e3e1f8a51218827168cdclaireho    /* 0x680 */
1725569331642446be05292e3e1f8a51218827168cdclaireho    Beh, Hah, Hah, Hah,
1735569331642446be05292e3e1f8a51218827168cdclaireho    Hah, Hah, Hah, Hah,
1745569331642446be05292e3e1f8a51218827168cdclaireho    Dal, Dal, Dal, Dal,
1755569331642446be05292e3e1f8a51218827168cdclaireho    Dal, Dal, Dal, Dal,
1765569331642446be05292e3e1f8a51218827168cdclaireho
1775569331642446be05292e3e1f8a51218827168cdclaireho    Dal, Reh, Reh, Reh,
1785569331642446be05292e3e1f8a51218827168cdclaireho    Reh, Reh, Reh, Reh,
1795569331642446be05292e3e1f8a51218827168cdclaireho    Reh, Reh, Seen, Seen,
1805569331642446be05292e3e1f8a51218827168cdclaireho    Seen, Sad, Sad, Tah,
1815569331642446be05292e3e1f8a51218827168cdclaireho
1825569331642446be05292e3e1f8a51218827168cdclaireho    Ain, Feh, Feh, Feh,
1835569331642446be05292e3e1f8a51218827168cdclaireho    Feh, Feh, Feh, Qaf,
1845569331642446be05292e3e1f8a51218827168cdclaireho    Qaf, Gaf, SwashKaf, Gaf,
1855569331642446be05292e3e1f8a51218827168cdclaireho    Kaf, Kaf, Kaf, Gaf,
1865569331642446be05292e3e1f8a51218827168cdclaireho
1875569331642446be05292e3e1f8a51218827168cdclaireho    Gaf, Gaf, Gaf, Gaf,
1885569331642446be05292e3e1f8a51218827168cdclaireho    Gaf, Lam, Lam, Lam,
1895569331642446be05292e3e1f8a51218827168cdclaireho    Lam, Noon, Noon, Noon,
1905569331642446be05292e3e1f8a51218827168cdclaireho    Noon, Noon, KnottedHeh, Hah,
1915569331642446be05292e3e1f8a51218827168cdclaireho
1925569331642446be05292e3e1f8a51218827168cdclaireho    /* 0x6c0 */
1935569331642446be05292e3e1f8a51218827168cdclaireho    TehMarbuta, HehGoal, HamzaOnHehGoal, HamzaOnHehGoal,
1945569331642446be05292e3e1f8a51218827168cdclaireho    Waw, Waw, Waw, Waw,
1955569331642446be05292e3e1f8a51218827168cdclaireho    Waw, Waw, Waw, Waw,
1965569331642446be05292e3e1f8a51218827168cdclaireho    Yeh, YehWithTail, Yeh, Waw,
1975569331642446be05292e3e1f8a51218827168cdclaireho
1985569331642446be05292e3e1f8a51218827168cdclaireho    Yeh, Yeh, YehBarre, YehBarre,
1995569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, TehMarbuta, Transparent, Transparent,
2005569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, Transparent,
2015569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, ArabicNone, ArabicNone, Transparent,
2025569331642446be05292e3e1f8a51218827168cdclaireho
2035569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, Transparent,
2045569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, ArabicNone, ArabicNone, Transparent,
2055569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, ArabicNone, Transparent, Transparent,
2065569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Dal, Reh,
2075569331642446be05292e3e1f8a51218827168cdclaireho
2085569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
2095569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
2105569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, Seen, Sad,
2115569331642446be05292e3e1f8a51218827168cdclaireho    Ain, ArabicNone, ArabicNone, KnottedHeh,
2125569331642446be05292e3e1f8a51218827168cdclaireho
2135569331642446be05292e3e1f8a51218827168cdclaireho    /* 0x700 */
2145569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
2155569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
2165569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
2175569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, ArabicNone, ArabicNone, ArabicNone,
2185569331642446be05292e3e1f8a51218827168cdclaireho
2195569331642446be05292e3e1f8a51218827168cdclaireho    Alaph, Transparent, Beth, Gamal,
2205569331642446be05292e3e1f8a51218827168cdclaireho    Gamal, Dalath, Dalath, He,
2215569331642446be05292e3e1f8a51218827168cdclaireho    SyriacWaw, Zain, Heth, Teth,
2225569331642446be05292e3e1f8a51218827168cdclaireho    Teth, Yudh, YudhHe, Kaph,
2235569331642446be05292e3e1f8a51218827168cdclaireho
2245569331642446be05292e3e1f8a51218827168cdclaireho    Lamadh, Mim, Nun, Semakh,
2255569331642446be05292e3e1f8a51218827168cdclaireho    FinalSemakh, SyriacE, Pe, ReversedPe,
2265569331642446be05292e3e1f8a51218827168cdclaireho    Sadhe, Qaph, Dalath, Shin,
2275569331642446be05292e3e1f8a51218827168cdclaireho    Taw, Beth, Gamal, Dalath,
2285569331642446be05292e3e1f8a51218827168cdclaireho
2295569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, Transparent,
2305569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, Transparent,
2315569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, Transparent,
2325569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, Transparent,
2335569331642446be05292e3e1f8a51218827168cdclaireho
2345569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, Transparent,
2355569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, Transparent,
2365569331642446be05292e3e1f8a51218827168cdclaireho    Transparent, Transparent, Transparent, ArabicNone,
2375569331642446be05292e3e1f8a51218827168cdclaireho    ArabicNone, Zain, Kaph, Fe,
2385569331642446be05292e3e1f8a51218827168cdclaireho};
2395569331642446be05292e3e1f8a51218827168cdclaireho
2405569331642446be05292e3e1f8a51218827168cdclairehostatic ArabicGroup arabicGroup(unsigned short uc)
2415569331642446be05292e3e1f8a51218827168cdclaireho{
2425569331642446be05292e3e1f8a51218827168cdclaireho    if (uc >= 0x0600 && uc < 0x750)
2435569331642446be05292e3e1f8a51218827168cdclaireho        return (ArabicGroup) arabic_group[uc-0x600];
2445569331642446be05292e3e1f8a51218827168cdclaireho    else if (uc == 0x200d)
2455569331642446be05292e3e1f8a51218827168cdclaireho        return Center;
2465569331642446be05292e3e1f8a51218827168cdclaireho    else if (HB_GetUnicodeCharCategory(uc) == HB_Separator_Space)
2475569331642446be05292e3e1f8a51218827168cdclaireho        return ArabicSpace;
2485569331642446be05292e3e1f8a51218827168cdclaireho    else
2495569331642446be05292e3e1f8a51218827168cdclaireho        return ArabicNone;
2505569331642446be05292e3e1f8a51218827168cdclaireho}
2515569331642446be05292e3e1f8a51218827168cdclaireho
2525569331642446be05292e3e1f8a51218827168cdclaireho
2535569331642446be05292e3e1f8a51218827168cdclaireho/*
2545569331642446be05292e3e1f8a51218827168cdclaireho   Arabic shaping obeys a number of rules according to the joining classes (see Unicode book, section on
2555569331642446be05292e3e1f8a51218827168cdclaireho   arabic).
2565569331642446be05292e3e1f8a51218827168cdclaireho
2575569331642446be05292e3e1f8a51218827168cdclaireho   Each unicode char has a joining class (right, dual (left&right), center (joincausing) or transparent).
2585569331642446be05292e3e1f8a51218827168cdclaireho   transparent joining is not encoded in HB_UChar16::joining(), but applies to all combining marks and format marks.
2595569331642446be05292e3e1f8a51218827168cdclaireho
2605569331642446be05292e3e1f8a51218827168cdclaireho   Right join-causing: dual + center
2615569331642446be05292e3e1f8a51218827168cdclaireho   Left join-causing: dual + right + center
2625569331642446be05292e3e1f8a51218827168cdclaireho
2635569331642446be05292e3e1f8a51218827168cdclaireho   Rules are as follows (for a string already in visual order, as we have it here):
2645569331642446be05292e3e1f8a51218827168cdclaireho
2655569331642446be05292e3e1f8a51218827168cdclaireho   R1 Transparent characters do not affect joining behaviour.
2665569331642446be05292e3e1f8a51218827168cdclaireho   R2 A right joining character, that has a right join-causing char on the right will get form XRight
2675569331642446be05292e3e1f8a51218827168cdclaireho   (R3 A left joining character, that has a left join-causing char on the left will get form XLeft)
2685569331642446be05292e3e1f8a51218827168cdclaireho   Note: the above rule is meaningless, as there are no pure left joining characters defined in Unicode
2695569331642446be05292e3e1f8a51218827168cdclaireho   R4 A dual joining character, that has a left join-causing char on the left and a right join-causing char on
2705569331642446be05292e3e1f8a51218827168cdclaireho             the right will get form XMedial
2715569331642446be05292e3e1f8a51218827168cdclaireho   R5  A dual joining character, that has a right join causing char on the right, and no left join causing char on the left
2725569331642446be05292e3e1f8a51218827168cdclaireho         will get form XRight
2735569331642446be05292e3e1f8a51218827168cdclaireho   R6 A dual joining character, that has a  left join causing char on the left, and no right join causing char on the right
2745569331642446be05292e3e1f8a51218827168cdclaireho         will get form XLeft
2755569331642446be05292e3e1f8a51218827168cdclaireho   R7 Otherwise the character will get form XIsolated
2765569331642446be05292e3e1f8a51218827168cdclaireho
2775569331642446be05292e3e1f8a51218827168cdclaireho   Additionally we have to do the minimal ligature support for lam-alef ligatures:
2785569331642446be05292e3e1f8a51218827168cdclaireho
2795569331642446be05292e3e1f8a51218827168cdclaireho   L1 Transparent characters do not affect ligature behaviour.
2805569331642446be05292e3e1f8a51218827168cdclaireho   L2 Any sequence of Alef(XRight) + Lam(XMedial) will form the ligature Alef.Lam(XLeft)
2815569331642446be05292e3e1f8a51218827168cdclaireho   L3 Any sequence of Alef(XRight) + Lam(XLeft) will form the ligature Alef.Lam(XIsolated)
2825569331642446be05292e3e1f8a51218827168cdclaireho
2835569331642446be05292e3e1f8a51218827168cdclaireho   The state table below handles rules R1-R7.
2845569331642446be05292e3e1f8a51218827168cdclaireho*/
2855569331642446be05292e3e1f8a51218827168cdclaireho
2865569331642446be05292e3e1f8a51218827168cdclairehotypedef enum {
2875569331642446be05292e3e1f8a51218827168cdclaireho    JNone,
2885569331642446be05292e3e1f8a51218827168cdclaireho    JCausing,
2895569331642446be05292e3e1f8a51218827168cdclaireho    JDual,
2905569331642446be05292e3e1f8a51218827168cdclaireho    JRight,
2915569331642446be05292e3e1f8a51218827168cdclaireho    JTransparent
2925569331642446be05292e3e1f8a51218827168cdclaireho} Joining;
2935569331642446be05292e3e1f8a51218827168cdclaireho
2945569331642446be05292e3e1f8a51218827168cdclairehostatic const Joining joining_for_group[ArabicGroupsEnd] = {
2955569331642446be05292e3e1f8a51218827168cdclaireho    /* NonJoining */
2965569331642446be05292e3e1f8a51218827168cdclaireho    JNone, /* ArabicNone */
2975569331642446be05292e3e1f8a51218827168cdclaireho    JNone, /* ArabicSpace */
2985569331642446be05292e3e1f8a51218827168cdclaireho    /* Transparent */
2995569331642446be05292e3e1f8a51218827168cdclaireho    JTransparent, /* Transparent */
3005569331642446be05292e3e1f8a51218827168cdclaireho    /* Causing */
3015569331642446be05292e3e1f8a51218827168cdclaireho    JCausing, /* Center */
3025569331642446be05292e3e1f8a51218827168cdclaireho    JCausing, /* Kashida */
3035569331642446be05292e3e1f8a51218827168cdclaireho    /* Dual */
3045569331642446be05292e3e1f8a51218827168cdclaireho    JDual, /* Beh */
3055569331642446be05292e3e1f8a51218827168cdclaireho    JDual, /* Noon */
3065569331642446be05292e3e1f8a51218827168cdclaireho    JDual, /* Yeh */
3075569331642446be05292e3e1f8a51218827168cdclaireho    JDual, /* Hah */
3085569331642446be05292e3e1f8a51218827168cdclaireho    JDual, /* Seen */
3095569331642446be05292e3e1f8a51218827168cdclaireho    JDual, /* Tah */
3105569331642446be05292e3e1f8a51218827168cdclaireho    JDual, /* Ain */
3115569331642446be05292e3e1f8a51218827168cdclaireho    /* Right */
3125569331642446be05292e3e1f8a51218827168cdclaireho    JRight, /* Alef */
3135569331642446be05292e3e1f8a51218827168cdclaireho    JRight, /* Waw */
3145569331642446be05292e3e1f8a51218827168cdclaireho    JRight, /* Dal */
3155569331642446be05292e3e1f8a51218827168cdclaireho    JRight, /* Reh */
3165569331642446be05292e3e1f8a51218827168cdclaireho    JRight  /* HamzaOnHehGoal */
3175569331642446be05292e3e1f8a51218827168cdclaireho};
3185569331642446be05292e3e1f8a51218827168cdclaireho
3195569331642446be05292e3e1f8a51218827168cdclaireho
3205569331642446be05292e3e1f8a51218827168cdclairehotypedef struct {
3215569331642446be05292e3e1f8a51218827168cdclaireho    ArabicShape form1;
3225569331642446be05292e3e1f8a51218827168cdclaireho    ArabicShape form2;
3235569331642446be05292e3e1f8a51218827168cdclaireho} JoiningPair;
3245569331642446be05292e3e1f8a51218827168cdclaireho
3255569331642446be05292e3e1f8a51218827168cdclairehostatic const JoiningPair joining_table[5][4] =
3265569331642446be05292e3e1f8a51218827168cdclaireho/* None, Causing, Dual, Right */
3275569331642446be05292e3e1f8a51218827168cdclaireho{
3285569331642446be05292e3e1f8a51218827168cdclaireho    { { XIsolated, XIsolated }, { XIsolated, XCausing }, { XIsolated, XInitial }, { XIsolated, XIsolated } }, /* XIsolated */
3295569331642446be05292e3e1f8a51218827168cdclaireho    { { XFinal, XIsolated }, { XFinal, XCausing }, { XFinal, XInitial }, { XFinal, XIsolated } }, /* XFinal */
3305569331642446be05292e3e1f8a51218827168cdclaireho    { { XIsolated, XIsolated }, { XInitial, XCausing }, { XInitial, XMedial }, { XInitial, XFinal } }, /* XInitial */
3315569331642446be05292e3e1f8a51218827168cdclaireho    { { XFinal, XIsolated }, { XMedial, XCausing }, { XMedial, XMedial }, { XMedial, XFinal } }, /* XMedial */
3325569331642446be05292e3e1f8a51218827168cdclaireho    { { XIsolated, XIsolated }, { XIsolated, XCausing }, { XIsolated, XMedial }, { XIsolated, XFinal } }, /* XCausing */
3335569331642446be05292e3e1f8a51218827168cdclaireho};
3345569331642446be05292e3e1f8a51218827168cdclaireho
3355569331642446be05292e3e1f8a51218827168cdclaireho
3365569331642446be05292e3e1f8a51218827168cdclaireho/*
3375569331642446be05292e3e1f8a51218827168cdclairehoAccording to http://www.microsoft.com/middleeast/Arabicdev/IE6/KBase.asp
3385569331642446be05292e3e1f8a51218827168cdclaireho
3395569331642446be05292e3e1f8a51218827168cdclaireho1. Find the priority of the connecting opportunities in each word
3405569331642446be05292e3e1f8a51218827168cdclaireho2. Add expansion at the highest priority connection opportunity
3415569331642446be05292e3e1f8a51218827168cdclaireho3. If more than one connection opportunity have the same highest value,
3425569331642446be05292e3e1f8a51218827168cdclaireho   use the opportunity closest to the end of the word.
3435569331642446be05292e3e1f8a51218827168cdclaireho
3445569331642446be05292e3e1f8a51218827168cdclairehoFollowing is a chart that provides the priority for connection
3455569331642446be05292e3e1f8a51218827168cdclairehoopportunities and where expansion occurs. The character group names
3465569331642446be05292e3e1f8a51218827168cdclairehoare those in table 6.6 of the UNICODE 2.0 book.
3475569331642446be05292e3e1f8a51218827168cdclaireho
3485569331642446be05292e3e1f8a51218827168cdclaireho
3495569331642446be05292e3e1f8a51218827168cdclairehoPrioritY        Glyph                   Condition                                       Kashida Location
3505569331642446be05292e3e1f8a51218827168cdclaireho
3515569331642446be05292e3e1f8a51218827168cdclairehoArabic_Kashida        User inserted Kashida   The user entered a Kashida in a position.       After the user
3525569331642446be05292e3e1f8a51218827168cdclaireho                (Shift+j or Shift+[E with hat])    Thus, it is the highest priority to insert an   inserted kashida
3535569331642446be05292e3e1f8a51218827168cdclaireho                                        automatic kashida.
3545569331642446be05292e3e1f8a51218827168cdclaireho
3555569331642446be05292e3e1f8a51218827168cdclairehoArabic_Seen        Seen, Sad               Connecting to the next character.               After the character.
3565569331642446be05292e3e1f8a51218827168cdclaireho                                        (Initial or medial form).
3575569331642446be05292e3e1f8a51218827168cdclaireho
3585569331642446be05292e3e1f8a51218827168cdclairehoArabic_HaaDal        Teh Marbutah, Haa, Dal  Connecting to previous character.               Before the final form
3595569331642446be05292e3e1f8a51218827168cdclaireho                                                                                        of these characters.
3605569331642446be05292e3e1f8a51218827168cdclaireho
3615569331642446be05292e3e1f8a51218827168cdclairehoArabic_Alef     Alef, Tah, Lam,         Connecting to previous character.               Before the final form
3625569331642446be05292e3e1f8a51218827168cdclaireho                Kaf and Gaf                                                             of these characters.
3635569331642446be05292e3e1f8a51218827168cdclaireho
3645569331642446be05292e3e1f8a51218827168cdclairehoArabic_BaRa     Reh, Yeh                Connected to medial Beh                         Before preceding medial Baa
3655569331642446be05292e3e1f8a51218827168cdclaireho
3665569331642446be05292e3e1f8a51218827168cdclairehoArabic_Waw        Waw, Ain, Qaf, Feh      Connecting to previous character.               Before the final form of
3675569331642446be05292e3e1f8a51218827168cdclaireho                                                                                        these characters.
3685569331642446be05292e3e1f8a51218827168cdclaireho
3695569331642446be05292e3e1f8a51218827168cdclairehoArabic_Normal   Other connecting        Connecting to previous character.               Before the final form
3705569331642446be05292e3e1f8a51218827168cdclaireho                characters                                                              of these characters.
3715569331642446be05292e3e1f8a51218827168cdclaireho
3725569331642446be05292e3e1f8a51218827168cdclaireho
3735569331642446be05292e3e1f8a51218827168cdclaireho
3745569331642446be05292e3e1f8a51218827168cdclairehoThis seems to imply that we have at most one kashida point per arabic word.
3755569331642446be05292e3e1f8a51218827168cdclaireho
3765569331642446be05292e3e1f8a51218827168cdclaireho*/
3775569331642446be05292e3e1f8a51218827168cdclaireho
3785569331642446be05292e3e1f8a51218827168cdclairehostatic void getArabicProperties(const unsigned short *chars, int len, HB_ArabicProperties *properties)
3795569331642446be05292e3e1f8a51218827168cdclaireho{
3805569331642446be05292e3e1f8a51218827168cdclaireho/*     qDebug("arabicSyriacOpenTypeShape: properties:"); */
3815569331642446be05292e3e1f8a51218827168cdclaireho    int lastPos = 0;
3825569331642446be05292e3e1f8a51218827168cdclaireho    int lastGroup = ArabicNone;
3835569331642446be05292e3e1f8a51218827168cdclaireho    int i = 0;
3845569331642446be05292e3e1f8a51218827168cdclaireho
3855569331642446be05292e3e1f8a51218827168cdclaireho    ArabicGroup group = arabicGroup(chars[0]);
3865569331642446be05292e3e1f8a51218827168cdclaireho    Joining j = joining_for_group[group];
3875569331642446be05292e3e1f8a51218827168cdclaireho    ArabicShape shape = joining_table[XIsolated][j].form2;
3885569331642446be05292e3e1f8a51218827168cdclaireho    properties[0].justification = HB_NoJustification;
3895569331642446be05292e3e1f8a51218827168cdclaireho
3905569331642446be05292e3e1f8a51218827168cdclaireho    for (i = 1; i < len; ++i) {
3915569331642446be05292e3e1f8a51218827168cdclaireho        /* #### fix handling for spaces and punktuation */
3925569331642446be05292e3e1f8a51218827168cdclaireho        properties[i].justification = HB_NoJustification;
3935569331642446be05292e3e1f8a51218827168cdclaireho
3945569331642446be05292e3e1f8a51218827168cdclaireho        group = arabicGroup(chars[i]);
3955569331642446be05292e3e1f8a51218827168cdclaireho        j = joining_for_group[group];
3965569331642446be05292e3e1f8a51218827168cdclaireho
3975569331642446be05292e3e1f8a51218827168cdclaireho        if (j == JTransparent) {
3985569331642446be05292e3e1f8a51218827168cdclaireho            properties[i].shape = XIsolated;
3995569331642446be05292e3e1f8a51218827168cdclaireho            continue;
4005569331642446be05292e3e1f8a51218827168cdclaireho        }
4015569331642446be05292e3e1f8a51218827168cdclaireho
4025569331642446be05292e3e1f8a51218827168cdclaireho        properties[lastPos].shape = joining_table[shape][j].form1;
4035569331642446be05292e3e1f8a51218827168cdclaireho        shape = joining_table[shape][j].form2;
4045569331642446be05292e3e1f8a51218827168cdclaireho
4055569331642446be05292e3e1f8a51218827168cdclaireho        switch(lastGroup) {
4065569331642446be05292e3e1f8a51218827168cdclaireho        case Seen:
4075569331642446be05292e3e1f8a51218827168cdclaireho            if (properties[lastPos].shape == XInitial || properties[lastPos].shape == XMedial)
4085569331642446be05292e3e1f8a51218827168cdclaireho                properties[i-1].justification = HB_Arabic_Seen;
4095569331642446be05292e3e1f8a51218827168cdclaireho            break;
4105569331642446be05292e3e1f8a51218827168cdclaireho        case Hah:
4115569331642446be05292e3e1f8a51218827168cdclaireho            if (properties[lastPos].shape == XFinal)
4125569331642446be05292e3e1f8a51218827168cdclaireho                properties[lastPos-1].justification = HB_Arabic_HaaDal;
4135569331642446be05292e3e1f8a51218827168cdclaireho            break;
4145569331642446be05292e3e1f8a51218827168cdclaireho        case Alef:
4155569331642446be05292e3e1f8a51218827168cdclaireho            if (properties[lastPos].shape == XFinal)
4165569331642446be05292e3e1f8a51218827168cdclaireho                properties[lastPos-1].justification = HB_Arabic_Alef;
4175569331642446be05292e3e1f8a51218827168cdclaireho            break;
4185569331642446be05292e3e1f8a51218827168cdclaireho        case Ain:
4195569331642446be05292e3e1f8a51218827168cdclaireho            if (properties[lastPos].shape == XFinal)
4205569331642446be05292e3e1f8a51218827168cdclaireho                properties[lastPos-1].justification = HB_Arabic_Waw;
4215569331642446be05292e3e1f8a51218827168cdclaireho            break;
4225569331642446be05292e3e1f8a51218827168cdclaireho        case Noon:
4235569331642446be05292e3e1f8a51218827168cdclaireho            if (properties[lastPos].shape == XFinal)
4245569331642446be05292e3e1f8a51218827168cdclaireho                properties[lastPos-1].justification = HB_Arabic_Normal;
4255569331642446be05292e3e1f8a51218827168cdclaireho            break;
4265569331642446be05292e3e1f8a51218827168cdclaireho        case ArabicNone:
4275569331642446be05292e3e1f8a51218827168cdclaireho            break;
4285569331642446be05292e3e1f8a51218827168cdclaireho
4295569331642446be05292e3e1f8a51218827168cdclaireho        default:
4305569331642446be05292e3e1f8a51218827168cdclaireho            assert(FALSE);
4315569331642446be05292e3e1f8a51218827168cdclaireho        }
4325569331642446be05292e3e1f8a51218827168cdclaireho
4335569331642446be05292e3e1f8a51218827168cdclaireho        lastGroup = ArabicNone;
4345569331642446be05292e3e1f8a51218827168cdclaireho
4355569331642446be05292e3e1f8a51218827168cdclaireho        switch(group) {
4365569331642446be05292e3e1f8a51218827168cdclaireho        case ArabicNone:
4375569331642446be05292e3e1f8a51218827168cdclaireho        case Transparent:
4385569331642446be05292e3e1f8a51218827168cdclaireho        /* ### Center should probably be treated as transparent when it comes to justification. */
4395569331642446be05292e3e1f8a51218827168cdclaireho        case Center:
4405569331642446be05292e3e1f8a51218827168cdclaireho            break;
4415569331642446be05292e3e1f8a51218827168cdclaireho        case ArabicSpace:
4425569331642446be05292e3e1f8a51218827168cdclaireho            properties[i].justification = HB_Arabic_Space;
4435569331642446be05292e3e1f8a51218827168cdclaireho            break;
4445569331642446be05292e3e1f8a51218827168cdclaireho        case Kashida:
4455569331642446be05292e3e1f8a51218827168cdclaireho            properties[i].justification = HB_Arabic_Kashida;
4465569331642446be05292e3e1f8a51218827168cdclaireho            break;
4475569331642446be05292e3e1f8a51218827168cdclaireho        case Seen:
4485569331642446be05292e3e1f8a51218827168cdclaireho            lastGroup = Seen;
4495569331642446be05292e3e1f8a51218827168cdclaireho            break;
4505569331642446be05292e3e1f8a51218827168cdclaireho
4515569331642446be05292e3e1f8a51218827168cdclaireho        case Hah:
4525569331642446be05292e3e1f8a51218827168cdclaireho        case Dal:
4535569331642446be05292e3e1f8a51218827168cdclaireho            lastGroup = Hah;
4545569331642446be05292e3e1f8a51218827168cdclaireho            break;
4555569331642446be05292e3e1f8a51218827168cdclaireho
4565569331642446be05292e3e1f8a51218827168cdclaireho        case Alef:
4575569331642446be05292e3e1f8a51218827168cdclaireho        case Tah:
4585569331642446be05292e3e1f8a51218827168cdclaireho            lastGroup = Alef;
4595569331642446be05292e3e1f8a51218827168cdclaireho            break;
4605569331642446be05292e3e1f8a51218827168cdclaireho
4615569331642446be05292e3e1f8a51218827168cdclaireho        case Yeh:
4625569331642446be05292e3e1f8a51218827168cdclaireho        case Reh:
4635569331642446be05292e3e1f8a51218827168cdclaireho            if (properties[lastPos].shape == XMedial && arabicGroup(chars[lastPos]) == Beh)
4645569331642446be05292e3e1f8a51218827168cdclaireho                properties[lastPos-1].justification = HB_Arabic_BaRa;
4655569331642446be05292e3e1f8a51218827168cdclaireho            break;
4665569331642446be05292e3e1f8a51218827168cdclaireho
4675569331642446be05292e3e1f8a51218827168cdclaireho        case Ain:
4685569331642446be05292e3e1f8a51218827168cdclaireho        case Waw:
4695569331642446be05292e3e1f8a51218827168cdclaireho            lastGroup = Ain;
4705569331642446be05292e3e1f8a51218827168cdclaireho            break;
4715569331642446be05292e3e1f8a51218827168cdclaireho
4725569331642446be05292e3e1f8a51218827168cdclaireho        case Noon:
4735569331642446be05292e3e1f8a51218827168cdclaireho        case Beh:
4745569331642446be05292e3e1f8a51218827168cdclaireho        case HamzaOnHehGoal:
4755569331642446be05292e3e1f8a51218827168cdclaireho            lastGroup = Noon;
4765569331642446be05292e3e1f8a51218827168cdclaireho            break;
4775569331642446be05292e3e1f8a51218827168cdclaireho        case ArabicGroupsEnd:
4785569331642446be05292e3e1f8a51218827168cdclaireho            assert(FALSE);
4795569331642446be05292e3e1f8a51218827168cdclaireho        }
4805569331642446be05292e3e1f8a51218827168cdclaireho
4815569331642446be05292e3e1f8a51218827168cdclaireho        lastPos = i;
4825569331642446be05292e3e1f8a51218827168cdclaireho    }
4835569331642446be05292e3e1f8a51218827168cdclaireho    properties[lastPos].shape = joining_table[shape][JNone].form1;
4845569331642446be05292e3e1f8a51218827168cdclaireho
4855569331642446be05292e3e1f8a51218827168cdclaireho
4865569331642446be05292e3e1f8a51218827168cdclaireho    /*
4875569331642446be05292e3e1f8a51218827168cdclaireho     for (int i = 0; i < len; ++i)
4885569331642446be05292e3e1f8a51218827168cdclaireho         qDebug("arabic properties(%d): uc=%x shape=%d, justification=%d", i, chars[i], properties[i].shape, properties[i].justification);
4895569331642446be05292e3e1f8a51218827168cdclaireho    */
4905569331642446be05292e3e1f8a51218827168cdclaireho}
4915569331642446be05292e3e1f8a51218827168cdclaireho
4925569331642446be05292e3e1f8a51218827168cdclairehostatic Joining getNkoJoining(unsigned short uc)
4935569331642446be05292e3e1f8a51218827168cdclaireho{
4945569331642446be05292e3e1f8a51218827168cdclaireho    if (uc < 0x7ca)
4955569331642446be05292e3e1f8a51218827168cdclaireho        return JNone;
4965569331642446be05292e3e1f8a51218827168cdclaireho    if (uc <= 0x7ea)
4975569331642446be05292e3e1f8a51218827168cdclaireho        return JDual;
4985569331642446be05292e3e1f8a51218827168cdclaireho    if (uc <= 0x7f3)
4995569331642446be05292e3e1f8a51218827168cdclaireho        return JTransparent;
5005569331642446be05292e3e1f8a51218827168cdclaireho    if (uc <= 0x7f9)
5015569331642446be05292e3e1f8a51218827168cdclaireho        return JNone;
5025569331642446be05292e3e1f8a51218827168cdclaireho    if (uc == 0x7fa)
5035569331642446be05292e3e1f8a51218827168cdclaireho        return JCausing;
5045569331642446be05292e3e1f8a51218827168cdclaireho    return JNone;
5055569331642446be05292e3e1f8a51218827168cdclaireho}
5065569331642446be05292e3e1f8a51218827168cdclaireho
5075569331642446be05292e3e1f8a51218827168cdclairehostatic void getNkoProperties(const unsigned short *chars, int len, HB_ArabicProperties *properties)
5085569331642446be05292e3e1f8a51218827168cdclaireho{
5095569331642446be05292e3e1f8a51218827168cdclaireho    int lastPos = 0;
5105569331642446be05292e3e1f8a51218827168cdclaireho    int i = 0;
5115569331642446be05292e3e1f8a51218827168cdclaireho
5125569331642446be05292e3e1f8a51218827168cdclaireho    Joining j = getNkoJoining(chars[0]);
5135569331642446be05292e3e1f8a51218827168cdclaireho    ArabicShape shape = joining_table[XIsolated][j].form2;
5145569331642446be05292e3e1f8a51218827168cdclaireho    properties[0].justification = HB_NoJustification;
5155569331642446be05292e3e1f8a51218827168cdclaireho
5165569331642446be05292e3e1f8a51218827168cdclaireho    for (i = 1; i < len; ++i) {
5175569331642446be05292e3e1f8a51218827168cdclaireho        properties[i].justification = (HB_GetUnicodeCharCategory(chars[i]) == HB_Separator_Space) ?
5185569331642446be05292e3e1f8a51218827168cdclaireho                                      ArabicSpace : ArabicNone;
5195569331642446be05292e3e1f8a51218827168cdclaireho
5205569331642446be05292e3e1f8a51218827168cdclaireho        j = getNkoJoining(chars[i]);
5215569331642446be05292e3e1f8a51218827168cdclaireho
5225569331642446be05292e3e1f8a51218827168cdclaireho        if (j == JTransparent) {
5235569331642446be05292e3e1f8a51218827168cdclaireho            properties[i].shape = XIsolated;
5245569331642446be05292e3e1f8a51218827168cdclaireho            continue;
5255569331642446be05292e3e1f8a51218827168cdclaireho        }
5265569331642446be05292e3e1f8a51218827168cdclaireho
5275569331642446be05292e3e1f8a51218827168cdclaireho        properties[lastPos].shape = joining_table[shape][j].form1;
5285569331642446be05292e3e1f8a51218827168cdclaireho        shape = joining_table[shape][j].form2;
5295569331642446be05292e3e1f8a51218827168cdclaireho
5305569331642446be05292e3e1f8a51218827168cdclaireho
5315569331642446be05292e3e1f8a51218827168cdclaireho        lastPos = i;
5325569331642446be05292e3e1f8a51218827168cdclaireho    }
5335569331642446be05292e3e1f8a51218827168cdclaireho    properties[lastPos].shape = joining_table[shape][JNone].form1;
5345569331642446be05292e3e1f8a51218827168cdclaireho
5355569331642446be05292e3e1f8a51218827168cdclaireho
5365569331642446be05292e3e1f8a51218827168cdclaireho    /*
5375569331642446be05292e3e1f8a51218827168cdclaireho     for (int i = 0; i < len; ++i)
5385569331642446be05292e3e1f8a51218827168cdclaireho         qDebug("nko properties(%d): uc=%x shape=%d, justification=%d", i, chars[i], properties[i].shape, properties[i].justification);
5395569331642446be05292e3e1f8a51218827168cdclaireho    */
5405569331642446be05292e3e1f8a51218827168cdclaireho}
5415569331642446be05292e3e1f8a51218827168cdclaireho
5425569331642446be05292e3e1f8a51218827168cdclaireho/*
5435569331642446be05292e3e1f8a51218827168cdclaireho// The unicode to unicode shaping codec.
5445569331642446be05292e3e1f8a51218827168cdclaireho// does only presentation forms B at the moment, but that should be enough for
5455569331642446be05292e3e1f8a51218827168cdclaireho// simple display
5465569331642446be05292e3e1f8a51218827168cdclaireho*/
5475569331642446be05292e3e1f8a51218827168cdclairehostatic const hb_uint16 arabicUnicodeMapping[256][2] = {
5485569331642446be05292e3e1f8a51218827168cdclaireho    /* base of shaped forms, and number-1 of them (0 for non shaping,
5495569331642446be05292e3e1f8a51218827168cdclaireho       1 for right binding and 3 for dual binding */
5505569331642446be05292e3e1f8a51218827168cdclaireho
5515569331642446be05292e3e1f8a51218827168cdclaireho    /* These are just the glyphs available in Unicode,
5525569331642446be05292e3e1f8a51218827168cdclaireho       some characters are in R class, but have no glyphs in Unicode. */
5535569331642446be05292e3e1f8a51218827168cdclaireho
5545569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0600, 0 }, /* 0x0600 */
5555569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0601, 0 }, /* 0x0601 */
5565569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0602, 0 }, /* 0x0602 */
5575569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0603, 0 }, /* 0x0603 */
5585569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0604, 0 }, /* 0x0604 */
5595569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0605, 0 }, /* 0x0605 */
5605569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0606, 0 }, /* 0x0606 */
5615569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0607, 0 }, /* 0x0607 */
5625569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0608, 0 }, /* 0x0608 */
5635569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0609, 0 }, /* 0x0609 */
5645569331642446be05292e3e1f8a51218827168cdclaireho    { 0x060A, 0 }, /* 0x060A */
5655569331642446be05292e3e1f8a51218827168cdclaireho    { 0x060B, 0 }, /* 0x060B */
5665569331642446be05292e3e1f8a51218827168cdclaireho    { 0x060C, 0 }, /* 0x060C */
5675569331642446be05292e3e1f8a51218827168cdclaireho    { 0x060D, 0 }, /* 0x060D */
5685569331642446be05292e3e1f8a51218827168cdclaireho    { 0x060E, 0 }, /* 0x060E */
5695569331642446be05292e3e1f8a51218827168cdclaireho    { 0x060F, 0 }, /* 0x060F */
5705569331642446be05292e3e1f8a51218827168cdclaireho
5715569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0610, 0 }, /* 0x0610 */
5725569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0611, 0 }, /* 0x0611 */
5735569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0612, 0 }, /* 0x0612 */
5745569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0613, 0 }, /* 0x0613 */
5755569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0614, 0 }, /* 0x0614 */
5765569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0615, 0 }, /* 0x0615 */
5775569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0616, 0 }, /* 0x0616 */
5785569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0617, 0 }, /* 0x0617 */
5795569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0618, 0 }, /* 0x0618 */
5805569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0619, 0 }, /* 0x0619 */
5815569331642446be05292e3e1f8a51218827168cdclaireho    { 0x061A, 0 }, /* 0x061A */
5825569331642446be05292e3e1f8a51218827168cdclaireho    { 0x061B, 0 }, /* 0x061B */
5835569331642446be05292e3e1f8a51218827168cdclaireho    { 0x061C, 0 }, /* 0x061C */
5845569331642446be05292e3e1f8a51218827168cdclaireho    { 0x061D, 0 }, /* 0x061D */
5855569331642446be05292e3e1f8a51218827168cdclaireho    { 0x061E, 0 }, /* 0x061E */
5865569331642446be05292e3e1f8a51218827168cdclaireho    { 0x061F, 0 }, /* 0x061F */
5875569331642446be05292e3e1f8a51218827168cdclaireho
5885569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0620, 0 }, /* 0x0620 */
5895569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFE80, 0 }, /* 0x0621            HAMZA */
5905569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFE81, 1 }, /* 0x0622    R       ALEF WITH MADDA ABOVE */
5915569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFE83, 1 }, /* 0x0623    R       ALEF WITH HAMZA ABOVE */
5925569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFE85, 1 }, /* 0x0624    R       WAW WITH HAMZA ABOVE */
5935569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFE87, 1 }, /* 0x0625    R       ALEF WITH HAMZA BELOW */
5945569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFE89, 3 }, /* 0x0626    D       YEH WITH HAMZA ABOVE */
5955569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFE8D, 1 }, /* 0x0627    R       ALEF */
5965569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFE8F, 3 }, /* 0x0628    D       BEH */
5975569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFE93, 1 }, /* 0x0629    R       TEH MARBUTA */
5985569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFE95, 3 }, /* 0x062A    D       TEH */
5995569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFE99, 3 }, /* 0x062B    D       THEH */
6005569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFE9D, 3 }, /* 0x062C    D       JEEM */
6015569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEA1, 3 }, /* 0x062D    D       HAH */
6025569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEA5, 3 }, /* 0x062E    D       KHAH */
6035569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEA9, 1 }, /* 0x062F    R       DAL */
6045569331642446be05292e3e1f8a51218827168cdclaireho
6055569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEAB, 1 }, /* 0x0630    R       THAL */
6065569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEAD, 1 }, /* 0x0631    R       REH */
6075569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEAF, 1 }, /* 0x0632    R       ZAIN */
6085569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEB1, 3 }, /* 0x0633    D       SEEN */
6095569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEB5, 3 }, /* 0x0634    D       SHEEN */
6105569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEB9, 3 }, /* 0x0635    D       SAD */
6115569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEBD, 3 }, /* 0x0636    D       DAD */
6125569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEC1, 3 }, /* 0x0637    D       TAH */
6135569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEC5, 3 }, /* 0x0638    D       ZAH */
6145569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEC9, 3 }, /* 0x0639    D       AIN */
6155569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFECD, 3 }, /* 0x063A    D       GHAIN */
6165569331642446be05292e3e1f8a51218827168cdclaireho    { 0x063B, 0 }, /* 0x063B */
6175569331642446be05292e3e1f8a51218827168cdclaireho    { 0x063C, 0 }, /* 0x063C */
6185569331642446be05292e3e1f8a51218827168cdclaireho    { 0x063D, 0 }, /* 0x063D */
6195569331642446be05292e3e1f8a51218827168cdclaireho    { 0x063E, 0 }, /* 0x063E */
6205569331642446be05292e3e1f8a51218827168cdclaireho    { 0x063F, 0 }, /* 0x063F */
6215569331642446be05292e3e1f8a51218827168cdclaireho
6225569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0640, 0 }, /* 0x0640    C       TATWEEL // ### Join Causing, only one glyph */
6235569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFED1, 3 }, /* 0x0641    D       FEH */
6245569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFED5, 3 }, /* 0x0642    D       QAF */
6255569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFED9, 3 }, /* 0x0643    D       KAF */
6265569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEDD, 3 }, /* 0x0644    D       LAM */
6275569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEE1, 3 }, /* 0x0645    D       MEEM */
6285569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEE5, 3 }, /* 0x0646    D       NOON */
6295569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEE9, 3 }, /* 0x0647    D       HEH */
6305569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEED, 1 }, /* 0x0648    R       WAW */
6315569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0649, 3 }, /* 0x0649            ALEF MAKSURA // ### Dual, glyphs not consecutive, handle in code. */
6325569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFEF1, 3 }, /* 0x064A    D       YEH */
6335569331642446be05292e3e1f8a51218827168cdclaireho    { 0x064B, 0 }, /* 0x064B */
6345569331642446be05292e3e1f8a51218827168cdclaireho    { 0x064C, 0 }, /* 0x064C */
6355569331642446be05292e3e1f8a51218827168cdclaireho    { 0x064D, 0 }, /* 0x064D */
6365569331642446be05292e3e1f8a51218827168cdclaireho    { 0x064E, 0 }, /* 0x064E */
6375569331642446be05292e3e1f8a51218827168cdclaireho    { 0x064F, 0 }, /* 0x064F */
6385569331642446be05292e3e1f8a51218827168cdclaireho
6395569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0650, 0 }, /* 0x0650 */
6405569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0651, 0 }, /* 0x0651 */
6415569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0652, 0 }, /* 0x0652 */
6425569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0653, 0 }, /* 0x0653 */
6435569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0654, 0 }, /* 0x0654 */
6445569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0655, 0 }, /* 0x0655 */
6455569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0656, 0 }, /* 0x0656 */
6465569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0657, 0 }, /* 0x0657 */
6475569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0658, 0 }, /* 0x0658 */
6485569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0659, 0 }, /* 0x0659 */
6495569331642446be05292e3e1f8a51218827168cdclaireho    { 0x065A, 0 }, /* 0x065A */
6505569331642446be05292e3e1f8a51218827168cdclaireho    { 0x065B, 0 }, /* 0x065B */
6515569331642446be05292e3e1f8a51218827168cdclaireho    { 0x065C, 0 }, /* 0x065C */
6525569331642446be05292e3e1f8a51218827168cdclaireho    { 0x065D, 0 }, /* 0x065D */
6535569331642446be05292e3e1f8a51218827168cdclaireho    { 0x065E, 0 }, /* 0x065E */
6545569331642446be05292e3e1f8a51218827168cdclaireho    { 0x065F, 0 }, /* 0x065F */
6555569331642446be05292e3e1f8a51218827168cdclaireho
6565569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0660, 0 }, /* 0x0660 */
6575569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0661, 0 }, /* 0x0661 */
6585569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0662, 0 }, /* 0x0662 */
6595569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0663, 0 }, /* 0x0663 */
6605569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0664, 0 }, /* 0x0664 */
6615569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0665, 0 }, /* 0x0665 */
6625569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0666, 0 }, /* 0x0666 */
6635569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0667, 0 }, /* 0x0667 */
6645569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0668, 0 }, /* 0x0668 */
6655569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0669, 0 }, /* 0x0669 */
6665569331642446be05292e3e1f8a51218827168cdclaireho    { 0x066A, 0 }, /* 0x066A */
6675569331642446be05292e3e1f8a51218827168cdclaireho    { 0x066B, 0 }, /* 0x066B */
6685569331642446be05292e3e1f8a51218827168cdclaireho    { 0x066C, 0 }, /* 0x066C */
6695569331642446be05292e3e1f8a51218827168cdclaireho    { 0x066D, 0 }, /* 0x066D */
6705569331642446be05292e3e1f8a51218827168cdclaireho    { 0x066E, 0 }, /* 0x066E */
6715569331642446be05292e3e1f8a51218827168cdclaireho    { 0x066F, 0 }, /* 0x066F */
6725569331642446be05292e3e1f8a51218827168cdclaireho
6735569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0670, 0 }, /* 0x0670 */
6745569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB50, 1 }, /* 0x0671    R       ALEF WASLA */
6755569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0672, 0 }, /* 0x0672 */
6765569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0673, 0 }, /* 0x0673 */
6775569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0674, 0 }, /* 0x0674 */
6785569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0675, 0 }, /* 0x0675 */
6795569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0676, 0 }, /* 0x0676 */
6805569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0677, 0 }, /* 0x0677 */
6815569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0678, 0 }, /* 0x0678 */
6825569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB66, 3 }, /* 0x0679    D       TTEH */
6835569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB5E, 3 }, /* 0x067A    D       TTEHEH */
6845569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB52, 3 }, /* 0x067B    D       BEEH */
6855569331642446be05292e3e1f8a51218827168cdclaireho    { 0x067C, 0 }, /* 0x067C */
6865569331642446be05292e3e1f8a51218827168cdclaireho    { 0x067D, 0 }, /* 0x067D */
6875569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB56, 3 }, /* 0x067E    D       PEH */
6885569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB62, 3 }, /* 0x067F    D       TEHEH */
6895569331642446be05292e3e1f8a51218827168cdclaireho
6905569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB5A, 3 }, /* 0x0680    D       BEHEH */
6915569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0681, 0 }, /* 0x0681 */
6925569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0682, 0 }, /* 0x0682 */
6935569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB76, 3 }, /* 0x0683    D       NYEH */
6945569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB72, 3 }, /* 0x0684    D       DYEH */
6955569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0685, 0 }, /* 0x0685 */
6965569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB7A, 3 }, /* 0x0686    D       TCHEH */
6975569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB7E, 3 }, /* 0x0687    D       TCHEHEH */
6985569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB88, 1 }, /* 0x0688    R       DDAL */
6995569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0689, 0 }, /* 0x0689 */
7005569331642446be05292e3e1f8a51218827168cdclaireho    { 0x068A, 0 }, /* 0x068A */
7015569331642446be05292e3e1f8a51218827168cdclaireho    { 0x068B, 0 }, /* 0x068B */
7025569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB84, 1 }, /* 0x068C    R       DAHAL */
7035569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB82, 1 }, /* 0x068D    R       DDAHAL */
7045569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB86, 1 }, /* 0x068E    R       DUL */
7055569331642446be05292e3e1f8a51218827168cdclaireho    { 0x068F, 0 }, /* 0x068F */
7065569331642446be05292e3e1f8a51218827168cdclaireho
7075569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0690, 0 }, /* 0x0690 */
7085569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB8C, 1 }, /* 0x0691    R       RREH */
7095569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0692, 0 }, /* 0x0692 */
7105569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0693, 0 }, /* 0x0693 */
7115569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0694, 0 }, /* 0x0694 */
7125569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0695, 0 }, /* 0x0695 */
7135569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0696, 0 }, /* 0x0696 */
7145569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0697, 0 }, /* 0x0697 */
7155569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB8A, 1 }, /* 0x0698    R       JEH */
7165569331642446be05292e3e1f8a51218827168cdclaireho    { 0x0699, 0 }, /* 0x0699 */
7175569331642446be05292e3e1f8a51218827168cdclaireho    { 0x069A, 0 }, /* 0x069A */
7185569331642446be05292e3e1f8a51218827168cdclaireho    { 0x069B, 0 }, /* 0x069B */
7195569331642446be05292e3e1f8a51218827168cdclaireho    { 0x069C, 0 }, /* 0x069C */
7205569331642446be05292e3e1f8a51218827168cdclaireho    { 0x069D, 0 }, /* 0x069D */
7215569331642446be05292e3e1f8a51218827168cdclaireho    { 0x069E, 0 }, /* 0x069E */
7225569331642446be05292e3e1f8a51218827168cdclaireho    { 0x069F, 0 }, /* 0x069F */
7235569331642446be05292e3e1f8a51218827168cdclaireho
7245569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06A0, 0 }, /* 0x06A0 */
7255569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06A1, 0 }, /* 0x06A1 */
7265569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06A2, 0 }, /* 0x06A2 */
7275569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06A3, 0 }, /* 0x06A3 */
7285569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB6A, 3 }, /* 0x06A4    D       VEH */
7295569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06A5, 0 }, /* 0x06A5 */
7305569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB6E, 3 }, /* 0x06A6    D       PEHEH */
7315569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06A7, 0 }, /* 0x06A7 */
7325569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06A8, 0 }, /* 0x06A8 */
7335569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB8E, 3 }, /* 0x06A9    D       KEHEH */
7345569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06AA, 0 }, /* 0x06AA */
7355569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06AB, 0 }, /* 0x06AB */
7365569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06AC, 0 }, /* 0x06AC */
7375569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBD3, 3 }, /* 0x06AD    D       NG */
7385569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06AE, 0 }, /* 0x06AE */
7395569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB92, 3 }, /* 0x06AF    D       GAF */
7405569331642446be05292e3e1f8a51218827168cdclaireho
7415569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06B0, 0 }, /* 0x06B0 */
7425569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB9A, 3 }, /* 0x06B1    D       NGOEH */
7435569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06B2, 0 }, /* 0x06B2 */
7445569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB96, 3 }, /* 0x06B3    D       GUEH */
7455569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06B4, 0 }, /* 0x06B4 */
7465569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06B5, 0 }, /* 0x06B5 */
7475569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06B6, 0 }, /* 0x06B6 */
7485569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06B7, 0 }, /* 0x06B7 */
7495569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06B8, 0 }, /* 0x06B8 */
7505569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06B9, 0 }, /* 0x06B9 */
7515569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFB9E, 1 }, /* 0x06BA    R       NOON GHUNNA */
7525569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBA0, 3 }, /* 0x06BB    D       RNOON */
7535569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06BC, 0 }, /* 0x06BC */
7545569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06BD, 0 }, /* 0x06BD */
7555569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBAA, 3 }, /* 0x06BE    D       HEH DOACHASHMEE */
7565569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06BF, 0 }, /* 0x06BF */
7575569331642446be05292e3e1f8a51218827168cdclaireho
7585569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBA4, 1 }, /* 0x06C0    R       HEH WITH YEH ABOVE */
7595569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBA6, 3 }, /* 0x06C1    D       HEH GOAL */
7605569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06C2, 0 }, /* 0x06C2 */
7615569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06C3, 0 }, /* 0x06C3 */
7625569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06C4, 0 }, /* 0x06C4 */
7635569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBE0, 1 }, /* 0x06C5    R       KIRGHIZ OE */
7645569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBD9, 1 }, /* 0x06C6    R       OE */
7655569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBD7, 1 }, /* 0x06C7    R       U */
7665569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBDB, 1 }, /* 0x06C8    R       YU */
7675569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBE2, 1 }, /* 0x06C9    R       KIRGHIZ YU */
7685569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06CA, 0 }, /* 0x06CA */
7695569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBDE, 1 }, /* 0x06CB    R       VE */
7705569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBFC, 3 }, /* 0x06CC    D       FARSI YEH */
7715569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06CD, 0 }, /* 0x06CD */
7725569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06CE, 0 }, /* 0x06CE */
7735569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06CF, 0 }, /* 0x06CF */
7745569331642446be05292e3e1f8a51218827168cdclaireho
7755569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBE4, 3 }, /* 0x06D0    D       E */
7765569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06D1, 0 }, /* 0x06D1 */
7775569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBAE, 1 }, /* 0x06D2    R       YEH BARREE */
7785569331642446be05292e3e1f8a51218827168cdclaireho    { 0xFBB0, 1 }, /* 0x06D3    R       YEH BARREE WITH HAMZA ABOVE */
7795569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06D4, 0 }, /* 0x06D4 */
7805569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06D5, 0 }, /* 0x06D5 */
7815569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06D6, 0 }, /* 0x06D6 */
7825569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06D7, 0 }, /* 0x06D7 */
7835569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06D8, 0 }, /* 0x06D8 */
7845569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06D9, 0 }, /* 0x06D9 */
7855569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06DA, 0 }, /* 0x06DA */
7865569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06DB, 0 }, /* 0x06DB */
7875569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06DC, 0 }, /* 0x06DC */
7885569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06DD, 0 }, /* 0x06DD */
7895569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06DE, 0 }, /* 0x06DE */
7905569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06DF, 0 }, /* 0x06DF */
7915569331642446be05292e3e1f8a51218827168cdclaireho
7925569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06E0, 0 }, /* 0x06E0 */
7935569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06E1, 0 }, /* 0x06E1 */
7945569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06E2, 0 }, /* 0x06E2 */
7955569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06E3, 0 }, /* 0x06E3 */
7965569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06E4, 0 }, /* 0x06E4 */
7975569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06E5, 0 }, /* 0x06E5 */
7985569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06E6, 0 }, /* 0x06E6 */
7995569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06E7, 0 }, /* 0x06E7 */
8005569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06E8, 0 }, /* 0x06E8 */
8015569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06E9, 0 }, /* 0x06E9 */
8025569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06EA, 0 }, /* 0x06EA */
8035569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06EB, 0 }, /* 0x06EB */
8045569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06EC, 0 }, /* 0x06EC */
8055569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06ED, 0 }, /* 0x06ED */
8065569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06EE, 0 }, /* 0x06EE */
8075569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06EF, 0 }, /* 0x06EF */
8085569331642446be05292e3e1f8a51218827168cdclaireho
8095569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06F0, 0 }, /* 0x06F0 */
8105569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06F1, 0 }, /* 0x06F1 */
8115569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06F2, 0 }, /* 0x06F2 */
8125569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06F3, 0 }, /* 0x06F3 */
8135569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06F4, 0 }, /* 0x06F4 */
8145569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06F5, 0 }, /* 0x06F5 */
8155569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06F6, 0 }, /* 0x06F6 */
8165569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06F7, 0 }, /* 0x06F7 */
8175569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06F8, 0 }, /* 0x06F8 */
8185569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06F9, 0 }, /* 0x06F9 */
8195569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06FA, 0 }, /* 0x06FA */
8205569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06FB, 0 }, /* 0x06FB */
8215569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06FC, 0 }, /* 0x06FC */
8225569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06FD, 0 }, /* 0x06FD */
8235569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06FE, 0 }, /* 0x06FE */
8245569331642446be05292e3e1f8a51218827168cdclaireho    { 0x06FF, 0 }  /* 0x06FF */
8255569331642446be05292e3e1f8a51218827168cdclaireho};
8265569331642446be05292e3e1f8a51218827168cdclaireho
8275569331642446be05292e3e1f8a51218827168cdclaireho/* the arabicUnicodeMapping does not work for U+0649 ALEF MAKSURA, this table does */
8285569331642446be05292e3e1f8a51218827168cdclairehostatic const hb_uint16 alefMaksura[4] = {0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9};
8295569331642446be05292e3e1f8a51218827168cdclaireho
8305569331642446be05292e3e1f8a51218827168cdclaireho/*
8315569331642446be05292e3e1f8a51218827168cdclaireho// this is a bit tricky. Alef always binds to the right, so the second parameter descibing the shape
8325569331642446be05292e3e1f8a51218827168cdclaireho// of the lam can be either initial of medial. So initial maps to the isolated form of the ligature,
8335569331642446be05292e3e1f8a51218827168cdclaireho// medial to the final form
8345569331642446be05292e3e1f8a51218827168cdclaireho*/
8355569331642446be05292e3e1f8a51218827168cdclairehostatic const hb_uint16 arabicUnicodeLamAlefMapping[6][4] = {
8365569331642446be05292e3e1f8a51218827168cdclaireho    { 0xfffd, 0xfffd, 0xfef5, 0xfef6 }, /* 0x622        R       Alef with Madda above */
8375569331642446be05292e3e1f8a51218827168cdclaireho    { 0xfffd, 0xfffd, 0xfef7, 0xfef8 }, /* 0x623        R       Alef with Hamza above */
8385569331642446be05292e3e1f8a51218827168cdclaireho    { 0xfffd, 0xfffd, 0xfffd, 0xfffd }, /* 0x624        // Just to fill the table ;-) */
8395569331642446be05292e3e1f8a51218827168cdclaireho    { 0xfffd, 0xfffd, 0xfef9, 0xfefa }, /* 0x625        R       Alef with Hamza below */
8405569331642446be05292e3e1f8a51218827168cdclaireho    { 0xfffd, 0xfffd, 0xfffd, 0xfffd }, /* 0x626        // Just to fill the table ;-) */
8415569331642446be05292e3e1f8a51218827168cdclaireho    { 0xfffd, 0xfffd, 0xfefb, 0xfefc }  /* 0x627        R       Alef */
8425569331642446be05292e3e1f8a51218827168cdclaireho};
8435569331642446be05292e3e1f8a51218827168cdclaireho
8445569331642446be05292e3e1f8a51218827168cdclairehostatic int getShape(hb_uint8 cell, int shape)
8455569331642446be05292e3e1f8a51218827168cdclaireho{
8465569331642446be05292e3e1f8a51218827168cdclaireho    /* the arabicUnicodeMapping does not work for U+0649 ALEF MAKSURA, handle this here */
8475569331642446be05292e3e1f8a51218827168cdclaireho    int ch = (cell != 0x49)
8485569331642446be05292e3e1f8a51218827168cdclaireho              ? (shape ? arabicUnicodeMapping[cell][0] + shape : 0x600+cell)
8495569331642446be05292e3e1f8a51218827168cdclaireho              : alefMaksura[shape] ;
8505569331642446be05292e3e1f8a51218827168cdclaireho    return ch;
8515569331642446be05292e3e1f8a51218827168cdclaireho}
8525569331642446be05292e3e1f8a51218827168cdclaireho
8535569331642446be05292e3e1f8a51218827168cdclaireho
8545569331642446be05292e3e1f8a51218827168cdclaireho/*
8555569331642446be05292e3e1f8a51218827168cdclaireho  Two small helper functions for arabic shaping.
8565569331642446be05292e3e1f8a51218827168cdclaireho*/
8575569331642446be05292e3e1f8a51218827168cdclairehostatic HB_UChar16 prevChar(const HB_UChar16 *str, int pos)
8585569331642446be05292e3e1f8a51218827168cdclaireho{
8595569331642446be05292e3e1f8a51218827168cdclaireho    /*qDebug("leftChar: pos=%d", pos); */
8605569331642446be05292e3e1f8a51218827168cdclaireho    const HB_UChar16 *ch = str + pos - 1;
8615569331642446be05292e3e1f8a51218827168cdclaireho    pos--;
8625569331642446be05292e3e1f8a51218827168cdclaireho    while(pos > -1) {
8635569331642446be05292e3e1f8a51218827168cdclaireho        if(HB_GetUnicodeCharCategory(*ch) != HB_Mark_NonSpacing)
8645569331642446be05292e3e1f8a51218827168cdclaireho            return *ch;
8655569331642446be05292e3e1f8a51218827168cdclaireho        pos--;
8665569331642446be05292e3e1f8a51218827168cdclaireho        ch--;
8675569331642446be05292e3e1f8a51218827168cdclaireho    }
8685569331642446be05292e3e1f8a51218827168cdclaireho    return ReplacementCharacter;
8695569331642446be05292e3e1f8a51218827168cdclaireho}
8705569331642446be05292e3e1f8a51218827168cdclaireho
8715569331642446be05292e3e1f8a51218827168cdclairehostatic HB_UChar16 nextChar(const HB_UChar16 *str, hb_uint32 len, hb_uint32 pos)
8725569331642446be05292e3e1f8a51218827168cdclaireho{
8735569331642446be05292e3e1f8a51218827168cdclaireho    const HB_UChar16 *ch = str + pos + 1;
8745569331642446be05292e3e1f8a51218827168cdclaireho    pos++;
8755569331642446be05292e3e1f8a51218827168cdclaireho    while(pos < len) {
8765569331642446be05292e3e1f8a51218827168cdclaireho        /*qDebug("rightChar: %d isLetter=%d, joining=%d", pos, ch.isLetter(), ch.joining()); */
8775569331642446be05292e3e1f8a51218827168cdclaireho        if(HB_GetUnicodeCharCategory(*ch) != HB_Mark_NonSpacing)
8785569331642446be05292e3e1f8a51218827168cdclaireho            return *ch;
8795569331642446be05292e3e1f8a51218827168cdclaireho        /* assume it's a transparent char, this might not be 100% correct */
8805569331642446be05292e3e1f8a51218827168cdclaireho        pos++;
8815569331642446be05292e3e1f8a51218827168cdclaireho        ch++;
8825569331642446be05292e3e1f8a51218827168cdclaireho    }
8835569331642446be05292e3e1f8a51218827168cdclaireho    return ReplacementCharacter;
8845569331642446be05292e3e1f8a51218827168cdclaireho}
8855569331642446be05292e3e1f8a51218827168cdclaireho
8865569331642446be05292e3e1f8a51218827168cdclairehostatic void shapedString(const HB_UChar16 *uc, hb_uint32 stringLength, hb_uint32 from, hb_uint32 len, HB_UChar16 *shapeBuffer, int *shapedLength,
8875569331642446be05292e3e1f8a51218827168cdclaireho                         HB_Bool reverse, HB_GlyphAttributes *attributes, unsigned short *logClusters)
8885569331642446be05292e3e1f8a51218827168cdclaireho{
8895569331642446be05292e3e1f8a51218827168cdclaireho    HB_ArabicProperties *properties;
8905569331642446be05292e3e1f8a51218827168cdclaireho    hb_int32 f = from;
8915569331642446be05292e3e1f8a51218827168cdclaireho    hb_uint32 l = len;
8925569331642446be05292e3e1f8a51218827168cdclaireho    const HB_UChar16 *ch;
8935569331642446be05292e3e1f8a51218827168cdclaireho    HB_UChar16 *data;
8945569331642446be05292e3e1f8a51218827168cdclaireho    int clusterStart;
8955569331642446be05292e3e1f8a51218827168cdclaireho    hb_uint32 i;
8965569331642446be05292e3e1f8a51218827168cdclaireho    HB_STACKARRAY(HB_ArabicProperties, props, len + 2);
8975569331642446be05292e3e1f8a51218827168cdclaireho    properties = props;
8985569331642446be05292e3e1f8a51218827168cdclaireho
8995569331642446be05292e3e1f8a51218827168cdclaireho    assert(stringLength >= from + len);
9005569331642446be05292e3e1f8a51218827168cdclaireho
9015569331642446be05292e3e1f8a51218827168cdclaireho    if(len == 0) {
9025569331642446be05292e3e1f8a51218827168cdclaireho        *shapedLength = 0;
9035569331642446be05292e3e1f8a51218827168cdclaireho        return;
9045569331642446be05292e3e1f8a51218827168cdclaireho    }
9055569331642446be05292e3e1f8a51218827168cdclaireho
9065569331642446be05292e3e1f8a51218827168cdclaireho    if (from > 0) {
9075569331642446be05292e3e1f8a51218827168cdclaireho        --f;
9085569331642446be05292e3e1f8a51218827168cdclaireho        ++l;
9095569331642446be05292e3e1f8a51218827168cdclaireho        ++properties;
9105569331642446be05292e3e1f8a51218827168cdclaireho    }
9115569331642446be05292e3e1f8a51218827168cdclaireho    if (f + l < stringLength)
9125569331642446be05292e3e1f8a51218827168cdclaireho        ++l;
9135569331642446be05292e3e1f8a51218827168cdclaireho    getArabicProperties(uc+f, l, props);
9145569331642446be05292e3e1f8a51218827168cdclaireho
9155569331642446be05292e3e1f8a51218827168cdclaireho    ch = uc + from;
9165569331642446be05292e3e1f8a51218827168cdclaireho    data = shapeBuffer;
9175569331642446be05292e3e1f8a51218827168cdclaireho    clusterStart = 0;
9185569331642446be05292e3e1f8a51218827168cdclaireho
9195569331642446be05292e3e1f8a51218827168cdclaireho    for (i = 0; i < len; i++) {
9205569331642446be05292e3e1f8a51218827168cdclaireho        hb_uint8 r = *ch >> 8;
9215569331642446be05292e3e1f8a51218827168cdclaireho        int gpos = data - shapeBuffer;
9225569331642446be05292e3e1f8a51218827168cdclaireho
9235569331642446be05292e3e1f8a51218827168cdclaireho        if (r != 0x06) {
9245569331642446be05292e3e1f8a51218827168cdclaireho            if (r == 0x20) {
9255569331642446be05292e3e1f8a51218827168cdclaireho                if (*ch == 0x200c || *ch == 0x200d)
9265569331642446be05292e3e1f8a51218827168cdclaireho                    /* remove ZWJ and ZWNJ */
9275569331642446be05292e3e1f8a51218827168cdclaireho                    goto skip;
9285569331642446be05292e3e1f8a51218827168cdclaireho            }
9295569331642446be05292e3e1f8a51218827168cdclaireho            if (reverse)
9305569331642446be05292e3e1f8a51218827168cdclaireho                *data = HB_GetMirroredChar(*ch);
9315569331642446be05292e3e1f8a51218827168cdclaireho            else
9325569331642446be05292e3e1f8a51218827168cdclaireho                *data = *ch;
9335569331642446be05292e3e1f8a51218827168cdclaireho        } else {
9345569331642446be05292e3e1f8a51218827168cdclaireho            hb_uint8 c = *ch & 0xff;
9355569331642446be05292e3e1f8a51218827168cdclaireho            int pos = i + from;
9365569331642446be05292e3e1f8a51218827168cdclaireho            int shape = properties[i].shape;
9375569331642446be05292e3e1f8a51218827168cdclaireho/*            qDebug("mapping U+%x to shape %d glyph=0x%x", ch->unicode(), shape, getShape(c, shape)); */
9385569331642446be05292e3e1f8a51218827168cdclaireho            /* take care of lam-alef ligatures (lam right of alef) */
9395569331642446be05292e3e1f8a51218827168cdclaireho            hb_uint16 map;
9405569331642446be05292e3e1f8a51218827168cdclaireho            switch (c) {
9415569331642446be05292e3e1f8a51218827168cdclaireho                case 0x44: { /* lam */
9425569331642446be05292e3e1f8a51218827168cdclaireho                    const HB_UChar16 pch = nextChar(uc, stringLength, pos);
9435569331642446be05292e3e1f8a51218827168cdclaireho                    if ((pch >> 8) == 0x06) {
9445569331642446be05292e3e1f8a51218827168cdclaireho                        switch (pch & 0xff) {
9455569331642446be05292e3e1f8a51218827168cdclaireho                            case 0x22:
9465569331642446be05292e3e1f8a51218827168cdclaireho                            case 0x23:
9475569331642446be05292e3e1f8a51218827168cdclaireho                            case 0x25:
9485569331642446be05292e3e1f8a51218827168cdclaireho                            case 0x27:
9495569331642446be05292e3e1f8a51218827168cdclaireho/*                                 qDebug(" lam of lam-alef ligature"); */
9505569331642446be05292e3e1f8a51218827168cdclaireho                                map = arabicUnicodeLamAlefMapping[(pch & 0xff) - 0x22][shape];
9515569331642446be05292e3e1f8a51218827168cdclaireho                                goto next;
9525569331642446be05292e3e1f8a51218827168cdclaireho                            default:
9535569331642446be05292e3e1f8a51218827168cdclaireho                                break;
9545569331642446be05292e3e1f8a51218827168cdclaireho                        }
9555569331642446be05292e3e1f8a51218827168cdclaireho                    }
9565569331642446be05292e3e1f8a51218827168cdclaireho                    break;
9575569331642446be05292e3e1f8a51218827168cdclaireho                }
9585569331642446be05292e3e1f8a51218827168cdclaireho                case 0x22: /* alef with madda */
9595569331642446be05292e3e1f8a51218827168cdclaireho                case 0x23: /* alef with hamza above */
9605569331642446be05292e3e1f8a51218827168cdclaireho                case 0x25: /* alef with hamza below */
9615569331642446be05292e3e1f8a51218827168cdclaireho                case 0x27: /* alef */
9625569331642446be05292e3e1f8a51218827168cdclaireho                    if (prevChar(uc, pos) == 0x0644) {
9635569331642446be05292e3e1f8a51218827168cdclaireho                        /* have a lam alef ligature */
9645569331642446be05292e3e1f8a51218827168cdclaireho                        /*qDebug(" alef of lam-alef ligature"); */
9655569331642446be05292e3e1f8a51218827168cdclaireho                        goto skip;
9665569331642446be05292e3e1f8a51218827168cdclaireho                    }
9675569331642446be05292e3e1f8a51218827168cdclaireho                default:
9685569331642446be05292e3e1f8a51218827168cdclaireho                    break;
9695569331642446be05292e3e1f8a51218827168cdclaireho            }
9705569331642446be05292e3e1f8a51218827168cdclaireho            map = getShape(c, shape);
9715569331642446be05292e3e1f8a51218827168cdclaireho        next:
9725569331642446be05292e3e1f8a51218827168cdclaireho            *data = map;
9735569331642446be05292e3e1f8a51218827168cdclaireho        }
9745569331642446be05292e3e1f8a51218827168cdclaireho        /* ##### Fixme */
9755569331642446be05292e3e1f8a51218827168cdclaireho        /*glyphs[gpos].attributes.zeroWidth = zeroWidth; */
9765569331642446be05292e3e1f8a51218827168cdclaireho        if (HB_GetUnicodeCharCategory(*ch) == HB_Mark_NonSpacing) {
9775569331642446be05292e3e1f8a51218827168cdclaireho            attributes[gpos].mark = TRUE;
9785569331642446be05292e3e1f8a51218827168cdclaireho/*             qDebug("glyph %d (char %d) is mark!", gpos, i); */
9795569331642446be05292e3e1f8a51218827168cdclaireho        } else {
9805569331642446be05292e3e1f8a51218827168cdclaireho            attributes[gpos].mark = FALSE;
9815569331642446be05292e3e1f8a51218827168cdclaireho            clusterStart = data - shapeBuffer;
9825569331642446be05292e3e1f8a51218827168cdclaireho        }
9835569331642446be05292e3e1f8a51218827168cdclaireho        attributes[gpos].clusterStart = !attributes[gpos].mark;
9845569331642446be05292e3e1f8a51218827168cdclaireho        attributes[gpos].combiningClass = HB_GetUnicodeCharCombiningClass(*ch);
9855569331642446be05292e3e1f8a51218827168cdclaireho        attributes[gpos].justification = properties[i].justification;
9865569331642446be05292e3e1f8a51218827168cdclaireho/*         qDebug("data[%d] = %x (from %x)", gpos, (uint)data->unicode(), ch->unicode());*/
9875569331642446be05292e3e1f8a51218827168cdclaireho        data++;
9885569331642446be05292e3e1f8a51218827168cdclaireho    skip:
9895569331642446be05292e3e1f8a51218827168cdclaireho        ch++;
9905569331642446be05292e3e1f8a51218827168cdclaireho        logClusters[i] = clusterStart;
9915569331642446be05292e3e1f8a51218827168cdclaireho    }
9925569331642446be05292e3e1f8a51218827168cdclaireho    *shapedLength = data - shapeBuffer;
9935569331642446be05292e3e1f8a51218827168cdclaireho
9945569331642446be05292e3e1f8a51218827168cdclaireho    HB_FREE_STACKARRAY(props);
9955569331642446be05292e3e1f8a51218827168cdclaireho}
9965569331642446be05292e3e1f8a51218827168cdclaireho
9975569331642446be05292e3e1f8a51218827168cdclaireho#ifndef NO_OPENTYPE
9985569331642446be05292e3e1f8a51218827168cdclaireho
9995569331642446be05292e3e1f8a51218827168cdclairehostatic const HB_OpenTypeFeature arabic_features[] = {
10005569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
10015569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('i', 's', 'o', 'l'), IsolProperty },
10025569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('f', 'i', 'n', 'a'), FinaProperty },
10035569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('m', 'e', 'd', 'i'), MediProperty },
10045569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('i', 'n', 'i', 't'), InitProperty },
10055569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('r', 'l', 'i', 'g'), RligProperty },
10065569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('c', 'a', 'l', 't'), CaltProperty },
10075569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('l', 'i', 'g', 'a'), LigaProperty },
10085569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('d', 'l', 'i', 'g'), DligProperty },
10095569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('c', 's', 'w', 'h'), CswhProperty },
10105569331642446be05292e3e1f8a51218827168cdclaireho    /* mset is used in old Win95 fonts that don't have a 'mark' positioning table. */
10115569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('m', 's', 'e', 't'), MsetProperty },
10125569331642446be05292e3e1f8a51218827168cdclaireho    {0, 0}
10135569331642446be05292e3e1f8a51218827168cdclaireho};
10145569331642446be05292e3e1f8a51218827168cdclaireho
10155569331642446be05292e3e1f8a51218827168cdclairehostatic const HB_OpenTypeFeature syriac_features[] = {
10165569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
10175569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('i', 's', 'o', 'l'), IsolProperty },
10185569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('f', 'i', 'n', 'a'), FinaProperty },
10195569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('f', 'i', 'n', '2'), FinaProperty },
10205569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('f', 'i', 'n', '3'), FinaProperty },
10215569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('m', 'e', 'd', 'i'), MediProperty },
10225569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('m', 'e', 'd', '2'), MediProperty },
10235569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('i', 'n', 'i', 't'), InitProperty },
10245569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('r', 'l', 'i', 'g'), RligProperty },
10255569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('c', 'a', 'l', 't'), CaltProperty },
10265569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('l', 'i', 'g', 'a'), LigaProperty },
10275569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('d', 'l', 'i', 'g'), DligProperty },
10285569331642446be05292e3e1f8a51218827168cdclaireho    {0, 0}
10295569331642446be05292e3e1f8a51218827168cdclaireho};
10305569331642446be05292e3e1f8a51218827168cdclaireho
10315569331642446be05292e3e1f8a51218827168cdclairehostatic HB_Bool arabicSyriacOpenTypeShape(HB_ShaperItem *item, HB_Bool *ot_ok)
10325569331642446be05292e3e1f8a51218827168cdclaireho{
10335569331642446be05292e3e1f8a51218827168cdclaireho    const HB_UChar16 *uc;
10345569331642446be05292e3e1f8a51218827168cdclaireho    const int nglyphs = item->num_glyphs;
10355569331642446be05292e3e1f8a51218827168cdclaireho    hb_int32 f;
10365569331642446be05292e3e1f8a51218827168cdclaireho    hb_uint32 l;
10375569331642446be05292e3e1f8a51218827168cdclaireho    HB_ArabicProperties *properties;
10385569331642446be05292e3e1f8a51218827168cdclaireho    HB_DECLARE_STACKARRAY(HB_ArabicProperties, props)
10395569331642446be05292e3e1f8a51218827168cdclaireho    HB_DECLARE_STACKARRAY(hb_uint32, apply)
10405569331642446be05292e3e1f8a51218827168cdclaireho    HB_Bool shaped;
10415569331642446be05292e3e1f8a51218827168cdclaireho    int i = 0;
10425569331642446be05292e3e1f8a51218827168cdclaireho
10435569331642446be05292e3e1f8a51218827168cdclaireho    *ot_ok = TRUE;
10445569331642446be05292e3e1f8a51218827168cdclaireho
10455569331642446be05292e3e1f8a51218827168cdclaireho    if (!HB_ConvertStringToGlyphIndices(item))
10465569331642446be05292e3e1f8a51218827168cdclaireho        return FALSE;
10475569331642446be05292e3e1f8a51218827168cdclaireho    HB_HeuristicSetGlyphAttributes(item);
10485569331642446be05292e3e1f8a51218827168cdclaireho
10495569331642446be05292e3e1f8a51218827168cdclaireho    HB_INIT_STACKARRAY(HB_ArabicProperties, props, item->item.length + 2);
10505569331642446be05292e3e1f8a51218827168cdclaireho    HB_INIT_STACKARRAY(hb_uint32, apply, item->num_glyphs);
10515569331642446be05292e3e1f8a51218827168cdclaireho
10525569331642446be05292e3e1f8a51218827168cdclaireho    uc = item->string + item->item.pos;
10535569331642446be05292e3e1f8a51218827168cdclaireho
10545569331642446be05292e3e1f8a51218827168cdclaireho    properties = props;
10555569331642446be05292e3e1f8a51218827168cdclaireho    f = 0;
10565569331642446be05292e3e1f8a51218827168cdclaireho    l = item->item.length;
10575569331642446be05292e3e1f8a51218827168cdclaireho    if (item->item.pos > 0) {
10585569331642446be05292e3e1f8a51218827168cdclaireho        --f;
10595569331642446be05292e3e1f8a51218827168cdclaireho        ++l;
10605569331642446be05292e3e1f8a51218827168cdclaireho        ++properties;
10615569331642446be05292e3e1f8a51218827168cdclaireho    }
10625569331642446be05292e3e1f8a51218827168cdclaireho    if (f + l + item->item.pos < item->stringLength) {
10635569331642446be05292e3e1f8a51218827168cdclaireho        ++l;
10645569331642446be05292e3e1f8a51218827168cdclaireho    }
10655569331642446be05292e3e1f8a51218827168cdclaireho    if (item->item.script == HB_Script_Nko)
10665569331642446be05292e3e1f8a51218827168cdclaireho        getNkoProperties(uc+f, l, props);
10675569331642446be05292e3e1f8a51218827168cdclaireho    else
10685569331642446be05292e3e1f8a51218827168cdclaireho        getArabicProperties(uc+f, l, props);
10695569331642446be05292e3e1f8a51218827168cdclaireho
10705569331642446be05292e3e1f8a51218827168cdclaireho    for (i = 0; i < (int)item->num_glyphs; i++) {
10715569331642446be05292e3e1f8a51218827168cdclaireho        apply[i] = 0;
10725569331642446be05292e3e1f8a51218827168cdclaireho
10735569331642446be05292e3e1f8a51218827168cdclaireho        if (properties[i].shape == XIsolated)
10745569331642446be05292e3e1f8a51218827168cdclaireho            apply[i] |= MediProperty|FinaProperty|InitProperty;
10755569331642446be05292e3e1f8a51218827168cdclaireho        else if (properties[i].shape == XMedial)
10765569331642446be05292e3e1f8a51218827168cdclaireho            apply[i] |= IsolProperty|FinaProperty|InitProperty;
10775569331642446be05292e3e1f8a51218827168cdclaireho        else if (properties[i].shape == XFinal)
10785569331642446be05292e3e1f8a51218827168cdclaireho            apply[i] |= IsolProperty|MediProperty|InitProperty;
10795569331642446be05292e3e1f8a51218827168cdclaireho        else if (properties[i].shape == XInitial)
10805569331642446be05292e3e1f8a51218827168cdclaireho            apply[i] |= IsolProperty|MediProperty|FinaProperty;
10815569331642446be05292e3e1f8a51218827168cdclaireho
10825569331642446be05292e3e1f8a51218827168cdclaireho        item->attributes[i].justification = properties[i].justification;
10835569331642446be05292e3e1f8a51218827168cdclaireho    }
10845569331642446be05292e3e1f8a51218827168cdclaireho
10855569331642446be05292e3e1f8a51218827168cdclaireho    HB_FREE_STACKARRAY(props);
10865569331642446be05292e3e1f8a51218827168cdclaireho
10875569331642446be05292e3e1f8a51218827168cdclaireho    shaped = HB_OpenTypeShape(item, apply);
10885569331642446be05292e3e1f8a51218827168cdclaireho
10895569331642446be05292e3e1f8a51218827168cdclaireho    HB_FREE_STACKARRAY(apply);
10905569331642446be05292e3e1f8a51218827168cdclaireho
10915569331642446be05292e3e1f8a51218827168cdclaireho    if (!shaped) {
10925569331642446be05292e3e1f8a51218827168cdclaireho        *ot_ok = FALSE;
10935569331642446be05292e3e1f8a51218827168cdclaireho        return FALSE;
10945569331642446be05292e3e1f8a51218827168cdclaireho    }
10955569331642446be05292e3e1f8a51218827168cdclaireho    return HB_OpenTypePosition(item, nglyphs, /*doLogClusters*/TRUE);
10965569331642446be05292e3e1f8a51218827168cdclaireho}
10975569331642446be05292e3e1f8a51218827168cdclaireho
10985569331642446be05292e3e1f8a51218827168cdclaireho#endif
10995569331642446be05292e3e1f8a51218827168cdclaireho
11005569331642446be05292e3e1f8a51218827168cdclaireho/* #### stil missing: identify invalid character combinations */
11015569331642446be05292e3e1f8a51218827168cdclairehoHB_Bool HB_ArabicShape(HB_ShaperItem *item)
11025569331642446be05292e3e1f8a51218827168cdclaireho{
11035569331642446be05292e3e1f8a51218827168cdclaireho    int slen;
11045569331642446be05292e3e1f8a51218827168cdclaireho    HB_Bool haveGlyphs;
11055569331642446be05292e3e1f8a51218827168cdclaireho    HB_STACKARRAY(HB_UChar16, shapedChars, item->item.length);
11065569331642446be05292e3e1f8a51218827168cdclaireho
11075569331642446be05292e3e1f8a51218827168cdclaireho    assert(item->item.script == HB_Script_Arabic || item->item.script == HB_Script_Syriac
11085569331642446be05292e3e1f8a51218827168cdclaireho           || item->item.script == HB_Script_Nko);
11095569331642446be05292e3e1f8a51218827168cdclaireho
11105569331642446be05292e3e1f8a51218827168cdclaireho#ifndef NO_OPENTYPE
11115569331642446be05292e3e1f8a51218827168cdclaireho
11125569331642446be05292e3e1f8a51218827168cdclaireho    if (HB_SelectScript(item, item->item.script == HB_Script_Arabic ? arabic_features : syriac_features)) {
11135569331642446be05292e3e1f8a51218827168cdclaireho        HB_Bool ot_ok;
11145569331642446be05292e3e1f8a51218827168cdclaireho        if (arabicSyriacOpenTypeShape(item, &ot_ok))
11155569331642446be05292e3e1f8a51218827168cdclaireho            return TRUE;
11165569331642446be05292e3e1f8a51218827168cdclaireho        if (ot_ok)
11175569331642446be05292e3e1f8a51218827168cdclaireho            return FALSE;
11185569331642446be05292e3e1f8a51218827168cdclaireho            /* fall through to the non OT code*/
11195569331642446be05292e3e1f8a51218827168cdclaireho    }
11205569331642446be05292e3e1f8a51218827168cdclaireho#endif
11215569331642446be05292e3e1f8a51218827168cdclaireho
11225569331642446be05292e3e1f8a51218827168cdclaireho    if (item->item.script != HB_Script_Arabic)
11235569331642446be05292e3e1f8a51218827168cdclaireho        return HB_BasicShape(item);
11245569331642446be05292e3e1f8a51218827168cdclaireho
11255569331642446be05292e3e1f8a51218827168cdclaireho    shapedString(item->string, item->stringLength, item->item.pos, item->item.length, shapedChars, &slen,
11265569331642446be05292e3e1f8a51218827168cdclaireho                  item->item.bidiLevel % 2,
11275569331642446be05292e3e1f8a51218827168cdclaireho                  item->attributes, item->log_clusters);
11285569331642446be05292e3e1f8a51218827168cdclaireho
11295569331642446be05292e3e1f8a51218827168cdclaireho    haveGlyphs = item->font->klass
11305569331642446be05292e3e1f8a51218827168cdclaireho        ->convertStringToGlyphIndices(item->font,
11315569331642446be05292e3e1f8a51218827168cdclaireho                                      shapedChars, slen,
11325569331642446be05292e3e1f8a51218827168cdclaireho                                      item->glyphs, &item->num_glyphs,
11335569331642446be05292e3e1f8a51218827168cdclaireho                                      item->item.bidiLevel % 2);
11345569331642446be05292e3e1f8a51218827168cdclaireho
11355569331642446be05292e3e1f8a51218827168cdclaireho    HB_FREE_STACKARRAY(shapedChars);
11365569331642446be05292e3e1f8a51218827168cdclaireho
11375569331642446be05292e3e1f8a51218827168cdclaireho    if (!haveGlyphs)
11385569331642446be05292e3e1f8a51218827168cdclaireho        return FALSE;
11395569331642446be05292e3e1f8a51218827168cdclaireho
11405569331642446be05292e3e1f8a51218827168cdclaireho    HB_HeuristicPosition(item);
11415569331642446be05292e3e1f8a51218827168cdclaireho    return TRUE;
11425569331642446be05292e3e1f8a51218827168cdclaireho}
11435569331642446be05292e3e1f8a51218827168cdclaireho
11445569331642446be05292e3e1f8a51218827168cdclaireho
1145