Home | History | Annotate | Download | only in fxcrt
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "core/include/fxcrt/fx_ucd.h"
      8 #include "fx_arabic.h"
      9 
     10 namespace {
     11 
     12 const FX_ARBFORMTABLE g_FX_ArabicFormTables[] = {
     13     {0xFE81, 0xFE82, 0xFE81, 0xFE82},
     14     {0xFE83, 0xFE84, 0xFE83, 0xFE84},
     15     {0xFE85, 0xFE86, 0xFE85, 0xFE86},
     16     {0xFE87, 0xFE88, 0xFE87, 0xFE88},
     17     {0xFE89, 0xFE8A, 0xFE8B, 0xFE8C},
     18     {0xFE8D, 0xFE8E, 0xFE8D, 0xFE8E},
     19     {0xFE8F, 0xFE90, 0xFE91, 0xFE92},
     20     {0xFE93, 0xFE94, 0xFE93, 0xFE94},
     21     {0xFE95, 0xFE96, 0xFE97, 0xFE98},
     22     {0xFE99, 0xFE9A, 0xFE9B, 0xFE9C},
     23     {0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0},
     24     {0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4},
     25     {0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8},
     26     {0xFEA9, 0xFEAA, 0xFEA9, 0xFEAA},
     27     {0xFEAB, 0xFEAC, 0xFEAB, 0xFEAC},
     28     {0xFEAD, 0xFEAE, 0xFEAD, 0xFEAE},
     29     {0xFEAF, 0xFEB0, 0xFEAF, 0xFEB0},
     30     {0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4},
     31     {0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8},
     32     {0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC},
     33     {0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0},
     34     {0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4},
     35     {0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8},
     36     {0xFEC9, 0xFECA, 0xFECB, 0xFECC},
     37     {0xFECD, 0xFECE, 0xFECF, 0xFED0},
     38     {0x063B, 0x063B, 0x063B, 0x063B},
     39     {0x063C, 0x063C, 0x063C, 0x063C},
     40     {0x063D, 0x063D, 0x063D, 0x063D},
     41     {0x063E, 0x063E, 0x063E, 0x063E},
     42     {0x063F, 0x063F, 0x063F, 0x063F},
     43     {0x0640, 0x0640, 0x0640, 0x0640},
     44     {0xFED1, 0xFED2, 0xFED3, 0xFED4},
     45     {0xFED5, 0xFED6, 0xFED7, 0xFED8},
     46     {0xFED9, 0xFEDA, 0xFEDB, 0xFEDC},
     47     {0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0},
     48     {0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4},
     49     {0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8},
     50     {0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC},
     51     {0xFEED, 0xFEEE, 0xFEED, 0xFEEE},
     52     {0xFEEF, 0xFEF0, 0xFBFE, 0xFBFF},
     53     {0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4},
     54     {0x064B, 0x064B, 0x064B, 0x064B},
     55     {0x064C, 0x064C, 0x064C, 0x064C},
     56     {0x064D, 0x064D, 0x064D, 0x064D},
     57     {0x064E, 0x064E, 0x064E, 0x064E},
     58     {0x064F, 0x064F, 0x064F, 0x064F},
     59     {0x0650, 0x0650, 0x0650, 0x0650},
     60     {0x0651, 0x0651, 0x0651, 0x0651},
     61     {0x0652, 0x0652, 0x0652, 0x0652},
     62     {0x0653, 0x0653, 0x0653, 0x0653},
     63     {0x0654, 0x0654, 0x0654, 0x0654},
     64     {0x0655, 0x0655, 0x0655, 0x0655},
     65     {0x0656, 0x0656, 0x0656, 0x0656},
     66     {0x0657, 0x0657, 0x0657, 0x0657},
     67     {0x0658, 0x0658, 0x0658, 0x0658},
     68     {0x0659, 0x0659, 0x0659, 0x0659},
     69     {0x065A, 0x065A, 0x065A, 0x065A},
     70     {0x065B, 0x065B, 0x065B, 0x065B},
     71     {0x065C, 0x065C, 0x065C, 0x065C},
     72     {0x065D, 0x065D, 0x065D, 0x065D},
     73     {0x065E, 0x065E, 0x065E, 0x065E},
     74     {0x065F, 0x065F, 0x065F, 0x065F},
     75     {0x0660, 0x0660, 0x0660, 0x0660},
     76     {0x0661, 0x0661, 0x0661, 0x0661},
     77     {0x0662, 0x0662, 0x0662, 0x0662},
     78     {0x0663, 0x0663, 0x0663, 0x0663},
     79     {0x0664, 0x0664, 0x0664, 0x0664},
     80     {0x0665, 0x0665, 0x0665, 0x0665},
     81     {0x0666, 0x0666, 0x0666, 0x0666},
     82     {0x0667, 0x0667, 0x0667, 0x0667},
     83     {0x0668, 0x0668, 0x0668, 0x0668},
     84     {0x0669, 0x0669, 0x0669, 0x0669},
     85     {0x066A, 0x066A, 0x066A, 0x066A},
     86     {0x066B, 0x066B, 0x066B, 0x066B},
     87     {0x066C, 0x066C, 0x066C, 0x066C},
     88     {0x066D, 0x066D, 0x066D, 0x066D},
     89     {0x066E, 0x066E, 0x066E, 0x066E},
     90     {0x066F, 0x066F, 0x066F, 0x066F},
     91     {0x0670, 0x0670, 0x0670, 0x0670},
     92     {0xFB50, 0xFB51, 0xFB50, 0xFB51},
     93     {0x0672, 0x0672, 0x0672, 0x0672},
     94     {0x0673, 0x0673, 0x0673, 0x0673},
     95     {0x0674, 0x0674, 0x0674, 0x0674},
     96     {0x0675, 0x0675, 0x0675, 0x0675},
     97     {0x0676, 0x0676, 0x0676, 0x0676},
     98     {0x0677, 0x0677, 0x0677, 0x0677},
     99     {0x0678, 0x0678, 0x0678, 0x0678},
    100     {0xFB66, 0xFB67, 0xFB68, 0xFB69},
    101     {0xFB5E, 0xFB5F, 0xFB60, 0xFB61},
    102     {0xFB52, 0xFB53, 0xFB54, 0xFB55},
    103     {0x067C, 0x067C, 0x067C, 0x067C},
    104     {0x067D, 0x067D, 0x067D, 0x067D},
    105     {0xFB56, 0xFB57, 0xFB58, 0xFB59},
    106     {0xFB62, 0xFB63, 0xFB64, 0xFB65},
    107     {0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D},
    108     {0x0681, 0x0681, 0x0681, 0x0681},
    109     {0x0682, 0x0682, 0x0682, 0x0682},
    110     {0xFB76, 0xFB77, 0xFB78, 0xFB79},
    111     {0xFB72, 0xFB73, 0xFB74, 0xFB75},
    112     {0x0685, 0x0685, 0x0685, 0x0685},
    113     {0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D},
    114     {0xFB7E, 0xFB7F, 0xFB80, 0xFB81},
    115     {0xFB88, 0xFB89, 0xFB88, 0xFB89},
    116     {0x0689, 0x0689, 0x0689, 0x0689},
    117     {0x068A, 0x068A, 0x068A, 0x068A},
    118     {0x068B, 0x068B, 0x068B, 0x068B},
    119     {0xFB84, 0xFB85, 0xFB84, 0xFB85},
    120     {0xFB82, 0xFB83, 0xFB82, 0xFB83},
    121     {0xFB86, 0xFB87, 0xFB86, 0xFB87},
    122     {0x068F, 0x068F, 0x068F, 0x068F},
    123     {0x0690, 0x0690, 0x0690, 0x0690},
    124     {0xFB8C, 0xFB8D, 0xFB8C, 0xFB8D},
    125     {0x0692, 0x0692, 0x0692, 0x0692},
    126     {0x0693, 0x0693, 0x0693, 0x0693},
    127     {0x0694, 0x0694, 0x0694, 0x0694},
    128     {0x0695, 0x0695, 0x0695, 0x0695},
    129     {0x0696, 0x0696, 0x0696, 0x0696},
    130     {0x0697, 0x0697, 0x0697, 0x0697},
    131     {0xFB8A, 0xFB8B, 0xFB8A, 0xFB8B},
    132     {0x0699, 0x0699, 0x0699, 0x0699},
    133     {0x069A, 0x069A, 0x069A, 0x069A},
    134     {0x069B, 0x069B, 0x069B, 0x069B},
    135     {0x069C, 0x069C, 0x069C, 0x069C},
    136     {0x069D, 0x069D, 0x069D, 0x069D},
    137     {0x069E, 0x069E, 0x069E, 0x069E},
    138     {0x069F, 0x069F, 0x069F, 0x069F},
    139     {0x06A0, 0x06A0, 0x06A0, 0x06A0},
    140     {0x06A1, 0x06A1, 0x06A1, 0x06A1},
    141     {0x06A2, 0x06A2, 0x06A2, 0x06A2},
    142     {0x06A3, 0x06A3, 0x06A3, 0x06A3},
    143     {0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D},
    144     {0x06A5, 0x06A5, 0x06A5, 0x06A5},
    145     {0xFB6E, 0xFB6F, 0xFB70, 0xFB71},
    146     {0x06A7, 0x06A7, 0x06A7, 0x06A7},
    147     {0x06A8, 0x06A8, 0x06A8, 0x06A8},
    148     {0xFB8E, 0xFB8F, 0xFB90, 0xFB91},
    149     {0x06AA, 0x06AA, 0x06AA, 0x06AA},
    150     {0x06AB, 0x06AB, 0x06AB, 0x06AB},
    151     {0x06AC, 0x06AC, 0x06AC, 0x06AC},
    152     {0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6},
    153     {0x06AE, 0x06AE, 0x06AE, 0x06AE},
    154     {0xFB92, 0xFB93, 0xFB94, 0xFB95},
    155     {0x06B0, 0x06B0, 0x06B0, 0x06B0},
    156     {0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D},
    157     {0x06B2, 0x06B2, 0x06B2, 0x06B2},
    158     {0xFB96, 0xFB97, 0xFB98, 0xFB99},
    159     {0x06B4, 0x06B4, 0x06B4, 0x06B4},
    160     {0x06B5, 0x06B5, 0x06B5, 0x06B5},
    161     {0x06B6, 0x06B6, 0x06B6, 0x06B6},
    162     {0x06B7, 0x06B7, 0x06B7, 0x06B7},
    163     {0x06B8, 0x06B8, 0x06B8, 0x06B8},
    164     {0x06B9, 0x06B9, 0x06B9, 0x06B9},
    165     {0xFB9E, 0xFB9F, 0xFBE8, 0xFBE9},
    166     {0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3},
    167     {0x06BC, 0x06BC, 0x06BC, 0x06BC},
    168     {0x06BD, 0x06BD, 0x06BD, 0x06BD},
    169     {0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD},
    170     {0x06BF, 0x06BF, 0x06BF, 0x06BF},
    171     {0xFBA4, 0xFBA5, 0xFBA4, 0xFBA5},
    172     {0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9},
    173     {0x06C2, 0x06C2, 0x06C2, 0x06C2},
    174     {0x06C3, 0x06C3, 0x06C3, 0x06C3},
    175     {0x06C4, 0x06C4, 0x06C4, 0x06C4},
    176     {0xFBE0, 0xFBE1, 0xFBE0, 0xFBE1},
    177     {0xFBD9, 0xFBDA, 0xFBD9, 0xFBDA},
    178     {0xFBD7, 0xFBD8, 0xFBD7, 0xFBD8},
    179     {0xFBDB, 0xFBDC, 0xFBDB, 0xFBDC},
    180     {0xFBE2, 0xFBE3, 0xFBE2, 0xFBE3},
    181     {0x06CA, 0x06CA, 0x06CA, 0x06CA},
    182     {0xFBDE, 0xFBDF, 0xFBDE, 0xFBDF},
    183     {0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF},
    184     {0x06CD, 0x06CD, 0x06CD, 0x06CD},
    185     {0x06CE, 0x06CE, 0x06CE, 0x06CE},
    186     {0x06CF, 0x06CF, 0x06CF, 0x06CF},
    187     {0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7},
    188     {0x06D1, 0x06D1, 0x06D1, 0x06D1},
    189     {0xFBAE, 0xFBAF, 0xFBAE, 0xFBAF},
    190     {0xFBB0, 0xFBB1, 0xFBB0, 0xFBB1},
    191     {0x06D4, 0x06D4, 0x06D4, 0x06D4},
    192     {0x06D5, 0x06D5, 0x06D5, 0x06D5},
    193 };
    194 
    195 const FX_ARAALEF gs_FX_AlefTable[] = {
    196     {0x0622, 0xFEF5},
    197     {0x0623, 0xFEF7},
    198     {0x0625, 0xFEF9},
    199     {0x0627, 0xFEFB},
    200 };
    201 
    202 const FX_ARASHADDA gs_FX_ShaddaTable[] = {
    203     {0x064C, 0xFC5E},
    204     {0x064D, 0xFC5F},
    205     {0x064E, 0xFC60},
    206     {0x064F, 0xFC61},
    207     {0x0650, 0xFC62},
    208 };
    209 
    210 }  // namespace
    211 
    212 const FX_ARBFORMTABLE* FX_GetArabicFormTable(FX_WCHAR unicode) {
    213   if (unicode < 0x622 || unicode > 0x6d5) {
    214     return NULL;
    215   }
    216   return g_FX_ArabicFormTables + unicode - 0x622;
    217 }
    218 FX_WCHAR FX_GetArabicFromAlefTable(FX_WCHAR alef) {
    219   static const int32_t s_iAlefCount =
    220       sizeof(gs_FX_AlefTable) / sizeof(FX_ARAALEF);
    221   for (int32_t iStart = 0; iStart < s_iAlefCount; iStart++) {
    222     const FX_ARAALEF& v = gs_FX_AlefTable[iStart];
    223     if (v.wAlef == alef) {
    224       return v.wIsolated;
    225     }
    226   }
    227   return alef;
    228 }
    229 FX_WCHAR FX_GetArabicFromShaddaTable(FX_WCHAR shadda) {
    230   static const int32_t s_iShaddaCount =
    231       sizeof(gs_FX_ShaddaTable) / sizeof(FX_ARASHADDA);
    232   for (int32_t iStart = 0; iStart < s_iShaddaCount; iStart++) {
    233     const FX_ARASHADDA& v = gs_FX_ShaddaTable[iStart];
    234     if (v.wShadda == shadda) {
    235       return v.wIsolated;
    236     }
    237   }
    238   return shadda;
    239 }
    240 
    241 IFX_ArabicChar* IFX_ArabicChar::Create() {
    242   return new CFX_ArabicChar;
    243 }
    244 FX_BOOL CFX_ArabicChar::IsArabicChar(FX_WCHAR wch) const {
    245   FX_DWORD dwRet =
    246       kTextLayoutCodeProperties[(FX_WORD)wch] & FX_CHARTYPEBITSMASK;
    247   return dwRet >= FX_CHARTYPE_ArabicAlef;
    248 }
    249 FX_BOOL CFX_ArabicChar::IsArabicFormChar(FX_WCHAR wch) const {
    250   return (kTextLayoutCodeProperties[(FX_WORD)wch] & FX_CHARTYPEBITSMASK) ==
    251          FX_CHARTYPE_ArabicForm;
    252 }
    253 FX_WCHAR CFX_ArabicChar::GetFormChar(FX_WCHAR wch,
    254                                      FX_WCHAR prev,
    255                                      FX_WCHAR next) const {
    256   CFX_Char c(wch, kTextLayoutCodeProperties[(FX_WORD)wch]);
    257   CFX_Char p(prev, kTextLayoutCodeProperties[(FX_WORD)prev]);
    258   CFX_Char n(next, kTextLayoutCodeProperties[(FX_WORD)next]);
    259   return GetFormChar(&c, &p, &n);
    260 }
    261 FX_WCHAR CFX_ArabicChar::GetFormChar(const CFX_Char* cur,
    262                                      const CFX_Char* prev,
    263                                      const CFX_Char* next) const {
    264   FX_CHARTYPE eCur;
    265   FX_WCHAR wCur;
    266   const FX_ARBFORMTABLE* ft = ParseChar(cur, wCur, eCur);
    267   if (eCur < FX_CHARTYPE_ArabicAlef || eCur >= FX_CHARTYPE_ArabicNormal) {
    268     return wCur;
    269   }
    270   FX_CHARTYPE ePrev;
    271   FX_WCHAR wPrev;
    272   ParseChar(prev, wPrev, ePrev);
    273   if (wPrev == 0x0644 && eCur == FX_CHARTYPE_ArabicAlef) {
    274     return 0xFEFF;
    275   }
    276   FX_CHARTYPE eNext;
    277   FX_WCHAR wNext;
    278   ParseChar(next, wNext, eNext);
    279   FX_BOOL bAlef = (eNext == FX_CHARTYPE_ArabicAlef && wCur == 0x644);
    280   if (ePrev < FX_CHARTYPE_ArabicAlef) {
    281     if (bAlef) {
    282       return FX_GetArabicFromAlefTable(wNext);
    283     } else {
    284       return (eNext < FX_CHARTYPE_ArabicAlef) ? ft->wIsolated : ft->wInitial;
    285     }
    286   } else {
    287     if (bAlef) {
    288       wCur = FX_GetArabicFromAlefTable(wNext);
    289       return (ePrev != FX_CHARTYPE_ArabicDistortion) ? wCur : ++wCur;
    290     } else if (ePrev == FX_CHARTYPE_ArabicAlef ||
    291                ePrev == FX_CHARTYPE_ArabicSpecial) {
    292       return (eNext < FX_CHARTYPE_ArabicAlef) ? ft->wIsolated : ft->wInitial;
    293     } else {
    294       return (eNext < FX_CHARTYPE_ArabicAlef) ? ft->wFinal : ft->wMedial;
    295     }
    296   }
    297 }
    298 const FX_ARBFORMTABLE* CFX_ArabicChar::ParseChar(const CFX_Char* pTC,
    299                                                  FX_WCHAR& wChar,
    300                                                  FX_CHARTYPE& eType) const {
    301   if (pTC == NULL) {
    302     eType = FX_CHARTYPE_Unknown;
    303     wChar = 0xFEFF;
    304     return NULL;
    305   }
    306   eType = (FX_CHARTYPE)pTC->GetCharType();
    307   wChar = (FX_WCHAR)pTC->m_wCharCode;
    308   const FX_ARBFORMTABLE* pFT = FX_GetArabicFormTable(wChar);
    309   if (pFT == NULL || eType >= FX_CHARTYPE_ArabicNormal) {
    310     eType = FX_CHARTYPE_Unknown;
    311   }
    312   return pFT;
    313 }
    314 void FX_BidiReverseString(CFX_WideString& wsText,
    315                           int32_t iStart,
    316                           int32_t iCount) {
    317   FXSYS_assert(iStart > -1 && iStart < wsText.GetLength());
    318   FXSYS_assert(iCount >= 0 && iStart + iCount <= wsText.GetLength());
    319   FX_WCHAR wch;
    320   FX_WCHAR* pStart = (FX_WCHAR*)(const FX_WCHAR*)wsText;
    321   pStart += iStart;
    322   FX_WCHAR* pEnd = pStart + iCount - 1;
    323   while (pStart < pEnd) {
    324     wch = *pStart;
    325     *pStart++ = *pEnd;
    326     *pEnd-- = wch;
    327   }
    328 }
    329 void FX_BidiSetDeferredRun(CFX_Int32Array& values,
    330                            int32_t iStart,
    331                            int32_t iCount,
    332                            int32_t iValue) {
    333   FXSYS_assert(iStart > -1 && iStart <= values.GetSize());
    334   FXSYS_assert(iStart - iCount > -1);
    335   for (int32_t i = iStart - 1; i >= iStart - iCount; i--) {
    336     values.SetAt(i, iValue);
    337   }
    338 }
    339 const int32_t gc_FX_BidiNTypes[] = {
    340     FX_BIDICLASS_N,   FX_BIDICLASS_L,   FX_BIDICLASS_R,   FX_BIDICLASS_AN,
    341     FX_BIDICLASS_EN,  FX_BIDICLASS_AL,  FX_BIDICLASS_NSM, FX_BIDICLASS_CS,
    342     FX_BIDICLASS_ES,  FX_BIDICLASS_ET,  FX_BIDICLASS_BN,  FX_BIDICLASS_BN,
    343     FX_BIDICLASS_N,   FX_BIDICLASS_B,   FX_BIDICLASS_RLO, FX_BIDICLASS_RLE,
    344     FX_BIDICLASS_LRO, FX_BIDICLASS_LRE, FX_BIDICLASS_PDF, FX_BIDICLASS_ON,
    345 };
    346 void FX_BidiClassify(const CFX_WideString& wsText,
    347                      CFX_Int32Array& classes,
    348                      FX_BOOL bWS) {
    349   FXSYS_assert(wsText.GetLength() == classes.GetSize());
    350   int32_t iCount = wsText.GetLength();
    351   const FX_WCHAR* pwsStart = (const FX_WCHAR*)wsText;
    352   FX_WCHAR wch;
    353   int32_t iCls;
    354   if (bWS) {
    355     for (int32_t i = 0; i < iCount; i++) {
    356       wch = *pwsStart++;
    357       iCls =
    358           ((kTextLayoutCodeProperties[(FX_WORD)wch] & FX_BIDICLASSBITSMASK) >>
    359            FX_BIDICLASSBITS);
    360       classes.SetAt(i, iCls);
    361     }
    362   } else {
    363     for (int32_t i = 0; i < iCount; i++) {
    364       wch = *pwsStart++;
    365       iCls =
    366           ((kTextLayoutCodeProperties[(FX_WORD)wch] & FX_BIDICLASSBITSMASK) >>
    367            FX_BIDICLASSBITS);
    368       classes.SetAt(i, gc_FX_BidiNTypes[iCls]);
    369     }
    370   }
    371 }
    372 int32_t FX_BidiResolveExplicit(int32_t iBaseLevel,
    373                                int32_t iDirection,
    374                                CFX_Int32Array& classes,
    375                                CFX_Int32Array& levels,
    376                                int32_t iStart,
    377                                int32_t iCount,
    378                                int32_t iNest) {
    379   FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL && iNest >= 0);
    380   FXSYS_assert(classes.GetSize() == levels.GetSize());
    381   FXSYS_assert(iStart >= 0 && iStart < classes.GetSize());
    382   FXSYS_assert(iCount >= 0 && iStart + iCount <= classes.GetSize());
    383   if (iCount < 1) {
    384     return 0;
    385   }
    386 #if 0
    387     int32_t iLastNest = iNest;
    388 #endif
    389   int32_t iSize = classes.GetSize();
    390   int32_t i = iStart, iCur, iCls;
    391   for (; i < iSize && iCount > 0; i++, iCount--) {
    392     iCur = iCls = classes.GetAt(i);
    393 #if 0
    394         switch (iCls) {
    395             case FX_BIDICLASS_LRO:
    396             case FX_BIDICLASS_LRE:
    397                 classes.SetAt(i, FX_BIDICLASS_BN);
    398                 iCls = FX_BIDICLASS_BN;
    399                 iNest ++;
    400                 if (FX_BidiGreaterEven(iBaseLevel) <= MAX_LEVEL) {
    401                     int32_t iLevel = FX_BidiGreaterEven(iBaseLevel);
    402                     levels.SetAt(i, iLevel);
    403                     i += FX_BidiResolveExplicit(iLevel,
    404                                                 (iCls == FX_BIDICLASS_LRE ? FX_BIDICLASS_N : FX_BIDICLASS_L),
    405                                                 classes,
    406                                                 levels,
    407                                                 i + 1,
    408                                                 iCount - 1,
    409                                                 iNest);
    410                     iNest --;
    411                     continue;
    412                 }
    413                 break;
    414             case FX_BIDICLASS_RLO:
    415             case FX_BIDICLASS_RLE:
    416                 classes.SetAt(i, FX_BIDICLASS_BN);
    417                 iCls = FX_BIDICLASS_BN;
    418                 iNest ++;
    419                 if (FX_BidiGreaterOdd(iBaseLevel) <= MAX_LEVEL) {
    420                     int32_t iLevel = FX_BidiGreaterOdd(iBaseLevel);
    421                     levels.SetAt(i, iLevel);
    422                     i += FX_BidiResolveExplicit(iLevel,
    423                                                 (iCls == FX_BIDICLASS_RLE ? FX_BIDICLASS_N : FX_BIDICLASS_R),
    424                                                 classes,
    425                                                 levels,
    426                                                 i + 1,
    427                                                 iCount - 1,
    428                                                 iNest);
    429                     iNest --;
    430                     continue;
    431                 }
    432                 break;
    433             case FX_BIDICLASS_PDF:
    434                 classes.SetAt(i, FX_BIDICLASS_BN);
    435                 iCls = FX_BIDICLASS_BN;
    436                 if (iNest) {
    437                     if (iLastNest < iNest) {
    438                         iNest --;
    439                     } else {
    440                         iSize = i;
    441                     }
    442                 }
    443                 break;
    444         }
    445         iCur = iCls;
    446 #endif
    447     if (iDirection != FX_BIDICLASS_N) {
    448       iCls = iDirection;
    449     }
    450     if (iCur != FX_BIDICLASS_BN) {
    451       classes.SetAt(i, iCls);
    452     }
    453     levels.SetAt(i, iBaseLevel);
    454   }
    455   return i - iStart;
    456 }
    457 const int32_t gc_FX_BidiWeakStates[][10] = {
    458     {FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWSxa,
    459      FX_BWSao, FX_BWSao, FX_BWSao},
    460     {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSxr,
    461      FX_BWSro, FX_BWSro, FX_BWSrt},
    462     {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSxl,
    463      FX_BWSlo, FX_BWSlo, FX_BWSlt},
    464     {FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWSao,
    465      FX_BWSao, FX_BWSao, FX_BWSao},
    466     {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSro,
    467      FX_BWSro, FX_BWSro, FX_BWSrt},
    468     {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlo,
    469      FX_BWSlo, FX_BWSlo, FX_BWSlt},
    470     {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSrt,
    471      FX_BWSro, FX_BWSro, FX_BWSrt},
    472     {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlt,
    473      FX_BWSlo, FX_BWSlo, FX_BWSlt},
    474     {FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWScn,
    475      FX_BWSac, FX_BWSao, FX_BWSao},
    476     {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSra,
    477      FX_BWSrc, FX_BWSro, FX_BWSrt},
    478     {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSre,
    479      FX_BWSrs, FX_BWSrs, FX_BWSret},
    480     {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSla,
    481      FX_BWSlc, FX_BWSlo, FX_BWSlt},
    482     {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSle,
    483      FX_BWSls, FX_BWSls, FX_BWSlet},
    484     {FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWSao,
    485      FX_BWSao, FX_BWSao, FX_BWSao},
    486     {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSro,
    487      FX_BWSro, FX_BWSro, FX_BWSrt},
    488     {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSro,
    489      FX_BWSro, FX_BWSro, FX_BWSrt},
    490     {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlo,
    491      FX_BWSlo, FX_BWSlo, FX_BWSlt},
    492     {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlo,
    493      FX_BWSlo, FX_BWSlo, FX_BWSlt},
    494     {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSret,
    495      FX_BWSro, FX_BWSro, FX_BWSret},
    496     {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlet,
    497      FX_BWSlo, FX_BWSlo, FX_BWSlet},
    498 };
    499 const int32_t gc_FX_BidiWeakActions[][10] = {
    500     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR,
    501      FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN},
    502     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
    503      FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
    504     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
    505      FX_BWAxxL, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
    506     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR,
    507      FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN},
    508     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
    509      FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
    510     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
    511      FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
    512     {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAExE, FX_BWANxR,
    513      FX_BWAxIx, FX_BWANxN, FX_BWANxN, FX_BWAxIx},
    514     {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWALxL, FX_BWANxR,
    515      FX_BWAxIx, FX_BWANxN, FX_BWANxN, FX_BWAxIx},
    516     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR,
    517      FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxxN},
    518     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
    519      FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxIx},
    520     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
    521      FX_BWAxxE, FX_BWAxIx, FX_BWAxIx, FX_BWAxxE},
    522     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
    523      FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxIx},
    524     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
    525      FX_BWAxxL, FX_BWAxIx, FX_BWAxIx, FX_BWAxxL},
    526     {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWAAxA, FX_BWANxR,
    527      FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANxN},
    528     {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWANxE, FX_BWANxR,
    529      FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
    530     {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAExE, FX_BWANxR,
    531      FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
    532     {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWANxL, FX_BWANxR,
    533      FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
    534     {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWALxL, FX_BWANxR,
    535      FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
    536     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
    537      FX_BWAxxE, FX_BWAxxN, FX_BWAxxN, FX_BWAxxE},
    538     {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
    539      FX_BWAxxL, FX_BWAxxN, FX_BWAxxN, FX_BWAxxL},
    540 };
    541 void FX_BidiResolveWeak(int32_t iBaseLevel,
    542                         CFX_Int32Array& classes,
    543                         CFX_Int32Array& levels) {
    544   FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
    545   FXSYS_assert(classes.GetSize() == levels.GetSize());
    546   int32_t iSize = classes.GetSize();
    547   if (iSize < 1) {
    548     return;
    549   }
    550   iSize--;
    551   int32_t iLevelCur = iBaseLevel;
    552   int32_t iState = FX_IsOdd(iBaseLevel) ? FX_BWSxr : FX_BWSxl;
    553   int32_t i = 0, iCount = 0, iClsCur, iClsRun, iClsNew, iAction;
    554   for (; i <= iSize; i++) {
    555     iClsCur = classes.GetAt(i);
    556 #if 0
    557         if (iClsCur == FX_BIDICLASS_BN) {
    558             levels.SetAt(i, iLevelCur);
    559             if (i == iSize && iLevelCur != iBaseLevel) {
    560                 iClsCur = FX_BidiDirection(iLevelCur);
    561                 classes.SetAt(i, iClsCur);
    562             } else if (i < iSize) {
    563                 int32_t iLevelNext, iLevelNew;
    564                 iClsNew = classes.GetAt(i + 1);
    565                 iLevelNext = levels.GetAt(i + 1);
    566                 if (iClsNew != FX_BIDICLASS_BN && iLevelCur != iLevelNext) {
    567                     iLevelNew = iLevelNext;
    568                     if (iLevelCur > iLevelNew) {
    569                         iLevelNew = iLevelCur;
    570                     }
    571                     levels.SetAt(i, iLevelNew);
    572                     iClsCur = FX_BidiDirection(iLevelNew);
    573                     classes.SetAt(i, iClsCur);
    574                     iLevelCur = iLevelNext;
    575                 } else {
    576                     if (iCount) {
    577                         iCount ++;
    578                     }
    579                     continue;
    580                 }
    581             } else {
    582                 if (iCount) {
    583                     iCount ++;
    584                 }
    585                 continue;
    586             }
    587         }
    588 #endif
    589     FXSYS_assert(iClsCur <= FX_BIDICLASS_BN);
    590     iAction = gc_FX_BidiWeakActions[iState][iClsCur];
    591     iClsRun = FX_BidiGetDeferredType(iAction);
    592     if (iClsRun != FX_BIDIWEAKACTION_XX && iCount > 0) {
    593       FX_BidiSetDeferredRun(classes, i, iCount, iClsRun);
    594       iCount = 0;
    595     }
    596     iClsNew = FX_BidiGetResolvedType(iAction);
    597     if (iClsNew != FX_BIDIWEAKACTION_XX) {
    598       classes.SetAt(i, iClsNew);
    599     }
    600     if (FX_BIDIWEAKACTION_IX & iAction) {
    601       iCount++;
    602     }
    603     iState = gc_FX_BidiWeakStates[iState][iClsCur];
    604   }
    605   iClsCur = FX_BidiDirection(iLevelCur);
    606   iClsRun = FX_BidiGetDeferredType(gc_FX_BidiWeakActions[iState][iClsCur]);
    607   if (iClsRun != FX_BIDIWEAKACTION_XX && iCount > 0) {
    608     FX_BidiSetDeferredRun(classes, i, iCount, iClsRun);
    609   }
    610 }
    611 const int32_t gc_FX_BidiNeutralStates[][5] = {
    612     {FX_BNSrn, FX_BNSl, FX_BNSr, FX_BNSr, FX_BNSr},
    613     {FX_BNSln, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl},
    614     {FX_BNSrn, FX_BNSl, FX_BNSr, FX_BNSr, FX_BNSr},
    615     {FX_BNSln, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl},
    616     {FX_BNSna, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl},
    617     {FX_BNSna, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl},
    618 };
    619 const int32_t gc_FX_BidiNeutralActions[][5] = {
    620     {FX_BNAIn, 0, 0, 0, 0},
    621     {FX_BNAIn, 0, 0, 0, FX_BCL},
    622     {FX_BNAIn, FX_BNAEn, FX_BNARn, FX_BNARn, FX_BNARn},
    623     {FX_BNAIn, FX_BNALn, FX_BNAEn, FX_BNAEn, FX_BNALnL},
    624     {FX_BNAIn, 0, 0, 0, FX_BCL},
    625     {FX_BNAIn, FX_BNAEn, FX_BNARn, FX_BNARn, FX_BNAEn},
    626 };
    627 int32_t FX_BidiGetDeferredNeutrals(int32_t iAction, int32_t iLevel) {
    628   iAction = (iAction >> 4) & 0xF;
    629   if (iAction == (FX_BIDINEUTRALACTION_En >> 4)) {
    630     return FX_BidiDirection(iLevel);
    631   } else {
    632     return iAction;
    633   }
    634 }
    635 int32_t FX_BidiGetResolvedNeutrals(int32_t iAction) {
    636   iAction = (iAction & 0xF);
    637   if (iAction == FX_BIDINEUTRALACTION_In) {
    638     return 0;
    639   } else {
    640     return iAction;
    641   }
    642 }
    643 void FX_BidiResolveNeutrals(int32_t iBaseLevel,
    644                             CFX_Int32Array& classes,
    645                             const CFX_Int32Array& levels) {
    646   FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
    647   FXSYS_assert(classes.GetSize() == levels.GetSize());
    648   int32_t iSize = classes.GetSize();
    649   if (iSize < 1) {
    650     return;
    651   }
    652   iSize--;
    653   int32_t iLevel = iBaseLevel;
    654   int32_t iState = FX_IsOdd(iBaseLevel) ? FX_BNSr : FX_BNSl;
    655   int32_t i = 0, iCount = 0, iClsCur, iClsRun, iClsNew, iAction;
    656   for (; i <= iSize; i++) {
    657     iClsCur = classes.GetAt(i);
    658     if (iClsCur == FX_BIDICLASS_BN) {
    659       if (iCount) {
    660         iCount++;
    661       }
    662       continue;
    663     }
    664     FXSYS_assert(iClsCur < FX_BIDICLASS_AL);
    665     iAction = gc_FX_BidiNeutralActions[iState][iClsCur];
    666     iClsRun = FX_BidiGetDeferredNeutrals(iAction, iLevel);
    667     if (iClsRun != FX_BIDICLASS_N && iCount > 0) {
    668       FX_BidiSetDeferredRun(classes, i, iCount, iClsRun);
    669       iCount = 0;
    670     }
    671     iClsNew = FX_BidiGetResolvedNeutrals(iAction);
    672     if (iClsNew != FX_BIDICLASS_N) {
    673       classes.SetAt(i, iClsNew);
    674     }
    675     if (FX_BIDINEUTRALACTION_In & iAction) {
    676       iCount++;
    677     }
    678     iState = gc_FX_BidiNeutralStates[iState][iClsCur];
    679     iLevel = levels.GetAt(i);
    680   }
    681   iClsCur = FX_BidiDirection(iLevel);
    682   iClsRun = FX_BidiGetDeferredNeutrals(
    683       gc_FX_BidiNeutralActions[iState][iClsCur], iLevel);
    684   if (iClsRun != FX_BIDICLASS_N && iCount > 0) {
    685     FX_BidiSetDeferredRun(classes, i, iCount, iClsRun);
    686   }
    687 }
    688 const int32_t gc_FX_BidiAddLevel[][4] = {
    689     {0, 1, 2, 2},
    690     {1, 0, 1, 1},
    691 };
    692 void FX_BidiResolveImplicit(const CFX_Int32Array& classes,
    693                             CFX_Int32Array& levels) {
    694   FXSYS_assert(classes.GetSize() == levels.GetSize());
    695   int32_t iSize = classes.GetSize();
    696   if (iSize < 1) {
    697     return;
    698   }
    699   iSize--;
    700   int32_t iCls, iLevel;
    701   for (int32_t i = 0; i <= iSize; i++) {
    702     iCls = classes.GetAt(i);
    703     if (iCls == FX_BIDICLASS_BN) {
    704       continue;
    705     }
    706     FXSYS_assert(iCls > FX_BIDICLASS_ON && iCls < FX_BIDICLASS_AL);
    707     iLevel = levels.GetAt(i);
    708     iLevel += gc_FX_BidiAddLevel[FX_IsOdd(iLevel)][iCls - 1];
    709     levels.SetAt(i, iLevel);
    710   }
    711 }
    712 void FX_BidiResolveWhitespace(int32_t iBaseLevel,
    713                               const CFX_Int32Array& classes,
    714                               CFX_Int32Array& levels) {
    715   FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
    716   FXSYS_assert(classes.GetSize() == levels.GetSize());
    717   int32_t iSize = classes.GetSize();
    718   if (iSize < 1) {
    719     return;
    720   }
    721   iSize--;
    722   int32_t iLevel = iBaseLevel;
    723   int32_t i = 0, iCount = 0;
    724   for (; i <= iSize; i++) {
    725     switch (classes.GetAt(i)) {
    726       case FX_BIDICLASS_WS:
    727         iCount++;
    728         break;
    729       case FX_BIDICLASS_RLE:
    730       case FX_BIDICLASS_LRE:
    731       case FX_BIDICLASS_LRO:
    732       case FX_BIDICLASS_RLO:
    733       case FX_BIDICLASS_PDF:
    734       case FX_BIDICLASS_BN:
    735         levels.SetAt(i, iLevel);
    736         iCount++;
    737         break;
    738       case FX_BIDICLASS_S:
    739       case FX_BIDICLASS_B:
    740         if (iCount > 0) {
    741           FX_BidiSetDeferredRun(levels, i, iCount, iBaseLevel);
    742         }
    743         levels.SetAt(i, iBaseLevel);
    744         iCount = 0;
    745         break;
    746       default:
    747         iCount = 0;
    748         break;
    749     }
    750     iLevel = levels.GetAt(i);
    751   }
    752   if (iCount > 0) {
    753     FX_BidiSetDeferredRun(levels, i, iCount, iBaseLevel);
    754   }
    755 }
    756 int32_t FX_BidiReorderLevel(int32_t iBaseLevel,
    757                             CFX_WideString& wsText,
    758                             const CFX_Int32Array& levels,
    759                             int32_t iStart,
    760                             FX_BOOL bReverse) {
    761   FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
    762   FXSYS_assert(wsText.GetLength() == levels.GetSize());
    763   FXSYS_assert(iStart >= 0 && iStart < wsText.GetLength());
    764   int32_t iSize = wsText.GetLength();
    765   if (iSize < 1) {
    766     return 0;
    767   }
    768   bReverse = bReverse || FX_IsOdd(iBaseLevel);
    769   int32_t i = iStart, iLevel;
    770   for (; i < iSize; i++) {
    771     if ((iLevel = levels.GetAt(i)) == iBaseLevel) {
    772       continue;
    773     }
    774     if (iLevel < iBaseLevel) {
    775       break;
    776     }
    777     i += FX_BidiReorderLevel(iBaseLevel + 1, wsText, levels, i, bReverse) - 1;
    778   }
    779   int32_t iCount = i - iStart;
    780   if (bReverse && iCount > 1) {
    781     FX_BidiReverseString(wsText, iStart, iCount);
    782   }
    783   return iCount;
    784 }
    785 void FX_BidiReorder(int32_t iBaseLevel,
    786                     CFX_WideString& wsText,
    787                     const CFX_Int32Array& levels) {
    788   FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
    789   FXSYS_assert(wsText.GetLength() == levels.GetSize());
    790   int32_t iSize = wsText.GetLength();
    791   if (iSize < 1) {
    792     return;
    793   }
    794   int32_t i = 0;
    795   while (i < iSize) {
    796     i += FX_BidiReorderLevel(iBaseLevel, wsText, levels, i, FALSE);
    797   }
    798 }
    799 void FX_BidiLine(CFX_WideString& wsText, int32_t iBaseLevel) {
    800   int32_t iLength = wsText.GetLength();
    801   if (iLength < 2) {
    802     return;
    803   }
    804   CFX_Int32Array classes, levels;
    805   classes.SetAtGrow(iLength - 1, 0);
    806   levels.SetAtGrow(iLength - 1, 0);
    807   FX_BidiClassify(wsText, classes, FALSE);
    808   FX_BidiResolveExplicit(iBaseLevel, FX_BIDICLASS_N, classes, levels, 0,
    809                          iLength, 0);
    810   FX_BidiResolveWeak(iBaseLevel, classes, levels);
    811   FX_BidiResolveNeutrals(iBaseLevel, classes, levels);
    812   FX_BidiResolveImplicit(classes, levels);
    813   FX_BidiClassify(wsText, classes, TRUE);
    814   FX_BidiResolveWhitespace(iBaseLevel, classes, levels);
    815   FX_BidiReorder(iBaseLevel, wsText, levels);
    816   classes.RemoveAll();
    817   levels.RemoveAll();
    818 }
    819 template <class baseType>
    820 class CFX_BidiLineTemplate {
    821  public:
    822   void FX_BidiReverseString(CFX_ArrayTemplate<baseType>& chars,
    823                             int32_t iStart,
    824                             int32_t iCount) {
    825     FXSYS_assert(iStart > -1 && iStart < chars.GetSize());
    826     FXSYS_assert(iCount >= 0 && iStart + iCount <= chars.GetSize());
    827     baseType *pStart, *pEnd;
    828     int32_t iEnd = iStart + iCount - 1, iTemp;
    829     while (iStart < iEnd) {
    830       pStart = chars.GetDataPtr(iStart++);
    831       pEnd = chars.GetDataPtr(iEnd--);
    832       iTemp = pStart->m_iBidiPos;
    833       pStart->m_iBidiPos = pEnd->m_iBidiPos;
    834       pEnd->m_iBidiPos = iTemp;
    835     }
    836   }
    837   void FX_BidiSetDeferredRun(CFX_ArrayTemplate<baseType>& chars,
    838                              FX_BOOL bClass,
    839                              int32_t iStart,
    840                              int32_t iCount,
    841                              int32_t iValue) {
    842     FXSYS_assert(iStart > -1 && iStart <= chars.GetSize());
    843     FXSYS_assert(iStart - iCount > -1);
    844     baseType* pTC;
    845     int32_t iLast = iStart - iCount;
    846     if (bClass) {
    847       for (int32_t i = iStart - 1; i >= iLast; i--) {
    848         pTC = chars.GetDataPtr(i);
    849         pTC->m_iBidiClass = (int16_t)iValue;
    850       }
    851     } else {
    852       for (int32_t i = iStart - 1; i >= iLast; i--) {
    853         pTC = chars.GetDataPtr(i);
    854         pTC->m_iBidiLevel = (int16_t)iValue;
    855       }
    856     }
    857   }
    858   void FX_BidiClassify(CFX_ArrayTemplate<baseType>& chars,
    859                        int32_t iCount,
    860                        FX_BOOL bWS) {
    861     FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
    862     baseType* pTC;
    863     if (bWS) {
    864       for (int32_t i = 0; i < iCount; i++) {
    865         pTC = chars.GetDataPtr(i);
    866         pTC->m_iBidiClass =
    867             (int16_t)(pTC->m_dwCharProps & FX_BIDICLASSBITSMASK) >>
    868             FX_BIDICLASSBITS;
    869       }
    870     } else {
    871       for (int32_t i = 0; i < iCount; i++) {
    872         pTC = chars.GetDataPtr(i);
    873         pTC->m_iBidiClass = (int16_t)
    874             gc_FX_BidiNTypes[(pTC->m_dwCharProps & FX_BIDICLASSBITSMASK) >>
    875                              FX_BIDICLASSBITS];
    876       }
    877     }
    878   }
    879   void FX_BidiResolveExplicit(CFX_ArrayTemplate<baseType>& chars,
    880                               int32_t iCount,
    881                               int32_t iBaseLevel) {
    882     FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
    883     FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
    884     if (iCount < 1) {
    885       return;
    886     }
    887     baseType* pTC;
    888     for (int32_t i = 0; i < iCount; i++) {
    889       pTC = chars.GetDataPtr(i);
    890       pTC->m_iBidiLevel = (int16_t)iBaseLevel;
    891     }
    892   }
    893   void FX_BidiResolveWeak(CFX_ArrayTemplate<baseType>& chars,
    894                           int32_t iCount,
    895                           int32_t iBaseLevel) {
    896     FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
    897     iCount--;
    898     if (iCount < 1) {
    899       return;
    900     }
    901     baseType *pTC, *pTCNext;
    902     int32_t iLevelCur = iBaseLevel;
    903     int32_t iState = FX_IsOdd(iBaseLevel) ? FX_BWSxr : FX_BWSxl;
    904     int32_t i = 0, iNum = 0, iClsCur, iClsRun, iClsNew, iAction;
    905     for (; i <= iCount; i++) {
    906       pTC = chars.GetDataPtr(i);
    907       iClsCur = pTC->m_iBidiClass;
    908       if (iClsCur == FX_BIDICLASS_BN) {
    909         pTC->m_iBidiLevel = (int16_t)iLevelCur;
    910         if (i == iCount && iLevelCur != iBaseLevel) {
    911           iClsCur = FX_BidiDirection(iLevelCur);
    912           pTC->m_iBidiClass = (int16_t)iClsCur;
    913         } else if (i < iCount) {
    914           pTCNext = chars.GetDataPtr(i + 1);
    915           int32_t iLevelNext, iLevelNew;
    916           iClsNew = pTCNext->m_iBidiClass;
    917           iLevelNext = pTCNext->m_iBidiLevel;
    918           if (iClsNew != FX_BIDICLASS_BN && iLevelCur != iLevelNext) {
    919             iLevelNew = iLevelNext;
    920             if (iLevelCur > iLevelNew) {
    921               iLevelNew = iLevelCur;
    922             }
    923             pTC->m_iBidiLevel = (int16_t)iLevelNew;
    924             iClsCur = FX_BidiDirection(iLevelNew);
    925             pTC->m_iBidiClass = (int16_t)iClsCur;
    926             iLevelCur = iLevelNext;
    927           } else {
    928             if (iNum > 0) {
    929               iNum++;
    930             }
    931             continue;
    932           }
    933         } else {
    934           if (iNum > 0) {
    935             iNum++;
    936           }
    937           continue;
    938         }
    939       }
    940       FXSYS_assert(iClsCur <= FX_BIDICLASS_BN);
    941       iAction = gc_FX_BidiWeakActions[iState][iClsCur];
    942       iClsRun = FX_BidiGetDeferredType(iAction);
    943       if (iClsRun != FX_BIDIWEAKACTION_XX && iNum > 0) {
    944         FX_BidiSetDeferredRun(chars, TRUE, i, iNum, iClsRun);
    945         iNum = 0;
    946       }
    947       iClsNew = FX_BidiGetResolvedType(iAction);
    948       if (iClsNew != FX_BIDIWEAKACTION_XX) {
    949         pTC->m_iBidiClass = (int16_t)iClsNew;
    950       }
    951       if (FX_BIDIWEAKACTION_IX & iAction) {
    952         iNum++;
    953       }
    954       iState = gc_FX_BidiWeakStates[iState][iClsCur];
    955     }
    956     if (iNum > 0) {
    957       iClsCur = FX_BidiDirection(iBaseLevel);
    958       iClsRun = FX_BidiGetDeferredType(gc_FX_BidiWeakActions[iState][iClsCur]);
    959       if (iClsRun != FX_BIDIWEAKACTION_XX) {
    960         FX_BidiSetDeferredRun(chars, TRUE, i, iNum, iClsRun);
    961       }
    962     }
    963   }
    964   void FX_BidiResolveNeutrals(CFX_ArrayTemplate<baseType>& chars,
    965                               int32_t iCount,
    966                               int32_t iBaseLevel) {
    967     FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
    968     FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
    969     iCount--;
    970     if (iCount < 1) {
    971       return;
    972     }
    973     baseType* pTC;
    974     int32_t iLevel = iBaseLevel;
    975     int32_t iState = FX_IsOdd(iBaseLevel) ? FX_BNSr : FX_BNSl;
    976     int32_t i = 0, iNum = 0, iClsCur, iClsRun, iClsNew, iAction;
    977     for (; i <= iCount; i++) {
    978       pTC = chars.GetDataPtr(i);
    979       iClsCur = pTC->m_iBidiClass;
    980       if (iClsCur == FX_BIDICLASS_BN) {
    981         if (iNum) {
    982           iNum++;
    983         }
    984         continue;
    985       }
    986       FXSYS_assert(iClsCur < FX_BIDICLASS_AL);
    987       iAction = gc_FX_BidiNeutralActions[iState][iClsCur];
    988       iClsRun = FX_BidiGetDeferredNeutrals(iAction, iLevel);
    989       if (iClsRun != FX_BIDICLASS_N && iNum > 0) {
    990         FX_BidiSetDeferredRun(chars, TRUE, i, iNum, iClsRun);
    991         iNum = 0;
    992       }
    993       iClsNew = FX_BidiGetResolvedNeutrals(iAction);
    994       if (iClsNew != FX_BIDICLASS_N) {
    995         pTC->m_iBidiClass = (int16_t)iClsNew;
    996       }
    997       if (FX_BIDINEUTRALACTION_In & iAction) {
    998         iNum++;
    999       }
   1000       iState = gc_FX_BidiNeutralStates[iState][iClsCur];
   1001       iLevel = pTC->m_iBidiLevel;
   1002     }
   1003     if (iNum > 0) {
   1004       iClsCur = FX_BidiDirection(iLevel);
   1005       iClsRun = FX_BidiGetDeferredNeutrals(
   1006           gc_FX_BidiNeutralActions[iState][iClsCur], iLevel);
   1007       if (iClsRun != FX_BIDICLASS_N) {
   1008         FX_BidiSetDeferredRun(chars, TRUE, i, iNum, iClsRun);
   1009       }
   1010     }
   1011   }
   1012   void FX_BidiResolveImplicit(CFX_ArrayTemplate<baseType>& chars,
   1013                               int32_t iCount) {
   1014     FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
   1015     baseType* pTC;
   1016     int32_t iCls, iLevel;
   1017     for (int32_t i = 0; i < iCount; i++) {
   1018       pTC = chars.GetDataPtr(i);
   1019       iCls = pTC->m_iBidiClass;
   1020       if (iCls == FX_BIDICLASS_BN) {
   1021         continue;
   1022       }
   1023       FXSYS_assert(iCls > FX_BIDICLASS_ON && iCls < FX_BIDICLASS_AL);
   1024       iLevel = pTC->m_iBidiLevel;
   1025       iLevel += gc_FX_BidiAddLevel[FX_IsOdd(iLevel)][iCls - 1];
   1026       pTC->m_iBidiLevel = (int16_t)iLevel;
   1027     }
   1028   }
   1029   void FX_BidiResolveWhitespace(CFX_ArrayTemplate<baseType>& chars,
   1030                                 int32_t iCount,
   1031                                 int32_t iBaseLevel) {
   1032     FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
   1033     FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
   1034     if (iCount < 1) {
   1035       return;
   1036     }
   1037     iCount--;
   1038     int32_t iLevel = iBaseLevel;
   1039     int32_t i = 0, iNum = 0;
   1040     baseType* pTC;
   1041     for (; i <= iCount; i++) {
   1042       pTC = chars.GetDataPtr(i);
   1043       switch (pTC->m_iBidiClass) {
   1044         case FX_BIDICLASS_WS:
   1045           iNum++;
   1046           break;
   1047         case FX_BIDICLASS_RLE:
   1048         case FX_BIDICLASS_LRE:
   1049         case FX_BIDICLASS_LRO:
   1050         case FX_BIDICLASS_RLO:
   1051         case FX_BIDICLASS_PDF:
   1052         case FX_BIDICLASS_BN:
   1053           pTC->m_iBidiLevel = (int16_t)iLevel;
   1054           iNum++;
   1055           break;
   1056         case FX_BIDICLASS_S:
   1057         case FX_BIDICLASS_B:
   1058           if (iNum > 0) {
   1059             FX_BidiSetDeferredRun(chars, FALSE, i, iNum, iBaseLevel);
   1060           }
   1061           pTC->m_iBidiLevel = (int16_t)iBaseLevel;
   1062           iNum = 0;
   1063           break;
   1064         default:
   1065           iNum = 0;
   1066           break;
   1067       }
   1068       iLevel = pTC->m_iBidiLevel;
   1069     }
   1070     if (iNum > 0) {
   1071       FX_BidiSetDeferredRun(chars, FALSE, i, iNum, iBaseLevel);
   1072     }
   1073   }
   1074   int32_t FX_BidiReorderLevel(CFX_ArrayTemplate<baseType>& chars,
   1075                               int32_t iCount,
   1076                               int32_t iBaseLevel,
   1077                               int32_t iStart,
   1078                               FX_BOOL bReverse) {
   1079     FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
   1080     FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
   1081     FXSYS_assert(iStart >= 0 && iStart < iCount);
   1082     if (iCount < 1) {
   1083       return 0;
   1084     }
   1085     baseType* pTC;
   1086     bReverse = bReverse || FX_IsOdd(iBaseLevel);
   1087     int32_t i = iStart, iLevel;
   1088     for (; i < iCount; i++) {
   1089       pTC = chars.GetDataPtr(i);
   1090       if ((iLevel = pTC->m_iBidiLevel) == iBaseLevel) {
   1091         continue;
   1092       }
   1093       if (iLevel < iBaseLevel) {
   1094         break;
   1095       }
   1096       i += FX_BidiReorderLevel(chars, iCount, iBaseLevel + 1, i, bReverse) - 1;
   1097     }
   1098     int32_t iNum = i - iStart;
   1099     if (bReverse && iNum > 1) {
   1100       FX_BidiReverseString(chars, iStart, iNum);
   1101     }
   1102     return iNum;
   1103   }
   1104   void FX_BidiReorder(CFX_ArrayTemplate<baseType>& chars,
   1105                       int32_t iCount,
   1106                       int32_t iBaseLevel) {
   1107     FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
   1108     FXSYS_assert(iBaseLevel >= 0 && iBaseLevel <= FX_BIDIMAXLEVEL);
   1109     int32_t i = 0;
   1110     while (i < iCount) {
   1111       i += FX_BidiReorderLevel(chars, iCount, iBaseLevel, i, FALSE);
   1112     }
   1113   }
   1114   void FX_BidiPosition(CFX_ArrayTemplate<baseType>& chars, int32_t iCount) {
   1115     FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
   1116     baseType* pTC;
   1117     int32_t i = 0;
   1118     while (i < iCount) {
   1119       pTC = chars.GetDataPtr(i);
   1120       pTC = chars.GetDataPtr(pTC->m_iBidiPos);
   1121       pTC->m_iBidiOrder = i++;
   1122     }
   1123   }
   1124 
   1125   void FX_BidiLine(CFX_ArrayTemplate<baseType>& chars,
   1126                    int32_t iCount,
   1127                    int32_t iBaseLevel) {
   1128     FXSYS_assert(iCount > -1 && iCount <= chars.GetSize());
   1129     if (iCount < 2) {
   1130       return;
   1131     }
   1132     FX_BidiClassify(chars, iCount, FALSE);
   1133     FX_BidiResolveExplicit(chars, iCount, iBaseLevel);
   1134     FX_BidiResolveWeak(chars, iCount, iBaseLevel);
   1135     FX_BidiResolveNeutrals(chars, iCount, iBaseLevel);
   1136     FX_BidiResolveImplicit(chars, iCount);
   1137     FX_BidiClassify(chars, iCount, TRUE);
   1138     FX_BidiResolveWhitespace(chars, iCount, iBaseLevel);
   1139     FX_BidiReorder(chars, iCount, iBaseLevel);
   1140     FX_BidiPosition(chars, iCount);
   1141   }
   1142 };
   1143 void FX_BidiLine(CFX_TxtCharArray& chars, int32_t iCount, int32_t iBaseLevel) {
   1144   CFX_BidiLineTemplate<CFX_TxtChar> blt;
   1145   blt.FX_BidiLine(chars, iCount, iBaseLevel);
   1146 }
   1147 void FX_BidiLine(CFX_RTFCharArray& chars, int32_t iCount, int32_t iBaseLevel) {
   1148   CFX_BidiLineTemplate<CFX_RTFChar> blt;
   1149   blt.FX_BidiLine(chars, iCount, iBaseLevel);
   1150 }
   1151