12ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* GENERATED SOURCE. DO NOT MODIFY. */
2f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// © 2016 and later: Unicode, Inc. and others.
3f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
42ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*
52ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*******************************************************************************
62ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*   Copyright (C) 2001-2012, International Business Machines
72ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*   Corporation and others.  All Rights Reserved.
82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*******************************************************************************
92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*/
102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.text;
122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.UBiDiProps;
142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.lang.UCharacterDirection;
152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/**
172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Shape Arabic text on a character basis.
182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>ArabicShaping performs basic operations for "shaping" Arabic text. It is most
202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * useful for use with legacy data formats and legacy display technology
212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * (simple terminals). All operations are performed on Unicode characters.</p>
222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Text-based shaping means that some character code points in the text are
242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * replaced by others depending on the context. It transforms one kind of text
252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * into another. In comparison, modern displays for Arabic text select
262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * appropriate, context-dependent font glyphs for each text element, which means
272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * that they transform text into a glyph vector.</p>
282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Text transformations are necessary when modern display technology is not
302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * available or when text needs to be transformed to or from legacy formats that
312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * use "shaped" characters. Since the Arabic script is cursive, connecting
322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * adjacent letters to each other, computers select images for each letter based
332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * on the surrounding letters. This usually results in four images per Arabic
342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * letter: initial, middle, final, and isolated forms. In Unicode, on the other
352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * hand, letters are normally stored abstract, and a display system is expected
362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * to select the necessary glyphs. (This makes searching and other text
372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * processing easier because the same letter has only one code.) It is possible
382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * to mimic this with text transformations because there are characters in
392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Unicode that are rendered as letters with a specific shape
402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * (or cursive connectivity). They were included for interoperability with
412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * legacy systems and codepages, and for unsophisticated display systems.</p>
422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>A second kind of text transformations is supported for Arabic digits:
442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For compatibility with legacy codepages that only include European digits,
452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * it is possible to replace one set of digits by another, changing the
462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * character code points. These operations can be performed for either
472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Arabic-Indic Digits (U+0660...U+0669) or Eastern (Extended) Arabic-Indic
482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * digits (U+06f0...U+06f9).</p>
492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Some replacements may result in more or fewer characters (code points).
512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * By default, this means that the destination buffer may receive text with a
522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * length different from the source length. Some legacy systems rely on the
532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * length of the text to be constant. They expect extra spaces to be added
542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * or consumed either next to the affected character or at the end of the
552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * text.</p>
56836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide Only a subset of ICU is exposed in Android
572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic final class ArabicShaping {
592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private final int options;
602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private boolean isLogical; // convenience
612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private boolean spacesRelativeToTextBeginEnd;
622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private char tailChar;
632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
65f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Convert a range of text in the source array, putting the result
662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * into a range of text in the destination array, and return the number
672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of characters written.
682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param source An array containing the input text
702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param sourceStart The start of the range of text to convert
712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param sourceLength The length of the range of text to convert
722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param dest The destination array that will receive the result.
73f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *   It may be <code>NULL</code> only if  <code>destSize</code> is 0.
742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param destStart The start of the range of the destination buffer to use.
752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param destSize The size (capacity) of the destination buffer.
762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   If <code>destSize</code> is 0, then no output is produced,
772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   but the necessary buffer size is returned ("preflighting").  This
78f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *   does not validate the text against the options, for example,
792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   if letters are being unshaped, and spaces are being consumed
80f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *   following lamalef, this will not detect a lamalef without a
812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   corresponding space.  An error will be thrown when the actual
822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   conversion is attempted.
832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The number of chars written to the destination buffer.
842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   If an error occurs, then no output was written, or it may be
852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   incomplete.
862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws ArabicShapingException if the text cannot be converted according to the options.
872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int shape(char[] source, int sourceStart, int sourceLength,
892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     char[] dest, int destStart, int destSize) throws ArabicShapingException {
902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (source == null) {
912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("source can not be null");
922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (sourceStart < 0 || sourceLength < 0 || sourceStart + sourceLength > source.length) {
942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("bad source start (" + sourceStart +
952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                               ") or length (" + sourceLength +
962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                               ") for buffer of length " + source.length);
972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (dest == null && destSize != 0) {
992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("null dest requires destSize == 0");
1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((destSize != 0) &&
1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            (destStart < 0 || destSize < 0 || destStart + destSize > dest.length)) {
103f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            throw new IllegalArgumentException("bad dest start (" + destStart +
104f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                                               ") or size (" + destSize +
1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                               ") for buffer of length " + dest.length);
1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* Validate input options */
108f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        if ( ((options&TASHKEEL_MASK) != 0) &&
1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             !(((options & TASHKEEL_MASK)==TASHKEEL_BEGIN)  ||
110f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert               ((options & TASHKEEL_MASK)==TASHKEEL_END)    ||
111f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert               ((options & TASHKEEL_MASK)==TASHKEEL_RESIZE) ||
112f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert               ((options & TASHKEEL_MASK)==TASHKEEL_REPLACE_BY_TATWEEL))) {
1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Wrong Tashkeel argument");
1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       ///CLOVER:OFF
1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       //According to Steven Loomis, the code is unreachable when you OR all the constants within the if statements
118f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert       if(((options&LAMALEF_MASK) != 0) &&
1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              !(((options & LAMALEF_MASK)==LAMALEF_BEGIN)  ||
120f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                ((options & LAMALEF_MASK)==LAMALEF_END)    ||
121f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                ((options & LAMALEF_MASK)==LAMALEF_RESIZE) ||
122f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                ((options & LAMALEF_MASK)==LAMALEF_AUTO)   ||
123f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                ((options & LAMALEF_MASK)==LAMALEF_NEAR))) {
1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           throw new IllegalArgumentException("Wrong Lam Alef argument");
1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       }
1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       ///CLOVER:ON
127f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       /* Validate Tashkeel (Tashkeel replacement options should be enabled in shaping mode only)*/
129f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert       if(((options&TASHKEEL_MASK) != 0) && (options&LETTERS_MASK) == LETTERS_UNSHAPE) {
1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Tashkeel replacement should not be enabled in deshaping mode ");
1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       }
1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       return internalShape(source, sourceStart, sourceLength, dest, destStart, destSize);
1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Convert a range of text in place.  This may only be used if the Length option
1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * does not grow or shrink the text.
1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param source An array containing the input text
1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param start The start of the range of text to convert
1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param length The length of the range of text to convert
1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws ArabicShapingException if the text cannot be converted according to the options.
1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void shape(char[] source, int start, int length) throws ArabicShapingException {
1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((options & LAMALEF_MASK) == LAMALEF_RESIZE) {
1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new ArabicShapingException("Cannot shape in place with length option resize.");
1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        shape(source, start, length, source, start, length);
1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Convert a string, returning the new string.
1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param text the string to convert
1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the converted string
1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws ArabicShapingException if the string cannot be converted according to the options.
1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String shape(String text) throws ArabicShapingException {
1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        char[] src = text.toCharArray();
1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        char[] dest = src;
1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (((options & LAMALEF_MASK) == LAMALEF_RESIZE) &&
1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ((options & LETTERS_MASK) == LETTERS_UNSHAPE)) {
1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            dest = new char[src.length * 2]; // max
1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int len = shape(src, 0, src.length, dest, 0, dest.length);
1672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return new String(dest, 0, len);
1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Construct ArabicShaping using the options flags.
1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The flags are as follows:<br>
1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 'LENGTH' flags control whether the text can change size, and if not,
175f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * how to maintain the size of the text when LamAlef ligatures are
1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * formed or broken.<br>
1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 'TEXT_DIRECTION' flags control whether the text is read and written
1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in visual order or in logical order.<br>
1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 'LETTERS_SHAPE' flags control whether conversion is to or from
1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * presentation forms.<br>
1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 'DIGITS' flags control whether digits are shaped, and whether from
1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * European to Arabic-Indic or vice-versa.<br>
1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 'DIGIT_TYPE' flags control whether standard or extended Arabic-Indic
1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * digits are used when performing digit conversion.
1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public ArabicShaping(int options) {
1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.options = options;
1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((options & DIGITS_MASK) > 0x80) {
1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("bad DIGITS options");
1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
191f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        isLogical = ( (options & TEXT_DIRECTION_MASK) == TEXT_DIRECTION_LOGICAL );
1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* Validate options */
1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        spacesRelativeToTextBeginEnd = ( (options & SPACES_RELATIVE_TO_TEXT_MASK) == SPACES_RELATIVE_TO_TEXT_BEGIN_END );
1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( (options&SHAPE_TAIL_TYPE_MASK) == SHAPE_TAIL_NEW_UNICODE){
1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            tailChar = NEW_TAIL_CHAR;
1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            tailChar = OLD_TAIL_CHAR;
1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
201f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
202f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /* Seen Tail options */
2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: the result must have the same length as the source.
205f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Shaping mode: The SEEN family character will expand into two characters using space near
2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *               the SEEN family character(i.e. the space after the character).
2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *               if there are no spaces found, ArabicShapingException will be thrown
2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * De-shaping mode: Any Seen character followed by Tail character will be
2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                  replaced by one cell Seen and a space will replace the Tail.
2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: Seen options
2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int SEEN_TWOCELL_NEAR = 0x200000;
2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
215f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /** Bit mask for Seen memory options.
2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int SEEN_MASK = 0x700000;
2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
219f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /* YehHamza options */
2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: the result must have the same length as the source.
222f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Shaping mode: The YEHHAMZA character will expand into two characters using space near it
2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *              (i.e. the space after the character)
2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *               if there are no spaces found, ArabicShapingException will be thrown
2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * De-shaping mode: Any Yeh (final or isolated) character followed by Hamza character will be
2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                  replaced by one cell YehHamza and space will replace the Hamza.
2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: YehHamza options
2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int YEHHAMZA_TWOCELL_NEAR  = 0x1000000;
2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
233f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /** Bit mask for YehHamza memory options.
2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int YEHHAMZA_MASK = 0x3800000;
2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
237f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /* New Tashkeel options */
2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: the result must have the same length as the source.
240f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Shaping mode: Tashkeel characters will be replaced by spaces.
2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *               Spaces will be placed at beginning of the buffer
2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * De-shaping mode: N/A
2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: Tashkeel options
2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int TASHKEEL_BEGIN = 0x40000;
2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: the result must have the same length as the source.
250f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Shaping mode: Tashkeel characters will be replaced by spaces.
2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *               Spaces will be placed at end of the buffer
2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * De-shaping mode: N/A
2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: Tashkeel options
2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int TASHKEEL_END = 0x60000;
2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: allow the result to have a different length than the source.
260f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Shaping mode: Tashkeel characters will be removed, buffer length will shrink.
261f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * De-shaping mode: N/A
2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: Tashkeel options
2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int TASHKEEL_RESIZE = 0x80000;
2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: the result must have the same length as the source.
2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Shaping mode: Tashkeel characters will be replaced by Tatweel if it is connected to adjacent
2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *               characters (i.e. shaped on Tatweel) or replaced by space if it is not connected.
2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * De-shaping mode: N/A
2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: YehHamza options
2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int TASHKEEL_REPLACE_BY_TATWEEL = 0xC0000;
2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
277f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /** Bit mask for Tashkeel replacement with Space or Tatweel memory options.
2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int TASHKEEL_MASK  = 0xE0000;
280f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
281f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /* Space location Control options */
2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This option effects the meaning of BEGIN and END options. if this option is not used the default
284f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * for BEGIN and END will be as following:
2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The Default (for both Visual LTR, Visual RTL and Logical Text)
2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           1. BEGIN always refers to the start address of physical memory.
2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           2. END always refers to the end address of physical memory.
2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
289f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * If this option is used it will swap the meaning of BEGIN and END only for Visual LTR text.
2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The affect on BEGIN and END Memory Options will be as following:
292f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *    A. BEGIN For Visual LTR text: This will be the beginning (right side) of the visual text
2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *       (corresponding to the physical memory address end, same as END in default behavior)
294f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *    B. BEGIN For Logical text: Same as BEGIN in default behavior.
295f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *    C. END For Visual LTR text: This will be the end (left side) of the visual text. (corresponding to
296f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *      the physical memory address beginning, same as BEGIN in default behavior)
297f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *    D. END For Logical text: Same as END in default behavior.
2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: All LamAlef BEGIN, END and AUTO options.
2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int SPACES_RELATIVE_TO_TEXT_BEGIN_END = 0x4000000;
3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
302f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /** Bit mask for swapping BEGIN and END for Visual LTR text
3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int SPACES_RELATIVE_TO_TEXT_MASK = 0x4000000;
305f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
307f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * If this option is used, shaping will use the new Unicode code point for TAIL (i.e. 0xFE73).
3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If this option is not specified (Default), old unofficial Unicode TAIL code point is used (i.e. 0x200B)
309f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * De-shaping will not use this option as it will always search for both the new Unicode code point for the
3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * TAIL (i.e. 0xFE73) or the old unofficial Unicode TAIL code point (i.e. 0x200B) and de-shape the
3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Seen-Family letter accordingly.
3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Shaping Mode: Only shaping.
3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * De-shaping Mode: N/A.
3152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: All Seen options
3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int SHAPE_TAIL_NEW_UNICODE = 0x8000000;
3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
319f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /** Bit mask for new Unicode Tail option
3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int SHAPE_TAIL_TYPE_MASK = 0x8000000;
3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: allow the result to have a different length than the source.
3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LENGTH_GROW_SHRINK = 0;
3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: allow the result to have a different length than the source.
3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: LamAlef options
3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This option is an alias to LENGTH_GROW_SHRINK
3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LAMALEF_RESIZE   = 0;
334f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: the result must have the same length as the source.
3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If more room is necessary, then try to consume spaces next to modified characters.
3382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LENGTH_FIXED_SPACES_NEAR = 1;
3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: the result must have the same length as the source.
3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If more room is necessary, then try to consume spaces next to modified characters.
3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: LamAlef options
3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This option is an alias to LENGTH_FIXED_SPACES_NEAR
3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LAMALEF_NEAR = 1 ;
348f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: the result must have the same length as the source.
3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If more room is necessary, then try to consume spaces at the end of the text.
3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LENGTH_FIXED_SPACES_AT_END = 2;
3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: the result must have the same length as the source.
3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If more room is necessary, then try to consume spaces at the end of the text.
3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: LamAlef options
3602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This option is an alias to LENGTH_FIXED_SPACES_AT_END
3612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LAMALEF_END = 2;
363f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: the result must have the same length as the source.
3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If more room is necessary, then try to consume spaces at the beginning of the text.
3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LENGTH_FIXED_SPACES_AT_BEGINNING = 3;
3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: the result must have the same length as the source.
3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If more room is necessary, then try to consume spaces at the beginning of the text.
3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: LamAlef options
3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This option is an alias to LENGTH_FIXED_SPACES_AT_BEGINNING
3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
376f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    public static final int LAMALEF_BEGIN = 3;
3772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Memory option: the result must have the same length as the source.
3802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Shaping Mode: For each LAMALEF character found, expand LAMALEF using space at end.
3812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *               If there is no space at end, use spaces at beginning of the buffer. If there
3822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *               is no space at beginning of the buffer, use spaces at the near (i.e. the space
3832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *               after the LAMALEF character).
3842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
385f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Deshaping Mode: Perform the same function as the flag equals LAMALEF_END.
3862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Affects: LamAlef options
3872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
388f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    public static final int LAMALEF_AUTO  = 0x10000;
389f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
390f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /**
391f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Bit mask for memory options.
3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LENGTH_MASK = 0x10003;
3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
395f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /** Bit mask for LamAlef memory options.
3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LAMALEF_MASK  = 0x10003;
3992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
400f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /**
401f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Direction indicator: the source is in logical (keyboard) order.
4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int TEXT_DIRECTION_LOGICAL = 0;
4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Direction indicator:the source is in visual RTL order,
4072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the rightmost displayed character stored first.
4082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This option is an alias to U_SHAPE_TEXT_DIRECTION_LOGICAL
4092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int TEXT_DIRECTION_VISUAL_RTL = 0;
411f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
412f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /**
4132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Direction indicator: the source is in visual (display) order, that is,
4142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the leftmost displayed character is stored first.
4152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int TEXT_DIRECTION_VISUAL_LTR = 4;
4172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
418f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /**
419f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Bit mask for direction indicators.
4202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int TEXT_DIRECTION_MASK = 4;
4222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
425f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Letter shaping option: do not perform letter shaping.
4262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LETTERS_NOOP = 0;
4282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
429f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /**
4302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Letter shaping option: replace normative letter characters in the U+0600 (Arabic) block,
4312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * by shaped ones in the U+FE70 (Presentation Forms B) block. Performs Lam-Alef ligature
4322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * substitution.
4332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LETTERS_SHAPE = 8;
4352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
436f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /**
4372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Letter shaping option: replace shaped letter characters in the U+FE70 (Presentation Forms B) block
4382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * by normative ones in the U+0600 (Arabic) block.  Converts Lam-Alef ligatures to pairs of Lam and
4392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Alef characters, consuming spaces if required.
4402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LETTERS_UNSHAPE = 0x10;
4422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Letter shaping option: replace normative letter characters in the U+0600 (Arabic) block,
4452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * except for the TASHKEEL characters at U+064B...U+0652, by shaped ones in the U+Fe70
4462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * (Presentation Forms B) block.  The TASHKEEL characters will always be converted to
4472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the isolated forms rather than to their correct shape.
4482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LETTERS_SHAPE_TASHKEEL_ISOLATED = 0x18;
4502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
451f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /**
452f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Bit mask for letter shaping options.
4532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int LETTERS_MASK = 0x18;
4552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
457f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /**
458f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Digit shaping option: do not perform digit shaping.
4592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIGITS_NOOP = 0;
4612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Digit shaping option: Replace European digits (U+0030...U+0039) by Arabic-Indic digits.
4642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIGITS_EN2AN = 0x20;
4662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Digit shaping option: Replace Arabic-Indic digits by European digits (U+0030...U+0039).
4692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIGITS_AN2EN = 0x40;
4712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Digit shaping option:
4742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Replace European digits (U+0030...U+0039) by Arabic-Indic digits
4752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * if the most recent strongly directional character
476f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC).
4772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The initial state at the start of the text is assumed to be not an Arabic,
4782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * letter, so European digits at the start of the text will not change.
4792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Compare to DIGITS_ALEN2AN_INIT_AL.
4802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIGITS_EN2AN_INIT_LR = 0x60;
4822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Digit shaping option:
4852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Replace European digits (U+0030...U+0039) by Arabic-Indic digits
4862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * if the most recent strongly directional character
487f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * is an Arabic letter (its Bidi direction value is RIGHT_TO_LEFT_ARABIC).
4882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The initial state at the start of the text is assumed to be an Arabic,
4892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * letter, so European digits at the start of the text will change.
4902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Compare to DIGITS_ALEN2AN_INT_LR.
4912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIGITS_EN2AN_INIT_AL = 0x80;
4932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Not a valid option value. */
4952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //private static final int DIGITS_RESERVED = 0xa0;
4962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
497f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /**
498f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Bit mask for digit shaping options.
4992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIGITS_MASK = 0xe0;
5012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
502f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /**
503f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Digit type option: Use Arabic-Indic digits (U+0660...U+0669).
5042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIGIT_TYPE_AN = 0;
5062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
507f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /**
508f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Digit type option: Use Eastern (Extended) Arabic-Indic digits (U+06f0...U+06f9).
5092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIGIT_TYPE_AN_EXTENDED = 0x100;
5112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
512f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /**
513f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Bit mask for digit type options.
5142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIGIT_TYPE_MASK = 0x0100; // 0x3f00?
5162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
5182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * some constants
5192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char HAMZAFE_CHAR       = '\ufe80';
5212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char HAMZA06_CHAR       = '\u0621';
5222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char YEH_HAMZA_CHAR     = '\u0626';
5232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char YEH_HAMZAFE_CHAR   = '\uFE89';
5242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char LAMALEF_SPACE_SUB  = '\uffff';
5252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char TASHKEEL_SPACE_SUB = '\ufffe';
5262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char LAM_CHAR      = '\u0644';
5272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char SPACE_CHAR    = '\u0020';
5282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char SHADDA_CHAR   = '\uFE7C';
529f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    private static final char SHADDA06_CHAR = '\u0651';
5302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char TATWEEL_CHAR  = '\u0640';
5312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char SHADDA_TATWEEL_CHAR = '\uFE7D';
5322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char NEW_TAIL_CHAR = '\uFE73';
5332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char OLD_TAIL_CHAR = '\u200B';
5342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int SHAPE_MODE      = 0;
5352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int DESHAPE_MODE    = 1;
5362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
5382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
539f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Override
5402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean equals(Object rhs) {
541f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        return rhs != null &&
542f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            rhs.getClass() == ArabicShaping.class &&
5432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            options == ((ArabicShaping)rhs).options;
5442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
5472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     ///CLOVER:OFF
549f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Override
5502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int hashCode() {
5512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return options;
5522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
5552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
556f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Override
5572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String toString() {
5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuilder buf = new StringBuilder(super.toString());
5592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append('[');
5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (options & LAMALEF_MASK) {
5622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LAMALEF_RESIZE: buf.append("LamAlef resize"); break;
5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LAMALEF_NEAR: buf.append("LamAlef spaces at near"); break;
5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LAMALEF_BEGIN: buf.append("LamAlef spaces at begin"); break;
5652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LAMALEF_END: buf.append("LamAlef spaces at end"); break;
5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LAMALEF_AUTO: buf.append("lamAlef auto"); break;
5672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (options & TEXT_DIRECTION_MASK) {
5692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case TEXT_DIRECTION_LOGICAL: buf.append(", logical"); break;
5702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case TEXT_DIRECTION_VISUAL_LTR: buf.append(", visual"); break;
5712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (options & LETTERS_MASK) {
5732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LETTERS_NOOP: buf.append(", no letter shaping"); break;
5742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LETTERS_SHAPE: buf.append(", shape letters"); break;
5752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LETTERS_SHAPE_TASHKEEL_ISOLATED: buf.append(", shape letters tashkeel isolated"); break;
5762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LETTERS_UNSHAPE: buf.append(", unshape letters"); break;
5772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (options & SEEN_MASK) {
5792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case SEEN_TWOCELL_NEAR: buf.append(", Seen at near"); break;
5802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (options & YEHHAMZA_MASK) {
5822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case YEHHAMZA_TWOCELL_NEAR: buf.append(", Yeh Hamza at near"); break;
5832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (options & TASHKEEL_MASK) {
5852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case TASHKEEL_BEGIN: buf.append(", Tashkeel at begin"); break;
5862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case TASHKEEL_END: buf.append(", Tashkeel at end"); break;
5872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case TASHKEEL_REPLACE_BY_TATWEEL: buf.append(", Tashkeel replace with tatweel"); break;
5882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case TASHKEEL_RESIZE: buf.append(", Tashkeel resize"); break;
5892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (options & DIGITS_MASK) {
5922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case DIGITS_NOOP: buf.append(", no digit shaping"); break;
5932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case DIGITS_EN2AN: buf.append(", shape digits to AN"); break;
5942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case DIGITS_AN2EN: buf.append(", shape digits to EN"); break;
5952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case DIGITS_EN2AN_INIT_LR: buf.append(", shape digits to AN contextually: default EN"); break;
5962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case DIGITS_EN2AN_INIT_AL: buf.append(", shape digits to AN contextually: default AL"); break;
5972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (options & DIGIT_TYPE_MASK) {
5992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case DIGIT_TYPE_AN: buf.append(", standard Arabic-Indic digits"); break;
6002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case DIGIT_TYPE_AN_EXTENDED: buf.append(", extended Arabic-Indic digits"); break;
6012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
6022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append("]");
6032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return buf.toString();
6052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
6062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    ///CLOVER:ON
6072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //
6092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // ported api
6102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //
6112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int IRRELEVANT = 4;
6132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int LAMTYPE = 16;
6142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int ALEFTYPE = 32;
6152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int LINKR = 1;
6172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int LINKL = 2;
6182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int LINK_MASK = 3;
6192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
620f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    private static final int irrelevantPos[] = {
621f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        0x0, 0x2, 0x4, 0x6, 0x8, 0xA, 0xC, 0xE
6222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
6232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*
6252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char convertLamAlef[] =  {
626f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        '\u0622', // FEF5
6272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        '\u0622', // FEF6
6282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        '\u0623', // FEF7
6292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        '\u0623', // FEF8
6302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        '\u0625', // FEF9
6312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        '\u0625', // FEFA
6322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        '\u0627', // FEFB
633f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        '\u0627'  // FEFC
6342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
6352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*/
636f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
6372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int tailFamilyIsolatedFinal[] = {
6382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEB1 */ 1,
6392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEB2 */ 1,
6402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEB3 */ 0,
6412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEB4 */ 0,
6422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEB5 */ 1,
6432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEB6 */ 1,
6442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEB7 */ 0,
6452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEB8 */ 0,
6462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEB9 */ 1,
6472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEBA */ 1,
6482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEBB */ 0,
6492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEBC */ 0,
6502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEBD */ 1,
6512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FEBE */ 1
6522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
6532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int tashkeelMedial[] = {
6552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE70 */ 0,
6562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE71 */ 1,
6572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE72 */ 0,
6582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE73 */ 0,
6592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE74 */ 0,
6602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE75 */ 0,
6612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE76 */ 0,
6622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE77 */ 1,
6632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE78 */ 0,
6642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE79 */ 1,
6652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE7A */ 0,
6662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE7B */ 1,
6672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE7C */ 0,
6682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE7D */ 1,
6692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE7E */ 0,
6702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FE7F */ 1
6712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
6722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char yehHamzaToYeh[] =
6742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
6752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* isolated*/ 0xFEEF,
6762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* final   */ 0xFEF0
6772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
6782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char convertNormalizedLamAlef[] = {
6802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        '\u0622', // 065C
6812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        '\u0623', // 065D
6822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        '\u0625', // 065E
6832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        '\u0627', // 065F
6842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
6852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int[] araLink = {
6872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1           + 32 + 256 * 0x11,  /*0x0622*/
6882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1           + 32 + 256 * 0x13,  /*0x0623*/
6892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1                + 256 * 0x15,  /*0x0624*/
6902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1           + 32 + 256 * 0x17,  /*0x0625*/
6912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x19,  /*0x0626*/
6922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1           + 32 + 256 * 0x1D,  /*0x0627*/
6932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x1F,  /*0x0628*/
6942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1                + 256 * 0x23,  /*0x0629*/
6952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x25,  /*0x062A*/
6962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x29,  /*0x062B*/
6972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x2D,  /*0x062C*/
6982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x31,  /*0x062D*/
6992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x35,  /*0x062E*/
7002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1                + 256 * 0x39,  /*0x062F*/
7012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1                + 256 * 0x3B,  /*0x0630*/
7022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1                + 256 * 0x3D,  /*0x0631*/
7032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1                + 256 * 0x3F,  /*0x0632*/
7042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x41,  /*0x0633*/
7052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x45,  /*0x0634*/
7062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x49,  /*0x0635*/
7072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x4D,  /*0x0636*/
7082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x51,  /*0x0637*/
7092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x55,  /*0x0638*/
7102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x59,  /*0x0639*/
7112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x5D,  /*0x063A*/
7122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        0, 0, 0, 0, 0,                  /*0x063B-0x063F*/
7132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2,                          /*0x0640*/
7142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x61,  /*0x0641*/
7152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x65,  /*0x0642*/
7162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x69,  /*0x0643*/
7172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2       + 16 + 256 * 0x6D,  /*0x0644*/
7182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x71,  /*0x0645*/
7192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x75,  /*0x0646*/
7202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x79,  /*0x0647*/
7212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1                + 256 * 0x7D,  /*0x0648*/
7222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1                + 256 * 0x7F,  /*0x0649*/
7232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2            + 256 * 0x81,  /*0x064A*/
7242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        4, 4, 4, 4,                     /*0x064B-0x064E*/
7252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        4, 4, 4, 4,                     /*0x064F-0x0652*/
7262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        4, 4, 4, 0, 0,                  /*0x0653-0x0657*/
7272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        0, 0, 0, 0,                     /*0x0658-0x065B*/
7282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1                + 256 * 0x85,  /*0x065C*/
7292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1                + 256 * 0x87,  /*0x065D*/
7302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1                + 256 * 0x89,  /*0x065E*/
7312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1                + 256 * 0x8B,  /*0x065F*/
7322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        0, 0, 0, 0, 0,                  /*0x0660-0x0664*/
7332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        0, 0, 0, 0, 0,                  /*0x0665-0x0669*/
7342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        0, 0, 0, 0, 0, 0,               /*0x066A-0x066F*/
7352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        4,                              /*0x0670*/
7362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        0,                              /*0x0671*/
7372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1           + 32,               /*0x0672*/
7382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1           + 32,               /*0x0673*/
7392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        0,                              /*0x0674*/
7402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1           + 32,               /*0x0675*/
7412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 1,                           /*0x0676-0x0677*/
7422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2, 1+2, 1+2, 1+2, 1+2, 1+2,   /*0x0678-0x067D*/
7432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2, 1+2, 1+2, 1+2, 1+2, 1+2,   /*0x067E-0x0683*/
7442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2, 1+2, 1+2, 1+2,             /*0x0684-0x0687*/
7452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /*0x0688-0x0691*/
7462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 1, 1, 1, 1, 1, 1, 1,         /*0x0692-0x0699*/
7472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2, 1+2, 1+2, 1+2, 1+2, 1+2,   /*0x069A-0x06A3*/
7482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2, 1+2, 1+2, 1+2,             /*0x069A-0x06A3*/
7492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2, 1+2, 1+2, 1+2, 1+2, 1+2,   /*0x06A4-0x06AD*/
7502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2, 1+2, 1+2, 1+2,             /*0x06A4-0x06AD*/
7512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2, 1+2, 1+2, 1+2, 1+2, 1+2,   /*0x06AE-0x06B7*/
7522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2, 1+2, 1+2, 1+2,             /*0x06AE-0x06B7*/
7532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2, 1+2, 1+2, 1+2, 1+2, 1+2,   /*0x06B8-0x06BF*/
7542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2, 1+2,                       /*0x06B8-0x06BF*/
7552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1,                              /*0x06C0*/
7562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2,                            /*0x06C1*/
7572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /*0x06C2-0x06CB*/
7582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2,                            /*0x06CC*/
7592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1,                              /*0x06CD*/
7602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+2, 1+2, 1+2, 1+2,             /*0x06CE-0x06D1*/
7612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 1                            /*0x06D2-0x06D3*/
7622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
7632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int[] presLink = {
7652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2,                        /*0xFE70*/
7662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2,                        /*0xFE71*/
7672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2, 0, 1+ 2, 0, 1+ 2,      /*0xFE72-0xFE76*/
7682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 2,                        /*0xFE77*/
7692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+ 2, 1 + 2, 1+2, 1 + 2,      /*0xFE78-0xFE81*/
7702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1+ 2, 1 + 2, 1+2, 1 + 2,      /*0xFE82-0xFE85*/
7712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        0, 0 + 32, 1 + 32, 0 + 32,    /*0xFE86-0xFE89*/
7722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 32, 0, 1,  0 + 32,        /*0xFE8A-0xFE8D*/
7732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 32, 0, 2,  1 + 2,         /*0xFE8E-0xFE91*/
7742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0 + 32, 1 + 32, 0,         /*0xFE92-0xFE95*/
7752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        2, 1 + 2, 1, 0,               /*0xFE96-0xFE99*/
7762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1 + 2,               /*0xFE9A-0xFE9D*/
7772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1 + 2,               /*0xFE9E-0xFEA1*/
7782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1 + 2,               /*0xFEA2-0xFEA5*/
7792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1 + 2,               /*0xFEA6-0xFEA9*/
7802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1 + 2,               /*0xFEAA-0xFEAD*/
7812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 1, 0,                   /*0xFEAE-0xFEB1*/
7822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 1, 0,                   /*0xFEB2-0xFEB5*/
7832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFEB6-0xFEB9*/
7842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFEBA-0xFEBD*/
7852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFEBE-0xFEC1*/
7862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFEC2-0xFEC5*/
7872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFEC6-0xFEC9*/
7882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFECA-0xFECD*/
7892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFECE-0xFED1*/
7902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFED2-0xFED5*/
7912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFED6-0xFED9*/
7922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFEDA-0xFEDD*/
7932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFEDE-0xFEE1*/
7942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0 + 16, 2 + 16, 1 + 2 +16, /*0xFEE2-0xFEE5*/
7952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1 + 16, 0, 2, 1+2,            /*0xFEE6-0xFEE9*/
7962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFEEA-0xFEED*/
7972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFEEE-0xFEF1*/
7982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 1, 0,                   /*0xFEF2-0xFEF5*/
7992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 2, 1+2,                 /*0xFEF6-0xFEF9*/
8002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 1, 0,                   /*0xFEFA-0xFEFD*/
8012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1, 0, 1, 0,
8022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        1
8032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
8042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static int[] convertFEto06 = {
8062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /***********0******1******2******3******4******5******6******7******8******9******A******B******C******D******E******F***/
8072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*FE7*/   0x64B, 0x64B, 0x64C, 0x64C, 0x64D, 0x64D, 0x64E, 0x64E, 0x64F, 0x64F, 0x650, 0x650, 0x651, 0x651, 0x652, 0x652,
8082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*FE8*/   0x621, 0x622, 0x622, 0x623, 0x623, 0x624, 0x624, 0x625, 0x625, 0x626, 0x626, 0x626, 0x626, 0x627, 0x627, 0x628,
8092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*FE9*/   0x628, 0x628, 0x628, 0x629, 0x629, 0x62A, 0x62A, 0x62A, 0x62A, 0x62B, 0x62B, 0x62B, 0x62B, 0x62C, 0x62C, 0x62C,
8102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*FEA*/   0x62C, 0x62D, 0x62D, 0x62D, 0x62D, 0x62E, 0x62E, 0x62E, 0x62E, 0x62F, 0x62F, 0x630, 0x630, 0x631, 0x631, 0x632,
8112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*FEB*/   0x632, 0x633, 0x633, 0x633, 0x633, 0x634, 0x634, 0x634, 0x634, 0x635, 0x635, 0x635, 0x635, 0x636, 0x636, 0x636,
8122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*FEC*/   0x636, 0x637, 0x637, 0x637, 0x637, 0x638, 0x638, 0x638, 0x638, 0x639, 0x639, 0x639, 0x639, 0x63A, 0x63A, 0x63A,
8132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*FED*/   0x63A, 0x641, 0x641, 0x641, 0x641, 0x642, 0x642, 0x642, 0x642, 0x643, 0x643, 0x643, 0x643, 0x644, 0x644, 0x644,
8142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*FEE*/   0x644, 0x645, 0x645, 0x645, 0x645, 0x646, 0x646, 0x646, 0x646, 0x647, 0x647, 0x647, 0x647, 0x648, 0x648, 0x649,
8152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*FEF*/   0x649, 0x64A, 0x64A, 0x64A, 0x64A, 0x65C, 0x65C, 0x65D, 0x65D, 0x65E, 0x65E, 0x65F, 0x65F
8162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
8172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int shapeTable[][][] = {
8192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        { {0,0,0,0}, {0,0,0,0}, {0,1,0,3}, {0,1,0,1} },
8202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        { {0,0,2,2}, {0,0,1,2}, {0,1,1,2}, {0,1,1,3} },
8212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        { {0,0,0,0}, {0,0,0,0}, {0,1,0,3}, {0,1,0,3} },
8222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        { {0,0,1,2}, {0,0,1,2}, {0,1,1,2}, {0,1,1,3} }
8232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
8242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
8262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This function shapes European digits to Arabic-Indic digits
8272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in-place, writing over the input characters.  Data is in visual
8282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * order.
8292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void shapeToArabicDigitsWithContext(char[] dest,
8312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                int start,
8322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                int length,
8332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                char digitBase,
8342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                boolean lastStrongWasAL) {
8352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UBiDiProps bdp=UBiDiProps.INSTANCE;
8362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        digitBase -= '0'; // move common adjustment out of loop
8372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for(int i = start + length; --i >= start;) {
8392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char ch = dest[i];
8402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            switch (bdp.getClass(ch)) {
8412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case UCharacterDirection.LEFT_TO_RIGHT:
8422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case UCharacterDirection.RIGHT_TO_LEFT:
8432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                lastStrongWasAL = false;
8442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
8452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case UCharacterDirection.RIGHT_TO_LEFT_ARABIC:
8462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                lastStrongWasAL = true;
8472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
8482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case UCharacterDirection.EUROPEAN_NUMBER:
8492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (lastStrongWasAL && ch <= '\u0039') {
8502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    dest[i] = (char)(ch + digitBase);
8512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
8522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
8532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            default:
8542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
8552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
8562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
8572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
8582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
8602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : invertBuffer
8612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: This function inverts the buffer, it's used
8622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           in case the user specifies the buffer to be
8632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           TEXT_DIRECTION_LOGICAL
8642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static void invertBuffer(char[] buffer,
8662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                     int start,
8672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                     int length) {
8682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for(int i = start, j = start + length - 1; i < j; i++, --j) {
8702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char temp = buffer[i];
8712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buffer[i] = buffer[j];
8722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buffer[j] = temp;
8732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
8742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
8752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
8772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : changeLamAlef
8782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: Converts the Alef characters into an equivalent
8792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           LamAlef location in the 0x06xx Range, this is an
8802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           intermediate stage in the operation of the program
881f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           later it'll be converted into the 0xFExx LamAlefs
8822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           in the shaping function.
8832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static char changeLamAlef(char ch) {
8852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch(ch) {
8862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case '\u0622': return '\u065C';
8872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case '\u0623': return '\u065D';
8882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case '\u0625': return '\u065E';
8892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case '\u0627': return '\u065F';
8902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        default:  return '\u0000'; // not a lamalef
8912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
8922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
8932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
8952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : specialChar
8962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: Special Arabic characters need special handling in the shapeUnicode
8972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           function, this function returns 1 or 2 for these special characters
8982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static int specialChar(char ch) {
900f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        if ((ch > '\u0621' && ch < '\u0626') ||
9012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            (ch == '\u0627') ||
9022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            (ch > '\u062E' && ch < '\u0633') ||
9032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            (ch > '\u0647' && ch < '\u064A') ||
9042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            (ch == '\u0629')) {
9052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 1;
9062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if (ch >= '\u064B' && ch<= '\u0652') {
9072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 2;
908f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        } else if (ch >= 0x0653 && ch <= 0x0655 ||
9092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   ch == 0x0670 ||
9102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   ch >= 0xFE70 && ch <= 0xFE7F) {
9112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 3;
9122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
9132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 0;
9142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
916f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
9172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
9182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : getLink
919f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Function: Resolves the link between the characters as
9202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           Arabic characters have four forms :
9212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           Isolated, Initial, Middle and Final Form
9222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static int getLink(char ch) {
9242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (ch >= '\u0622' && ch <= '\u06D3') {
9252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return araLink[ch - '\u0622'];
9262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if (ch == '\u200D') {
9272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 3;
9282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if (ch >= '\u206D' && ch <= '\u206F') {
9292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 4;
9302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if (ch >= '\uFE70' && ch <= '\uFEFC') {
9312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return presLink[ch - '\uFE70'];
9322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
9332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 0;
9342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
9382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : countSpaces
9392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: Counts the number of spaces
9402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           at each end of the logical buffer
9412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
942f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    private static int countSpacesLeft(char[] dest,
9432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                       int start,
9442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                       int count) {
9452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = start, e = start + count; i < e; ++i) {
9462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dest[i] != SPACE_CHAR) {
9472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return i - start;
9482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
9492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return count;
9512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static int countSpacesRight(char[] dest,
9542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        int start,
9552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        int count) {
9562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = start + count; --i >= start;) {
9582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dest[i] != SPACE_CHAR) {
9592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return start + count - 1 - i;
9602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
9612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return count;
9632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
9662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : isTashkeelChar
9672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: Returns true for Tashkeel characters else return false
9682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static boolean isTashkeelChar(char ch) {
9702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ( ch >='\u064B' && ch <= '\u0652' );
9712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
9742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *Name     : isSeenTailFamilyChar
975f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *Function : returns 1 if the character is a seen family isolated character
9762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           in the FE range otherwise returns 0
9772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static int isSeenTailFamilyChar(char ch) {
9802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (ch >= 0xfeb1 && ch < 0xfebf){
9812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             return tailFamilyIsolatedFinal [ch - 0xFEB1];
9822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
9832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             return 0;
9842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     /* Name     : isSeenFamilyChar
9882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      * Function : returns 1 if the character is a seen family character in the Unicode
9892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      *            06 range otherwise returns 0
9902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static int isSeenFamilyChar(char  ch){
9932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (ch >= 0x633 && ch <= 0x636){
9942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 1;
9952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }else {
9962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 0;
9972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
10012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *Name     : isTailChar
1002f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *Function : returns true if the character matches one of the tail characters
10032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           (0xfe73 or 0x200b) otherwise returns false
10042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static boolean isTailChar(char ch) {
10072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if(ch == OLD_TAIL_CHAR || ch == NEW_TAIL_CHAR){
10082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return true;
10092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }else{
10102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return false;
10112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
10122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1013f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
10142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
10152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *Name     : isAlefMaksouraChar
1016f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *Function : returns true if the character is a Alef Maksoura Final or isolated
10172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           otherwise returns false
10182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static boolean isAlefMaksouraChar(char ch) {
10202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ( (ch == 0xFEEF) || ( ch == 0xFEF0) || (ch == 0x0649));
1021f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    }
10222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
10242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name     : isYehHamzaChar
10252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function : returns true if the character is a yehHamza isolated or yehhamza
10262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *            final is found otherwise returns false
10272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static boolean isYehHamzaChar(char ch) {
10292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if((ch==0xFE89)||(ch==0xFE8A)){
10302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return true;
10312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }else{
10322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return false;
10332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1034f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    }
10352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
10372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *Name     : isTashkeelCharFE
10382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *Function : Returns true for Tashkeel characters in FE range else return false
10392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1040f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
10412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static boolean isTashkeelCharFE(char ch) {
10422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ( ch!=0xFE75 &&(ch>=0xFE70 && ch<= 0xFE7F) );
10432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1045f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    /*
10462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name: isTashkeelOnTatweelChar
1047f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Function: Checks if the Tashkeel Character is on Tatweel or not,if the
1048f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           Tashkeel on tatweel (FE range), it returns 1 else if the
1049f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           Tashkeel with shadda on tatweel (FC range)return 2 otherwise
10502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           returns 0
10512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static int isTashkeelOnTatweelChar(char ch){
10532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (ch >= 0xfe70 && ch <= 0xfe7f && ch != NEW_TAIL_CHAR && ch != 0xFE75 && ch != SHADDA_TATWEEL_CHAR)
10542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        {
10552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return tashkeelMedial [ch - 0xFE70];
10562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if( (ch >= 0xfcf2 && ch <= 0xfcf4) || (ch == SHADDA_TATWEEL_CHAR)) {
10572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 2;
10582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
10592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 0;
10602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
10612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1062f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
10632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
10642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name: isIsolatedTashkeelChar
1065f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Function: Checks if the Tashkeel Character is in the isolated form
1066f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           (i.e. Unicode FE range) returns 1 else if the Tashkeel
10672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           with shadda is in the isolated form (i.e. Unicode FC range)
10682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           returns 1 otherwise returns 0
10692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static int isIsolatedTashkeelChar(char ch){
10712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (ch >= 0xfe70 && ch <= 0xfe7f && ch != NEW_TAIL_CHAR && ch != 0xFE75){
10722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return (1 - tashkeelMedial [ch - 0xFE70]);
10732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if(ch >= 0xfc5e && ch <= 0xfc63){
10742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 1;
10752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else{
10762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 0;
10772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
10782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1079f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
10802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
10812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : isAlefChar
10822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: Returns 1 for Alef characters else return 0
10832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static boolean isAlefChar(char ch) {
10852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ch == '\u0622' || ch == '\u0623' || ch == '\u0625' || ch == '\u0627';
10862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1087f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
10882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
10892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : isLamAlefChar
10902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: Returns true for LamAlef characters else return false
10912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static boolean isLamAlefChar(char ch) {
10932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ch >= '\uFEF5' && ch <= '\uFEFC';
10942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static boolean isNormalizedLamAlefChar(char ch) {
10972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ch >= '\u065C' && ch <= '\u065F';
10982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
11012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : calculateSize
11022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: This function calculates the destSize to be used in preflighting
11032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           when the destSize is equal to 0
11042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
11052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int calculateSize(char[] source,
11062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              int sourceStart,
11072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              int sourceLength) {
1108f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
11092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int destSize = sourceLength;
1110f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
11112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (options & LETTERS_MASK) {
11122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LETTERS_SHAPE:
11132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LETTERS_SHAPE_TASHKEEL_ISOLATED:
11142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (isLogical) {
11152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (int i = sourceStart, e = sourceStart + sourceLength - 1; i < e; ++i) {
11162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((source[i] == LAM_CHAR && isAlefChar(source[i+1])) || isTashkeelCharFE(source[i])){
11172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        --destSize;
11182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
11192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
11202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else { // visual
11212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for(int i = sourceStart + 1, e = sourceStart + sourceLength; i < e; ++i) {
11222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((source[i] == LAM_CHAR && isAlefChar(source[i-1])) || isTashkeelCharFE(source[i])) {
11232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        --destSize;
11242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
11252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
11262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
11272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
11282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LETTERS_UNSHAPE:
11302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for(int i = sourceStart, e = sourceStart + sourceLength; i < e; ++i) {
11312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (isLamAlefChar(source[i])) {
11322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    destSize++;
11332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
11342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
11352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
11362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        default:
11382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
11392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return destSize;
11422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1143f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1144f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
11452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
11462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : countSpaceSub
11472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: Counts number of times the subChar appears in the array
11482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
11492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static int countSpaceSub(char [] dest,int length, char subChar){
11502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i = 0;
11512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int count = 0;
11522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (i < length) {
11532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if (dest[i] == subChar) {
11542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              count++;
11552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              }
11562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          i++;
1157f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        }
1158f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        return count;
11592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1160f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
11612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
11622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : shiftArray
11632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: Shifts characters to replace space sub characters
11642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
11652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static void shiftArray(char [] dest,int start, int e, char subChar){
11662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int w = e;
11672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int r = e;
11682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (--r >= start) {
11692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          char ch = dest[r];
11702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if (ch != subChar) {
11712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            --w;
11722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (w != r) {
11732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              dest[w] = ch;
11742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
11752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
11762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   }
11782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
11802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : flipArray
11812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: inverts array, so that start becomes end and vice versa
11822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
11832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      private static int flipArray(char [] dest, int start, int e, int w){
11842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int r;
11852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (w > start) {
11862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // shift, assume small buffer size so don't use arraycopy
11872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          r = w;
11882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          w = start;
11892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          while (r < e) {
11902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            dest[w++] = dest[r++];
11912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           }
11922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         } else {
11932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             w = e;
11942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         }
11952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return w;
11962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      }
1197f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
11982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
11992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name     : handleTashkeelWithTatweel
1200f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Function : Replaces Tashkeel as following:
1201f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *            Case 1 :if the Tashkeel on tatweel, replace it with Tatweel.
1202f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *            Case 2 :if the Tashkeel aggregated with Shadda on Tatweel, replace
12032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                   it with Shadda on Tatweel.
12042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *            Case 3: if the Tashkeel is isolated replace it with Space.
12052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
12062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
12072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static int handleTashkeelWithTatweel(char[] dest, int sourceLength) {
12082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     int i;
12092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     for(i = 0; i < sourceLength; i++){
12102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                         if((isTashkeelOnTatweelChar(dest[i]) == 1)){
12112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                             dest[i] = TATWEEL_CHAR;
12122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }else if((isTashkeelOnTatweelChar(dest[i]) == 2)){
12132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                             dest[i] = SHADDA_TATWEEL_CHAR;
12142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }else if((isIsolatedTashkeelChar(dest[i])==1) && dest[i] != SHADDA_CHAR){
12152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                             dest[i] = SPACE_CHAR;
12162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
12172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     }
12182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     return sourceLength;
12192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
12222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *Name     : handleGeneratedSpaces
12232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *Function : The shapeUnicode function converts Lam + Alef into LamAlef + space,
1224f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           and Tashkeel to space.
1225f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           handleGeneratedSpaces function puts these generated spaces
12262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           according to the options the user specifies. LamAlef and Tashkeel
1227f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           spaces can be replaced at begin, at end, at near or decrease the
12282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           buffer size.
12292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
12302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           There is also Auto option for LamAlef and tashkeel, which will put
1231f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           the spaces at end of the buffer (or end of text if the user used
12322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           the option SPACES_RELATIVE_TO_TEXT_BEGIN_END).
12332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
1234f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           If the text type was visual_LTR and the option
1235f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           SPACES_RELATIVE_TO_TEXT_BEGIN_END was selected the END
12362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           option will place the space at the beginning of the buffer and
1237f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           BEGIN will place the space at the end of the buffer.
12382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1239f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert  private int handleGeneratedSpaces(char[] dest,
12402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int start,
12412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int length) {
1242f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
12432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      int lenOptionsLamAlef = options & LAMALEF_MASK;
12442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      int lenOptionsTashkeel = options & TASHKEEL_MASK;
12452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      boolean lamAlefOn = false;
12462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      boolean tashkeelOn = false;
1247f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
12482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      if (!isLogical & !spacesRelativeToTextBeginEnd) {
12492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          switch (lenOptionsLamAlef) {
12502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          case LAMALEF_BEGIN: lenOptionsLamAlef = LAMALEF_END; break;
12512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          case LAMALEF_END: lenOptionsLamAlef = LAMALEF_BEGIN; break;
12522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          default: break;
1253f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert         }
12542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          switch (lenOptionsTashkeel){
12552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          case TASHKEEL_BEGIN: lenOptionsTashkeel = TASHKEEL_END; break;
12562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          case TASHKEEL_END: lenOptionsTashkeel = TASHKEEL_BEGIN; break;
12572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          default: break;
12582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
12592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1260f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1261f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
12622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      if (lenOptionsLamAlef == LAMALEF_NEAR) {
12632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          for (int i = start, e = i + length; i < e; ++i) {
12642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              if (dest[i] == LAMALEF_SPACE_SUB) {
12652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  dest[i] = SPACE_CHAR;
12662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              }
12672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
1268f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
12692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      } else {
1270f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
12712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          final int e = start + length;
12722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          int wL = countSpaceSub(dest, length, LAMALEF_SPACE_SUB);
12732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          int wT = countSpaceSub(dest, length, TASHKEEL_SPACE_SUB);
12742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if (lenOptionsLamAlef == LAMALEF_END){
12762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            lamAlefOn = true;
12772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
12782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if (lenOptionsTashkeel == TASHKEEL_END){
12792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            tashkeelOn = true;
12802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
12812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1283f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert          if (lamAlefOn && (lenOptionsLamAlef == LAMALEF_END)) {
12842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            shiftArray(dest, start, e, LAMALEF_SPACE_SUB);
12852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            while (wL > start) {
12862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dest[--wL] = SPACE_CHAR;
1287f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            }
12882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
12892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if (tashkeelOn && (lenOptionsTashkeel == TASHKEEL_END)){
12912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            shiftArray(dest, start, e, TASHKEEL_SPACE_SUB);
12922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            while (wT > start) {
12932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 dest[--wT] = SPACE_CHAR;
12942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
12952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
1296f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1297f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert          lamAlefOn = false;
12982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          tashkeelOn = false;
1299f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
13002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if (lenOptionsLamAlef == LAMALEF_RESIZE){
13012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            lamAlefOn = true;
13022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
13032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if (lenOptionsTashkeel == TASHKEEL_RESIZE){
13042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            tashkeelOn = true;
13052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
1306f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
13072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if (lamAlefOn && (lenOptionsLamAlef == LAMALEF_RESIZE)){
13082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              shiftArray(dest, start, e, LAMALEF_SPACE_SUB);
13092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              wL = flipArray(dest,start,e, wL);
13102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              length = wL - start;
13112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
1312f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert          if (tashkeelOn && (lenOptionsTashkeel == TASHKEEL_RESIZE)) {
13132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              shiftArray(dest, start, e, TASHKEEL_SPACE_SUB);
13142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              wT = flipArray(dest,start,e, wT);
13152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              length = wT - start;
1316f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert          }
1317f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1318f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert          lamAlefOn = false;
1319f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert          tashkeelOn = false;
13202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1321f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert          if ((lenOptionsLamAlef == LAMALEF_BEGIN) ||
13222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              (lenOptionsLamAlef == LAMALEF_AUTO)){
13232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                lamAlefOn = true;
13242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
13252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if (lenOptionsTashkeel == TASHKEEL_BEGIN){
13262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                tashkeelOn = true;
13272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
13282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if (lamAlefOn && ((lenOptionsLamAlef == LAMALEF_BEGIN)||
13302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            (lenOptionsLamAlef == LAMALEF_AUTO))) { // spaces at beginning
13312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              shiftArray(dest, start, e, LAMALEF_SPACE_SUB);
13322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               wL = flipArray(dest,start,e, wL);
13332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  while (wL < e) {
13342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                      dest[wL++] = SPACE_CHAR;
13352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  }
13362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              }
13372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              if(tashkeelOn && (lenOptionsTashkeel == TASHKEEL_BEGIN)){
13382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               shiftArray(dest, start, e, TASHKEEL_SPACE_SUB);
13392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               wT = flipArray(dest,start,e, wT);
13402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  while (wT < e) {
13412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                      dest[wT++] = SPACE_CHAR;
13422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  }
13432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              }
13442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           }
1345f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
13462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      return length;
13472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  }
1348f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1349f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
13502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  /*
13512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   *Name     :expandCompositCharAtBegin
13522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   *Function :Expands the LamAlef character to Lam and Alef consuming the required
1353f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert   *         space from beginning of the buffer. If the text type was visual_LTR
13542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   *         and the option SPACES_RELATIVE_TO_TEXT_BEGIN_END was selected
13552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   *         the spaces will be located at end of buffer.
13562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   *         If there are no spaces to expand the LamAlef, an exception is thrown.
13572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*/
13582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private boolean expandCompositCharAtBegin(char[] dest,int start, int length,
13592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            int lacount) {
13602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     boolean spaceNotFound = false;
1361f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
13622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     if (lacount > countSpacesRight(dest, start, length)) {
13632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         spaceNotFound = true;
13642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         return spaceNotFound;
13652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     }
13662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     for (int r = start + length - lacount, w = start + length; --r >= start;) {
13672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         char ch = dest[r];
13682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         if (isNormalizedLamAlefChar(ch)) {
13692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             dest[--w] = LAM_CHAR;
13702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             dest[--w] = convertNormalizedLamAlef[ch - '\u065C'];
13712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         } else {
13722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             dest[--w] = ch;
13732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         }
13742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     }
13752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     return spaceNotFound;
1376f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
13772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  }
13782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  /*
13802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   *Name     : expandCompositCharAtEnd
1381f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert   *Function : Expands the LamAlef character to Lam and Alef consuming the
13822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   *           required space from end of the buffer. If the text type was
13832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   *           Visual LTR and the option SPACES_RELATIVE_TO_TEXT_BEGIN_END
1384f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert   *           was used, the spaces will be consumed from begin of buffer. If
1385f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert   *           there are no spaces to expand the LamAlef, an exception is thrown.
13862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   */
13872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  private boolean  expandCompositCharAtEnd(char[] dest,int start, int length,
13892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                          int lacount){
13902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      boolean spaceNotFound = false;
1391f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
13922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      if (lacount > countSpacesLeft(dest, start, length)) {
13932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          spaceNotFound = true;
13942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          return spaceNotFound;
13952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      }
13962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      for (int r = start + lacount, w = start, e = start + length; r < e; ++r) {
13972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          char ch = dest[r];
13982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if (isNormalizedLamAlefChar(ch)) {
13992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              dest[w++] = convertNormalizedLamAlef[ch - '\u065C'];
14002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              dest[w++] = LAM_CHAR;
14012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          } else {
14022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              dest[w++] = ch;
14032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
14042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      }
14052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      return spaceNotFound;
14062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  }
14072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  /*
14092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   *Name     : expandCompositCharAtNear
14102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   *Function : Expands the LamAlef character into Lam + Alef, YehHamza character
1411f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert   *           into Yeh + Hamza, SeenFamily character into SeenFamily character
1412f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert   *           + Tail, while consuming the space next to the character.
14132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   */
14142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  private boolean expandCompositCharAtNear(char[] dest,int start, int length,
14162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                       int yehHamzaOption, int seenTailOption, int lamAlefOption){
1417f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
14182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      boolean spaceNotFound = false;
1419f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1420f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1421f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
14222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      if (isNormalizedLamAlefChar(dest[start])) {
14232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          spaceNotFound = true;
14242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          return spaceNotFound;
14252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      }
1426f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert      for (int i = start + length; --i >=start;) {
14272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          char ch = dest[i];
14282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if (lamAlefOption == 1 && isNormalizedLamAlefChar(ch)) {
14292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              if (i>start &&dest[i-1] == SPACE_CHAR) {
14302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  dest[i] = LAM_CHAR;
14312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  dest[--i] = convertNormalizedLamAlef[ch - '\u065C'];
14322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              } else {
14332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  spaceNotFound = true;
14342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  return spaceNotFound;
14352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              }
14362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }else if(seenTailOption == 1 && isSeenTailFamilyChar(ch) == 1){
14372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              if(i>start &&dest[i-1] == SPACE_CHAR){
14382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  dest[i-1] = tailChar;
14392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              } else{
14402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  spaceNotFound = true;
14412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  return spaceNotFound;
14422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              }
14432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }else if(yehHamzaOption == 1 && isYehHamzaChar(ch)){
1444f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
14452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               if(i>start &&dest[i-1] == SPACE_CHAR){
14462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  dest[i] = yehHamzaToYeh[ch - YEH_HAMZAFE_CHAR];
14472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  dest[i-1] = HAMZAFE_CHAR;
14482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              }else{
14492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  spaceNotFound = true;
14502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  return spaceNotFound;
14512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
1452f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1453f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
14542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
14552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      }
14562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller      return false;
14572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller  }
1459f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
14602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
14612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : expandCompositChar
14622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: LamAlef needs special handling as the LamAlef is
14632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           one character while expanding it will give two
14642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           characters Lam + Alef, so we need to expand the LamAlef
14652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           in near or far spaces according to the options the user
14662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           specifies or increase the buffer size.
14672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           Dest has enough room for the expansion if we are growing.
14682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           lamalef are normalized to the 'special characters'
14692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
14702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int expandCompositChar(char[] dest,
14712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              int start,
14722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              int length,
14732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              int lacount,
14742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              int shapingMode) throws ArabicShapingException {
14752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int lenOptionsLamAlef = options & LAMALEF_MASK;
14772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int lenOptionsSeen = options & SEEN_MASK;
1478f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        int lenOptionsYehHamza = options & YEHHAMZA_MASK;
14792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean spaceNotFound = false;
1480f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
14812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!isLogical && !spacesRelativeToTextBeginEnd) {
14822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            switch (lenOptionsLamAlef) {
14832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case LAMALEF_BEGIN: lenOptionsLamAlef = LAMALEF_END; break;
14842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case LAMALEF_END: lenOptionsLamAlef = LAMALEF_BEGIN; break;
14852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            default: break;
14862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
14872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1488f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
14892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if(shapingMode == 1){
14902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if(lenOptionsLamAlef == LAMALEF_AUTO){
14912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(isLogical){
14922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    spaceNotFound = expandCompositCharAtEnd(dest, start, length, lacount);
14932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if(spaceNotFound){
14942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        spaceNotFound = expandCompositCharAtBegin(dest, start, length, lacount);
14952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
14962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if(spaceNotFound){
14972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        spaceNotFound = expandCompositCharAtNear(dest, start, length,0,0,1);
14982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
14992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if(spaceNotFound){
15002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        throw new ArabicShapingException("No spacefor lamalef");
15012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
15022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }else{
15032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    spaceNotFound = expandCompositCharAtBegin(dest, start, length, lacount);
15042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if(spaceNotFound){
15052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        spaceNotFound = expandCompositCharAtEnd(dest, start, length, lacount);
15062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
15072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if(spaceNotFound){
15082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        spaceNotFound = expandCompositCharAtNear(dest, start, length,0,0,1);
15092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
15102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if(spaceNotFound){
15112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        throw new ArabicShapingException("No spacefor lamalef");
15122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
15132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
15142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }else if(lenOptionsLamAlef == LAMALEF_END){
15152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                spaceNotFound = expandCompositCharAtEnd(dest, start, length, lacount);
15162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(spaceNotFound){
15172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    throw new ArabicShapingException("No spacefor lamalef");
15182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
15192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }else if(lenOptionsLamAlef == LAMALEF_BEGIN){
15202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                spaceNotFound = expandCompositCharAtBegin(dest, start, length, lacount);
15212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(spaceNotFound){
15222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    throw new ArabicShapingException("No spacefor lamalef");
1523f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                }
15242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }else if(lenOptionsLamAlef == LAMALEF_NEAR){
15252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                spaceNotFound = expandCompositCharAtNear(dest, start, length,0,0,1);
15262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(spaceNotFound){
1527f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    throw new ArabicShapingException("No spacefor lamalef");
15282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
15292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }else if(lenOptionsLamAlef == LAMALEF_RESIZE){
15302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (int r = start + length, w = r + lacount; --r >= start;) {
15312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    char ch = dest[r];
15322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (isNormalizedLamAlefChar(ch)) {
15332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        dest[--w] = '\u0644';
15342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        dest[--w] = convertNormalizedLamAlef[ch - '\u065C'];
15352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
15362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        dest[--w] = ch;
15372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
15382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
15392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                length += lacount;
15402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
15412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }else{
15422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(lenOptionsSeen == SEEN_TWOCELL_NEAR){
15432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                spaceNotFound = expandCompositCharAtNear(dest, start, length,0,1,0);
15442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(spaceNotFound){
1545f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    throw new ArabicShapingException("No space for Seen tail expansion");
15462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
15472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
15482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if(lenOptionsYehHamza == YEHHAMZA_TWOCELL_NEAR){
15492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                spaceNotFound = expandCompositCharAtNear(dest, start, length,1,0,0);
15502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(spaceNotFound){
1551f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    throw new ArabicShapingException("No space for YehHamza expansion");
15522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
1553f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            }
15542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
15552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return length;
15562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
15572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1558f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
15592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Convert the input buffer from FExx Range into 06xx Range
15602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to put all characters into the 06xx range
15612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * even the lamalef is converted to the special region in
15622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the 06xx range.  Return the number of lamalef chars found.
15632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
15642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int normalize(char[] dest, int start, int length) {
15652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int lacount = 0;
15662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = start, e = i + length; i < e; ++i) {
15672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char ch = dest[i];
15682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ch >= '\uFE70' && ch <= '\uFEFC') {
15692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (isLamAlefChar(ch)) {
15702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ++lacount;
15712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
15722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dest[i] = (char)convertFEto06[ch - '\uFE70'];
15732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
15742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
15752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return lacount;
15762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
15772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
15792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : deshapeNormalize
15802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: Convert the input buffer from FExx Range into 06xx Range
1581f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           even the lamalef is converted to the special region in the 06xx range.
1582f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           According to the options the user enters, all seen family characters
1583f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *           followed by a tail character are merged to seen tail family character and
15842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           any yeh followed by a hamza character are merged to yehhamza character.
15852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           Method returns the number of lamalef chars found.
15862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
15872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int deshapeNormalize(char[] dest, int start, int length) {
15882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int lacount = 0;
15892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int yehHamzaComposeEnabled = 0;
15902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int seenComposeEnabled = 0;
15912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        yehHamzaComposeEnabled = ((options&YEHHAMZA_MASK) == YEHHAMZA_TWOCELL_NEAR) ? 1 : 0;
15932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        seenComposeEnabled = ((options&SEEN_MASK) == SEEN_TWOCELL_NEAR)? 1 : 0;
1594f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
15952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = start, e = i + length; i < e; ++i) {
15962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char ch = dest[i];
1597f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1598f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        if( (yehHamzaComposeEnabled == 1) && ((ch == HAMZA06_CHAR) || (ch == HAMZAFE_CHAR))
15992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               && (i < (length - 1)) && isAlefMaksouraChar(dest[i+1] )) {
16002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dest[i] = SPACE_CHAR;
16012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dest[i+1] = YEH_HAMZA_CHAR;
1602f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert       } else if ( (seenComposeEnabled == 1) && (isTailChar(ch)) && (i< (length - 1))
16032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                       && (isSeenTailFamilyChar(dest[i+1])==1) ) {
16042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               dest[i] = SPACE_CHAR;
16052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       }
16062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       else if (ch >= '\uFE70' && ch <= '\uFEFC') {
16072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (isLamAlefChar(ch)) {
16082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ++lacount;
16092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dest[i] = (char)convertFEto06[ch - '\uFE70'];
16112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
16122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
16132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return lacount;
16142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
16152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
16172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : shapeUnicode
16182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: Converts an Arabic Unicode buffer in 06xx Range into a shaped
16192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           arabic Unicode buffer in FExx Range
16202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1621f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    private int shapeUnicode(char[] dest,
16222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                             int start,
16232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                             int length,
16242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                             int destSize,
16252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                             int tashkeelFlag)throws ArabicShapingException {
1626f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
16272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int lamalef_count = normalize(dest, start, length);
16282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // resolve the link between the characters.
16302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Arabic characters have four forms: Isolated, Initial, Medial and Final.
16312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Tashkeel characters have two, isolated or medial, and sometimes only isolated.
16322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // tashkeelFlag == 0: shape normally, 1: shape isolated, 2: don't shape
16332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean lamalef_found = false, seenfam_found = false;
16352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean yehhamza_found = false, tashkeel_found = false;
16362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i = start + length - 1;
16372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int currLink = getLink(dest[i]);
16382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int nextLink = 0;
16392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int prevLink = 0;
16402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int lastLink = 0;
16412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //int prevPos = i;
16422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int lastPos = i;
16432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int nx = -2;
16442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int nw = 0;
16452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (i >= 0) {
1647f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            // If high byte of currLink != 0 then there might be more than one shape
1648f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            if ((currLink & '\uFF00') != 0 || isTashkeelChar(dest[i])) {
16492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                nw = i - 1;
16502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                nx = -2;
16512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                while (nx < 0) { // we need to know about next char
16522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (nw == -1) {
16532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        nextLink = 0;
16542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        nx = Integer.MAX_VALUE;
16552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
16562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        nextLink = getLink(dest[nw]);
16572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if ((nextLink & IRRELEVANT) == 0) {
16582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            nx = nw;
16592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        } else {
16602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            --nw;
16612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
16622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
16632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (((currLink & ALEFTYPE) > 0) && ((lastLink & LAMTYPE) > 0)) {
1666f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    lamalef_found = true;
16672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    char wLamalef = changeLamAlef(dest[i]); // get from 0x065C-0x065f
16682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (wLamalef != '\u0000') {
16692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // replace alef by marker, it will be removed later
16702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        dest[i] = '\uffff';
16712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        dest[lastPos] = wLamalef;
16722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        i = lastPos;
16732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
16742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    lastLink = prevLink;
16762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    currLink = getLink(wLamalef); // requires '\u0000', unfortunately
16772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ((i > 0) && (dest[i-1] == SPACE_CHAR))
1679f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                {
16802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ( isSeenFamilyChar(dest[i]) == 1){
16812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        seenfam_found = true;
16822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else if (dest[i] == YEH_HAMZA_CHAR) {
16832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        yehhamza_found = true;
16842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
16852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else if(i==0){
16872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ( isSeenFamilyChar(dest[i]) == 1){
16882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        seenfam_found = true;
16892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else if (dest[i] == YEH_HAMZA_CHAR) {
16902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        yehhamza_found = true;
16912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
16922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // get the proper shape according to link ability of neighbors
16962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // and of character; depends on the order of the shapes
16972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // (isolated, initial, middle, final) in the compatibility area
16982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int flag = specialChar(dest[i]);
17002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int shape = shapeTable[nextLink & LINK_MASK]
17022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    [lastLink & LINK_MASK]
17032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    [currLink & LINK_MASK];
17042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (flag == 1) {
17062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    shape &= 0x1;
17072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else if (flag == 2) {
17082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (tashkeelFlag == 0 &&
1709f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                        ((lastLink & LINKL) != 0) &&
1710f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                        ((nextLink & LINKR) != 0) &&
1711f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                        dest[i] != '\u064C' &&
17122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        dest[i] != '\u064D' &&
1713f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                        !((nextLink & ALEFTYPE) == ALEFTYPE &&
17142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                          (lastLink & LAMTYPE) == LAMTYPE)) {
1715f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
17162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        shape = 1;
1717f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
17182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else if(tashkeelFlag == 2 && dest[i] == SHADDA06_CHAR){
17192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        shape = 1;
1720f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
17212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
17222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        shape = 0;
17232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
17242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
17252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (flag == 2) {
1726f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    if (tashkeelFlag == 2 && dest[i] != SHADDA06_CHAR) {
17272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        dest[i] = TASHKEEL_SPACE_SUB;
17282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        tashkeel_found = true;
17292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
17302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    else{
17312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        dest[i] = (char)('\uFE70' + irrelevantPos[dest[i] - '\u064B'] + shape);
17322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
1733f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    // else leave tashkeel alone
17342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
17352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    dest[i] = (char)('\uFE70' + (currLink >> 8) + shape);
17362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
17372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // move one notch forward
17402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ((currLink & IRRELEVANT) == 0) {
17412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                prevLink = lastLink;
17422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                lastLink = currLink;
17432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                //prevPos = lastPos;
17442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                lastPos = i;
17452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            --i;
17482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (i == nx) {
17492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                currLink = nextLink;
17502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                nx = -2;
17512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (i != -1) {
17522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                currLink = getLink(dest[i]);
17532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
17552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1756f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        // If we found a lam/alef pair in the buffer
17572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // call handleGeneratedSpaces to remove the spaces that were added
17582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        destSize = length;
17602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (lamalef_found || tashkeel_found) {
17612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            destSize = handleGeneratedSpaces(dest, start, length);
17622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
17632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (seenfam_found || yehhamza_found){
17642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            destSize = expandCompositChar(dest, start, destSize, lamalef_count, SHAPE_MODE);
17652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
17662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return destSize;
17672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
17682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
17702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Name    : deShapeUnicode
17712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Function: Converts an Arabic Unicode buffer in FExx Range into unshaped
17722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *           arabic Unicode buffer in 06xx Range
17732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1774f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    private int deShapeUnicode(char[] dest,
17752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                               int start,
17762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                               int length,
17772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                               int destSize) throws ArabicShapingException {
17782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1779f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        int lamalef_count = deshapeNormalize(dest, start, length);
17802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // If there was a lamalef in the buffer call expandLamAlef
17822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (lamalef_count != 0) {
17832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // need to adjust dest to fit expanded buffer... !!!
1784f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            destSize = expandCompositChar(dest, start, length, lamalef_count,DESHAPE_MODE);
17852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
17862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            destSize = length;
17872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
17882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return destSize;
17902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
17912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1792f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    private int internalShape(char[] source,
17932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              int sourceStart,
17942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              int sourceLength,
17952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              char[] dest,
17962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              int destStart,
17972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              int destSize) throws ArabicShapingException {
17982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (sourceLength == 0) {
18002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 0;
18012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
18022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (destSize == 0) {
18042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (((options & LETTERS_MASK) != LETTERS_NOOP) &&
18052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ((options & LAMALEF_MASK) == LAMALEF_RESIZE)) {
1806f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
18072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return calculateSize(source, sourceStart, sourceLength);
18082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
18092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return sourceLength; // by definition
18102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
18122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // always use temp buffer
18142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        char[] temp = new char[sourceLength * 2]; // all lamalefs requiring expansion
18152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        System.arraycopy(source, sourceStart, temp, 0, sourceLength);
18162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isLogical) {
18182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            invertBuffer(temp, 0, sourceLength);
18192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
18202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int outputSize = sourceLength;
18222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (options & LETTERS_MASK) {
18242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LETTERS_SHAPE_TASHKEEL_ISOLATED:
18252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            outputSize = shapeUnicode(temp, 0, sourceLength, destSize, 1);
18262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
18272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LETTERS_SHAPE:
1829f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            if( ((options&TASHKEEL_MASK) != 0) &&
18302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ((options&TASHKEEL_MASK) !=TASHKEEL_REPLACE_BY_TATWEEL)) {
18312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   /* Call the shaping function with tashkeel flag == 2 for removal of tashkeel */
18322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                outputSize = shapeUnicode(temp, 0, sourceLength, destSize, 2);
18332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }else {
18342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   //default Call the shaping function with tashkeel flag == 1 */
18352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    outputSize = shapeUnicode(temp, 0, sourceLength, destSize, 0);
18362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   /*After shaping text check if user wants to remove tashkeel and replace it with tatweel*/
18382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   if( (options&TASHKEEL_MASK) == TASHKEEL_REPLACE_BY_TATWEEL){
18392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                       outputSize = handleTashkeelWithTatweel(temp,sourceLength);
18402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   }
18412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               }
18422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
18432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LETTERS_UNSHAPE:
18452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            outputSize = deShapeUnicode(temp, 0, sourceLength, destSize);
1846f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            break;
18472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        default:
18492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
18502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1851f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
18522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (outputSize > destSize) {
18532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new ArabicShapingException("not enough room for result data");
18542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
18552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((options & DIGITS_MASK) != DIGITS_NOOP) {
18572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char digitBase = '\u0030'; // European digits
18582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            switch (options & DIGIT_TYPE_MASK) {
18592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case DIGIT_TYPE_AN:
18602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                digitBase = '\u0660';  // Arabic-Indic digits
18612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
18622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case DIGIT_TYPE_AN_EXTENDED:
18642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                digitBase = '\u06f0';  // Eastern Arabic-Indic digits (Persian and Urdu)
18652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
18662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            default:
18682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
18692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            switch (options & DIGITS_MASK) {
18722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case DIGITS_EN2AN:
18732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                {
18742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int digitDelta = digitBase - '\u0030';
18752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    for (int i = 0; i < outputSize; ++i) {
18762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        char ch = temp[i];
18772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (ch <= '\u0039' && ch >= '\u0030') {
18782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            temp[i] += digitDelta;
18792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
18802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
18812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
18822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
18832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case DIGITS_AN2EN:
18852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                {
18862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    char digitTop = (char)(digitBase + 9);
18872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int digitDelta = '\u0030' - digitBase;
18882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    for (int i = 0; i < outputSize; ++i) {
18892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        char ch = temp[i];
18902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (ch <= digitTop && ch >= digitBase) {
18912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            temp[i] += digitDelta;
18922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
18932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
18942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
18952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
18962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case DIGITS_EN2AN_INIT_LR:
18982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                shapeToArabicDigitsWithContext(temp, 0, outputSize, digitBase, false);
18992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
19002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
19012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case DIGITS_EN2AN_INIT_AL:
19022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                shapeToArabicDigitsWithContext(temp, 0, outputSize, digitBase, true);
19032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
19042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
19052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            default:
19062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
19072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
19082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
19092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
19102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isLogical) {
19112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            invertBuffer(temp, 0, outputSize);
19122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1913f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
19142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        System.arraycopy(temp, 0, dest, destStart, outputSize);
1915f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
19162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return outputSize;
19172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
19182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller}
1919