Back to index

lightning-sunbird  0.9+nobinonly
nsBidiUtils.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * IBM Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2000
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Maha Abou El Rous <mahar@eg.ibm.com>
00025  *   Lina Kemmel <lkemmel@il.ibm.com>
00026  *   Simon Montagu <smontagu@netscape.com>
00027  *   Roozbeh Pournader <roozbeh@sharif.edu>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either of the GNU General Public License Version 2 or later (the "GPL"),
00031  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 #include "nsBidiUtils.h"
00043 
00044 #define FE_TO_06_OFFSET 0xfe70
00045 
00046 static const PRUnichar FE_TO_06 [][2] = {
00047     {0x064b,0x0000},{0x064b,0x0640},{0x064c,0x0000},
00048     {0x0000,0x0000},{0x064d,0x0000},{0x0000,0x0000},
00049     {0x064e,0x0000},{0x064e,0x0640},{0x064f,0x0000},
00050     {0x064f,0x0640},{0x0650,0x0000},{0x0650,0x0640},
00051     {0x0651,0x0000},{0x0651,0x0640},{0x0652,0x0000},
00052     {0x0652,0x0640},{0x0621,0x0000},{0x0622,0x0000},
00053     {0x0622,0x0000},{0x0623,0x0000},{0x0623,0x0000},
00054     {0x0624,0x0000},{0x0624,0x0000},{0x0625,0x0000},
00055     {0x0625,0x0000},{0x0626,0x0000},{0x0626,0x0000},
00056     {0x0626,0x0000},{0x0626,0x0000},{0x0627,0x0000},
00057     {0x0627,0x0000},{0x0628,0x0000},{0x0628,0x0000},
00058     {0x0628,0x0000},{0x0628,0x0000},{0x0629,0x0000},
00059     {0x0629,0x0000},{0x062a,0x0000},{0x062a,0x0000},
00060     {0x062a,0x0000},{0x062a,0x0000},{0x062b,0x0000},
00061     {0x062b,0x0000},{0x062b,0x0000},{0x062b,0x0000},
00062     {0x062c,0x0000},{0x062c,0x0000},{0x062c,0x0000},
00063     {0x062c,0x0000},{0x062d,0x0000},{0x062d,0x0000},
00064     {0x062d,0x0000},{0x062d,0x0000},{0x062e,0x0000},
00065     {0x062e,0x0000},{0x062e,0x0000},{0x062e,0x0000},
00066     {0x062f,0x0000},{0x062f,0x0000},{0x0630,0x0000},
00067     {0x0630,0x0000},{0x0631,0x0000},{0x0631,0x0000},
00068     {0x0632,0x0000},{0x0632,0x0000},{0x0633,0x0000},
00069     {0x0633,0x0000},{0x0633,0x0000},{0x0633,0x0000},
00070     {0x0634,0x0000},{0x0634,0x0000},{0x0634,0x0000},
00071     {0x0634,0x0000},{0x0635,0x0000},{0x0635,0x0000},
00072     {0x0635,0x0000},{0x0635,0x0000},{0x0636,0x0000},
00073     {0x0636,0x0000},{0x0636,0x0000},{0x0636,0x0000},
00074     {0x0637,0x0000},{0x0637,0x0000},{0x0637,0x0000},
00075     {0x0637,0x0000},{0x0638,0x0000},{0x0638,0x0000},
00076     {0x0638,0x0000},{0x0638,0x0000},{0x0639,0x0000},
00077     {0x0639,0x0000},{0x0639,0x0000},{0x0639,0x0000},
00078     {0x063a,0x0000},{0x063a,0x0000},{0x063a,0x0000},
00079     {0x063a,0x0000},{0x0641,0x0000},{0x0641,0x0000},
00080     {0x0641,0x0000},{0x0641,0x0000},{0x0642,0x0000},
00081     {0x0642,0x0000},{0x0642,0x0000},{0x0642,0x0000},
00082     {0x0643,0x0000},{0x0643,0x0000},{0x0643,0x0000},
00083     {0x0643,0x0000},{0x0644,0x0000},{0x0644,0x0000},
00084     {0x0644,0x0000},{0x0644,0x0000},{0x0645,0x0000},
00085     {0x0645,0x0000},{0x0645,0x0000},{0x0645,0x0000},
00086     {0x0646,0x0000},{0x0646,0x0000},{0x0646,0x0000},
00087     {0x0646,0x0000},{0x0647,0x0000},{0x0647,0x0000},
00088     {0x0647,0x0000},{0x0647,0x0000},{0x0648,0x0000},
00089     {0x0648,0x0000},{0x0649,0x0000},{0x0649,0x0000},
00090     {0x064a,0x0000},{0x064a,0x0000},{0x064a,0x0000},
00091     {0x064a,0x0000},{0x0644,0x0622},{0x0644,0x0622},
00092     {0x0644,0x0623},{0x0644,0x0623},{0x0644,0x0625},
00093     {0x0644,0x0625},{0x0644,0x0627},{0x0644,0x0627}
00094 };
00095 
00096 static const PRUnichar FB_TO_06 [] = {
00097     0x0671,0x0671,0x067B,0x067B,0x067B,0x067B,0x067E,0x067E, //FB50-FB57
00098     0x067E,0x067E,0x0680,0x0680,0x0680,0x0680,0x067A,0x067A, //FB58-FB5F
00099     0x067A,0x067A,0x067F,0x067F,0x067F,0x067F,0x0679,0x0679, //FB60-FB67
00100     0x0679,0x0679,0x06A4,0x06A4,0x06A4,0x06A4,0x06A6,0x06A6, //FB68-FB6F
00101     0x06A6,0x06A6,0x0684,0x0684,0x0684,0x0684,0x0683,0x0683, //FB70-FB77
00102     0x0683,0x0683,0x0686,0x0686,0x0686,0x0686,0x0687,0x0687, //FB78-FB7F
00103     0x0687,0x0687,0x068D,0x068D,0x068C,0x068C,0x068E,0x068E, //FB80-FB87
00104     0x0688,0x0688,0x0698,0x0698,0x0691,0x0691,0x06A9,0x06A9, //FB88-FB8F
00105     0x06A9,0x06A9,0x06AF,0x06AF,0x06AF,0x06AF,0x06B3,0x06B3, //FB90-FB97
00106     0x06B3,0x06B3,0x06B1,0x06B1,0x06B1,0x06B1,0x06BA,0x06BA, //FB98-FB9F
00107     0x06BB,0x06BB,0x06BB,0x06BB,0x06C0,0x06C0,0x06C1,0x06C1, //FBA0-FBA7
00108     0x06C1,0x06C1,0x06BE,0x06BE,0x06BE,0x06BE,0x06D2,0x06D2, //FBA8-FBAF
00109     0x06D3,0x06D3,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, //FBB0-FBB7
00110     0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, //FBB8-FBBF
00111     0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, //FBC0-FBC7
00112     0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, //FBC8-FBCF
00113     0x0000,0x0000,0x0000,0x06AD,0x06AD,0x06AD,0x06AD,0x06C7, //FBD0-FBD7
00114     0x06C7,0x06C6,0x06C6,0x06C8,0x06C8,0x0677,0x06CB,0x06CB, //FBD8-FBDF
00115     0x06C5,0x06C5,0x06C9,0x06C9,0x06D0,0x06D0,0x06D0,0x06D0, //FBE0-FBE7
00116     0x0649,0x0649,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, //FBE8-FBEF
00117     0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, //FBF0-FBF7
00118     0x0000,0x0000,0x0000,0x0000,0x06CC,0x06CC,0x06CC,0x06CC  //FBF8-FBFF
00119 };
00120 
00121 #define PresentationToOriginal(c, order)                  \
00122     (((0xFE70 <= (c) && (c) <= 0xFEFC)) ?                 \
00123          FE_TO_06[(c)- FE_TO_06_OFFSET][order] :                    \
00124      (((0xFB50 <= (c) && (c) <= 0xFBFF) && (order) == 0) ? \
00125          FB_TO_06[(c)-0xFB50] : (PRUnichar) 0x0000))
00126 
00127 //============ Begin Arabic Basic to Presentation Form B Code ============
00128 // Note: the following code are moved from gfx/src/windows/nsRenderingContextWin.cpp
00129 static const PRUint8 gArabicMap1[] = {
00130             0x81, 0x83, 0x85, 0x87, 0x89, 0x8D, // 0622-0627
00131 0x8F, 0x93, 0x95, 0x99, 0x9D, 0xA1, 0xA5, 0xA9, // 0628-062F
00132 0xAB, 0xAD, 0xAF, 0xB1, 0xB5, 0xB9, 0xBD, 0xC1, // 0630-0637
00133 0xC5, 0xC9, 0xCD                                // 0638-063A
00134 };
00135 
00136 static const PRUint8 gArabicMap2[] = {
00137       0xD1, 0xD5, 0xD9, 0xDD, 0xE1, 0xE5, 0xE9, // 0641-0647
00138 0xED, 0xEF, 0xF1                                // 0648-064A
00139 };
00140 
00141 static const PRUint8 gArabicMapEx[] = {
00142       0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0671-0677
00143 0x00, 0x66, 0x5E, 0x52, 0x00, 0x00, 0x56, 0x62, // 0678-067F
00144 0x5A, 0x00, 0x00, 0x76, 0x72, 0x00, 0x7A, 0x7E, // 0680-0687
00145 0x88, 0x00, 0x00, 0x00, 0x84, 0x82, 0x86, 0x00, // 0688-068F
00146 0x00, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0690-0697
00147 0x8A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0698-069F
00148 0x00, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x6E, 0x00, // 06A0-06A7
00149 0x00, 0x8E, 0x00, 0x00, 0x00, 0xD3, 0x00, 0x92, // 06A8-06AF
00150 0x00, 0x9A, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, // 06B0-06B7
00151 0x00, 0x00, 0x9E, 0xA0, 0x00, 0x00, 0xAA, 0x00, // 06B8-06BF
00152 0xA4, 0xA6, 0x00, 0x00, 0x00, 0xE0, 0xD9, 0xD7, // 06C0-06C7
00153 0xDB, 0xE2, 0x00, 0xDE, 0xFC, 0x00, 0x00, 0x00, // 06C8-06CF
00154 0xE4, 0x00, 0xAE, 0xB0                          // 06D0-06D3
00155 };
00156 
00157 #define PresentationFormB(c, form)                                       \
00158     (((0x0622<=(c)) && ((c)<=0x063A)) ?                                  \
00159       (0xFE00|(gArabicMap1[(c)-0x0622] + (form))) :                      \
00160        (((0x0641<=(c)) && ((c)<=0x064A)) ?                               \
00161         (0xFE00|(gArabicMap2[(c)-0x0641] + (form))) :                    \
00162          (((0x0671<=(c)) && ((c))<=0x06D3) && gArabicMapEx[(c)-0x0671]) ? \
00163           (0xFB00|(gArabicMapEx[(c)-0x0671] + (form))) : (c)))
00164 
00165 typedef enum {
00166    eIsolated,  // or Char N
00167    eFinal,     // or Char R
00168    eInitial,   // or Char L
00169    eMedial     // or Char M
00170 } eArabicForm;
00171 
00172 typedef enum {
00173    eTr = 0, // Transparent
00174    eRJ = 1, // Right-Joining
00175    eLJ = 2, // Left-Joining
00176    eDJ = 3, // Dual-Joining
00177    eNJ = 4, // Non-Joining
00178    eJC = 7, // Joining Causing
00179    eRightJCMask = 2, // bit of Right-Join Causing 
00180    eLeftJCMask = 1   // bit of Left-Join Causing 
00181 } eArabicJoiningClass;
00182 
00183 #define RightJCClass(j) (eRightJCMask&(j))
00184 #define LeftJCClass(j)  (eLeftJCMask&(j))
00185 
00186 #define DecideForm(jl,j,jr)                                 \
00187   (((eRJ == (j)) && RightJCClass(jr)) ? eFinal              \
00188                                       :                     \
00189    ((eDJ == (j)) ?                                          \
00190     ((RightJCClass(jr)) ?                                   \
00191      (((LeftJCClass(jl)) ? eMedial                          \
00192                          : eFinal))                         \
00193                         :                                   \
00194      (((LeftJCClass(jl)) ? eInitial                         \
00195                          : eIsolated))                      \
00196     )                     : eIsolated))                     \
00197 
00198 // All letters without an equivalen in the FB50 block are 'eNJ' here. This
00199 // should be fixed after finding some better mechanism for handling Arabic.
00200 static const PRInt8 gJoiningClass[] = {
00201 eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, // 0600-0607
00202 eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, // 0608-060F
00203 eTr, eTr, eTr, eTr, eTr, eTr, eNJ, eNJ, // 0610-0617
00204 eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, // 0618-061F
00205 eNJ, eNJ, eRJ, eRJ, eRJ, eRJ, eDJ, eRJ, // 0620-0627
00206 eDJ, eRJ, eDJ, eDJ, eDJ, eDJ, eDJ, eRJ, // 0628-062F
00207 eRJ, eRJ, eRJ, eDJ, eDJ, eDJ, eDJ, eDJ, // 0630-0637
00208 eDJ, eDJ, eDJ, eNJ, eNJ, eNJ, eNJ, eNJ, // 0638-063F
00209 eJC, eDJ, eDJ, eDJ, eDJ, eDJ, eDJ, eDJ, // 0640-0647
00210 eRJ, eDJ, eDJ, eTr, eTr, eTr, eTr, eTr, // 0648-064F
00211 eTr, eTr, eTr, eTr, eTr, eTr, eTr, eTr, // 0650-0657
00212 eTr, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, // 0658-065F
00213 eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, // 0660-0667
00214 eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, // 0668-066F
00215 eTr, eRJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, // 0670-0677
00216 eNJ, eDJ, eDJ, eDJ, eNJ, eNJ, eDJ, eDJ, // 0678-067F
00217 eDJ, eNJ, eNJ, eDJ, eDJ, eNJ, eDJ, eDJ, // 0680-0687
00218 eRJ, eNJ, eNJ, eNJ, eRJ, eRJ, eRJ, eNJ, // 0688-068F
00219 eNJ, eRJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, // 0690-0697
00220 eRJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, // 0698-069F
00221 eNJ, eNJ, eNJ, eNJ, eDJ, eNJ, eDJ, eNJ, // 06A0-06A7
00222 eNJ, eDJ, eNJ, eNJ, eNJ, eDJ, eNJ, eDJ, // 06A8-06AF
00223 eNJ, eDJ, eNJ, eDJ, eNJ, eNJ, eNJ, eNJ, // 06B0-06B7
00224 eNJ, eNJ, eDJ, eDJ, eNJ, eNJ, eDJ, eNJ, // 06B8-06BF
00225 eRJ, eDJ, eNJ, eNJ, eNJ, eRJ, eRJ, eRJ, // 06C0-06C7
00226 eRJ, eRJ, eNJ, eRJ, eDJ, eNJ, eNJ, eNJ, // 06C8-06CF
00227 eDJ, eNJ, eRJ, eRJ, eNJ, eNJ, eTr, eTr, // 06D0-06D7
00228 eTr, eTr, eTr, eTr, eTr, eNJ, eNJ, eTr, // 06D8-06DF
00229 eTr, eTr, eTr, eTr, eTr, eNJ, eNJ, eTr, // 06E0-06E7
00230 eTr, eNJ, eTr, eTr, eTr, eTr, eNJ, eNJ, // 06E8-06EF
00231 eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, // 06F0-06F7
00232 eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ, eNJ  // 06F8-06FF
00233 };
00234 
00235 #define GetJoiningClass(c)                   \
00236   ((IS_ARABIC_CHAR(c)) ?                     \
00237       (gJoiningClass[(c) - 0x0600]) :        \
00238       ((0x200D == (c)) ? eJC : eTr))
00239 
00240 static const PRUint16 gArabicLigatureMap[] = 
00241 {
00242 0x82DF, // 0xFE82 0xFEDF -> 0xFEF5
00243 0x82E0, // 0xFE82 0xFEE0 -> 0xFEF6
00244 0x84DF, // 0xFE84 0xFEDF -> 0xFEF7
00245 0x84E0, // 0xFE84 0xFEE0 -> 0xFEF8
00246 0x88DF, // 0xFE88 0xFEDF -> 0xFEF9
00247 0x88E0, // 0xFE88 0xFEE0 -> 0xFEFA
00248 0x8EDF, // 0xFE8E 0xFEDF -> 0xFEFB
00249 0x8EE0  // 0xFE8E 0xFEE0 -> 0xFEFC
00250 };
00251 
00252 #define ARABIC_TO_HINDI_DIGIT_INCREMENT (START_HINDI_DIGITS - START_ARABIC_DIGITS)
00253 #define NUM_TO_ARABIC(c) \
00254   ((((c)>=START_HINDI_DIGITS) && ((c)<=END_HINDI_DIGITS)) ? \
00255    ((c) - (PRUint16)ARABIC_TO_HINDI_DIGIT_INCREMENT) : \
00256    (c))
00257 #define NUM_TO_HINDI(c) \
00258   ((((c)>=START_ARABIC_DIGITS) && ((c)<=END_ARABIC_DIGITS)) ? \
00259    ((c) + (PRUint16)ARABIC_TO_HINDI_DIGIT_INCREMENT): \
00260    (c))
00261 
00262 // helper function to reverse a PRUnichar buffer
00263 static void ReverseString(PRUnichar* aBuffer, PRUint32 aLen)
00264 {
00265   PRUnichar *start, *end;
00266   PRUnichar swapChar;
00267 
00268   for (start = aBuffer, end = aBuffer + aLen - 1; start < end; ++start, --end) {
00269     swapChar = *start;
00270     *start = *end;
00271     *end = swapChar;
00272   }
00273 }
00274 
00275 nsresult ArabicShaping(const PRUnichar* aString, PRUint32 aLen,
00276                        PRUnichar* aBuf, PRUint32 *aBufLen, 
00277                        PRBool aInputLogical, PRBool aOutputLogical)
00278 {
00279   nsAutoString tempString(aString, aLen);
00280   if (tempString.Length() != aLen)
00281     return NS_ERROR_OUT_OF_MEMORY;
00282   PRUnichar *tempBuf = tempString.BeginWriting();
00283   if (aInputLogical) {
00284     ReverseString(tempBuf, aLen);
00285   }
00286   const PRUnichar* src = tempBuf;
00287   const PRUnichar* p;
00288   PRUnichar* dest = aBuf;
00289   PRUnichar formB;
00290   PRInt8 leftJ, thisJ, rightJ;
00291   PRInt8 leftNoTrJ, rightNoTrJ;
00292   thisJ = leftNoTrJ = eNJ;
00293   rightJ = GetJoiningClass(*(src));
00294   while(src<tempBuf+aLen-1) {
00295     leftJ = thisJ;
00296 
00297     if ((eTr != leftJ) || ((leftJ == eTr) && 
00298         ( ( (src-1) >= tempBuf) && !IS_ARABIC_CHAR(*(src-1)))))
00299       leftNoTrJ = thisJ;
00300 
00301     if(src-2 >= (tempBuf)){
00302       for(p=src-2; (p >= (tempBuf))&& (eTr == leftNoTrJ) && (IS_ARABIC_CHAR(*(p+1))) ; p--)  
00303         leftNoTrJ = GetJoiningClass(*(p)) ;
00304     }
00305 
00306     thisJ = rightJ;
00307     rightJ = rightNoTrJ = GetJoiningClass(*(src+1)) ;
00308 
00309     if(src+2 <= (tempBuf+aLen-1)){
00310       for(p=src+2; (p <= (tempBuf+aLen-1))&&(eTr == rightNoTrJ) && (IS_ARABIC_CHAR(*(src+1))); p++)
00311         rightNoTrJ = GetJoiningClass(*(p)) ;
00312     }
00313 
00314     formB = PresentationFormB(*src, DecideForm(leftNoTrJ, thisJ, rightNoTrJ));
00315     *dest++ = formB;
00316     src++;
00317 
00318   }
00319   if((eTr != thisJ) || 
00320      ((thisJ == eTr) && (((src-1)>=tempBuf) && (!IS_ARABIC_CHAR(*(src-1))))))
00321     leftNoTrJ = thisJ;
00322 
00323   if(src-2 >= (tempBuf)){
00324     for(p=src-2; (src-2 >= (tempBuf)) && (eTr == leftNoTrJ) && (IS_ARABIC_CHAR(*(p+1))); p--)
00325       leftNoTrJ = GetJoiningClass(*(p)) ;
00326   }
00327 
00328   formB = PresentationFormB(*src, DecideForm(leftNoTrJ, rightJ, eNJ));
00329   *dest++ = formB;
00330   src++;
00331 
00332   PRUnichar *lSrc = aBuf;
00333   PRUnichar *lDest = aBuf;
00334   while(lSrc < (dest-1)) {
00335     PRUnichar next = *(lSrc+1);
00336     if(((0xFEDF == next) || (0xFEE0 == next)) && 
00337        (0xFE80 == (0xFFF1 & *lSrc))) {
00338       PRBool done = PR_FALSE;
00339       PRUint16 key = ((*lSrc) << 8) | ( 0x00FF & next);
00340       PRUint16 i;
00341       for(i=0;i<8;i++) {
00342         if(key == gArabicLigatureMap[i]) {
00343           done = PR_TRUE;
00344           // lam and alef in the source are mapped to a lam-alef ligature in the
00345           // destination, so lSrc is incremented by 2 here
00346           *lDest++ = 0xFEF5 + i;
00347           lSrc+=2;
00348           break;
00349         }
00350       }
00351       if(! done)
00352         *lDest++ = *lSrc++; 
00353     } else if (0x200C == *lSrc || 0x200D == *lSrc)
00354     // Strip zero-width joining controls ZWJ and ZWNJ from the shaped text
00355       lSrc++;
00356     else 
00357       *lDest++ = *lSrc++; 
00358 
00359   }
00360   if(lSrc < dest)
00361     *lDest++ = *lSrc++; 
00362 
00363   *aBufLen = lDest - aBuf;
00364   NS_ASSERTION(*aBufLen <= aLen, "ArabicShaping() likely did a buffer overflow!");
00365 
00366   if (aOutputLogical) {
00367     ReverseString(aBuf, *aBufLen);
00368   }
00369   return NS_OK;
00370 }
00371 
00372 nsresult Conv_FE_06(const nsString& aSrc, nsString& aDst)
00373 {
00374   PRUnichar *aSrcUnichars = (PRUnichar *)aSrc.get();
00375   PRUint32 i, size = aSrc.Length();
00376   aDst.Truncate();
00377   for (i=0;i<size;i++) { // i : Source
00378     if (aSrcUnichars[i] == 0x0000) 
00379       break; // no need to convert char after the NULL
00380     if (IS_FE_CHAR(aSrcUnichars[i])) {
00381       //ahmed for lamalf
00382       PRUnichar ch = (PresentationToOriginal(aSrcUnichars[i], 1));
00383       if(ch)
00384         aDst += ch;
00385       ch=(PresentationToOriginal(aSrcUnichars[i], 0));
00386       if(ch)
00387         aDst += ch;
00388       else //if it is 00, just output what we have in FExx
00389         aDst += aSrcUnichars[i];
00390     } else {
00391       aDst += aSrcUnichars[i]; // copy it even if it is not in FE range
00392     }
00393   }// for : loop the buffer
00394   return NS_OK;
00395 }
00396 
00397 nsresult Conv_FE_06_WithReverse(const nsString& aSrc, nsString& aDst)
00398 {
00399   PRUnichar *aSrcUnichars = (PRUnichar *)aSrc.get();
00400   PRBool foundArabic = PR_FALSE;
00401   PRUint32 i, endArabic, beginArabic, size;
00402   beginArabic = 0;
00403   size = aSrc.Length();
00404   aDst.Truncate();
00405   for (endArabic=0;endArabic<size;endArabic++) {
00406     if (aSrcUnichars[endArabic] == 0x0000) 
00407       break; // no need to convert char after the NULL
00408 
00409     while( (IS_FE_CHAR(aSrcUnichars[endArabic]))||
00410            (IS_ARABIC_CHAR(aSrcUnichars[endArabic]))||
00411            (IS_ARABIC_DIGIT(aSrcUnichars[endArabic]))||
00412            (aSrcUnichars[endArabic]==0x0020)) 
00413     {
00414       if(! foundArabic ) {
00415         beginArabic=endArabic;
00416         foundArabic= PR_TRUE;
00417       }
00418       endArabic++;
00419     }
00420     if(foundArabic) {
00421       endArabic--;
00422       for (i=endArabic; i>=beginArabic; i--) {
00423         if(IS_FE_CHAR(aSrcUnichars[i])) {
00424           //ahmed for the bug of lamalf
00425           aDst += PresentationToOriginal(aSrcUnichars[i], 0);
00426           if (PresentationToOriginal(aSrcUnichars[i], 1)) {
00427             // Two characters, we have to resize the buffer :(
00428              aDst += PresentationToOriginal(aSrcUnichars[i], 1);
00429           } // if expands to 2 char
00430         } else {
00431           // do we need to check the following if ?
00432           if((IS_ARABIC_CHAR(aSrcUnichars[i]))||
00433              (IS_ARABIC_DIGIT(aSrcUnichars[i]))||
00434              (aSrcUnichars[i]==0x0020))
00435             aDst += aSrcUnichars[i];
00436         }     
00437       }
00438     } else {
00439       aDst += aSrcUnichars[endArabic]; 
00440     }
00441     foundArabic=PR_FALSE;
00442   }// for : loop the buffer
00443   return NS_OK;
00444 }
00445 
00446 nsresult Conv_06_FE_WithReverse(const nsString& aSrc,
00447                                 nsString& aDst,
00448                                 PRUint32 aDir)
00449 {
00450   PRUnichar *aSrcUnichars = (PRUnichar *)aSrc.get();
00451   PRUint32 i, beginArabic, endArabic, size;
00452   beginArabic = 0;
00453   size = aSrc.Length();
00454   aDst.Truncate();
00455   PRBool foundArabic = PR_FALSE;
00456   for (endArabic=0;endArabic<size;endArabic++) {
00457     if (aSrcUnichars[endArabic] == 0x0000) 
00458       break; // no need to convert char after the NULL
00459 
00460     while( (IS_06_CHAR(aSrcUnichars[endArabic])) || 
00461            (IS_ARABIC_CHAR(aSrcUnichars[endArabic])) || 
00462            (aSrcUnichars[endArabic]==0x0020) || 
00463            (IS_ARABIC_DIGIT(aSrcUnichars[endArabic]))  ) 
00464     {
00465       if(! foundArabic) {
00466         beginArabic=endArabic;
00467         foundArabic=PR_TRUE;
00468       }
00469       endArabic++;
00470     }
00471     if(foundArabic) {
00472       endArabic--;
00473       PRUnichar buf[8192];
00474       PRUint32 len=8192;
00475 
00476       ArabicShaping(&aSrcUnichars[beginArabic], endArabic-beginArabic+1,
00477                     buf, &len, 
00478                     PR_TRUE, PR_FALSE);
00479       // to reverse the numerals
00480       PRUint32 endNumeral, beginNumeral = 0;
00481       for (endNumeral=0;endNumeral<=len-1;endNumeral++){
00482         PRBool foundNumeral = PR_FALSE;
00483         while((endNumeral < len) && (IS_ARABIC_DIGIT(buf[endNumeral]))  ) {
00484           if(!foundNumeral)
00485           {
00486             foundNumeral=PR_TRUE;
00487             beginNumeral=endNumeral;
00488           }
00489           endNumeral++;
00490         }
00491         if(foundNumeral){
00492           endNumeral--;
00493           PRUnichar numbuf[20];
00494           for(i=beginNumeral; i<=endNumeral; i++){
00495             numbuf[i-beginNumeral]=buf[endNumeral-i+beginNumeral];
00496           }
00497           for(i=0;i<=endNumeral-beginNumeral;i++){
00498             buf[i+beginNumeral]=numbuf[i];
00499           }
00500         }
00501       }
00502       if(aDir==1){//ltr
00503         for (i=0;i<=len-1;i++){
00504           aDst+= buf[i];
00505         } 
00506       }
00507       else if(aDir==2){//rtl
00508         for (i=0;i<=len-1;i++){
00509           aDst+= buf[len-1-i];
00510         } 
00511       }
00512     } else {
00513       aDst += aSrcUnichars[endArabic];
00514     }
00515     foundArabic=PR_FALSE;
00516   }// for : loop the buffer
00517   return NS_OK;
00518 }
00519 
00520 nsresult HandleNumbers(PRUnichar* aBuffer, PRUint32 aSize, PRUint32 aNumFlag)
00521 {
00522   PRUint32 i;
00523   // IBMBIDI_NUMERAL_NOMINAL *
00524   // IBMBIDI_NUMERAL_REGULAR
00525   // IBMBIDI_NUMERAL_HINDICONTEXT
00526   // IBMBIDI_NUMERAL_ARABIC
00527   // IBMBIDI_NUMERAL_HINDI
00528 
00529   switch (aNumFlag) {
00530     case IBMBIDI_NUMERAL_HINDI:
00531       for (i=0;i<aSize;i++)
00532         aBuffer[i] = NUM_TO_HINDI(aBuffer[i]);
00533       break;
00534     case IBMBIDI_NUMERAL_ARABIC:
00535       for (i=0;i<aSize;i++)
00536         aBuffer[i] = NUM_TO_ARABIC(aBuffer[i]);
00537       break;
00538     case IBMBIDI_NUMERAL_REGULAR:
00539     case IBMBIDI_NUMERAL_HINDICONTEXT:
00540         // for clipboard handling
00541         //XXX do we really want to convert numerals when copying text?
00542       for (i=1;i<aSize;i++) {
00543         if (IS_ARABIC_CHAR(aBuffer[i-1])) 
00544           aBuffer[i] = NUM_TO_HINDI(aBuffer[i]);
00545         else 
00546           aBuffer[i] = NUM_TO_ARABIC(aBuffer[i]);
00547       }
00548     case IBMBIDI_NUMERAL_NOMINAL:
00549     default:
00550       break;
00551   }
00552   return NS_OK;
00553 }
00554 
00555 nsresult HandleNumbers(const nsString& aSrc, nsString& aDst)
00556 {
00557   aDst = aSrc;
00558   return HandleNumbers((PRUnichar *)aDst.get(),aDst.Length(), IBMBIDI_NUMERAL_REGULAR);
00559 }
00560