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*******************************************************************************
698d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert*   Copyright (C) 2001-2016, International Business Machines
72ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*   Corporation and others.  All Rights Reserved.
82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*******************************************************************************
92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*/
102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* FOOD FOR THOUGHT: currently the reordering modes are a mixture of
122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * algorithm for direct BiDi, algorithm for inverse Bidi and the bizarre
132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * concept of RUNS_ONLY which is a double operation.
142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * It could be advantageous to divide this into 3 concepts:
152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * a) Operation: direct / inverse / RUNS_ONLY
162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * b) Direct algorithm: default / NUMBERS_SPECIAL / GROUP_NUMBERS_WITH_L
172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * c) Inverse algorithm: default / INVERSE_LIKE_DIRECT / NUMBERS_SPECIAL
182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This would allow combinations not possible today like RUNS_ONLY with
192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * NUMBERS_SPECIAL.
202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Also allow to set INSERT_MARKS for the direct step of RUNS_ONLY and
212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * REMOVE_CONTROLS for the inverse step.
222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Not all combinations would be supported, and probably not all do make sense.
232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This would need to document which ones are supported and what are the
242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * fallbacks for unsupported combinations.
252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller//TODO: make sample program do something simple but real and complete
282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.text;
302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.awt.font.NumericShaper;
322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.awt.font.TextAttribute;
332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.lang.reflect.Array;
342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.AttributedCharacterIterator;
352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Arrays;
362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.UBiDiProps;
382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.lang.UCharacter;
392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.lang.UCharacterDirection;
402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.lang.UProperty;
412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/**
432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <h2>Bidi algorithm for ICU</h2>
452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This is an implementation of the Unicode Bidirectional Algorithm. The
472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * algorithm is defined in the <a
482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Annex #9</a>.
492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>
502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Note: Libraries that perform a bidirectional algorithm and reorder strings
522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * accordingly are sometimes called "Storage Layout Engines". ICU's Bidi and
532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * shaping (ArabicShaping) classes can be used at the core of such "Storage
542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Layout Engines".
552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <h3>General remarks about the API:</h3>
572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The &quot;limit&quot; of a sequence of characters is the position just after
592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * their last character, i.e., one more than that position.
602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>
612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Some of the API methods provide access to &quot;runs&quot;. Such a
632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * &quot;run&quot; is defined as a sequence of characters that are at the same
642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * embedding level after performing the Bidi algorithm.
652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <h3>Basic concept: paragraph</h3>
672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * A piece of text can be divided into several paragraphs by characters
682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * with the Bidi class <code>Block Separator</code>. For handling of
692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * paragraphs, see:
702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ul>
712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #countParagraphs}
722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #getParaLevel}
732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #getParagraph}
742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #getParagraphByIndex}
752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ul>
762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <h3>Basic concept: text direction</h3>
782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The direction of a piece of text may be:
792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ul>
802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #LTR}
812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #RTL}
822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #MIXED}
832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #NEUTRAL}
842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ul>
852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <h3>Basic concept: levels</h3>
872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Levels in this API represent embedding levels according to the Unicode
892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Bidirectional Algorithm.
902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Their low-order bit (even/odd value) indicates the visual direction.<p>
912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Levels can be abstract values when used for the
932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>paraLevel</code> and <code>embeddingLevels</code>
942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * arguments of <code>setPara()</code>; there:
952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ul>
962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>the high-order bit of an <code>embeddingLevels[]</code>
972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * value indicates whether the using application is
982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * specifying the level of a character to <i>override</i> whatever the
992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Bidi implementation would resolve it to.</li>
1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li><code>paraLevel</code> can be set to the
1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * pseudo-level values <code>LEVEL_DEFAULT_LTR</code>
1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and <code>LEVEL_DEFAULT_RTL</code>.</li>
1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ul>
1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>The related constants are not real, valid level values.
1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>DEFAULT_XXX</code> can be used to specify
1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * a default for the paragraph level for
1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * when the <code>setPara()</code> method
1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * shall determine it but there is no
1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * strongly typed character in the input.<p>
1112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Note that the value for <code>LEVEL_DEFAULT_LTR</code> is even
1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and the one for <code>LEVEL_DEFAULT_RTL</code> is odd,
1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * just like with normal LTR and RTL level values -
1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * these special values are designed that way. Also, the implementation
1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * assumes that MAX_EXPLICIT_LEVEL is odd.
1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <b>See Also:</b>
1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ul>
1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #LEVEL_DEFAULT_LTR}
1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #LEVEL_DEFAULT_RTL}
1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #LEVEL_OVERRIDE}
1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #MAX_EXPLICIT_LEVEL}
1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #setPara}
1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ul>
1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <h3>Basic concept: Reordering Mode</h3>
1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Reordering mode values indicate which variant of the Bidi algorithm to
1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * use.
1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <b>See Also:</b>
1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ul>
1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #setReorderingMode}
1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #REORDER_DEFAULT}
1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #REORDER_NUMBERS_SPECIAL}
1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #REORDER_GROUP_NUMBERS_WITH_R}
1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #REORDER_RUNS_ONLY}
1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #REORDER_INVERSE_NUMBERS_AS_L}
1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #REORDER_INVERSE_LIKE_DIRECT}
1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #REORDER_INVERSE_FOR_NUMBERS_SPECIAL}
1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ul>
1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <h3>Basic concept: Reordering Options</h3>
1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Reordering options can be applied during Bidi text transformations.
1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <b>See Also:</b>
1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ul>
1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #setReorderingOptions}
1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #OPTION_DEFAULT}
1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #OPTION_INSERT_MARKS}
1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #OPTION_REMOVE_CONTROLS}
1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>{@link #OPTION_STREAMING}
1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ul>
1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <h4> Sample code for the ICU Bidi API </h4>
1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <h5>Rendering a paragraph with the ICU Bidi API</h5>
1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This is (hypothetical) sample code that illustrates how the ICU Bidi API
1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * could be used to render a paragraph of text. Rendering code depends highly on
1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the graphics system, therefore this sample code must make a lot of
1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * assumptions, which may or may not match any existing graphics system's
1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * properties.
1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>
1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The basic assumptions are:
167bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *
1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ul>
1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>Rendering is done from left to right on a horizontal line.</li>
1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>A run of single-style, unidirectional text can be rendered at once.
1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </li>
1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>Such a run of text is passed to the graphics system with characters
1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * (code units) in logical order.</li>
1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>The line-breaking algorithm is very complicated and Locale-dependent -
1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and therefore its implementation omitted from this sample code.</li>
1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ul>
1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <pre>
1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1801fba789ac68efdd9120a7373f49daef42833e674Neil Fuller *  package android.icu.dev.test.bidi;
1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1821fba789ac68efdd9120a7373f49daef42833e674Neil Fuller *  import android.icu.text.Bidi;
1831fba789ac68efdd9120a7373f49daef42833e674Neil Fuller *  import android.icu.text.BidiRun;
1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  public class Sample {
1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static final int styleNormal = 0;
1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static final int styleSelected = 1;
1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static final int styleBold = 2;
1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static final int styleItalics = 4;
1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static final int styleSuper=8;
1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static final int styleSub = 16;
1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static class StyleRun {
1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          int limit;
1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          int style;
1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          public StyleRun(int limit, int style) {
1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              this.limit = limit;
2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              this.style = style;
2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          }
2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      }
2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static class Bounds {
2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          int start;
2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          int limit;
2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          public Bounds(int start, int limit) {
2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              this.start = start;
2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              this.limit = limit;
2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          }
2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      }
2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static int getTextWidth(String text, int start, int limit,
2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                              StyleRun[] styleRuns, int styleRunCount) {
2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          // simplistic way to compute the width
2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          return limit - start;
2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      }
2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // set limit and StyleRun limit for a line
2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // from text[start] and from styleRuns[styleRunStart]
2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // using Bidi.getLogicalRun(...)
2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // returns line width
2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static int getLineBreak(String text, Bounds line, Bidi para,
2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                              StyleRun styleRuns[], Bounds styleRun) {
2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          // dummy return
2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          return 0;
2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      }
2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // render runs on a line sequentially, always from left to right
2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // prepare rendering a new line
2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static void startLine(byte textDirection, int lineWidth) {
2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          System.out.println();
2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      }
2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // render a run of text and advance to the right by the run width
2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // the text[start..limit-1] is always in logical order
2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static void renderRun(String text, int start, int limit,
2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                            byte textDirection, int style) {
2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      }
2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // We could compute a cross-product
2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // from the style runs with the directional runs
2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // and then reorder it.
2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // Instead, here we iterate over each run type
2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // and render the intersections -
2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // with shortcuts in simple (and common) cases.
2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // renderParagraph() is the main function.
2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // render a directional run with
2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // (possibly) multiple style runs intersecting with it
2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static void renderDirectionalRun(String text, int start, int limit,
2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                       byte direction, StyleRun styleRuns[],
2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                       int styleRunCount) {
2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          int i;
2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          // iterate over style runs
2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          if (direction == Bidi.LTR) {
2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              int styleLimit;
261bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *              for (i = 0; i &lt; styleRunCount; ++i) {
2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  styleLimit = styleRuns[i].limit;
263bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *                  if (start &lt; styleLimit) {
264bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *                      if (styleLimit &gt; limit) {
2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                          styleLimit = limit;
2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      }
2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      renderRun(text, start, styleLimit,
2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                direction, styleRuns[i].style);
2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      if (styleLimit == limit) {
2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                          break;
2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      }
2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      start = styleLimit;
2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  }
2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              }
2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          } else {
2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              int styleStart;
2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
278bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *              for (i = styleRunCount-1; i &gt;= 0; --i) {
279bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *                  if (i &gt; 0) {
2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      styleStart = styleRuns[i-1].limit;
2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  } else {
2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      styleStart = 0;
2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  }
284bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *                  if (limit &gt;= styleStart) {
285bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *                      if (styleStart &lt; start) {
2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                          styleStart = start;
2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      }
2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      renderRun(text, styleStart, limit, direction,
2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                styleRuns[i].style);
2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      if (styleStart == start) {
2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                          break;
2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      }
2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      limit = styleStart;
2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  }
2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              }
2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          }
2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      }
2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      // the line object represents text[start..limit-1]
3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static void renderLine(Bidi line, String text, int start, int limit,
3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                             StyleRun styleRuns[], int styleRunCount) {
3022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          byte direction = line.getDirection();
3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          if (direction != Bidi.MIXED) {
3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              // unidirectional
305bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *              if (styleRunCount &lt;= 1) {
3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  renderRun(text, start, limit, direction, styleRuns[0].style);
3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              } else {
3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  renderDirectionalRun(text, start, limit, direction,
3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                       styleRuns, styleRunCount);
3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              }
3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          } else {
3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              // mixed-directional
3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              int count, i;
3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              BidiRun run;
3152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              try {
3172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  count = line.countRuns();
3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              } catch (IllegalStateException e) {
3192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  e.printStackTrace();
3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  return;
3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              }
322bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *              if (styleRunCount &lt;= 1) {
3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  int style = styleRuns[0].style;
3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  // iterate over directional runs
326bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *                  for (i = 0; i &lt; count; ++i) {
3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      run = line.getVisualRun(i);
3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      renderRun(text, run.getStart(), run.getLimit(),
3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                run.getDirection(), style);
3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  }
3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              } else {
3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  // iterate over both directional and style runs
333bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *                  for (i = 0; i &lt; count; ++i) {
3342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      run = line.getVisualRun(i);
3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      renderDirectionalRun(text, run.getStart(),
3362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                           run.getLimit(), run.getDirection(),
3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                           styleRuns, styleRunCount);
3382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  }
3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              }
3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          }
3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      }
3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      static void renderParagraph(String text, byte textDirection,
3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                  StyleRun styleRuns[], int styleRunCount,
3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                  int lineWidth) {
3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          int length = text.length();
3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          Bidi para = new Bidi();
3482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          try {
3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              para.setPara(text,
3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                           textDirection != 0 ? Bidi.LEVEL_DEFAULT_RTL
3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                              : Bidi.LEVEL_DEFAULT_LTR,
3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                           null);
3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          } catch (Exception e) {
3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              e.printStackTrace();
3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              return;
3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          }
357bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *          byte paraLevel = (byte)(1 &amp; para.getParaLevel());
3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          StyleRun styleRun = new StyleRun(length, styleNormal);
3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
360bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *          if (styleRuns == null || styleRunCount &lt;= 0) {
3612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              styleRuns = new StyleRun[1];
3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              styleRunCount = 1;
3632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              styleRuns[0] = styleRun;
3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          }
365bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *          // assume styleRuns[styleRunCount-1].limit&gt;=length
3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          int width = getTextWidth(text, 0, length, styleRuns, styleRunCount);
368bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *          if (width &lt;= lineWidth) {
3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              // everything fits onto one line
3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              // prepare rendering a new line from either left or right
3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              startLine(paraLevel, width);
3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              renderLine(para, text, 0, length, styleRuns, styleRunCount);
3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          } else {
3762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              // we need to render several lines
3772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              Bidi line = new Bidi(length, 0);
3782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              int start = 0, limit;
3792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              int styleRunStart = 0, styleRunLimit;
3802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
3812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              for (;;) {
3822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  limit = length;
3832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  styleRunLimit = styleRunCount;
3842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  width = getLineBreak(text, new Bounds(start, limit),
3852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                       para, styleRuns,
3862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                       new Bounds(styleRunStart, styleRunLimit));
3872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  try {
3882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      line = para.setLine(start, limit);
3892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  } catch (Exception e) {
3902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      e.printStackTrace();
3912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      return;
3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  }
3932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  // prepare rendering a new line
3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  // from either left or right
3952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  startLine(paraLevel, width);
3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
397bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *                  if (styleRunStart &gt; 0) {
3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      int newRunCount = styleRuns.length - styleRunStart;
3992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      StyleRun[] newRuns = new StyleRun[newRunCount];
4002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      System.arraycopy(styleRuns, styleRunStart, newRuns, 0,
4012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                       newRunCount);
4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      renderLine(line, text, start, limit, newRuns,
4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                 styleRunLimit - styleRunStart);
4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  } else {
4052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      renderLine(line, text, start, limit, styleRuns,
4062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                                 styleRunLimit - styleRunStart);
4072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  }
4082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  if (limit == length) {
4092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      break;
4102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  }
4112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  start = limit;
4122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  styleRunStart = styleRunLimit - 1;
413bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin *                  if (start &gt;= styleRuns[styleRunStart].limit) {
4142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                      ++styleRunStart;
4152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                  }
4162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *              }
4172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          }
4182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      }
4192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      public static void main(String[] args)
4212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      {
4222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          renderParagraph("Some Latin text...", Bidi.LTR, null, 0, 80);
4232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *          renderParagraph("Some Hebrew text...", Bidi.RTL, null, 0, 60);
4242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *      }
4252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  }
4262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </pre>
42898d264ec1d3841aef62c0e0293c929c23c08c5c5Fredrik Roubert *
429836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide Only a subset of ICU is exposed in Android
4302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
4312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*
4332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * General implementation notes:
4342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Throughout the implementation, there are comments like (W2) that refer to
4362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * rules of the BiDi algorithm, in this example to the second rule of the
4372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * resolution of weak types.
4382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For handling surrogate pairs, where two UChar's form one "abstract" (or UTF-32)
4402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * character according to UTF-16, the second UChar gets the directional property of
4412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the entire character assigned, while the first one gets a BN, a boundary
4422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * neutral, type, which is ignored by most of the algorithm according to
4432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * rule (X9) and the implementation suggestions of the BiDi algorithm.
4442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Later, adjustWSLevels() will set the level for each BN to that of the
4462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * following character (UChar), which results in surrogate pairs getting the
4472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * same level on each of their surrogates.
4482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * In a UTF-8 implementation, the same thing could be done: the last byte of
4502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * a multi-byte sequence would get the "real" property, while all previous
4512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * bytes of that sequence would get BN.
4522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * It is not possible to assign all those parts of a character the same real
4542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * property because this would fail in the resolution of weak types with rules
4552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * that look at immediately surrounding types.
4562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * As a related topic, this implementation does not remove Boundary Neutral
4582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * types from the input, but ignores them wherever this is relevant.
4592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For example, the loop for the resolution of the weak types reads
4602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * types until it finds a non-BN.
4612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Also, explicit embedding codes are neither changed into BN nor removed.
4622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * They are only treated the same way real BNs are.
4632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * As stated before, adjustWSLevels() takes care of them at the end.
4642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For the purpose of conformance, the levels of all these codes
4652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * do not matter.
4662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Note that this implementation modifies the dirProps
4682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * after the initial setup, when applying X5c (replace FSI by LRI or RLI),
4692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * X6, N0 (replace paired brackets by L or R).
4702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * In this implementation, the resolution of weak types (W1 to W6),
4722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * neutrals (N1 and N2), and the assignment of the resolved level (In)
4732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * are all done in one single loop, in resolveImplicitLevels().
4742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Changes of dirProp values are done on the fly, without writing
4752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * them back to the dirProps array.
4762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This implementation contains code that allows to bypass steps of the
4792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * algorithm that are not needed on the specific paragraph
4802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in order to speed up the most common cases considerably,
4812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * like text that is entirely LTR, or RTL text without numbers.
4822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Most of this is done by setting a bit for each directional property
4842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in a flags variable and later checking for whether there are
4852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * any LTR characters or any RTL characters, or both, whether
4862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * there are any explicit embedding codes, etc.
4872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If the (Xn) steps are performed, then the flags are re-evaluated,
4892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * because they will then not contain the embedding codes any more
4902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and will be adjusted for override codes, so that subsequently
4912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * more bypassing may be possible than what the initial flags suggested.
4922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If the text is not mixed-directional, then the
4942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * algorithm steps for the weak type resolution are not performed,
4952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and all levels are set to the paragraph level.
4962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
4972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If there are no explicit embedding codes, then the (Xn) steps
4982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * are not performed.
4992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
5002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If embedding levels are supplied as a parameter, then all
5012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * explicit embedding codes are ignored, and the (Xn) steps
5022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * are not performed.
5032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
5042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * White Space types could get the level of the run they belong to,
5052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and are checked with a test of (flags&MASK_EMBEDDING) to
5062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * consider if the paragraph direction should be considered in
5072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the flags variable.
5082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
5092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If there are no White Space types in the paragraph, then
5102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * (L1) is not necessary in adjustWSLevels().
5112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
5122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class Bidi {
5142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static class Point {
5162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int pos;    /* position in text */
5172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int flag;   /* flag for LRM/RLM, before/after */
5182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static class InsertPoints {
5212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int size;
5222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int confirmed;
5232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Point[] points = new Point[0];
5242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static class Opening {
5272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int   position;                 /* position of opening bracket */
5282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int   match;                    /* matching char or -position of closing bracket */
5292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int   contextPos;               /* position of last strong char found before opening */
5302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short flags;                    /* bits for L or R/AL found within the pair */
5312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte  contextDir;               /* L or R according to last strong char before opening */
5322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static class IsoRun {
5352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int   contextPos;               /* position of char determining context */
5362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short start;                    /* index of first opening entry for this run */
5372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short limit;                    /* index after last opening entry for this run */
5382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte  level;                    /* level of this run */
5392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte  lastStrong;               /* bidi class of last strong char found in this run */
5402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte  lastBase;                 /* bidi class of last base char found in this run */
5412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte  contextDir;               /* L or R to use as context for following openings */
5422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static class BracketData {
5452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Opening[] openings = new Opening[SIMPLE_OPENINGS_COUNT];
5462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int   isoRunLast;               /* index of last used entry */
5472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* array of nested isolated sequence entries; can never excess UBIDI_MAX_EXPLICIT_LEVEL
5482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           + 1 for index 0, + 1 for before the first isolated sequence */
5492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        IsoRun[]  isoRuns = new IsoRun[MAX_EXPLICIT_LEVEL+2];
5502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean   isNumbersSpecial;     /*reordering mode for NUMBERS_SPECIAL */
5512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static class Isolate {
5542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int   startON;
5552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int   start1;
5562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short stateImp;
5572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short state;
5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Paragraph level setting<p>
5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constant indicating that the base direction depends on the first strong
5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * directional character in the text according to the Unicode Bidirectional
5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Algorithm. If no strong directional character is present,
5652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * then set the paragraph level to 0 (left-to-right).<p>
5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If this value is used in conjunction with reordering modes
5682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_INVERSE_LIKE_DIRECT</code> or
5692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_INVERSE_FOR_NUMBERS_SPECIAL</code>, the text to reorder
5702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is assumed to be visual LTR, and the text after reordering is required
5712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to be the corresponding logical string with appropriate contextual
5722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * direction. The direction of the result string will be RTL if either
5732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the rightmost or leftmost strong character of the source text is RTL
5742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * or Arabic Letter, the direction will be LTR otherwise.<p>
5752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If reordering option <code>OPTION_INSERT_MARKS</code> is set, an RLM may
5772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * be added at the beginning of the result string to ensure round trip
5782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * (that the result string, when reordered back to visual, will produce
5792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the original source text).
5802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_LIKE_DIRECT
5812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL
5822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final byte LEVEL_DEFAULT_LTR = (byte)0x7e;
5842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Paragraph level setting<p>
5862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constant indicating that the base direction depends on the first strong
5882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * directional character in the text according to the Unicode Bidirectional
5892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Algorithm. If no strong directional character is present,
5902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * then set the paragraph level to 1 (right-to-left).<p>
5912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If this value is used in conjunction with reordering modes
5932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_INVERSE_LIKE_DIRECT</code> or
5942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_INVERSE_FOR_NUMBERS_SPECIAL</code>, the text to reorder
5952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is assumed to be visual LTR, and the text after reordering is required
5962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to be the corresponding logical string with appropriate contextual
5972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * direction. The direction of the result string will be RTL if either
5982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the rightmost or leftmost strong character of the source text is RTL
5992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * or Arabic Letter, or if the text contains no strong character;
6002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the direction will be LTR otherwise.<p>
6012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
6022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If reordering option <code>OPTION_INSERT_MARKS</code> is set, an RLM may
6032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * be added at the beginning of the result string to ensure round trip
6042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * (that the result string, when reordered back to visual, will produce
6052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the original source text).
6062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_LIKE_DIRECT
6072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL
6082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final byte LEVEL_DEFAULT_RTL = (byte)0x7f;
6102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Maximum explicit embedding level.
6132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * (The maximum resolved level can be up to <code>MAX_EXPLICIT_LEVEL+1</code>).
6142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final byte MAX_EXPLICIT_LEVEL = 125;
6162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Bit flag for level input.
6192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Overrides directional properties.
6202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final byte LEVEL_OVERRIDE = (byte)0x80;
6222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Special value which can be returned by the mapping methods when a
6252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * logical index has no corresponding visual index or vice-versa. This may
6262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * happen for the logical-to-visual mapping of a Bidi control when option
6272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>OPTION_REMOVE_CONTROLS</code> is
6282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * specified. This can also happen for the visual-to-logical mapping of a
6292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Bidi mark (LRM or RLM) inserted by option
6302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>OPTION_INSERT_MARKS</code>.
6312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getVisualIndex
6322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getVisualMap
6332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getLogicalIndex
6342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getLogicalMap
6352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_INSERT_MARKS
6362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_REMOVE_CONTROLS
6372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int MAP_NOWHERE = -1;
6392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Left-to-right text.
6422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <ul>
6432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>As return value for <code>getDirection()</code>, it means
6442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *     that the source string contains no right-to-left characters, or
6452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *     that the source string is empty and the paragraph level is even.
6462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>As return value for <code>getBaseDirection()</code>, it
6472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *     means that the first strong character of the source string has
6482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *     a left-to-right direction.
6492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * </ul>
6502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final byte LTR = 0;
6522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Right-to-left text.
6552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <ul>
6562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>As return value for <code>getDirection()</code>, it means
6572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *     that the source string contains no left-to-right characters, or
6582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *     that the source string is empty and the paragraph level is odd.
6592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>As return value for <code>getBaseDirection()</code>, it
6602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *     means that the first strong character of the source string has
6612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *     a right-to-left direction.
6622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * </ul>
6632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final byte RTL = 1;
6652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Mixed-directional text.
6682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>As return value for <code>getDirection()</code>, it means
6692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    that the source string contains both left-to-right and
6702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    right-to-left characters.
6712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final byte MIXED = 2;
6732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * No strongly directional text.
6762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>As return value for <code>getBaseDirection()</code>, it means
6772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    that the source string is missing or empty, or contains neither
6782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    left-to-right nor right-to-left characters.
6792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final byte NEUTRAL = 3;
6812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * option bit for writeReordered():
6842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * keep combining characters after their base characters in RTL runs
6852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
6862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #writeReordered
6872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final short KEEP_BASE_COMBINING = 1;
6892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * option bit for writeReordered():
6922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * replace characters with the "mirrored" property in RTL runs
6932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * by their mirror-image mappings
6942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
6952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #writeReordered
6962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final short DO_MIRRORING = 2;
6982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
7002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * option bit for writeReordered():
7012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * surround the run with LRMs if necessary;
7022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * this is part of the approximate "inverse Bidi" algorithm
7032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
7042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>This option does not imply corresponding adjustment of the index
705bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * mappings.
7062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
7072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setInverse
7082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #writeReordered
7092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final short INSERT_LRM_FOR_NUMERIC = 4;
7112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
7132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * option bit for writeReordered():
7142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * remove Bidi control characters
7152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * (this does not affect INSERT_LRM_FOR_NUMERIC)
7162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
7172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>This option does not imply corresponding adjustment of the index
718bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * mappings.
7192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
7202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #writeReordered
7212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #INSERT_LRM_FOR_NUMERIC
7222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final short REMOVE_BIDI_CONTROLS = 8;
7242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
7262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * option bit for writeReordered():
7272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * write the output in reverse order
7282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
7292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>This has the same effect as calling <code>writeReordered()</code>
7302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * first without this option, and then calling
7312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>writeReverse()</code> without mirroring.
7322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Doing this in the same step is faster and avoids a temporary buffer.
7332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * An example for using this option is output to a character terminal that
734bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * is designed for RTL scripts and stores text in reverse order.
7352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
7362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #writeReordered
7372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final short OUTPUT_REVERSE = 16;
7392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Reordering mode: Regular Logical to Visual Bidi algorithm according to Unicode.
7412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
7422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final short REORDER_DEFAULT = 0;
7442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Reordering mode: Logical to Visual algorithm which handles numbers in
7462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a way which mimicks the behavior of Windows XP.
7472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
7482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final short REORDER_NUMBERS_SPECIAL = 1;
7502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Reordering mode: Logical to Visual algorithm grouping numbers with
7522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * adjacent R characters (reversible algorithm).
7532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
7542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final short REORDER_GROUP_NUMBERS_WITH_R = 2;
7562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Reordering mode: Reorder runs only to transform a Logical LTR string
7582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to the logical RTL string with the same display, or vice-versa.<br>
7592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If this mode is set together with option
7602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>OPTION_INSERT_MARKS</code>, some Bidi controls in the source
7612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * text may be removed and other controls may be added to produce the
7622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * minimum combination which has the required display.
7632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_INSERT_MARKS
7642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
7652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final short REORDER_RUNS_ONLY = 3;
7672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Reordering mode: Visual to Logical algorithm which handles numbers
7692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * like L (same algorithm as selected by <code>setInverse(true)</code>.
7702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setInverse
7712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
7722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final short REORDER_INVERSE_NUMBERS_AS_L = 4;
7742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Reordering mode: Visual to Logical algorithm equivalent to the regular
7762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Logical to Visual algorithm.
7772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
7782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final short REORDER_INVERSE_LIKE_DIRECT = 5;
7802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Reordering mode: Inverse Bidi (Visual to Logical) algorithm for the
7822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_NUMBERS_SPECIAL</code> Bidi algorithm.
7832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
7842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final short REORDER_INVERSE_FOR_NUMBERS_SPECIAL = 6;
7862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*  Number of values for reordering mode. */
7882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final short REORDER_COUNT = 7;
7892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Reordering mode values must be ordered so that all the regular logical to
7912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * visual modes come first, and all inverse Bidi modes come last.
7922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final short REORDER_LAST_LOGICAL_TO_VISUAL =
7942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            REORDER_NUMBERS_SPECIAL;
7952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
7972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Option value for <code>setReorderingOptions</code>:
7982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * disable all the options which can be set with this method
7992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingOptions
8002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int OPTION_DEFAULT = 0;
8022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Option bit for <code>setReorderingOptions</code>:
8052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * insert Bidi marks (LRM or RLM) when needed to ensure correct result of
8062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a reordering to a Logical order
8072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>This option must be set or reset before calling
809bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * <code>setPara</code>.
8102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>This option is significant only with reordering modes which generate
812bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * a result with Logical order, specifically.
8132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <ul>
8142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   <li><code>REORDER_RUNS_ONLY</code></li>
8152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   <li><code>REORDER_INVERSE_NUMBERS_AS_L</code></li>
8162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   <li><code>REORDER_INVERSE_LIKE_DIRECT</code></li>
8172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   <li><code>REORDER_INVERSE_FOR_NUMBERS_SPECIAL</code></li>
8182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * </ul>
8192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>If this option is set in conjunction with reordering mode
8212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_INVERSE_NUMBERS_AS_L</code> or with calling
8222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setInverse(true)</code>, it implies option
8232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>INSERT_LRM_FOR_NUMERIC</code> in calls to method
824bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * <code>writeReordered()</code>.
8252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>For other reordering modes, a minimum number of LRM or RLM characters
8272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * will be added to the source text after reordering it so as to ensure
8282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * round trip, i.e. when applying the inverse reordering mode on the
8292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * resulting logical text with removal of Bidi marks
8302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * (option <code>OPTION_REMOVE_CONTROLS</code> set before calling
8312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setPara()</code> or option
8322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REMOVE_BIDI_CONTROLS</code> in
8332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>writeReordered</code>), the result will be identical to the
8342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * source text in the first transformation.
8352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>This option will be ignored if specified together with option
8372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>OPTION_REMOVE_CONTROLS</code>. It inhibits option
8382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REMOVE_BIDI_CONTROLS</code> in calls to method
8392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>writeReordered()</code> and it implies option
8402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>INSERT_LRM_FOR_NUMERIC</code> in calls to method
8412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>writeReordered()</code> if the reordering mode is
842bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * <code>REORDER_INVERSE_NUMBERS_AS_L</code>.
8432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
8452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingOptions
8462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #INSERT_LRM_FOR_NUMERIC
8472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REMOVE_BIDI_CONTROLS
8482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_REMOVE_CONTROLS
8492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_RUNS_ONLY
8502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_NUMBERS_AS_L
8512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_LIKE_DIRECT
8522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL
8532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int OPTION_INSERT_MARKS = 1;
8552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Option bit for <code>setReorderingOptions</code>:
8582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * remove Bidi control characters
8592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>This option must be set or reset before calling
861bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * <code>setPara</code>.
8622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>This option nullifies option
8642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>OPTION_INSERT_MARKS</code>. It inhibits option
8652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>INSERT_LRM_FOR_NUMERIC</code> in calls to method
8662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>writeReordered()</code> and it implies option
867bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * <code>REMOVE_BIDI_CONTROLS</code> in calls to that method.
8682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
8702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingOptions
8712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_INSERT_MARKS
8722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #INSERT_LRM_FOR_NUMERIC
8732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REMOVE_BIDI_CONTROLS
8742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int OPTION_REMOVE_CONTROLS = 2;
8762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Option bit for <code>setReorderingOptions</code>:
8792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * process the output as part of a stream to be continued
8802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>This option must be set or reset before calling
882bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * <code>setPara</code>.
8832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>This option specifies that the caller is interested in processing
8852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * large text object in parts. The results of the successive calls are
8862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * expected to be concatenated by the caller. Only the call for the last
887bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * part will have this option bit off.
8882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>When this option bit is on, <code>setPara()</code> may process
8902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * less than the full source text in order to truncate the text at a
8912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * meaningful boundary. The caller should call
8922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>getProcessedLength()</code> immediately after calling
8932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setPara()</code> in order to determine how much of the source
8942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * text has been processed. Source text beyond that length should be
8952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * resubmitted in following calls to <code>setPara</code>. The
8962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * processed length may be less than the length of the source text if a
8972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * character preceding the last character of the source text constitutes a
8982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * reasonable boundary (like a block separator) for text to be continued.<br>
8992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If the last character of the source text constitutes a reasonable
9002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * boundary, the whole text will be processed at once.<br>
9012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If nowhere in the source text there exists
9022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * such a reasonable boundary, the processed length will be zero.<br>
9032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The caller should check for such an occurrence and do one of the following:
9042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <ul><li>submit a larger amount of text with a better chance to include
9052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         a reasonable boundary.</li>
9062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *     <li>resubmit the same text after turning off option
9072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>OPTION_STREAMING</code>.</li></ul>
9082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * In all cases, this option should be turned off before processing the last
909bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * part of the text.
9102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
9112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>When the <code>OPTION_STREAMING</code> option is used, it is
9122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * recommended to call <code>orderParagraphsLTR(true)</code> before calling
9132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setPara()</code> so that later paragraphs may be concatenated to
9142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * previous paragraphs on the right.
9152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
9162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
9172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingOptions
9182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getProcessedLength
9192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int OPTION_STREAMING = 4;
9212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
9232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   Comparing the description of the Bidi algorithm with this implementation
9242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   is easier with the same names for the Bidi types in the code as there.
9252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   See UCharacterDirection
9262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte L   = UCharacterDirection.LEFT_TO_RIGHT;                  /*  0 */
9282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte R   = UCharacterDirection.RIGHT_TO_LEFT;                  /*  1 */
9292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte EN  = UCharacterDirection.EUROPEAN_NUMBER;                /*  2 */
9302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte ES  = UCharacterDirection.EUROPEAN_NUMBER_SEPARATOR;      /*  3 */
9312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte ET  = UCharacterDirection.EUROPEAN_NUMBER_TERMINATOR;     /*  4 */
9322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte AN  = UCharacterDirection.ARABIC_NUMBER;                  /*  5 */
9332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte CS  = UCharacterDirection.COMMON_NUMBER_SEPARATOR;        /*  6 */
9342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte B   = UCharacterDirection.BLOCK_SEPARATOR;                /*  7 */
9352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte S   = UCharacterDirection.SEGMENT_SEPARATOR;              /*  8 */
9362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte WS  = UCharacterDirection.WHITE_SPACE_NEUTRAL;            /*  9 */
9372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte ON  = UCharacterDirection.OTHER_NEUTRAL;                  /* 10 */
9382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte LRE = UCharacterDirection.LEFT_TO_RIGHT_EMBEDDING;        /* 11 */
9392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte LRO = UCharacterDirection.LEFT_TO_RIGHT_OVERRIDE;         /* 12 */
9402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte AL  = UCharacterDirection.RIGHT_TO_LEFT_ARABIC;           /* 13 */
9412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte RLE = UCharacterDirection.RIGHT_TO_LEFT_EMBEDDING;        /* 14 */
9422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte RLO = UCharacterDirection.RIGHT_TO_LEFT_OVERRIDE;         /* 15 */
9432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte PDF = UCharacterDirection.POP_DIRECTIONAL_FORMAT;         /* 16 */
9442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte NSM = UCharacterDirection.DIR_NON_SPACING_MARK;           /* 17 */
9452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte BN  = UCharacterDirection.BOUNDARY_NEUTRAL;               /* 18 */
9462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte FSI = UCharacterDirection.FIRST_STRONG_ISOLATE;           /* 19 */
9472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte LRI = UCharacterDirection.LEFT_TO_RIGHT_ISOLATE;          /* 20 */
9482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte RLI = UCharacterDirection.RIGHT_TO_LEFT_ISOLATE;          /* 21 */
9492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte PDI = UCharacterDirection.POP_DIRECTIONAL_ISOLATE;        /* 22 */
9502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte ENL = PDI + 1;    /* EN after W7 */                       /* 23 */
9512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte ENR = ENL + 1;    /* EN not subject to W7 */              /* 24 */
9522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
9542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Value returned by <code>BidiClassifier</code> when there is no need to
9552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * override the standard Bidi class for a given code point.
956f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *
957f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * <p>This constant is deprecated; use UCharacter.getIntPropertyMaxValue(UProperty.BIDI_CLASS)+1 instead.
958f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *
9592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see BidiClassifier
960f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
9612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
962f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Deprecated
963f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    public static final int CLASS_DEFAULT = UCharacterDirection.CHAR_DIRECTION_COUNT;
9642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* number of paras entries allocated initially */
9662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int SIMPLE_PARAS_COUNT = 10;
9672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* number of isolate run entries for paired brackets allocated initially */
9682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int SIMPLE_OPENINGS_COUNT = 20;
9692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char CR = '\r';
9712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final char LF = '\n';
9722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int LRM_BEFORE = 1;
9742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int LRM_AFTER = 2;
9752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int RLM_BEFORE = 4;
9762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int RLM_AFTER = 8;
9772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* flags for Opening.flags */
9792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte FOUND_L = (byte)DirPropFlag(L);
9802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte FOUND_R = (byte)DirPropFlag(R);
9812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
9832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The following bit is used for the directional isolate status.
9842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Stack entries corresponding to isolate sequences are greater than ISOLATE.
9852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int ISOLATE = 0x0100;
9872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
9902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * reference to parent paragraph object (reference to self if this object is
9912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a paragraph object); set to null in a newly opened object; set to a
9922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * real value after a successful execution of setPara or setLine
9932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    Bidi                paraBidi;
9952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    final UBiDiProps    bdp;
9972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* character array representing the current text */
9992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    char[]              text;
10002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* length of the current text */
10022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int                 originalLength;
10032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* if the option OPTION_STREAMING is set, this is the length of
10052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * text actually processed by <code>setPara</code>, which may be shorter
10062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * than the original length. Otherwise, it is identical to the original
10072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * length.
10082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int                 length;
10102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* if option OPTION_REMOVE_CONTROLS is set, and/or Bidi
10122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * marks are allowed to be inserted in one of the reordering modes, the
10132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * length of the result string may be different from the processed length.
10142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int                 resultLength;
10162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* indicators for whether memory may be allocated after construction */
10182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    boolean             mayAllocateText;
10192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    boolean             mayAllocateRuns;
10202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* arrays with one value per text-character */
10222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    byte[]              dirPropsMemory = new byte[1];
10232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    byte[]              levelsMemory = new byte[1];
10242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    byte[]              dirProps;
10252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    byte[]              levels;
10262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* are we performing an approximation of the "inverse Bidi" algorithm? */
10282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    boolean             isInverse;
10292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* are we using the basic algorithm or its variation? */
10312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int                 reorderingMode;
10322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* bitmask for reordering options */
10342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int                 reorderingOptions;
10352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* must block separators receive level 0? */
10372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    boolean             orderParagraphsLTR;
10382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* the paragraph level */
10402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    byte                paraLevel;
10412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* original paraLevel when contextual */
10422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* must be one of DEFAULT_xxx or 0 if not contextual */
10432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    byte                defaultParaLevel;
10442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* context data */
10462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    String              prologue;
10472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    String              epilogue;
10482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* the following is set in setPara, used in processPropertySeq */
10502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    ImpTabPair          impTabPair;  /* reference to levels state table pair */
10522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* the overall paragraph or line directionality*/
10532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    byte                direction;
10542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* flags is a bit set for which directional properties are in the text */
10562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int                 flags;
10572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* lastArabicPos is index to the last AL in the text, -1 if none */
10592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int                 lastArabicPos;
10602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* characters after trailingWSStart are WS and are */
10622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* implicitly at the paraLevel (rule (L1)) - levels may not reflect that */
10632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int                 trailingWSStart;
10642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* fields for paragraph handling, set in getDirProps() */
10662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int                 paraCount;
10672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int[]               paras_limit = new int[SIMPLE_PARAS_COUNT];
10682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    byte[]              paras_level = new byte[SIMPLE_PARAS_COUNT];
10692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* fields for line reordering */
10712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int                 runCount;     /* ==-1: runs not set up yet */
10722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    BidiRun[]           runsMemory = new BidiRun[0];
10732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    BidiRun[]           runs;
10742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* for non-mixed text, we only need a tiny array of runs (no allocation) */
10762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    BidiRun[]           simpleRuns = {new BidiRun()};
10772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* fields for managing isolate sequences */
10792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    Isolate[]           isolates;
10802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* maximum or current nesting depth of isolate sequences */
10812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Within resolveExplicitLevels() and checkExplicitLevels(), this is the maximal
10822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       nesting encountered.
10832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       Within resolveImplicitLevels(), this is the index of the current isolates
10842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       stack entry. */
10852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int                 isolateCount;
10862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* mapping of runs in logical order to visual order */
10882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int[]               logicalToVisualRunsMap;
10892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* flag to indicate that the map has been updated */
10902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    boolean             isGoodLogicalToVisualRunsMap;
10912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* customized class provider */
10932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    BidiClassifier      customClassifier = null;
10942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* for inverse Bidi with insertion of directional marks */
10962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    InsertPoints        insertPoints = new InsertPoints();
10972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* for option OPTION_REMOVE_CONTROLS */
10992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int                 controlCount;
11002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
11022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Sometimes, bit values are more appropriate
11032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to deal with directionality properties.
11042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Abbreviations in these method names refer to names
11052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * used in the Bidi algorithm.
11062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
11072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static int DirPropFlag(byte dir) {
11082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (1 << dir);
11092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
11102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    boolean testDirPropFlagAt(int flag, int index) {
11122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ((DirPropFlag(dirProps[index]) & flag) != 0);
11132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
11142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int DirPropFlagMultiRuns = DirPropFlag((byte)31);
11162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* to avoid some conditional statements, use tiny constant arrays */
11182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int DirPropFlagLR[] = { DirPropFlag(L), DirPropFlag(R) };
11192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int DirPropFlagE[] = { DirPropFlag(LRE), DirPropFlag(RLE) };
11202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int DirPropFlagO[] = { DirPropFlag(LRO), DirPropFlag(RLO) };
11212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int DirPropFlagLR(byte level) { return DirPropFlagLR[level & 1]; }
11232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int DirPropFlagE(byte level)  { return DirPropFlagE[level & 1]; }
11242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int DirPropFlagO(byte level)  { return DirPropFlagO[level & 1]; }
11252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte DirFromStrong(byte strong) { return strong == L ? L : R; }
11262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final byte NoOverride(byte level) { return (byte)(level & ~LEVEL_OVERRIDE); }
11272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*  are there any characters that are LTR or RTL? */
11292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int MASK_LTR =
11302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        DirPropFlag(L)|DirPropFlag(EN)|DirPropFlag(ENL)|DirPropFlag(ENR)|DirPropFlag(AN)|DirPropFlag(LRE)|DirPropFlag(LRO)|DirPropFlag(LRI);
11312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int MASK_RTL = DirPropFlag(R)|DirPropFlag(AL)|DirPropFlag(RLE)|DirPropFlag(RLO)|DirPropFlag(RLI);
11322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int MASK_R_AL = DirPropFlag(R)|DirPropFlag(AL);
11342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int MASK_STRONG_EN_AN = DirPropFlag(L)|DirPropFlag(R)|DirPropFlag(AL)|DirPropFlag(EN)|DirPropFlag(AN);
11352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* explicit embedding codes */
11362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int MASK_EXPLICIT = DirPropFlag(LRE)|DirPropFlag(LRO)|DirPropFlag(RLE)|DirPropFlag(RLO)|DirPropFlag(PDF);
11372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int MASK_BN_EXPLICIT = DirPropFlag(BN)|MASK_EXPLICIT;
11382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* explicit isolate codes */
11402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int MASK_ISO = DirPropFlag(LRI)|DirPropFlag(RLI)|DirPropFlag(FSI)|DirPropFlag(PDI);
11412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* paragraph and segment separators */
11432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int MASK_B_S = DirPropFlag(B)|DirPropFlag(S);
11442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* all types that are counted as White Space or Neutral in some steps */
11462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int MASK_WS = MASK_B_S|DirPropFlag(WS)|MASK_BN_EXPLICIT|MASK_ISO;
11472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* types that are neutrals or could becomes neutrals in (Wn) */
11492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int MASK_POSSIBLE_N = DirPropFlag(ON)|DirPropFlag(CS)|DirPropFlag(ES)|DirPropFlag(ET)|MASK_WS;
11502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
11522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * These types may be changed to "e",
11532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the embedding type (L or R) of the run,
11542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in the Bidi algorithm (N2)
11552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
11562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int MASK_EMBEDDING = DirPropFlag(NSM)|MASK_POSSIBLE_N;
11572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
11592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  the dirProp's L and R are defined to 0 and 1 values in UCharacterDirection.java
11602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
11612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static byte GetLRFromLevel(byte level)
11622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
11632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (byte)(level & 1);
11642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
11652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static boolean IsDefaultLevel(byte level)
11672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
11682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ((level & LEVEL_DEFAULT_LTR) == LEVEL_DEFAULT_LTR);
11692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
11702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static boolean IsBidiControlChar(int c)
11722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
11732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* check for range 0x200c to 0x200f (ZWNJ, ZWJ, LRM, RLM) or
11742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                           0x202a to 0x202e (LRE, RLE, PDF, LRO, RLO) */
11752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (((c & 0xfffffffc) == 0x200c) || ((c >= 0x202a) && (c <= 0x202e))
11762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                             || ((c >= 0x2066) && (c <= 0x2069)));
11772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
11782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    void verifyValidPara()
11802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
11812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!(this == this.paraBidi)) {
11822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalStateException();
11832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
11852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    void verifyValidParaOrLine()
11872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
11882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Bidi para = this.paraBidi;
11892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* verify Para */
11902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (this == para) {
11912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
11922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* verify Line */
11942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((para == null) || (para != para.paraBidi)) {
11952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalStateException();
11962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
11982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    void verifyRange(int index, int start, int limit)
12002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
12012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (index < start || index >= limit) {
12022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Value " + index +
12032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                      " is out of range " + start + " to " + limit);
12042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
12082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Allocate a <code>Bidi</code> object.
12092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Such an object is initially empty. It is assigned
12102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the Bidi properties of a piece of text containing one or more paragraphs
12112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * by <code>setPara()</code>
12122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * or the Bidi properties of a line within a paragraph by
12132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setLine()</code>.<p>
12142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This object can be reused.<p>
12152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setPara()</code> and <code>setLine()</code> will allocate
12162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * additional memory for internal structures as necessary.
12172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
12182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Bidi()
12192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
12202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this(0, 0);
12212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
12242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Allocate a <code>Bidi</code> object with preallocated memory
12252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * for internal structures.
12262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method provides a <code>Bidi</code> object like the default constructor
12272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * but it also preallocates memory for internal structures
12282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * according to the sizings supplied by the caller.<p>
12292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The preallocation can be limited to some of the internal memory
12302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * by setting some values to 0 here. That means that if, e.g.,
12312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>maxRunCount</code> cannot be reasonably predetermined and should not
12322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * be set to <code>maxLength</code> (the only failproof value) to avoid
12332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * wasting  memory, then <code>maxRunCount</code> could be set to 0 here
12342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and the internal structures that are associated with it will be allocated
12352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * on demand, just like with the default constructor.
12362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
12372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param maxLength is the maximum text or line length that internal memory
12382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        will be preallocated for. An attempt to associate this object with a
12392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        longer text will fail, unless this value is 0, which leaves the allocation
12402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        up to the implementation.
12412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
12422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param maxRunCount is the maximum anticipated number of same-level runs
12432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        that internal memory will be preallocated for. An attempt to access
12442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        visual runs on an object that was not preallocated for as many runs
12452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        as the text was actually resolved to will fail,
12462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        unless this value is 0, which leaves the allocation up to the implementation.<br><br>
12472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        The number of runs depends on the actual text and maybe anywhere between
12482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        1 and <code>maxLength</code>. It is typically small.
12492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
12502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if maxLength or maxRunCount is less than 0
12512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
12522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Bidi(int maxLength, int maxRunCount)
12532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
12542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* check the argument values */
12552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (maxLength < 0 || maxRunCount < 0) {
12562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException();
12572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* reset the object, all reference variables null, all flags false,
12602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           all sizes 0.
12612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           In fact, we don't need to do anything, since class members are
12622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           initialized as zero when an instance is created.
12632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
12642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*
12652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        mayAllocateText = false;
12662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        mayAllocateRuns = false;
12672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        orderParagraphsLTR = false;
12682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        paraCount = 0;
12692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        runCount = 0;
12702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        trailingWSStart = 0;
12712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        flags = 0;
12722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        paraLevel = 0;
12732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        defaultParaLevel = 0;
12742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        direction = 0;
12752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
12762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* get Bidi properties */
12772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bdp = UBiDiProps.INSTANCE;
12782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* allocate memory for arrays as requested */
12802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (maxLength > 0) {
12812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            getInitialDirPropsMemory(maxLength);
12822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            getInitialLevelsMemory(maxLength);
12832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
12842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            mayAllocateText = true;
12852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (maxRunCount > 0) {
12882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // if maxRunCount == 1, use simpleRuns[]
12892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (maxRunCount > 1) {
12902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                getInitialRunsMemory(maxRunCount);
12912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
12922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
12932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            mayAllocateRuns = true;
12942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
12982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * We are allowed to allocate memory if object==null or
12992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * mayAllocate==true for each array that we need.
13002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
13012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Assume sizeNeeded>0.
13022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If object != null, then assume size > 0.
13032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
13042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private Object getMemory(String label, Object array, Class<?> arrayClass,
13052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            boolean mayAllocate, int sizeNeeded)
13062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
13072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int len = Array.getLength(array);
13082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* we have at least enough memory and must not allocate */
13102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (sizeNeeded == len) {
13112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return array;
13122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
13132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!mayAllocate) {
13142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* we must not allocate */
13152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (sizeNeeded <= len) {
13162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return array;
13172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
13182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new OutOfMemoryError("Failed to allocate memory for "
13192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                       + label);
13202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
13212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* we may try to grow or shrink */
13222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FOOD FOR THOUGHT: when shrinking it should be possible to avoid
13232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           the allocation altogether and rely on this.length */
13242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        try {
13252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return Array.newInstance(arrayClass, sizeNeeded);
13262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } catch (Exception e) {
13272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new OutOfMemoryError("Failed to allocate memory for "
13282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                       + label);
13292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
13302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* helper methods for each allocated array */
13332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void getDirPropsMemory(boolean mayAllocate, int len)
13342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
13352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Object array = getMemory("DirProps", dirPropsMemory, Byte.TYPE, mayAllocate, len);
13362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        dirPropsMemory = (byte[]) array;
13372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    void getDirPropsMemory(int len)
13402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
13412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getDirPropsMemory(mayAllocateText, len);
13422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void getLevelsMemory(boolean mayAllocate, int len)
13452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
13462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Object array = getMemory("Levels", levelsMemory, Byte.TYPE, mayAllocate, len);
13472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        levelsMemory = (byte[]) array;
13482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    void getLevelsMemory(int len)
13512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
13522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getLevelsMemory(mayAllocateText, len);
13532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void getRunsMemory(boolean mayAllocate, int len)
13562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
13572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Object array = getMemory("Runs", runsMemory, BidiRun.class, mayAllocate, len);
13582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        runsMemory = (BidiRun[]) array;
13592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    void getRunsMemory(int len)
13622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
13632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getRunsMemory(mayAllocateRuns, len);
13642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* additional methods used by constructor - always allow allocation */
13672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void getInitialDirPropsMemory(int len)
13682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
13692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getDirPropsMemory(true, len);
13702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void getInitialLevelsMemory(int len)
13732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
13742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getLevelsMemory(true, len);
13752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void getInitialRunsMemory(int len)
13782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
13792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getRunsMemory(true, len);
13802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
13832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Modify the operation of the Bidi algorithm such that it
13842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * approximates an "inverse Bidi" algorithm. This method
13852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * must be called before <code>setPara()</code>.
13862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
13872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>The normal operation of the Bidi algorithm as described
13882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in the Unicode Technical Report is to take text stored in logical
13892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * (keyboard, typing) order and to determine the reordering of it for visual
13902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * rendering.
13912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Some legacy systems store text in visual order, and for operations
13922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * with standard, Unicode-based algorithms, the text needs to be transformed
13932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to logical order. This is effectively the inverse algorithm of the
13942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * described Bidi algorithm. Note that there is no standard algorithm for
13952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * this "inverse Bidi" and that the current implementation provides only an
1396bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * approximation of "inverse Bidi".
13972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
13982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>With <code>isInversed</code> set to <code>true</code>,
13992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * this method changes the behavior of some of the subsequent methods
14002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in a way that they can be used for the inverse Bidi algorithm.
14012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Specifically, runs of text with numeric characters will be treated in a
14022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * special way and may need to be surrounded with LRM characters when they are
1403bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * written in reordered sequence.
14042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>Output runs should be retrieved using <code>getVisualRun()</code>.
14062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Since the actual input for "inverse Bidi" is visually ordered text and
14072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>getVisualRun()</code> gets the reordered runs, these are actually
1408bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * the runs of the logically ordered output.
14092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>Calling this method with argument <code>isInverse</code> set to
14112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>true</code> is equivalent to calling <code>setReorderingMode</code>
14122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * with argument <code>reorderingMode</code>
14132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * set to <code>REORDER_INVERSE_NUMBERS_AS_L</code>.<br>
14142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Calling this method with argument <code>isInverse</code> set to
14152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>false</code> is equivalent to calling <code>setReorderingMode</code>
14162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * with argument <code>reorderingMode</code>
14172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * set to <code>REORDER_DEFAULT</code>.
14182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param isInverse specifies "forward" or "inverse" Bidi operation.
14202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setPara
14222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #writeReordered
14232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
14242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_NUMBERS_AS_L
14252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_DEFAULT
14262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
14272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setInverse(boolean isInverse) {
14282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.isInverse = (isInverse);
14292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.reorderingMode = isInverse ? REORDER_INVERSE_NUMBERS_AS_L
14302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                : REORDER_DEFAULT;
14312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
14322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
14342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Is this <code>Bidi</code> object set to perform the inverse Bidi
14352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * algorithm?
14362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>Note: calling this method after setting the reordering mode with
14372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setReorderingMode</code> will return <code>true</code> if the
14382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * reordering mode was set to
14392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_INVERSE_NUMBERS_AS_L</code>, <code>false</code>
1440bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * for all other values.
14412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return <code>true</code> if the <code>Bidi</code> object is set to
14432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * perform the inverse Bidi algorithm by handling numbers as L.
14442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setInverse
14462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
14472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_NUMBERS_AS_L
14482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
14492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean isInverse() {
14502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return isInverse;
14512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
14522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
14542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Modify the operation of the Bidi algorithm such that it implements some
14552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * variant to the basic Bidi algorithm or approximates an "inverse Bidi"
14562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * algorithm, depending on different values of the "reordering mode".
14572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method must be called before <code>setPara()</code>, and stays in
14582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * effect until called again with a different argument.
14592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>The normal operation of the Bidi algorithm as described in the Unicode
14612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Standard Annex #9 is to take text stored in logical (keyboard, typing)
1462bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * order and to determine how to reorder it for visual rendering.
14632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>With the reordering mode set to a value other than
14652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_DEFAULT</code>, this method changes the behavior of some of
14662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the subsequent methods in a way such that they implement an inverse Bidi
1467bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * algorithm or some other algorithm variants.
14682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>Some legacy systems store text in visual order, and for operations
14702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * with standard, Unicode-based algorithms, the text needs to be transformed
14712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * into logical order. This is effectively the inverse algorithm of the
14722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * described Bidi algorithm. Note that there is no standard algorithm for
1473bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * this "inverse Bidi", so a number of variants are implemented here.
14742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>In other cases, it may be desirable to emulate some variant of the
14762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Logical to Visual algorithm (e.g. one used in MS Windows), or perform a
1477bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * Logical to Logical transformation.
14782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <ul>
14802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>When the Reordering Mode is set to
14812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_DEFAULT</code>,
14822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the standard Bidi Logical to Visual algorithm is applied.</li>
14832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>When the reordering mode is set to
14852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_NUMBERS_SPECIAL</code>,
14862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the algorithm used to perform Bidi transformations when calling
14872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setPara</code> should approximate the algorithm used in Microsoft
14882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Windows XP rather than strictly conform to the Unicode Bidi algorithm.
14892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <br>
14902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The differences between the basic algorithm and the algorithm addressed
14912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * by this option are as follows:
14922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <ul>
14932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   <li>Within text at an even embedding level, the sequence "123AB"
14942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   (where AB represent R or AL letters) is transformed to "123BA" by the
14952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   Unicode algorithm and to "BA123" by the Windows algorithm.</li>
14962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   <li>Arabic-Indic numbers (AN) are handled by the Windows algorithm just
14982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   like regular numbers (EN).</li>
14992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * </ul></li>
15002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>When the reordering mode is set to
15022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_GROUP_NUMBERS_WITH_R</code>,
15032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * numbers located between LTR text and RTL text are associated with the RTL
15042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * text. For instance, an LTR paragraph with content "abc 123 DEF" (where
15052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * upper case letters represent RTL characters) will be transformed to
15062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * "abc FED 123" (and not "abc 123 FED"), "DEF 123 abc" will be transformed
15072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to "123 FED abc" and "123 FED abc" will be transformed to "DEF 123 abc".
15082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This makes the algorithm reversible and makes it useful when round trip
15092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * (from visual to logical and back to visual) must be achieved without
15102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * adding LRM characters. However, this is a variation from the standard
15112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Unicode Bidi algorithm.<br>
15122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The source text should not contain Bidi control characters other than LRM
15132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * or RLM.</li>
15142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>When the reordering mode is set to
15162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_RUNS_ONLY</code>,
15172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a "Logical to Logical" transformation must be performed:
15182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <ul>
15192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>If the default text level of the source text (argument
15202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>paraLevel</code> in <code>setPara</code>) is even, the source text
15212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * will be handled as LTR logical text and will be transformed to the RTL
15222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * logical text which has the same LTR visual display.</li>
15232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>If the default level of the source text is odd, the source text
15242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * will be handled as RTL logical text and will be transformed to the
15252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * LTR logical text which has the same LTR visual display.</li>
15262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * </ul>
15272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This mode may be needed when logical text which is basically Arabic or
15282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Hebrew, with possible included numbers or phrases in English, has to be
15292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * displayed as if it had an even embedding level (this can happen if the
15302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * displaying application treats all text as if it was basically LTR).
15312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <br>
15322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This mode may also be needed in the reverse case, when logical text which
15332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is basically English, with possible included phrases in Arabic or Hebrew,
15342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * has to be displayed as if it had an odd embedding level.
15352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <br>
15362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Both cases could be handled by adding LRE or RLE at the head of the
15372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * text, if the display subsystem supports these formatting controls. If it
15382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * does not, the problem may be handled by transforming the source text in
15392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * this mode before displaying it, so that it will be displayed properly.
15402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <br>
15412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The source text should not contain Bidi control characters other than LRM
15422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * or RLM.</li>
15432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>When the reordering mode is set to
15452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_INVERSE_NUMBERS_AS_L</code>, an "inverse Bidi"
15462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * algorithm is applied.
15472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Runs of text with numeric characters will be treated like LTR letters and
15482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * may need to be surrounded with LRM characters when they are written in
15492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * reordered sequence (the option <code>INSERT_LRM_FOR_NUMERIC</code> can
15502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * be used with method <code>writeReordered</code> to this end. This mode
15512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is equivalent to calling <code>setInverse()</code> with
15522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * argument <code>isInverse</code> set to <code>true</code>.</li>
15532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>When the reordering mode is set to
15552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_INVERSE_LIKE_DIRECT</code>, the "direct" Logical to
15562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Visual Bidi algorithm is used as an approximation of an "inverse Bidi"
15572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * algorithm. This mode is similar to mode
15582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_INVERSE_NUMBERS_AS_L</code> but is closer to the
15592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * regular Bidi algorithm.
15602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <br>
15612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For example, an LTR paragraph with the content "FED 123 456 CBA" (where
15622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * upper case represents RTL characters) will be transformed to
15632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * "ABC 456 123 DEF", as opposed to "DEF 123 456 ABC"
15642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * with mode <code>REORDER_INVERSE_NUMBERS_AS_L</code>.<br>
15652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * When used in conjunction with option
15662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>OPTION_INSERT_MARKS</code>, this mode generally
15672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * adds Bidi marks to the output significantly more sparingly than mode
15682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_INVERSE_NUMBERS_AS_L</code>.<br> with option
15692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>INSERT_LRM_FOR_NUMERIC</code> in calls to
15702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>writeReordered</code>.</li>
15712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>When the reordering mode is set to
15732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_INVERSE_FOR_NUMBERS_SPECIAL</code>, the Logical to Visual
15742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Bidi algorithm used in Windows XP is used as an approximation of an "inverse
15752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Bidi" algorithm.
15762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <br>
15772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For example, an LTR paragraph with the content "abc FED123" (where
15782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * upper case represents RTL characters) will be transformed to
15792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * "abc 123DEF.</li>
15802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * </ul>
15812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>In all the reordering modes specifying an "inverse Bidi" algorithm
15832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * (i.e. those with a name starting with <code>REORDER_INVERSE</code>),
15842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * output runs should be retrieved using <code>getVisualRun()</code>, and
15852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the output text with <code>writeReordered()</code>. The caller should
15862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * keep in mind that in "inverse Bidi" modes the input is actually visually
15872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * ordered text and reordered output returned by <code>getVisualRun()</code>
15882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * or <code>writeReordered()</code> are actually runs or character string
15892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of logically ordered output.<br>
15902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For all the "inverse Bidi" modes, the source text should not contain
1591bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * Bidi control characters other than LRM or RLM.
15922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>Note that option <code>OUTPUT_REVERSE</code> of
15942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>writeReordered</code> has no useful meaning and should not be used
15952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in conjunction with any value of the reordering mode specifying "inverse
15962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Bidi" or with value <code>REORDER_RUNS_ONLY</code>.
15972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param reorderingMode specifies the required variant of the Bidi
15992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                       algorithm.
16002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
16012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setInverse
16022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setPara
16032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #writeReordered
16042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #INSERT_LRM_FOR_NUMERIC
16052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OUTPUT_REVERSE
16062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_DEFAULT
16072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_NUMBERS_SPECIAL
16082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_GROUP_NUMBERS_WITH_R
16092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_RUNS_ONLY
16102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_NUMBERS_AS_L
16112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_LIKE_DIRECT
16122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL
16132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
16142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setReorderingMode(int reorderingMode) {
16152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((reorderingMode < REORDER_DEFAULT) ||
16162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            (reorderingMode >= REORDER_COUNT))
16172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;                     /* don't accept a wrong value */
16182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.reorderingMode = reorderingMode;
16192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.isInverse =
16202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            reorderingMode == REORDER_INVERSE_NUMBERS_AS_L;
16212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
16222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
16242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * What is the requested reordering mode for a given Bidi object?
16252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
16262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the current reordering mode of the Bidi object
16272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
16282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingMode
16292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
16302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getReorderingMode() {
16312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return this.reorderingMode;
16322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
16332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
16352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Specify which of the reordering options should be applied during Bidi
16362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * transformations.
16372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
16382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param options A combination of zero or more of the following
16392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * reordering options:
16402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>OPTION_DEFAULT</code>, <code>OPTION_INSERT_MARKS</code>,
16412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>OPTION_REMOVE_CONTROLS</code>, <code>OPTION_STREAMING</code>.
16422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
16432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getReorderingOptions
16442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_DEFAULT
16452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_INSERT_MARKS
16462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_REMOVE_CONTROLS
16472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_STREAMING
16482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
16492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setReorderingOptions(int options) {
16502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((options & OPTION_REMOVE_CONTROLS) != 0) {
16512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.reorderingOptions = options & ~OPTION_INSERT_MARKS;
16522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
16532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.reorderingOptions = options;
16542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
16552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
16562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
16582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * What are the reordering options applied to a given Bidi object?
16592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
16602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the current reordering options of the Bidi object
16612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
16622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setReorderingOptions
16632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
16642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getReorderingOptions() {
16652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return this.reorderingOptions;
16662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
16672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
16692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the base direction of the text provided according to the Unicode
16702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Bidirectional Algorithm. The base direction is derived from the first
16712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * character in the string with bidirectional character type L, R, or AL.
16722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If the first such character has type L, LTR is returned. If the first
16732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * such character has type R or AL, RTL is returned. If the string does
16742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * not contain any character of these types, then NEUTRAL is returned.
16752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is a lightweight function for use when only the base direction is
16762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * needed and no further bidi processing of the text is needed.
16772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param paragraph the text whose paragraph level direction is needed.
16782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return LTR, RTL, NEUTRAL
16792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #LTR
16802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #RTL
16812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #NEUTRAL
16822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
16832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static byte getBaseDirection(CharSequence paragraph) {
16842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (paragraph == null || paragraph.length() == 0) {
16852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return NEUTRAL;
16862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
16872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int length = paragraph.length();
16892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int c;// codepoint
16902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte direction;
16912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < length; ) {
16932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // U16_NEXT(paragraph, i, length, c) for C++
16942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            c = UCharacter.codePointAt(paragraph, i);
16952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            direction = UCharacter.getDirectionality(c);
16962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (direction == UCharacterDirection.LEFT_TO_RIGHT) {
16972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return LTR;
16982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (direction == UCharacterDirection.RIGHT_TO_LEFT
16992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                || direction == UCharacterDirection.RIGHT_TO_LEFT_ARABIC) {
17002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return RTL;
17012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            i = UCharacter.offsetByCodePoints(paragraph, i, 1);// set i to the head index of next codepoint
17042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
17052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return NEUTRAL;
17062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
17072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* perform (P2)..(P3) ------------------------------------------------------- */
17092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
17112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns the directionality of the first strong character
17122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * after the last B in prologue, if any.
17132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Requires prologue!=null.
17142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
17152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private byte firstL_R_AL() {
17162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte result = ON;
17172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < prologue.length(); ) {
17182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int uchar = prologue.codePointAt(i);
17192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            i += Character.charCount(uchar);
17202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            byte dirProp = (byte)getCustomizedClass(uchar);
17212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (result == ON) {
17222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (dirProp == L || dirProp == R || dirProp == AL) {
17232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    result = dirProp;
17242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
17252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
17262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (dirProp == B) {
17272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    result = ON;
17282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
17292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
17312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return result;
17322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
17332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
17352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Check that there are enough entries in the arrays paras_limit and paras_level
17362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
17372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void checkParaCount() {
17382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] saveLimits;
17392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte[] saveLevels;
17402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int count = paraCount;
17412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (count <= paras_level.length)
17422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
17432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int oldLength = paras_level.length;
17442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        saveLimits = paras_limit;
17452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        saveLevels = paras_level;
17462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        try {
17472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paras_limit = new int[count * 2];
17482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paras_level = new byte[count * 2];
17492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } catch (Exception e) {
17502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new OutOfMemoryError("Failed to allocate memory for paras");
17512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
17522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        System.arraycopy(saveLimits, 0, paras_limit, 0, oldLength);
17532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        System.arraycopy(saveLevels, 0, paras_level, 0, oldLength);
17542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
17552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
17572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the directional properties for the text, calculate the flags bit-set, and
17582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * determine the paragraph level if necessary (in paras_level[i]).
17592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * FSI initiators are also resolved and their dirProp replaced with LRI or RLI.
17602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * When encountering an FSI, it is initially replaced with an LRI, which is the
17612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * default. Only if a strong R or AL is found within its scope will the LRI be
17622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * replaced by an RLI.
17632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
17642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int NOT_SEEKING_STRONG = 0;        /* 0: not contextual paraLevel, not after FSI */
17652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int SEEKING_STRONG_FOR_PARA = 1;   /* 1: looking for first strong char in para */
17662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int SEEKING_STRONG_FOR_FSI = 2;    /* 2: looking for first strong after FSI */
17672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int LOOKING_FOR_PDI = 3;           /* 3: found strong after FSI, looking for PDI */
17682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void getDirProps()
17702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
17712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i = 0, i0, i1;
17722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        flags = 0;          /* collect all directionalities in the text */
17732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int uchar;
17742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte dirProp;
17752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte defaultParaLevel = 0;   /* initialize to avoid compiler warnings */
17762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean isDefaultLevel = IsDefaultLevel(paraLevel);
17772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* for inverse Bidi, the default para level is set to RTL if there is a
17782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           strong R or AL character at either end of the text                */
17792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean isDefaultLevelInverse=isDefaultLevel &&
17802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                (reorderingMode == REORDER_INVERSE_LIKE_DIRECT ||
17812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL);
17822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        lastArabicPos = -1;
17832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int controlCount = 0;
17842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean removeBidiControls = (reorderingOptions & OPTION_REMOVE_CONTROLS) != 0;
17852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte state;
17872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte lastStrong = ON;           /* for default level & inverse Bidi */
17882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* The following stacks are used to manage isolate sequences. Those
17892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       sequences may be nested, but obviously never more deeply than the
17902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       maximum explicit embedding level.
17912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       lastStack is the index of the last used entry in the stack. A value of -1
17922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       means that there is no open isolate sequence.
17932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       lastStack is reset to -1 on paragraph boundaries. */
17942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* The following stack contains the position of the initiator of
17952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       each open isolate sequence */
17962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] isolateStartStack= new int[MAX_EXPLICIT_LEVEL+1];
17972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* The following stack contains the last known state before
17982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       encountering the initiator of an isolate sequence */
17992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte[] previousStateStack = new byte[MAX_EXPLICIT_LEVEL+1];
18002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int  stackLast=-1;
18012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((reorderingOptions & OPTION_STREAMING) != 0)
18032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            length = 0;
18042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        defaultParaLevel = (byte)(paraLevel & 1);
18052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isDefaultLevel) {
18072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paras_level[0] = defaultParaLevel;
18082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            lastStrong = defaultParaLevel;
18092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (prologue != null &&                        /* there is a prologue */
18102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                (dirProp = firstL_R_AL()) != ON) {     /* with a strong character */
18112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (dirProp == L)
18122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    paras_level[0] = 0;             /* set the default para level */
18132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else
18142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    paras_level[0] = 1;             /* set the default para level */
18152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                state = NOT_SEEKING_STRONG;
18162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
18172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                state = SEEKING_STRONG_FOR_PARA;
18182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
18202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paras_level[0] = paraLevel;
18212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            state = NOT_SEEKING_STRONG;
18222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
18232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* count paragraphs and determine the paragraph level (P2..P3) */
18242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*
18252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * see comment on constant fields:
18262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * the LEVEL_DEFAULT_XXX values are designed so that
18272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * their low-order bit alone yields the intended default
18282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
18292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (i = 0; i < originalLength; /* i is incremented in the loop */) {
18312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            i0 = i;                     /* index of first code unit */
18322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            uchar = UTF16.charAt(text, 0, originalLength, i);
18332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            i += UTF16.getCharCount(uchar);
18342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            i1 = i - 1; /* index of last code unit, gets the directional property */
18352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            dirProp = (byte)getCustomizedClass(uchar);
18372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            flags |= DirPropFlag(dirProp);
18382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            dirProps[i1] = dirProp;
18392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (i1 > i0) {     /* set previous code units' properties to BN */
18402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                flags |= DirPropFlag(BN);
18412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                do {
18422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    dirProps[--i1] = BN;
18432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } while (i1 > i0);
18442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (removeBidiControls && IsBidiControlChar(uchar)) {
18462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                controlCount++;
18472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == L) {
18492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (state == SEEKING_STRONG_FOR_PARA) {
18502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    paras_level[paraCount - 1] = 0;
18512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    state = NOT_SEEKING_STRONG;
18522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
18532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else if (state == SEEKING_STRONG_FOR_FSI) {
18542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (stackLast <= MAX_EXPLICIT_LEVEL) {
18552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        /* no need for next statement, already set by default */
18562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        /* dirProps[isolateStartStack[stackLast]] = LRI; */
18572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        flags |= DirPropFlag(LRI);
18582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
18592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    state = LOOKING_FOR_PDI;
18602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
18612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                lastStrong = L;
18622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                continue;
18632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == R || dirProp == AL) {
18652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (state == SEEKING_STRONG_FOR_PARA) {
18662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    paras_level[paraCount - 1] = 1;
18672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    state = NOT_SEEKING_STRONG;
18682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
18692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else if (state == SEEKING_STRONG_FOR_FSI) {
18702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (stackLast <= MAX_EXPLICIT_LEVEL) {
18712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        dirProps[isolateStartStack[stackLast]] = RLI;
18722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        flags |= DirPropFlag(RLI);
18732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
18742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    state = LOOKING_FOR_PDI;
18752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
18762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                lastStrong = R;
18772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (dirProp == AL)
18782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    lastArabicPos = i - 1;
18792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                continue;
18802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp >= FSI && dirProp <= RLI) { /* FSI, LRI or RLI */
18822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                stackLast++;
18832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (stackLast <= MAX_EXPLICIT_LEVEL) {
18842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    isolateStartStack[stackLast] = i - 1;
18852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    previousStateStack[stackLast] = state;
18862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
18872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (dirProp == FSI) {
18882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    dirProps[i-1] = LRI;    /* default if no strong char */
18892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    state = SEEKING_STRONG_FOR_FSI;
18902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
18912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else
18922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    state = LOOKING_FOR_PDI;
18932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                continue;
18942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == PDI) {
18962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (state == SEEKING_STRONG_FOR_FSI) {
18972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (stackLast <= MAX_EXPLICIT_LEVEL) {
18982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        /* no need for next statement, already set by default */
18992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        /* dirProps[isolateStartStack[stackLast]] = LRI; */
19002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        flags |= DirPropFlag(LRI);
19012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
19022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
19032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (stackLast >= 0) {
19042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (stackLast <= MAX_EXPLICIT_LEVEL)
19052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        state = previousStateStack[stackLast];
19062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stackLast--;
19072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
19082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                continue;
19092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
19102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == B) {
19112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (i < originalLength && uchar == CR && text[i] == LF) /* do nothing on the CR */
19122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    continue;
19132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                paras_limit[paraCount - 1] = i;
19142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (isDefaultLevelInverse && lastStrong == R)
19152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    paras_level[paraCount - 1] = 1;
19162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ((reorderingOptions & OPTION_STREAMING) != 0) {
19172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* When streaming, we only process whole paragraphs
19182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   thus some updates are only done on paragraph boundaries */
19192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   length = i;          /* i is index to next character */
19202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   this.controlCount = controlCount;
19212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
19222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (i < originalLength) {       /* B not last char in text */
19232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    paraCount++;
19242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    checkParaCount();   /* check that there is enough memory for a new para entry */
19252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (isDefaultLevel) {
19262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        paras_level[paraCount - 1] = defaultParaLevel;
19272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        state = SEEKING_STRONG_FOR_PARA;
19282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        lastStrong = defaultParaLevel;
19292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
19302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        paras_level[paraCount - 1] = paraLevel;
19312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        state = NOT_SEEKING_STRONG;
19322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
19332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stackLast = -1;
19342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
19352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                continue;
19362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
19372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
19382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* +Ignore still open isolate sequences with overflow */
19392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (stackLast > MAX_EXPLICIT_LEVEL) {
19402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            stackLast = MAX_EXPLICIT_LEVEL;
19412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            state=SEEKING_STRONG_FOR_FSI;   /* to be on the safe side */
19422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
19432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* Resolve direction of still unresolved open FSI sequences */
19442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (stackLast >= 0) {
19452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (state == SEEKING_STRONG_FOR_FSI) {
19462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* no need for next statement, already set by default */
19472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* dirProps[isolateStartStack[stackLast]] = LRI; */
19482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                flags |= DirPropFlag(LRI);
19492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
19502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
19512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            state = previousStateStack[stackLast];
19522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            stackLast--;
19532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
19542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* When streaming, ignore text after the last paragraph separator */
19552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((reorderingOptions & OPTION_STREAMING) != 0) {
19562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (length < originalLength)
19572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                paraCount--;
19582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
19592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paras_limit[paraCount - 1] = originalLength;
19602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.controlCount = controlCount;
19612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
19622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* For inverse bidi, default para direction is RTL if there is
19632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           a strong R or AL at either end of the paragraph */
19642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isDefaultLevelInverse && lastStrong == R) {
19652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paras_level[paraCount - 1] = 1;
19662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
19672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isDefaultLevel) {
19682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paraLevel = paras_level[0];
19692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
19702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* The following is needed to resolve the text direction for default level
19712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           paragraphs containing no strong character */
19722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (i = 0; i < paraCount; i++)
19732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            flags |= DirPropFlagLR(paras_level[i]);
19742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
19752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) {
19762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            flags |= DirPropFlag(L);
19772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
19782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
19792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
19802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* determine the paragraph level at position index */
19812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    byte GetParaLevelAt(int pindex)
19822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
19832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (defaultParaLevel == 0 || pindex < paras_limit[0])
19842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return paraLevel;
19852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i;
19862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (i = 1; i < paraCount; i++)
19872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (pindex < paras_limit[i])
19882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
19892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (i >= paraCount)
19902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            i = paraCount - 1;
19912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return paras_level[i];
19922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
19932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
19942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Functions for handling paired brackets ----------------------------------- */
19952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
19962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* In the isoRuns array, the first entry is used for text outside of any
19972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       isolate sequence.  Higher entries are used for each more deeply nested
19982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       isolate sequence. isoRunLast is the index of the last used entry.  The
19992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       openings array is used to note the data of opening brackets not yet
20002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       matched by a closing bracket, or matched but still susceptible to change
20012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       level.
20022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       Each isoRun entry contains the index of the first and
20032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       one-after-last openings entries for pending opening brackets it
20042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       contains.  The next openings entry to use is the one-after-last of the
20052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       most deeply nested isoRun entry.
20062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       isoRun entries also contain their current embedding level and the last
20072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       encountered strong character, since these will be needed to resolve
20082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       the level of paired brackets.  */
20092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void bracketInit(BracketData bd) {
20112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRunLast = 0;
20122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRuns[0] = new IsoRun();
20132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRuns[0].start = 0;
20142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRuns[0].limit = 0;
20152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRuns[0].level = GetParaLevelAt(0);
20162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRuns[0].lastStrong = bd.isoRuns[0].lastBase = bd.isoRuns[0].contextDir = (byte)(GetParaLevelAt(0) & 1);
20172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRuns[0].contextPos = 0;
20182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.openings = new Opening[SIMPLE_OPENINGS_COUNT];
20192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isNumbersSpecial = reorderingMode == REORDER_NUMBERS_SPECIAL ||
20202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL;
20212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
20222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* paragraph boundary */
20242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void bracketProcessB(BracketData bd, byte level) {
20252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRunLast = 0;
20262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRuns[0].limit = 0;
20272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRuns[0].level = level;
20282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRuns[0].lastStrong = bd.isoRuns[0].lastBase = bd.isoRuns[0].contextDir = (byte)(level & 1);
20292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRuns[0].contextPos = 0;
20302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
20312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* LRE, LRO, RLE, RLO, PDF */
20332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void bracketProcessBoundary(BracketData bd, int lastCcPos,
20342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        byte contextLevel, byte embeddingLevel) {
20352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast];
20362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((DirPropFlag(dirProps[lastCcPos]) & MASK_ISO) != 0) /* after an isolate */
20372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
20382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (NoOverride(embeddingLevel) > NoOverride(contextLevel))  /* not a PDF */
20392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            contextLevel = embeddingLevel;
20402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun.limit = pLastIsoRun.start;
20412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun.level = embeddingLevel;
20422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun.lastStrong = pLastIsoRun.lastBase = pLastIsoRun.contextDir = (byte)(contextLevel & 1);
20432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun.contextPos = lastCcPos;
20442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
20452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* LRI or RLI */
20472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void bracketProcessLRI_RLI(BracketData bd, byte level) {
20482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast];
20492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short lastLimit;
20502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun.lastBase = ON;
20512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        lastLimit = pLastIsoRun.limit;
20522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRunLast++;
20532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun = bd.isoRuns[bd.isoRunLast];
20542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (pLastIsoRun == null)
20552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun = bd.isoRuns[bd.isoRunLast] = new IsoRun();
20562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun.start = pLastIsoRun.limit = lastLimit;
20572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun.level = level;
20582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun.lastStrong = pLastIsoRun.lastBase = pLastIsoRun.contextDir = (byte)(level & 1);
20592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun.contextPos = 0;
20602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
20612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* PDI */
20632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void bracketProcessPDI(BracketData bd) {
20642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        IsoRun pLastIsoRun;
20652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bd.isoRunLast--;
20662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun = bd.isoRuns[bd.isoRunLast];
20672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun.lastBase = ON;
20682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
20692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* newly found opening bracket: create an openings entry */
20712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void bracketAddOpening(BracketData bd, char match, int position) {
20722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast];
20732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Opening pOpening;
20742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (pLastIsoRun.limit >= bd.openings.length) {  /* no available new entry */
20752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Opening[] saveOpenings = bd.openings;
20762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int count;
20772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            try {
20782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                count = bd.openings.length;
20792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                bd.openings = new Opening[count * 2];
20802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } catch (Exception e) {
20812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                throw new OutOfMemoryError("Failed to allocate memory for openings");
20822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
20832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            System.arraycopy(saveOpenings, 0, bd.openings, 0, count);
20842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
20852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pOpening = bd.openings[pLastIsoRun.limit];
20862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (pOpening == null)
20872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pOpening = bd.openings[pLastIsoRun.limit]= new Opening();
20882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pOpening.position = position;
20892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pOpening.match = match;
20902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pOpening.contextDir = pLastIsoRun.contextDir;
20912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pOpening.contextPos = pLastIsoRun.contextPos;
20922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pOpening.flags = 0;
20932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pLastIsoRun.limit++;
20942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
20952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* change N0c1 to N0c2 when a preceding bracket is assigned the embedding level */
20972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void fixN0c(BracketData bd, int openingIndex, int newPropPosition, byte newProp) {
20982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* This function calls itself recursively */
20992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast];
21002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Opening qOpening;
21012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int k, openingPosition, closingPosition;
21022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (k = openingIndex+1; k < pLastIsoRun.limit; k++) {
21032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            qOpening = bd.openings[k];
21042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (qOpening.match >= 0)    /* not an N0c match */
21052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                continue;
21062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (newPropPosition < qOpening.contextPos)
21072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
21082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (newPropPosition >= qOpening.position)
21092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                continue;
21102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (newProp == qOpening.contextDir)
21112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
21122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            openingPosition = qOpening.position;
21132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            dirProps[openingPosition] = newProp;
21142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            closingPosition = -(qOpening.match);
21152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            dirProps[closingPosition] = newProp;
21162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            qOpening.match = 0;                                 /* prevent further changes */
21172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fixN0c(bd, k, openingPosition, newProp);
21182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fixN0c(bd, k, closingPosition, newProp);
21192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
21202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
21212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* process closing bracket; return L or R if N0b or N0c, ON if N0d */
21232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private byte bracketProcessClosing(BracketData bd, int openIdx, int position) {
21242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast];
21252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Opening pOpening, qOpening;
21262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte direction;
21272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean stable;
21282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte newProp;
21292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pOpening = bd.openings[openIdx];
21302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        direction = (byte)(pLastIsoRun.level & 1);
21312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        stable = true;          /* assume stable until proved otherwise */
21322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* The stable flag is set when brackets are paired and their
21342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           level is resolved and cannot be changed by what will be
21352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           found later in the source string.
21362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           An unstable match can occur only when applying N0c, where
21372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           the resolved level depends on the preceding context, and
21382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           this context may be affected by text occurring later.
21392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           Example: RTL paragraph containing:  abc[(latin) HEBREW]
21402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           When the closing parenthesis is encountered, it appears
21412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           that N0c1 must be applied since 'abc' sets an opposite
21422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           direction context and both parentheses receive level 2.
21432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           However, when the closing square bracket is processed,
21442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           N0b applies because of 'HEBREW' being included within the
21452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           brackets, thus the square brackets are treated like R and
21462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           receive level 1. However, this changes the preceding
21472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           context of the opening parenthesis, and it now appears
21482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           that N0c2 must be applied to the parentheses rather than
21492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           N0c1. */
21502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ((direction == 0 && (pOpening.flags & FOUND_L) > 0) ||
21522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                (direction == 1 && (pOpening.flags & FOUND_R) > 0)) {   /* N0b */
21532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                newProp = direction;
21542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
21552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            else if ((pOpening.flags & (FOUND_L | FOUND_R)) != 0) {     /* N0c */
21562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* it is stable if there is no preceding text or in
21572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                       conditions too complicated and not worth checking */
21582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stable = (openIdx == pLastIsoRun.start);
21592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (direction != pOpening.contextDir)
21602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    newProp = pOpening.contextDir;                      /* N0c1 */
21612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else
21622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    newProp = direction;                                /* N0c2 */
21632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
21642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* forget this and any brackets nested within this pair */
21652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.limit = (short)openIdx;
21662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return ON;                                                  /* N0d */
21672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
21682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        dirProps[pOpening.position] = newProp;
21692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        dirProps[position] = newProp;
21702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* Update nested N0c pairs that may be affected */
21712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fixN0c(bd, openIdx, pOpening.position, newProp);
21722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (stable) {
21732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.limit = (short)openIdx; /* forget any brackets nested within this pair */
21742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* remove lower located synonyms if any */
21752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            while (pLastIsoRun.limit > pLastIsoRun.start &&
21762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   bd.openings[pLastIsoRun.limit - 1].position == pOpening.position)
21772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pLastIsoRun.limit--;
21782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
21792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int k;
21802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pOpening.match = -position;
21812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* neutralize lower located synonyms if any */
21822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            k = openIdx - 1;
21832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            while (k >= pLastIsoRun.start &&
21842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   bd.openings[k].position == pOpening.position)
21852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                bd.openings[k--].match = 0;
21862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* neutralize any unmatched opening between the current pair;
21872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               this will also neutralize higher located synonyms if any */
21882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (k = openIdx + 1; k < pLastIsoRun.limit; k++) {
21892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                qOpening =bd.openings[k];
21902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (qOpening.position >= position)
21912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
21922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (qOpening.match > 0)
21932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    qOpening.match = 0;
21942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
21952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
21962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return newProp;
21972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
21982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* handle strong characters, digits and candidates for closing brackets */
22002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void bracketProcessChar(BracketData bd, int position) {
22012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        IsoRun pLastIsoRun = bd.isoRuns[bd.isoRunLast];
22022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte dirProp, newProp;
22032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte level;
22042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        dirProp = dirProps[position];
22052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (dirProp == ON) {
22062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char c, match;
22072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int idx;
22082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* First see if it is a matching closing bracket. Hopefully, this is
22092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               more efficient than checking if it is a closing bracket at all */
22102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            c = text[position];
22112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (idx = pLastIsoRun.limit - 1; idx >= pLastIsoRun.start; idx--) {
22122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (bd.openings[idx].match != c)
22132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    continue;
22142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* We have a match */
22152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                newProp = bracketProcessClosing(bd, idx, position);
22162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(newProp == ON) {         /* N0d */
22172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    c = 0;          /* prevent handling as an opening */
22182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
22192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
22202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pLastIsoRun.lastBase = ON;
22212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pLastIsoRun.contextDir = newProp;
22222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pLastIsoRun.contextPos = position;
22232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                level = levels[position];
22242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ((level & LEVEL_OVERRIDE) != 0) {    /* X4, X5 */
22252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    short flag;
22262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int i;
22272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    newProp = (byte)(level & 1);
22282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    pLastIsoRun.lastStrong = newProp;
22292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    flag = (short)DirPropFlag(newProp);
22302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    for (i = pLastIsoRun.start; i < idx; i++)
22312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        bd.openings[i].flags |= flag;
22322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* matching brackets are not overridden by LRO/RLO */
22332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    levels[position] &= ~LEVEL_OVERRIDE;
22342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
22352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* matching brackets are not overridden by LRO/RLO */
22362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levels[bd.openings[idx].position] &= ~LEVEL_OVERRIDE;
22372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
22382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
22392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* We get here only if the ON character is not a matching closing
22402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               bracket or it is a case of N0d */
22412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* Now see if it is an opening bracket */
22422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (c != 0)
22432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                match = (char)UCharacter.getBidiPairedBracket(c); /* get the matching char */
22442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            else
22452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                match = 0;
22462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (match != c &&               /* has a matching char */
22472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                UCharacter.getIntPropertyValue(c, UProperty.BIDI_PAIRED_BRACKET_TYPE) ==
22482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* opening bracket */         UCharacter.BidiPairedBracketType.OPEN) {
22492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* special case: process synonyms
22502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   create an opening entry for each synonym */
22512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (match == 0x232A) {      /* RIGHT-POINTING ANGLE BRACKET */
22522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    bracketAddOpening(bd, (char)0x3009, position);
22532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
22542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else if (match == 0x3009) { /* RIGHT ANGLE BRACKET */
22552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    bracketAddOpening(bd, (char)0x232A, position);
22562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
22572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                bracketAddOpening(bd, match, position);
22582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
22592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
22602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        level = levels[position];
22612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((level & LEVEL_OVERRIDE) != 0) {    /* X4, X5 */
22622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            newProp = (byte)(level & 1);
22632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp != S && dirProp != WS && dirProp != ON)
22642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dirProps[position] = newProp;
22652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.lastBase = newProp;
22662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.lastStrong = newProp;
22672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.contextDir = newProp;
22682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.contextPos = position;
22692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
22702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        else if (dirProp <= R || dirProp == AL) {
22712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            newProp = DirFromStrong(dirProp);
22722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.lastBase = dirProp;
22732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.lastStrong = dirProp;
22742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.contextDir = newProp;
22752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.contextPos = position;
22762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
22772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        else if(dirProp == EN) {
22782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.lastBase = EN;
22792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (pLastIsoRun.lastStrong == L) {
22802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                newProp = L;                    /* W7 */
22812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (!bd.isNumbersSpecial)
22822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    dirProps[position] = ENL;
22832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pLastIsoRun.contextDir = L;
22842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pLastIsoRun.contextPos = position;
22852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
22862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            else {
22872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                newProp = R;                    /* N0 */
22882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (pLastIsoRun.lastStrong == AL)
22892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    dirProps[position] = AN;    /* W2 */
22902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else
22912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    dirProps[position] = ENR;
22922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pLastIsoRun.contextDir = R;
22932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pLastIsoRun.contextPos = position;
22942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
22952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
22962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        else if (dirProp == AN) {
22972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            newProp = R;                        /* N0 */
22982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.lastBase = AN;
22992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.contextDir = R;
23002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.contextPos = position;
23012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
23022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        else if (dirProp == NSM) {
23032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* if the last real char was ON, change NSM to ON so that it
23042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               will stay ON even if the last real char is a bracket which
23052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               may be changed to L or R */
23062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            newProp = pLastIsoRun.lastBase;
23072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (newProp == ON)
23082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dirProps[position] = newProp;
23092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
23102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        else {
23112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            newProp = dirProp;
23122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pLastIsoRun.lastBase = dirProp;
23132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
23142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (newProp <= R || newProp == AL) {
23152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int i;
23162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            short flag = (short)DirPropFlag(DirFromStrong(newProp));
23172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (i = pLastIsoRun.start; i < pLastIsoRun.limit; i++)
23182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (position > bd.openings[i].position)
23192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    bd.openings[i].flags |= flag;
23202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
23212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
23222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
23232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* perform (X1)..(X9) ------------------------------------------------------- */
23242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
23252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* determine if the text is mixed-directional or single-directional */
23262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private byte directionFromFlags() {
23272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* if the text contains AN and neutrals, then some neutrals may become RTL */
23282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!((flags & MASK_RTL) != 0 ||
23292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              ((flags & DirPropFlag(AN)) != 0 &&
23302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               (flags & MASK_POSSIBLE_N) != 0))) {
23312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return LTR;
23322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ((flags & MASK_LTR) == 0) {
23332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return RTL;
23342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
23352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return MIXED;
23362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
23372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
23382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
23392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
23402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Resolve the explicit levels as specified by explicit embedding codes.
23412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Recalculate the flags to have them reflect the real properties
23422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * after taking the explicit embeddings into account.
23432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
23442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The BiDi algorithm is designed to result in the same behavior whether embedding
23452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * levels are externally specified (from "styled text", supposedly the preferred
23462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * method) or set by explicit embedding codes (LRx, RLx, PDF, FSI, PDI) in the plain text.
23472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * That is why (X9) instructs to remove all not-isolate explicit codes (and BN).
23482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * However, in a real implementation, the removal of these codes and their index
23492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * positions in the plain text is undesirable since it would result in
23502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * reallocated, reindexed text.
23512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Instead, this implementation leaves the codes in there and just ignores them
23522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in the subsequent processing.
23532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * In order to get the same reordering behavior, positions with a BN or a not-isolate
23542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * explicit embedding code just get the same level assigned as the last "real"
23552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * character.
23562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
23572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Some implementations, not this one, then overwrite some of these
23582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * directionality properties at "real" same-level-run boundaries by
23592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * L or R codes so that the resolution of weak types can be performed on the
23602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * entire paragraph at once instead of having to parse it once more and
23612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * perform that resolution on same-level-runs.
23622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This limits the scope of the implicit rules in effectively
23632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the same way as the run limits.
23642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
23652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Instead, this implementation does not modify these codes, except for
23662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * paired brackets whose properties (ON) may be replaced by L or R.
23672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * On one hand, the paragraph has to be scanned for same-level-runs, but
23682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * on the other hand, this saves another loop to reset these codes,
23692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * or saves making and modifying a copy of dirProps[].
23702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
23712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
23722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Note that (Pn) and (Xn) changed significantly from version 4 of the BiDi algorithm.
23732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
23742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
23752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Handling the stack of explicit levels (Xn):
23762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
23772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * With the BiDi stack of explicit levels, as pushed with each
23782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * LRE, RLE, LRO, RLO, LRI, RLI and FSI and popped with each PDF and PDI,
23792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the explicit level must never exceed MAX_EXPLICIT_LEVEL.
23802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
23812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * In order to have a correct push-pop semantics even in the case of overflows,
23822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * overflow counters and a valid isolate counter are used as described in UAX#9
23832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * section 3.3.2 "Explicit Levels and Directions".
23842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
23852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This implementation assumes that MAX_EXPLICIT_LEVEL is odd.
23862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
23872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Returns the direction
23882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
23892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
23902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private byte resolveExplicitLevels() {
23912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i = 0;
23922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte dirProp;
23932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte level = GetParaLevelAt(0);
23942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte dirct;
23952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        isolateCount = 0;
23962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
23972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* determine if the text is mixed-directional or single-directional */
23982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        dirct = directionFromFlags();
23992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
24002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* we may not need to resolve any explicit levels */
24012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (dirct != MIXED) {
24022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* not mixed directionality: levels don't matter - trailingWSStart will be 0 */
24032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return dirct;
24042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
24052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (reorderingMode > REORDER_LAST_LOGICAL_TO_VISUAL) {
24062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* inverse BiDi: mixed, but all characters are at the same embedding level */
24072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* set all levels to the paragraph level */
24082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int paraIndex, start, limit;
24092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (paraIndex = 0; paraIndex < paraCount; paraIndex++) {
24102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (paraIndex == 0)
24112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start = 0;
24122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else
24132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start = paras_limit[paraIndex - 1];
24142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                limit = paras_limit[paraIndex];
24152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                level = paras_level[paraIndex];
24162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (i = start; i < limit; i++)
24172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    levels[i] =level;
24182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
24192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return dirct;               /* no bracket matching for inverse BiDi */
24202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
24212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((flags & (MASK_EXPLICIT | MASK_ISO)) == 0) {
24222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* no embeddings, set all levels to the paragraph level */
24232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* we still have to perform bracket matching */
24242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int paraIndex, start, limit;
24252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            BracketData bracketData = new BracketData();
24262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            bracketInit(bracketData);
24272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (paraIndex = 0; paraIndex < paraCount; paraIndex++) {
24282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (paraIndex == 0)
24292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start = 0;
24302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else
24312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start = paras_limit[paraIndex-1];
24322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                limit = paras_limit[paraIndex];
24332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                level = paras_level[paraIndex];
24342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (i = start; i < limit; i++) {
24352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    levels[i] = level;
24362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    dirProp = dirProps[i];
24372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (dirProp == BN)
24382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        continue;
24392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (dirProp == B) {
24402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if ((i + 1) < length) {
24412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            if (text[i] == CR && text[i + 1] == LF)
24422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                continue;   /* skip CR when followed by LF */
24432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            bracketProcessB(bracketData, level);
24442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
24452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        continue;
24462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
24472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    bracketProcessChar(bracketData, i);
24482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
24492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
24502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return dirct;
24512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
24522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* continue to perform (Xn) */
24532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
24542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* (X1) level is set for all codes, embeddingLevel keeps track of the push/pop operations */
24552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* both variables may carry the LEVEL_OVERRIDE flag to indicate the override status */
24562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte embeddingLevel = level, newLevel;
24572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte previousLevel = level; /* previous level for regular (not CC) characters */
24582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int lastCcPos = 0;          /* index of last effective LRx,RLx, PDx */
24592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
24602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* The following stack remembers the embedding level and the ISOLATE flag of level runs.
24612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           stackLast points to its current entry. */
24622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short[] stack = new short[MAX_EXPLICIT_LEVEL + 2];  /* we never push anything >= MAX_EXPLICIT_LEVEL
24632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                               but we need one more entry as base */
24642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int stackLast = 0;
24652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int overflowIsolateCount = 0;
24662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int overflowEmbeddingCount = 0;
24672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int validIsolateCount = 0;
24682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        BracketData bracketData = new BracketData();
24692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bracketInit(bracketData);
24702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        stack[0] = level;       /* initialize base entry to para level, no override, no isolate */
24712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
24722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* recalculate the flags */
24732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        flags = 0;
24742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
24752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (i = 0; i < length; i++) {
24762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            dirProp = dirProps[i];
24772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            switch (dirProp) {
24782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case LRE:
24792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case RLE:
24802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case LRO:
24812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case RLO:
24822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* (X2, X3, X4, X5) */
24832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                flags |= DirPropFlag(BN);
24842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levels[i] = previousLevel;
24852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (dirProp == LRE || dirProp == LRO)
24862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* least greater even level */
24872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    newLevel = (byte)((embeddingLevel+2) & ~(LEVEL_OVERRIDE | 1));
24882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else
24892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* least greater odd level */
24902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    newLevel = (byte)((NoOverride(embeddingLevel) + 1) | 1);
24912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (newLevel <= MAX_EXPLICIT_LEVEL && overflowIsolateCount == 0 &&
24922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                      overflowEmbeddingCount == 0) {
24932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    lastCcPos = i;
24942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    embeddingLevel = newLevel;
24952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (dirProp == LRO || dirProp == RLO)
24962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        embeddingLevel |= LEVEL_OVERRIDE;
24972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stackLast++;
24982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stack[stackLast] = embeddingLevel;
24992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* we don't need to set LEVEL_OVERRIDE off for LRE and RLE
25002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                       since this has already been done for newLevel which is
25012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                       the source for embeddingLevel.
25022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     */
25032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
25042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (overflowIsolateCount == 0)
25052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        overflowEmbeddingCount++;
25062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
25072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
25082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case PDF:
25092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* (X7) */
25102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                flags |= DirPropFlag(BN);
25112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levels[i] = previousLevel;
25122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* handle all the overflow cases first */
25132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (overflowIsolateCount > 0) {
25142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
25152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
25162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (overflowEmbeddingCount > 0) {
25172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    overflowEmbeddingCount--;
25182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
25192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
25202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (stackLast > 0 && stack[stackLast] < ISOLATE) {   /* not an isolate entry */
25212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    lastCcPos = i;
25222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stackLast--;
25232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    embeddingLevel = (byte)stack[stackLast];
25242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
25252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
25262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case LRI:
25272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case RLI:
25282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                flags |= DirPropFlag(ON) | DirPropFlagLR(embeddingLevel);
25292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levels[i] = NoOverride(embeddingLevel);
25302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) {
25312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    bracketProcessBoundary(bracketData, lastCcPos,
25322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                           previousLevel, embeddingLevel);
25332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    flags |= DirPropFlagMultiRuns;
25342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
25352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                previousLevel = embeddingLevel;
25362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* (X5a, X5b) */
25372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (dirProp == LRI)
25382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* least greater even level */
25392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    newLevel=(byte)((embeddingLevel+2)&~(LEVEL_OVERRIDE|1));
25402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else
25412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* least greater odd level */
25422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    newLevel=(byte)((NoOverride(embeddingLevel)+1)|1);
25432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (newLevel <= MAX_EXPLICIT_LEVEL && overflowIsolateCount == 0
25442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                   && overflowEmbeddingCount == 0) {
25452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    flags |= DirPropFlag(dirProp);
25462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    lastCcPos = i;
25472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    validIsolateCount++;
25482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (validIsolateCount > isolateCount)
25492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        isolateCount = validIsolateCount;
25502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    embeddingLevel = newLevel;
25512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* we can increment stackLast without checking because newLevel
25522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                       will exceed UBIDI_MAX_EXPLICIT_LEVEL before stackLast overflows */
25532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stackLast++;
25542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stack[stackLast] = (short)(embeddingLevel + ISOLATE);
25552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    bracketProcessLRI_RLI(bracketData, embeddingLevel);
25562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
25572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* make it WS so that it is handled by adjustWSLevels() */
25582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    dirProps[i] = WS;
25592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    overflowIsolateCount++;
25602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
25612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
25622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case PDI:
25632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) {
25642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    bracketProcessBoundary(bracketData, lastCcPos,
25652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                           previousLevel, embeddingLevel);
25662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    flags |= DirPropFlagMultiRuns;
25672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
25682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* (X6a) */
25692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (overflowIsolateCount > 0) {
25702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    overflowIsolateCount--;
25712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* make it WS so that it is handled by adjustWSLevels() */
25722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    dirProps[i] = WS;
25732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
25742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                else if (validIsolateCount > 0) {
25752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    flags |= DirPropFlag(PDI);
25762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    lastCcPos = i;
25772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    overflowEmbeddingCount = 0;
25782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    while (stack[stackLast] < ISOLATE)  /* pop embedding entries */
25792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        stackLast--;                    /* until the last isolate entry */
25802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stackLast--;                        /* pop also the last isolate entry */
25812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    validIsolateCount--;
25822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    bracketProcessPDI(bracketData);
25832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else
25842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* make it WS so that it is handled by adjustWSLevels() */
25852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    dirProps[i] = WS;
25862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                embeddingLevel = (byte)(stack[stackLast] & ~ISOLATE);
25872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                flags |= DirPropFlag(ON) | DirPropFlagLR(embeddingLevel);
25882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                previousLevel = embeddingLevel;
25892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levels[i] = NoOverride(embeddingLevel);
25902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
25912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case B:
25922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                flags |= DirPropFlag(B);
25932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levels[i] = GetParaLevelAt(i);
25942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ((i + 1) < length) {
25952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (text[i] == CR && text[i + 1] == LF)
25962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        break;          /* skip CR when followed by LF */
25972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    overflowEmbeddingCount = overflowIsolateCount = 0;
25982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    validIsolateCount = 0;
25992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stackLast = 0;
26002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    previousLevel = embeddingLevel = GetParaLevelAt(i + 1);
26012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    stack[0] = embeddingLevel;   /* initialize base entry to para level, no override, no isolate */
26022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    bracketProcessB(bracketData, embeddingLevel);
26032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
26042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
26052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case BN:
26062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* BN, LRE, RLE, and PDF are supposed to be removed (X9) */
26072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* they will get their levels set correctly in adjustWSLevels() */
26082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levels[i] = previousLevel;
26092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                flags |= DirPropFlag(BN);
26102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
26112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            default:
26122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* all other types are normal characters and get the "real" level */
26132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (NoOverride(embeddingLevel) != NoOverride(previousLevel)) {
26142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    bracketProcessBoundary(bracketData, lastCcPos,
26152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                           previousLevel, embeddingLevel);
26162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    flags |= DirPropFlagMultiRuns;
26172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((embeddingLevel & LEVEL_OVERRIDE) != 0)
26182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        flags |= DirPropFlagO(embeddingLevel);
26192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    else
26202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        flags |= DirPropFlagE(embeddingLevel);
26212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
26222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                previousLevel = embeddingLevel;
26232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levels[i] = embeddingLevel;
26242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                bracketProcessChar(bracketData, i);
26252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* the dirProp may have been changed in bracketProcessChar() */
26262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                flags |= DirPropFlag(dirProps[i]);
26272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
26282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
26292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
26302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((flags & MASK_EMBEDDING) != 0) {
26312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            flags |= DirPropFlagLR(paraLevel);
26322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
26332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) {
26342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            flags |= DirPropFlag(L);
26352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
26362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* again, determine if the text is mixed-directional or single-directional */
26372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        dirct = directionFromFlags();
26382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
26392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return dirct;
26402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
26412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2642fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller    /**
26432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Use a pre-specified embedding levels array:
26442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
2645fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <p>Adjust the directional properties for overrides (->LEVEL_OVERRIDE),
26462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * ignore all explicit codes (X9),
26472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and check all the preset levels.
26482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
2649fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <p>Recalculate the flags to have them reflect the real properties
26502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * after taking the explicit embeddings into account.
26512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
26522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private byte checkExplicitLevels() {
26532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int isolateCount = 0;
26542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
26552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.flags = 0;     /* collect all directionalities in the text */
26562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.isolateCount = 0;
26572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2658fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller        int currentParaIndex = 0;
2659fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller        int currentParaLimit = paras_limit[0];
2660fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller        byte currentParaLevel = paraLevel;
2661fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller
2662fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller        for (int i = 0; i < length; ++i) {
2663fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            byte level = levels[i];
2664fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            byte dirProp = dirProps[i];
26652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == LRI || dirProp == RLI) {
26662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                isolateCount++;
26672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (isolateCount > this.isolateCount)
26682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    this.isolateCount = isolateCount;
26692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
26702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            else if (dirProp == PDI)
26712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                isolateCount--;
26722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            else if (dirProp == B)
26732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                isolateCount = 0;
2674fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller
2675fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            // optimized version of  byte currentParaLevel = GetParaLevelAt(i);
2676fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            if (defaultParaLevel != 0 &&
2677fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                    i == currentParaLimit && (currentParaIndex + 1) < paraCount) {
2678fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                currentParaLevel = paras_level[++currentParaIndex];
2679fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                currentParaLimit = paras_limit[currentParaIndex];
2680fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            }
2681fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller
2682fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            int overrideFlag = level & LEVEL_OVERRIDE;
2683fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            level &= ~LEVEL_OVERRIDE;
2684fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            if (level < currentParaLevel || MAX_EXPLICIT_LEVEL < level) {
2685fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                if (level == 0) {
2686fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                    if (dirProp == B) {
2687fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                        // Paragraph separators are ok with explicit level 0.
2688fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                        // Prevents reordering of paragraphs.
2689fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                    } else {
2690fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                        // Treat explicit level 0 as a wildcard for the paragraph level.
2691fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                        // Avoid making the caller guess what the paragraph level would be.
2692fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                        level = currentParaLevel;
2693fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                        levels[i] = (byte)(level | overrideFlag);
2694fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                    }
2695fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                } else {
2696fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                    // 1 <= level < currentParaLevel or MAX_EXPLICIT_LEVEL < level
2697fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                    throw new IllegalArgumentException("level " + level +
2698fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                                                       " out of bounds at " + i);
2699fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                }
2700fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            }
2701fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            if (overrideFlag != 0) {
27022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* keep the override flag in levels[i] but adjust the flags */
27032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                flags |= DirPropFlagO(level);
27042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
27052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* set the flags */
27062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                flags |= DirPropFlagE(level) | DirPropFlag(dirProp);
27072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
27082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
27092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((flags & MASK_EMBEDDING) != 0)
27102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            flags |= DirPropFlagLR(paraLevel);
27112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* determine if the text is mixed-directional or single-directional */
27122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return directionFromFlags();
27132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
27142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
27152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*********************************************************************/
27162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* The Properties state machine table                                */
27172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*********************************************************************/
27182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
27192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* All table cells are 8 bits:                                       */
27202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*      bits 0..4:  next state                                       */
27212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*      bits 5..7:  action to perform (if > 0)                       */
27222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
27232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Cells may be of format "n" where n represents the next state      */
27242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (except for the rightmost column).                                */
27252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Cells may also be of format "_(x,y)" where x represents an action */
27262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* to perform and y represents the next state.                       */
27272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
27282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*********************************************************************/
27292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Definitions and type for properties state tables                  */
27302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*********************************************************************/
27312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int IMPTABPROPS_COLUMNS = 16;
27322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int IMPTABPROPS_RES = IMPTABPROPS_COLUMNS - 1;
27332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static short GetStateProps(short cell) {
27342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (short)(cell & 0x1f);
27352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
27362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static short GetActionProps(short cell) {
27372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (short)(cell >> 5);
27382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
27392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
27402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short groupProp[] =          /* dirProp regrouped */
27412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
27422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*  L   R   EN  ES  ET  AN  CS  B   S   WS  ON  LRE LRO AL  RLE RLO PDF NSM BN  FSI LRI RLI PDI ENL ENR */
27432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            0,  1,  2,  7,  8,  3,  9,  6,  5,  4,  4,  10, 10, 12, 10, 10, 10, 11, 10, 4,  4,  4,  4,  13, 14
27442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
27452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short _L  = 0;
27462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short _R  = 1;
27472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short _EN = 2;
27482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short _AN = 3;
27492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short _ON = 4;
27502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short _S  = 5;
27512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short _B  = 6; /* reduced dirProp */
27522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
27532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*********************************************************************/
27542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
27552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*      PROPERTIES  STATE  TABLE                                     */
27562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
27572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* In table impTabProps,                                             */
27582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*      - the ON column regroups ON and WS, FSI, RLI, LRI and PDI    */
27592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*      - the BN column regroups BN, LRE, RLE, LRO, RLO, PDF         */
27602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*      - the Res column is the reduced property assigned to a run   */
27612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
27622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Action 1: process current run1, init new run1                     */
27632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*        2: init new run2                                           */
27642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*        3: process run1, process run2, init new run1               */
27652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*        4: process run1, set run1=run2, init new run2              */
27662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
27672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Notes:                                                            */
27682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*  1) This table is used in resolveImplicitLevels().                */
27692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*  2) This table triggers actions when there is a change in the Bidi*/
27702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     property of incoming characters (action 1).                   */
27712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*  3) Most such property sequences are processed immediately (in    */
27722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     fact, passed to processPropertySeq().                         */
27732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*  4) However, numbers are assembled as one sequence. This means    */
27742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     that undefined situations (like CS following digits, until    */
27752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     it is known if the next char will be a digit) are held until  */
27762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     following chars define them.                                  */
27772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     Example: digits followed by CS, then comes another CS or ON;  */
27782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*              the digits will be processed, then the CS assigned   */
27792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*              as the start of an ON sequence (action 3).           */
27802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*  5) There are cases where more than one sequence must be          */
27812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     processed, for instance digits followed by CS followed by L:  */
27822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     the digits must be processed as one sequence, and the CS      */
27832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     must be processed as an ON sequence, all this before starting */
27842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     assembling chars for the opening L sequence.                  */
27852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
27862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
27872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short impTabProps[][] =
27882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
27892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*                        L,     R,    EN,    AN,    ON,     S,     B,    ES,    ET,    CS,    BN,   NSM,    AL,   ENL,   ENR,   Res */
27902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 0 Init        */ {     1,     2,     4,     5,     7,    15,    17,     7,     9,     7,     0,     7,     3,    18,    21,   _ON },
27912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 1 L           */ {     1,  32+2,  32+4,  32+5,  32+7, 32+15, 32+17,  32+7,  32+9,  32+7,     1,     1,  32+3, 32+18, 32+21,    _L },
27922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 2 R           */ {  32+1,     2,  32+4,  32+5,  32+7, 32+15, 32+17,  32+7,  32+9,  32+7,     2,     2,  32+3, 32+18, 32+21,    _R },
27932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 3 AL          */ {  32+1,  32+2,  32+6,  32+6,  32+8, 32+16, 32+17,  32+8,  32+8,  32+8,     3,     3,     3, 32+18, 32+21,    _R },
27942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 4 EN          */ {  32+1,  32+2,     4,  32+5,  32+7, 32+15, 32+17, 64+10,    11, 64+10,     4,     4,  32+3,    18,    21,   _EN },
27952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 5 AN          */ {  32+1,  32+2,  32+4,     5,  32+7, 32+15, 32+17,  32+7,  32+9, 64+12,     5,     5,  32+3, 32+18, 32+21,   _AN },
27962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 6 AL:EN/AN    */ {  32+1,  32+2,     6,     6,  32+8, 32+16, 32+17,  32+8,  32+8, 64+13,     6,     6,  32+3,    18,    21,   _AN },
27972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 7 ON          */ {  32+1,  32+2,  32+4,  32+5,     7, 32+15, 32+17,     7, 64+14,     7,     7,     7,  32+3, 32+18, 32+21,   _ON },
27982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 8 AL:ON       */ {  32+1,  32+2,  32+6,  32+6,     8, 32+16, 32+17,     8,     8,     8,     8,     8,  32+3, 32+18, 32+21,   _ON },
27992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 9 ET          */ {  32+1,  32+2,     4,  32+5,     7, 32+15, 32+17,     7,     9,     7,     9,     9,  32+3,    18,    21,   _ON },
28002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*10 EN+ES/CS    */ {  96+1,  96+2,     4,  96+5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7,    10, 128+7,  96+3,    18,    21,   _EN },
28012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*11 EN+ET       */ {  32+1,  32+2,     4,  32+5,  32+7, 32+15, 32+17,  32+7,    11,  32+7,    11,    11,  32+3,    18,    21,   _EN },
28022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*12 AN+CS       */ {  96+1,  96+2,  96+4,     5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7,    12, 128+7,  96+3, 96+18, 96+21,   _AN },
28032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*13 AL:EN/AN+CS */ {  96+1,  96+2,     6,     6, 128+8, 96+16, 96+17, 128+8, 128+8, 128+8,    13, 128+8,  96+3,    18,    21,   _AN },
28042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*14 ON+ET       */ {  32+1,  32+2, 128+4,  32+5,     7, 32+15, 32+17,     7,    14,     7,    14,    14,  32+3,128+18,128+21,   _ON },
28052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*15 S           */ {  32+1,  32+2,  32+4,  32+5,  32+7,    15, 32+17,  32+7,  32+9,  32+7,    15,  32+7,  32+3, 32+18, 32+21,    _S },
28062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*16 AL:S        */ {  32+1,  32+2,  32+6,  32+6,  32+8,    16, 32+17,  32+8,  32+8,  32+8,    16,  32+8,  32+3, 32+18, 32+21,    _S },
28072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*17 B           */ {  32+1,  32+2,  32+4,  32+5,  32+7, 32+15,    17,  32+7,  32+9,  32+7,    17,  32+7,  32+3, 32+18, 32+21,    _B },
28082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*18 ENL         */ {  32+1,  32+2,    18,  32+5,  32+7, 32+15, 32+17, 64+19,    20, 64+19,    18,    18,  32+3,    18,    21,    _L },
28092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*19 ENL+ES/CS   */ {  96+1,  96+2,    18,  96+5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7,    19, 128+7,  96+3,    18,    21,    _L },
28102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*20 ENL+ET      */ {  32+1,  32+2,    18,  32+5,  32+7, 32+15, 32+17,  32+7,    20,  32+7,    20,    20,  32+3,    18,    21,    _L },
28112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*21 ENR         */ {  32+1,  32+2,    21,  32+5,  32+7, 32+15, 32+17, 64+22,    23, 64+22,    21,    21,  32+3,    18,    21,   _AN },
28122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*22 ENR+ES/CS   */ {  96+1,  96+2,    21,  96+5, 128+7, 96+15, 96+17, 128+7,128+14, 128+7,    22, 128+7,  96+3,    18,    21,   _AN },
28132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*23 ENR+ET      */ {  32+1,  32+2,    21,  32+5,  32+7, 32+15, 32+17,  32+7,    23,  32+7,    23,    23,  32+3,    18,    21,   _AN }
28142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
28152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
28162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*********************************************************************/
28172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* The levels state machine tables                                   */
28182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*********************************************************************/
28192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
28202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* All table cells are 8 bits:                                       */
28212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*      bits 0..3:  next state                                       */
28222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*      bits 4..7:  action to perform (if > 0)                       */
28232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
28242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Cells may be of format "n" where n represents the next state      */
28252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* (except for the rightmost column).                                */
28262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Cells may also be of format "_(x,y)" where x represents an action */
28272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* to perform and y represents the next state.                       */
28282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
28292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* This format limits each table to 16 states each and to 15 actions.*/
28302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
28312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*********************************************************************/
28322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Definitions and type for levels state tables                      */
28332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*********************************************************************/
28342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int IMPTABLEVELS_COLUMNS = _B + 2;
28352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int IMPTABLEVELS_RES = IMPTABLEVELS_COLUMNS - 1;
28362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static short GetState(byte cell) { return (short)(cell & 0x0f); }
28372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static short GetAction(byte cell) { return (short)(cell >> 4); }
28382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
28392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static class ImpTabPair {
28402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte[][][] imptab;
28412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short[][] impact;
28422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
28432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        ImpTabPair(byte[][] table1, byte[][] table2,
28442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   short[] act1, short[] act2) {
28452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            imptab = new byte[][][] {table1, table2};
28462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            impact = new short[][] {act1, act2};
28472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
28482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
28492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
28502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*********************************************************************/
28512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
28522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*      LEVELS  STATE  TABLES                                        */
28532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
28542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* In all levels state tables,                                       */
28552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*      - state 0 is the initial state                               */
28562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*      - the Res column is the increment to add to the text level   */
28572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*        for this property sequence.                                */
28582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
28592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* The impact arrays for each table of a pair map the local action   */
28602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* numbers of the table to the total list of actions. For instance,  */
28612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* action 2 in a given table corresponds to the action number which  */
28622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* appears in entry [2] of the impact array for that table.          */
28632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* The first entry of all impact arrays must be 0.                   */
28642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
28652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Action 1: init conditional sequence                               */
28662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*        2: prepend conditional sequence to current sequence        */
28672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*        3: set ON sequence to new level - 1                        */
28682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*        4: init EN/AN/ON sequence                                  */
28692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*        5: fix EN/AN/ON sequence followed by R                     */
28702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*        6: set previous level sequence to level 2                  */
28712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
28722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Notes:                                                            */
28732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*  1) These tables are used in processPropertySeq(). The input      */
28742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     is property sequences as determined by resolveImplicitLevels. */
28752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*  2) Most such property sequences are processed immediately        */
28762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     (levels are assigned).                                        */
28772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*  3) However, some sequences cannot be assigned a final level till */
28782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     one or more following sequences are received. For instance,   */
28792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     ON following an R sequence within an even-level paragraph.    */
28802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     If the following sequence is R, the ON sequence will be       */
28812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     assigned basic run level+1, and so will the R sequence.       */
28822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*  4) S is generally handled like ON, since its level will be fixed */
28832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*     to paragraph level in adjustWSLevels().                       */
28842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*                                                                   */
28852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
28862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final byte impTabL_DEFAULT[][] = /* Even paragraph level */
28872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*  In this table, conditional sequences receive the lower possible level
28882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            until proven otherwise.
28892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
28902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
28912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*                         L,     R,    EN,    AN,    ON,     S,     B, Res */
28922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 0 : init       */ {     0,     1,     0,     2,     0,     0,     0,  0 },
28932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 1 : R          */ {     0,     1,     3,     3,  0x14,  0x14,     0,  1 },
28942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 2 : AN         */ {     0,     1,     0,     2,  0x15,  0x15,     0,  2 },
28952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 3 : R+EN/AN    */ {     0,     1,     3,     3,  0x14,  0x14,     0,  2 },
28962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 4 : R+ON       */ {     0,  0x21,  0x33,  0x33,     4,     4,     0,  0 },
28972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 5 : AN+ON      */ {     0,  0x21,     0,  0x32,     5,     5,     0,  0 }
28982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
28992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final byte impTabR_DEFAULT[][] = /* Odd  paragraph level */
29012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*  In this table, conditional sequences receive the lower possible level
29022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            until proven otherwise.
29032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
29042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
29052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*                         L,     R,    EN,    AN,    ON,     S,     B, Res */
29062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 0 : init       */ {     1,     0,     2,     2,     0,     0,     0,  0 },
29072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 1 : L          */ {     1,     0,     1,     3,  0x14,  0x14,     0,  1 },
29082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 2 : EN/AN      */ {     1,     0,     2,     2,     0,     0,     0,  1 },
29092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 3 : L+AN       */ {     1,     0,     1,     3,     5,     5,     0,  1 },
29102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 4 : L+ON       */ {  0x21,     0,  0x21,     3,     4,     4,     0,  0 },
29112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 5 : L+AN+ON    */ {     1,     0,     1,     3,     5,     5,     0,  0 }
29122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
29132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short[] impAct0 = {0,1,2,3,4};
29152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final ImpTabPair impTab_DEFAULT = new ImpTabPair(
29172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            impTabL_DEFAULT, impTabR_DEFAULT, impAct0, impAct0);
29182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final byte impTabL_NUMBERS_SPECIAL[][] = { /* Even paragraph level */
29202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* In this table, conditional sequences receive the lower possible
29212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           level until proven otherwise.
29222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
29232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*                         L,     R,    EN,    AN,    ON,     S,     B, Res */
29242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 0 : init       */ {     0,     2,  0x11,  0x11,     0,     0,     0,  0 },
29252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 1 : L+EN/AN    */ {     0,  0x42,     1,     1,     0,     0,     0,  0 },
29262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 2 : R          */ {     0,     2,     4,     4,  0x13,  0x13,     0,  1 },
29272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 3 : R+ON       */ {     0,  0x22,  0x34,  0x34,     3,     3,     0,  0 },
29282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 4 : R+EN/AN    */ {     0,     2,     4,     4,  0x13,  0x13,     0,  2 }
29292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
29302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final ImpTabPair impTab_NUMBERS_SPECIAL = new ImpTabPair(
29312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            impTabL_NUMBERS_SPECIAL, impTabR_DEFAULT, impAct0, impAct0);
29322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final byte impTabL_GROUP_NUMBERS_WITH_R[][] = {
29342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* In this table, EN/AN+ON sequences receive levels as if associated with R
29352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           until proven that there is L or sor/eor on both sides. AN is handled like EN.
29362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
29372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*                         L,     R,    EN,    AN,    ON,     S,     B, Res */
29382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 0 init         */ {     0,     3,  0x11,  0x11,     0,     0,     0,  0 },
29392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 1 EN/AN        */ {  0x20,     3,     1,     1,     2,  0x20,  0x20,  2 },
29402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 2 EN/AN+ON     */ {  0x20,     3,     1,     1,     2,  0x20,  0x20,  1 },
29412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 3 R            */ {     0,     3,     5,     5,  0x14,     0,     0,  1 },
29422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 4 R+ON         */ {  0x20,     3,     5,     5,     4,  0x20,  0x20,  1 },
29432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 5 R+EN/AN      */ {     0,     3,     5,     5,  0x14,     0,     0,  2 }
29442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
29452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final byte impTabR_GROUP_NUMBERS_WITH_R[][] = {
29462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*  In this table, EN/AN+ON sequences receive levels as if associated with R
29472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            until proven that there is L on both sides. AN is handled like EN.
29482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
29492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*                         L,     R,    EN,    AN,    ON,     S,     B, Res */
29502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 0 init         */ {     2,     0,     1,     1,     0,     0,     0,  0 },
29512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 1 EN/AN        */ {     2,     0,     1,     1,     0,     0,     0,  1 },
29522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 2 L            */ {     2,     0,  0x14,  0x14,  0x13,     0,     0,  1 },
29532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 3 L+ON         */ {  0x22,     0,     4,     4,     3,     0,     0,  0 },
29542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 4 L+EN/AN      */ {  0x22,     0,     4,     4,     3,     0,     0,  1 }
29552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
29562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final ImpTabPair impTab_GROUP_NUMBERS_WITH_R = new
29572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ImpTabPair(impTabL_GROUP_NUMBERS_WITH_R,
29582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                       impTabR_GROUP_NUMBERS_WITH_R, impAct0, impAct0);
29592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final byte impTabL_INVERSE_NUMBERS_AS_L[][] = {
29612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* This table is identical to the Default LTR table except that EN and AN
29622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           are handled like L.
29632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
29642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*                         L,     R,    EN,    AN,    ON,     S,     B, Res */
29652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 0 : init       */ {     0,     1,     0,     0,     0,     0,     0,  0 },
29662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 1 : R          */ {     0,     1,     0,     0,  0x14,  0x14,     0,  1 },
29672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 2 : AN         */ {     0,     1,     0,     0,  0x15,  0x15,     0,  2 },
29682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 3 : R+EN/AN    */ {     0,     1,     0,     0,  0x14,  0x14,     0,  2 },
29692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 4 : R+ON       */ {  0x20,     1,  0x20,  0x20,     4,     4,  0x20,  1 },
29702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 5 : AN+ON      */ {  0x20,     1,  0x20,  0x20,     5,     5,  0x20,  1 }
29712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
29722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final byte impTabR_INVERSE_NUMBERS_AS_L[][] = {
29732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* This table is identical to the Default RTL table except that EN and AN
29742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           are handled like L.
29752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
29762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*                         L,     R,    EN,    AN,    ON,     S,     B, Res */
29772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 0 : init       */ {     1,     0,     1,     1,     0,     0,     0,  0 },
29782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 1 : L          */ {     1,     0,     1,     1,  0x14,  0x14,     0,  1 },
29792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 2 : EN/AN      */ {     1,     0,     1,     1,     0,     0,     0,  1 },
29802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 3 : L+AN       */ {     1,     0,     1,     1,     5,     5,     0,  1 },
29812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 4 : L+ON       */ {  0x21,     0,  0x21,  0x21,     4,     4,     0,  0 },
29822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 5 : L+AN+ON    */ {     1,     0,     1,     1,     5,     5,     0,  0 }
29832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
29842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final ImpTabPair impTab_INVERSE_NUMBERS_AS_L = new ImpTabPair
29852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            (impTabL_INVERSE_NUMBERS_AS_L, impTabR_INVERSE_NUMBERS_AS_L,
29862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             impAct0, impAct0);
29872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final byte impTabR_INVERSE_LIKE_DIRECT[][] = {  /* Odd  paragraph level */
29892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*  In this table, conditional sequences receive the lower possible level
29902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            until proven otherwise.
29912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
29922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*                         L,     R,    EN,    AN,    ON,     S,     B, Res */
29932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 0 : init       */ {     1,     0,     2,     2,     0,     0,     0,  0 },
29942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 1 : L          */ {     1,     0,     1,     2,  0x13,  0x13,     0,  1 },
29952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 2 : EN/AN      */ {     1,     0,     2,     2,     0,     0,     0,  1 },
29962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 3 : L+ON       */ {  0x21,  0x30,     6,     4,     3,     3,  0x30,  0 },
29972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 4 : L+ON+AN    */ {  0x21,  0x30,     6,     4,     5,     5,  0x30,  3 },
29982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 5 : L+AN+ON    */ {  0x21,  0x30,     6,     4,     5,     5,  0x30,  2 },
29992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 6 : L+ON+EN    */ {  0x21,  0x30,     6,     4,     3,     3,  0x30,  1 }
30002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
30012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short[] impAct1 = {0,1,13,14};
30022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final ImpTabPair impTab_INVERSE_LIKE_DIRECT = new ImpTabPair(
30032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            impTabL_DEFAULT, impTabR_INVERSE_LIKE_DIRECT, impAct0, impAct1);
30042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
30052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final byte impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS[][] = {
30062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* The case handled in this table is (visually):  R EN L
30072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
30082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*                         L,     R,    EN,    AN,    ON,     S,     B, Res */
30092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 0 : init       */ {     0,  0x63,     0,     1,     0,     0,     0,  0 },
30102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 1 : L+AN       */ {     0,  0x63,     0,     1,  0x12,  0x30,     0,  4 },
30112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 2 : L+AN+ON    */ {  0x20,  0x63,  0x20,     1,     2,  0x30,  0x20,  3 },
30122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 3 : R          */ {     0,  0x63,  0x55,  0x56,  0x14,  0x30,     0,  3 },
30132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 4 : R+ON       */ {  0x30,  0x43,  0x55,  0x56,     4,  0x30,  0x30,  3 },
30142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 5 : R+EN       */ {  0x30,  0x43,     5,  0x56,  0x14,  0x30,  0x30,  4 },
30152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 6 : R+AN       */ {  0x30,  0x43,  0x55,     6,  0x14,  0x30,  0x30,  4 }
30162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
30172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final byte impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS[][] = {
30182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* The cases handled in this table are (visually):  R EN L
30192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                            R L AN L
30202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
30212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*                         L,     R,    EN,    AN,    ON,     S,     B, Res */
30222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 0 : init       */ {  0x13,     0,     1,     1,     0,     0,     0,  0 },
30232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 1 : R+EN/AN    */ {  0x23,     0,     1,     1,     2,  0x40,     0,  1 },
30242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 2 : R+EN/AN+ON */ {  0x23,     0,     1,     1,     2,  0x40,     0,  0 },
30252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 3 : L          */ {     3,     0,     3,  0x36,  0x14,  0x40,     0,  1 },
30262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 4 : L+ON       */ {  0x53,  0x40,     5,  0x36,     4,  0x40,  0x40,  0 },
30272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 5 : L+ON+EN    */ {  0x53,  0x40,     5,  0x36,     4,  0x40,  0x40,  1 },
30282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 6 : L+AN       */ {  0x53,  0x40,     6,     6,     4,  0x40,  0x40,  3 }
30292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
30302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short[] impAct2 = {0,1,2,5,6,7,8};
30312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final short[] impAct3 = {0,1,9,10,11,12};
30322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final ImpTabPair impTab_INVERSE_LIKE_DIRECT_WITH_MARKS =
30332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            new ImpTabPair(impTabL_INVERSE_LIKE_DIRECT_WITH_MARKS,
30342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                           impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS, impAct2, impAct3);
30352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
30362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL = new ImpTabPair(
30372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            impTabL_NUMBERS_SPECIAL, impTabR_INVERSE_LIKE_DIRECT, impAct0, impAct1);
30382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
30392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final byte impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS[][] = {
30402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*  The case handled in this table is (visually):  R EN L
30412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
30422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*                         L,     R,    EN,    AN,    ON,     S,     B, Res */
30432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 0 : init       */ {     0,  0x62,     1,     1,     0,     0,     0,  0 },
30442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 1 : L+EN/AN    */ {     0,  0x62,     1,     1,     0,  0x30,     0,  4 },
30452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 2 : R          */ {     0,  0x62,  0x54,  0x54,  0x13,  0x30,     0,  3 },
30462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 3 : R+ON       */ {  0x30,  0x42,  0x54,  0x54,     3,  0x30,  0x30,  3 },
30472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* 4 : R+EN/AN    */ {  0x30,  0x42,     4,     4,  0x13,  0x30,  0x30,  4 }
30482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
30492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final ImpTabPair impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS = new
30502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ImpTabPair(impTabL_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS,
30512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                       impTabR_INVERSE_LIKE_DIRECT_WITH_MARKS, impAct2, impAct3);
30522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
30532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static class LevState {
30542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte[][] impTab;                /* level table pointer          */
30552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short[] impAct;                 /* action map array             */
30562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int startON;                    /* start of ON sequence         */
30572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int startL2EN;                  /* start of level 2 sequence    */
30582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int lastStrongRTL;              /* index of last found R or AL  */
30592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int runStart;                   /* start position of the run    */
30602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short state;                    /* current state                */
30612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte runLevel;                  /* run level before implicit solving */
30622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
30632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
30642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*------------------------------------------------------------------------*/
30652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
30662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int FIRSTALLOC = 10;
30672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
30682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  param pos:     position where to insert
30692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  param flag:    one of LRM_BEFORE, LRM_AFTER, RLM_BEFORE, RLM_AFTER
30702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
30712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void addPoint(int pos, int flag)
30722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
30732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Point point = new Point();
30742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
30752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int len = insertPoints.points.length;
30762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (len == 0) {
30772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            insertPoints.points = new Point[FIRSTALLOC];
30782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            len = FIRSTALLOC;
30792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
30802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (insertPoints.size >= len) { /* no room for new point */
30812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Point[] savePoints = insertPoints.points;
30822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            insertPoints.points = new Point[len * 2];
30832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            System.arraycopy(savePoints, 0, insertPoints.points, 0, len);
30842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
30852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        point.pos = pos;
30862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        point.flag = flag;
30872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        insertPoints.points[insertPoints.size] = point;
30882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        insertPoints.size++;
30892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
30902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
30912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void setLevelsOutsideIsolates(int start, int limit, byte level)
30922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
30932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte dirProp;
30942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int  isolateCount = 0, k;
30952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (k = start; k < limit; k++) {
30962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            dirProp = dirProps[k];
30972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == PDI)
30982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                isolateCount--;
30992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (isolateCount == 0)
31002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levels[k] = level;
31012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == LRI || dirProp == RLI)
31022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                isolateCount++;
31032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
31042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
31052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* perform rules (Wn), (Nn), and (In) on a run of the text ------------------ */
31072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
31092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This implementation of the (Wn) rules applies all rules in one pass.
31102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * In order to do so, it needs a look-ahead of typically 1 character
31112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * (except for W5: sequences of ET) and keeps track of changes
31122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in a rule Wp that affect a later Wq (p<q).
31132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
31142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The (Nn) and (In) rules are also performed in that same single loop,
31152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * but effectively one iteration behind for white space.
31162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
31172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Since all implicit rules are performed in one step, it is not necessary
31182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to actually store the intermediate directional properties in dirProps[].
31192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
31202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void processPropertySeq(LevState levState, short _prop,
31222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int start, int limit) {
31232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte cell;
31242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte[][] impTab = levState.impTab;
31252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short[] impAct = levState.impAct;
31262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short oldStateSeq,actionSeq;
31272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte level, addLevel;
31282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int start0, k;
31292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        start0 = start;                 /* save original start position */
31312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        oldStateSeq = levState.state;
31322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        cell = impTab[oldStateSeq][_prop];
31332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        levState.state = GetState(cell);        /* isolate the new state */
31342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        actionSeq = impAct[GetAction(cell)];    /* isolate the action */
31352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        addLevel = impTab[levState.state][IMPTABLEVELS_RES];
31362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (actionSeq != 0) {
31382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            switch (actionSeq) {
31392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 1:                     /* init ON seq */
31402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levState.startON = start0;
31412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
31422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 2:                     /* prepend ON seq to current seq */
31442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                start = levState.startON;
31452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
31462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 3:                     /* EN/AN after R+ON */
31482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                level = (byte)(levState.runLevel + 1);
31492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                setLevelsOutsideIsolates(levState.startON, start0, level);
31502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
31512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 4:                     /* EN/AN before R for NUMBERS_SPECIAL */
31532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                level = (byte)(levState.runLevel + 2);
31542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                setLevelsOutsideIsolates(levState.startON, start0, level);
31552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
31562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 5:                     /* L or S after possible relevant EN/AN */
31582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* check if we had EN after R/AL */
31592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (levState.startL2EN >= 0) {
31602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    addPoint(levState.startL2EN, LRM_BEFORE);
31612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
31622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levState.startL2EN = -1;  /* not within previous if since could also be -2 */
31632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* check if we had any relevant EN/AN after R/AL */
31642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ((insertPoints.points.length == 0) ||
31652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        (insertPoints.size <= insertPoints.confirmed)) {
31662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* nothing, just clean up */
31672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    levState.lastStrongRTL = -1;
31682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* check if we have a pending conditional segment */
31692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    level = impTab[oldStateSeq][IMPTABLEVELS_RES];
31702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((level & 1) != 0 && levState.startON > 0) { /* after ON */
31712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        start = levState.startON;   /* reset to basic run level */
31722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
31732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (_prop == _S) {              /* add LRM before S */
31742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        addPoint(start0, LRM_BEFORE);
31752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        insertPoints.confirmed = insertPoints.size;
31762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
31772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
31782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
31792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* reset previous RTL cont to level for LTR text */
31802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (k = levState.lastStrongRTL + 1; k < start0; k++) {
31812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* reset odd level, leave runLevel+2 as is */
31822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    levels[k] = (byte)((levels[k] - 2) & ~1);
31832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
31842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* mark insert points as confirmed */
31852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                insertPoints.confirmed = insertPoints.size;
31862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levState.lastStrongRTL = -1;
31872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (_prop == _S) {           /* add LRM before S */
31882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    addPoint(start0, LRM_BEFORE);
31892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    insertPoints.confirmed = insertPoints.size;
31902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
31912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
31922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 6:                     /* R/AL after possible relevant EN/AN */
31942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* just clean up */
31952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (insertPoints.points.length > 0)
31962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* remove all non confirmed insert points */
31972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    insertPoints.size = insertPoints.confirmed;
31982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levState.startON = -1;
31992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levState.startL2EN = -1;
32002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levState.lastStrongRTL = limit - 1;
32012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
32022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
32032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 7:                     /* EN/AN after R/AL + possible cont */
32042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* check for real AN */
32052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ((_prop == _AN) && (dirProps[start0] == AN) &&
32062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                (reorderingMode != REORDER_INVERSE_FOR_NUMBERS_SPECIAL))
32072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                {
32082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* real AN */
32092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (levState.startL2EN == -1) { /* if no relevant EN already found */
32102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        /* just note the rightmost digit as a strong RTL */
32112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        levState.lastStrongRTL = limit - 1;
32122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        break;
32132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
32142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (levState.startL2EN >= 0)  { /* after EN, no AN */
32152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        addPoint(levState.startL2EN, LRM_BEFORE);
32162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        levState.startL2EN = -2;
32172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
32182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* note AN */
32192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    addPoint(start0, LRM_BEFORE);
32202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
32212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
32222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* if first EN/AN after R/AL */
32232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (levState.startL2EN == -1) {
32242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    levState.startL2EN = start0;
32252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
32262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
32272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
32282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 8:                     /* note location of latest R/AL */
32292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levState.lastStrongRTL = limit - 1;
32302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levState.startON = -1;
32312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
32322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
32332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 9:                     /* L after R+ON/EN/AN */
32342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* include possible adjacent number on the left */
32352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (k = start0-1; k >= 0 && ((levels[k] & 1) == 0); k--) {
32362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
32372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (k >= 0) {
32382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    addPoint(k, RLM_BEFORE);    /* add RLM before */
32392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    insertPoints.confirmed = insertPoints.size; /* confirm it */
32402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
32412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levState.startON = start0;
32422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
32432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
32442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 10:                    /* AN after L */
32452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* AN numbers between L text on both sides may be trouble. */
32462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* tentatively bracket with LRMs; will be confirmed if followed by L */
32472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                addPoint(start0, LRM_BEFORE);   /* add LRM before */
32482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                addPoint(start0, LRM_AFTER);    /* add LRM after  */
32492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
32502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
32512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 11:                    /* R after L+ON/EN/AN */
32522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* false alert, infirm LRMs around previous AN */
32532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                insertPoints.size=insertPoints.confirmed;
32542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (_prop == _S) {          /* add RLM before S */
32552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    addPoint(start0, RLM_BEFORE);
32562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    insertPoints.confirmed = insertPoints.size;
32572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
32582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
32592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
32602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 12:                    /* L after L+ON/AN */
32612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                level = (byte)(levState.runLevel + addLevel);
32622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (k=levState.startON; k < start0; k++) {
32632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (levels[k] < level) {
32642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        levels[k] = level;
32652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
32662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
32672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                insertPoints.confirmed = insertPoints.size;   /* confirm inserts */
32682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                levState.startON = start0;
32692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
32702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
32712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 13:                    /* L after L+ON+EN/AN/ON */
32722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                level = levState.runLevel;
32732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (k = start0-1; k >= levState.startON; k--) {
32742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (levels[k] == level+3) {
32752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        while (levels[k] == level+3) {
32762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            levels[k--] -= 2;
32772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
32782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        while (levels[k] == level) {
32792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            k--;
32802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
32812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
32822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (levels[k] == level+2) {
32832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        levels[k] = level;
32842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        continue;
32852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
32862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    levels[k] = (byte)(level+1);
32872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
32882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
32892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
32902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 14:                    /* R after L+ON+EN/AN/ON */
32912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                level = (byte)(levState.runLevel+1);
32922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (k = start0-1; k >= levState.startON; k--) {
32932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (levels[k] > level) {
32942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        levels[k] -= 2;
32952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
32962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
32972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
32982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
32992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            default:                        /* we should never get here */
33002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                throw new IllegalStateException("Internal ICU error in processPropertySeq");
33012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
33022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
33032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((addLevel) != 0 || (start < start0)) {
33042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            level = (byte)(levState.runLevel + addLevel);
33052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (start >= levState.runStart) {
33062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (k = start; k < limit; k++) {
33072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    levels[k] = level;
33082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
33102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                setLevelsOutsideIsolates(start, limit, level);
33112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
33122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
33132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
33142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
33152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
33162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns the directionality of the last strong character at the end of the prologue, if any.
33172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Requires prologue!=null.
33182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
33192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private byte lastL_R_AL() {
33202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = prologue.length(); i > 0; ) {
33212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int uchar = prologue.codePointBefore(i);
33222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            i -= Character.charCount(uchar);
33232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            byte dirProp = (byte)getCustomizedClass(uchar);
33242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == L) {
33252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return _L;
33262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
33272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == R || dirProp == AL) {
33282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return _R;
33292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
33302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if(dirProp == B) {
33312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return _ON;
33322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
33332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
33342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return _ON;
33352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
33362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
33372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
33382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns the directionality of the first strong character, or digit, in the epilogue, if any.
33392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Requires epilogue!=null.
33402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
33412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private byte firstL_R_AL_EN_AN() {
33422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < epilogue.length(); ) {
33432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int uchar = epilogue.codePointAt(i);
33442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            i += Character.charCount(uchar);
33452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            byte dirProp = (byte)getCustomizedClass(uchar);
33462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == L) {
33472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return _L;
33482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
33492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == R || dirProp == AL) {
33502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return _R;
33512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
33522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == EN) {
33532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return _EN;
33542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
33552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProp == AN) {
33562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return _AN;
33572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
33582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
33592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return _ON;
33602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
33612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
33622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void resolveImplicitLevels(int start, int limit, short sor, short eor)
33632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
33642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte dirProp;
33652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        LevState levState = new LevState();
33662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i, start1, start2;
33672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short oldStateImp, stateImp, actionImp;
33682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short gprop, resProp, cell;
33692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean inverseRTL;
33702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        short nextStrongProp = R;
33712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int nextStrongPos = -1;
33722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
33732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* check for RTL inverse Bidi mode */
33742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FOOD FOR THOUGHT: in case of RTL inverse Bidi, it would make sense to
33752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * loop on the text characters from end to start.
33762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * This would need a different properties state table (at least different
33772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * actions) and different levels state tables (maybe very similar to the
33782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * LTR corresponding ones.
33792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
33802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        inverseRTL=((start<lastArabicPos) && ((GetParaLevelAt(start) & 1)>0) &&
33812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    (reorderingMode == REORDER_INVERSE_LIKE_DIRECT  ||
33822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL));
33832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* initialize for property and levels state table */
33842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        levState.startL2EN = -1;        /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */
33852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        levState.lastStrongRTL = -1;    /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */
33862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        levState.runStart = start;
33872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        levState.runLevel = levels[start];
33882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        levState.impTab = impTabPair.imptab[levState.runLevel & 1];
33892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        levState.impAct = impTabPair.impact[levState.runLevel & 1];
33902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (start == 0 && prologue != null) {
33912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            byte lastStrong = lastL_R_AL();
33922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (lastStrong != _ON) {
33932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                sor = lastStrong;
33942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
33952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
33962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* The isolates[] entries contain enough information to
33972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           resume the bidi algorithm in the same state as it was
33982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           when it was interrupted by an isolate sequence. */
33992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (dirProps[start] == PDI) {
34002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            levState.startON = isolates[isolateCount].startON;
34012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            start1 = isolates[isolateCount].start1;
34022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            stateImp = isolates[isolateCount].stateImp;
34032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            levState.state = isolates[isolateCount].state;
34042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            isolateCount--;
34052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
34062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            levState.startON = -1;
34072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            start1 = start;
34082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (dirProps[start] == NSM)
34092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                stateImp = (short)(1 + sor);
34102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            else
34112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                stateImp = 0;
34122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            levState.state = 0;
34132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            processPropertySeq(levState, sor, start, start);
34142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
34152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        start2 = start;                 /* to make the Java compiler happy */
34162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
34172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (i = start; i <= limit; i++) {
34182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (i >= limit) {
34192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int k;
34202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (k = limit - 1;
34212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     k > start &&
34222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                         (DirPropFlag(dirProps[k]) & MASK_BN_EXPLICIT) != 0;
34232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     k--);
34242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dirProp = dirProps[k];
34252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (dirProp == LRI || dirProp == RLI)
34262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;  /* no forced closing for sequence ending with LRI/RLI */
34272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                gprop = eor;
34282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
34292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                byte prop, prop1;
34302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                prop = dirProps[i];
34312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (prop == B)
34322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    isolateCount = -1;  /* current isolates stack entry == none */
34332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (inverseRTL) {
34342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (prop == AL) {
34352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        /* AL before EN does not make it AN */
34362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        prop = R;
34372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else if (prop == EN) {
34382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (nextStrongPos <= i) {
34392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            /* look for next strong char (L/R/AL) */
34402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            int j;
34412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            nextStrongProp = R;     /* set default */
34422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            nextStrongPos = limit;
34432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            for (j = i+1; j < limit; j++) {
34442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                prop1 = dirProps[j];
34452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                if (prop1 == L || prop1 == R || prop1 == AL) {
34462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    nextStrongProp = prop1;
34472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    nextStrongPos = j;
34482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    break;
34492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                }
34502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
34512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
34522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (nextStrongProp == AL) {
34532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            prop = AN;
34542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
34552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
34562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
34572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                gprop = groupProp[prop];
34582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
34592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            oldStateImp = stateImp;
34602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            cell = impTabProps[oldStateImp][gprop];
34612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            stateImp = GetStateProps(cell);     /* isolate the new state */
34622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            actionImp = GetActionProps(cell);   /* isolate the action */
34632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ((i == limit) && (actionImp == 0)) {
34642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* there is an unprocessed sequence if its property == eor   */
34652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                actionImp = 1;                  /* process the last sequence */
34662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
34672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (actionImp != 0) {
34682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                resProp = impTabProps[oldStateImp][IMPTABPROPS_RES];
34692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                switch (actionImp) {
34702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 1:             /* process current seq1, init new seq1 */
34712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    processPropertySeq(levState, resProp, start1, i);
34722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start1 = i;
34732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 2:             /* init new seq2 */
34752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start2 = i;
34762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 3:             /* process seq1, process seq2, init new seq1 */
34782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    processPropertySeq(levState, resProp, start1, start2);
34792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    processPropertySeq(levState, _ON, start2, i);
34802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start1 = i;
34812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 4:             /* process seq1, set seq1=seq2, init new seq2 */
34832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    processPropertySeq(levState, resProp, start1, start2);
34842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start1 = start2;
34852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start2 = i;
34862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                default:            /* we should never get here */
34882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    throw new IllegalStateException("Internal ICU error in resolveImplicitLevels");
34892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
34902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
34912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
34922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
34932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* flush possible pending sequence, e.g. ON */
34942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (limit == length && epilogue != null) {
34952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            byte firstStrong = firstL_R_AL_EN_AN();
34962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (firstStrong != _ON) {
34972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                eor = firstStrong;
34982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
34992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
35002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
35012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* look for the last char not a BN or LRE/RLE/LRO/RLO/PDF */
35022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (i = limit - 1;
35032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             i > start &&
35042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 (DirPropFlag(dirProps[i]) & MASK_BN_EXPLICIT) != 0;
35052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             i--);
35062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        dirProp = dirProps[i];
35072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((dirProp == LRI || dirProp == RLI) && limit < length) {
35082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            isolateCount++;
35092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (isolates[isolateCount] == null)
35102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                isolates[isolateCount] = new Isolate();
35112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            isolates[isolateCount].stateImp = stateImp;
35122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            isolates[isolateCount].state = levState.state;
35132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            isolates[isolateCount].start1 = start1;
35142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            isolates[isolateCount].startON = levState.startON;
35152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
35162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        else
35172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            processPropertySeq(levState, eor, limit, limit);
35182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
35192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
35202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* perform (L1) and (X9) ---------------------------------------------------- */
35212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
35222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
35232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Reset the embedding levels for some non-graphic characters (L1).
35242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method also sets appropriate levels for BN, and
35252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * explicit embedding types that are supposed to have been removed
35262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * from the paragraph in (X9).
35272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
35282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void adjustWSLevels() {
35292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i;
35302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
35312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((flags & MASK_WS) != 0) {
35322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int flag;
35332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            i = trailingWSStart;
35342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            while (i > 0) {
35352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* reset a sequence of WS/BN before eop and B/S to the paragraph paraLevel */
35362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                while (i > 0 && ((flag = DirPropFlag(dirProps[--i])) & MASK_WS) != 0) {
35372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (orderParagraphsLTR && (flag & DirPropFlag(B)) != 0) {
35382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        levels[i] = 0;
35392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
35402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        levels[i] = GetParaLevelAt(i);
35412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
35422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
35432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
35442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* reset BN to the next character's paraLevel until B/S, which restarts above loop */
35452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* here, i+1 is guaranteed to be <length */
35462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                while (i > 0) {
35472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    flag = DirPropFlag(dirProps[--i]);
35482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((flag & MASK_BN_EXPLICIT) != 0) {
35492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        levels[i] = levels[i + 1];
35502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else if (orderParagraphsLTR && (flag & DirPropFlag(B)) != 0) {
35512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        levels[i] = 0;
35522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        break;
35532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else if ((flag & MASK_B_S) != 0){
35542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        levels[i] = GetParaLevelAt(i);
35552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        break;
35562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
35572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
35582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
35592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
35602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
35612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
35622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
35632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Set the context before a call to setPara().<p>
35642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
35652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * setPara() computes the left-right directionality for a given piece
35662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of text which is supplied as one of its arguments. Sometimes this piece
35672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of text (the "main text") should be considered in context, because text
35682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * appearing before ("prologue") and/or after ("epilogue") the main text
35692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * may affect the result of this computation.<p>
35702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
35712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This function specifies the prologue and/or the epilogue for the next
35722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * call to setPara(). If successive calls to setPara()
35732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * all need specification of a context, setContext() must be called
35742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * before each call to setPara(). In other words, a context is not
35752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * "remembered" after the following successful call to setPara().<p>
35762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
35772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If a call to setPara() specifies DEFAULT_LTR or
35782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * DEFAULT_RTL as paraLevel and is preceded by a call to
35792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * setContext() which specifies a prologue, the paragraph level will
35802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * be computed taking in consideration the text in the prologue.<p>
35812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
35822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * When setPara() is called without a previous call to
35832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * setContext, the main text is handled as if preceded and followed
35842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * by strong directional characters at the current paragraph level.
35852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Calling setContext() with specification of a prologue will change
35862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * this behavior by handling the main text as if preceded by the last
35872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * strong character appearing in the prologue, if any.
35882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Calling setContext() with specification of an epilogue will change
35892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the behavior of setPara() by handling the main text as if followed
35902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * by the first strong character or digit appearing in the epilogue, if any.<p>
35912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
35922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Note 1: if <code>setContext</code> is called repeatedly without
35932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         calling <code>setPara</code>, the earlier calls have no effect,
35942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         only the last call will be remembered for the next call to
35952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>setPara</code>.<p>
35962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
35972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Note 2: calling <code>setContext(null, null)</code>
35982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         cancels any previous setting of non-empty prologue or epilogue.
35992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         The next call to <code>setPara()</code> will process no
36002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         prologue or epilogue.<p>
36012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
36022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Note 3: users must be aware that even after setting the context
36032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         before a call to setPara() to perform e.g. a logical to visual
36042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         transformation, the resulting string may not be identical to what it
36052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         would have been if all the text, including prologue and epilogue, had
36062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         been processed together.<br>
36072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Example (upper case letters represent RTL characters):<br>
36082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * &nbsp;&nbsp;prologue = "<code>abc DE</code>"<br>
36092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * &nbsp;&nbsp;epilogue = none<br>
36102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * &nbsp;&nbsp;main text = "<code>FGH xyz</code>"<br>
36112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * &nbsp;&nbsp;paraLevel = LTR<br>
36122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * &nbsp;&nbsp;display without prologue = "<code>HGF xyz</code>"
36132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *             ("HGF" is adjacent to "xyz")<br>
36142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * &nbsp;&nbsp;display with prologue = "<code>abc HGFED xyz</code>"
36152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *             ("HGF" is not adjacent to "xyz")<br>
36162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
36172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param prologue is the text which precedes the text that
36182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        will be specified in a coming call to setPara().
36192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        If there is no prologue to consider,
36202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        this parameter can be <code>null</code>.
36212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
36222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param epilogue is the text which follows the text that
36232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        will be specified in a coming call to setPara().
36242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        If there is no epilogue to consider,
36252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        this parameter can be <code>null</code>.
36262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
36272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setPara
36282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
36292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setContext(String prologue, String epilogue) {
36302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.prologue = prologue != null && prologue.length() > 0 ? prologue : null;
36312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.epilogue = epilogue != null && epilogue.length() > 0 ? epilogue : null;
36322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
36332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
36342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void setParaSuccess() {
36352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        prologue = null;                /* forget the last context */
36362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        epilogue = null;
36372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        paraBidi = this;                /* mark successful setPara */
36382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
36392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
36402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int Bidi_Min(int x, int y) {
36412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return x < y ? x : y;
36422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
36432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
36442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    int Bidi_Abs(int x) {
36452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return x >= 0 ? x : -x;
36462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
36472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
36482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    void setParaRunsOnly(char[] parmText, byte parmParaLevel) {
36492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] visualMap;
36502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String visualText;
36512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int saveLength, saveTrailingWSStart;
36522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte[] saveLevels;
36532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte saveDirection;
36542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i, j, visualStart, logicalStart,
36552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            oldRunCount, runLength, addedRuns, insertRemove,
36562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            start, limit, step, indexOddBit, logicalPos,
36572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            index, index1;
36582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int saveOptions;
36592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
36602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        reorderingMode = REORDER_DEFAULT;
36612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int parmLength = parmText.length;
36622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (parmLength == 0) {
36632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            setPara(parmText, parmParaLevel, null);
36642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            reorderingMode = REORDER_RUNS_ONLY;
36652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
36662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
36672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* obtain memory for mapping table and visual text */
36682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        saveOptions = reorderingOptions;
36692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((saveOptions & OPTION_INSERT_MARKS) > 0) {
36702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            reorderingOptions &= ~OPTION_INSERT_MARKS;
36712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            reorderingOptions |= OPTION_REMOVE_CONTROLS;
36722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
36732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        parmParaLevel &= 1;             /* accept only 0 or 1 */
36742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        setPara(parmText, parmParaLevel, null);
36752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* we cannot access directly levels since it is not yet set if
36762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * direction is not MIXED
36772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
36782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        saveLevels = new byte[this.length];
36792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        System.arraycopy(getLevels(), 0, saveLevels, 0, this.length);
36802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        saveTrailingWSStart = trailingWSStart;
36812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
36822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* FOOD FOR THOUGHT: instead of writing the visual text, we could use
36832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * the visual map and the dirProps array to drive the second call
36842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * to setPara (but must make provision for possible removal of
36852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Bidi controls.  Alternatively, only use the dirProps array via
36862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * customized classifier callback.
36872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
36882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        visualText = writeReordered(DO_MIRRORING);
36892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        visualMap = getVisualMap();
36902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.reorderingOptions = saveOptions;
36912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        saveLength = this.length;
36922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        saveDirection=this.direction;
36932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
36942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.reorderingMode = REORDER_INVERSE_LIKE_DIRECT;
36952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        parmParaLevel ^= 1;
36962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        setPara(visualText, parmParaLevel, null);
36972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        BidiLine.getRuns(this);
36982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* check if some runs must be split, count how many splits */
36992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        addedRuns = 0;
37002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        oldRunCount = this.runCount;
37012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        visualStart = 0;
37022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (i = 0; i < oldRunCount; i++, visualStart += runLength) {
37032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            runLength = runs[i].limit - visualStart;
37042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (runLength < 2) {
37052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                continue;
37062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
37072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            logicalStart = runs[i].start;
37082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (j = logicalStart+1; j < logicalStart+runLength; j++) {
37092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                index = visualMap[j];
37102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                index1 = visualMap[j-1];
37112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ((Bidi_Abs(index-index1)!=1) || (saveLevels[index]!=saveLevels[index1])) {
37122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    addedRuns++;
37132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
37142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
37152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
37162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (addedRuns > 0) {
37172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            getRunsMemory(oldRunCount + addedRuns);
37182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (runCount == 1) {
37192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* because we switch from UBiDi.simpleRuns to UBiDi.runs */
37202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                runsMemory[0] = runs[0];
37212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
37222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                System.arraycopy(runs, 0, runsMemory, 0, runCount);
37232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
37242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            runs = runsMemory;
37252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            runCount += addedRuns;
37262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (i = oldRunCount; i < runCount; i++) {
37272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (runs[i] == null) {
37282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    runs[i] = new BidiRun(0, 0, (byte)0);
37292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
37302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
37312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
37322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* split runs which are not consecutive in source text */
37332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int newI;
37342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (i = oldRunCount-1; i >= 0; i--) {
37352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            newI = i + addedRuns;
37362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            runLength = i==0 ? runs[0].limit :
37372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                               runs[i].limit - runs[i-1].limit;
37382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            logicalStart = runs[i].start;
37392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            indexOddBit = runs[i].level & 1;
37402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (runLength < 2) {
37412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (addedRuns > 0) {
37422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    runs[newI].copyFrom(runs[i]);
37432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
37442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                logicalPos = visualMap[logicalStart];
37452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                runs[newI].start = logicalPos;
37462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                runs[newI].level = (byte)(saveLevels[logicalPos] ^ indexOddBit);
37472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                continue;
37482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
37492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (indexOddBit > 0) {
37502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                start = logicalStart;
37512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                limit = logicalStart + runLength - 1;
37522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                step = 1;
37532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
37542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                start = logicalStart + runLength - 1;
37552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                limit = logicalStart;
37562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                step = -1;
37572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
37582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (j = start; j != limit; j += step) {
37592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                index = visualMap[j];
37602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                index1 = visualMap[j+step];
37612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ((Bidi_Abs(index-index1)!=1) || (saveLevels[index]!=saveLevels[index1])) {
37622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    logicalPos = Bidi_Min(visualMap[start], index);
37632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    runs[newI].start = logicalPos;
37642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    runs[newI].level = (byte)(saveLevels[logicalPos] ^ indexOddBit);
37652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    runs[newI].limit = runs[i].limit;
37662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    runs[i].limit -= Bidi_Abs(j - start) + 1;
37672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    insertRemove = runs[i].insertRemove & (LRM_AFTER|RLM_AFTER);
37682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    runs[newI].insertRemove = insertRemove;
37692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    runs[i].insertRemove &= ~insertRemove;
37702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start = j + step;
37712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    addedRuns--;
37722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    newI--;
37732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
37742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
37752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (addedRuns > 0) {
37762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                runs[newI].copyFrom(runs[i]);
37772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
37782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            logicalPos = Bidi_Min(visualMap[start], visualMap[limit]);
37792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            runs[newI].start = logicalPos;
37802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            runs[newI].level = (byte)(saveLevels[logicalPos] ^ indexOddBit);
37812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
37822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
37832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller//    cleanup1:
37842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* restore initial paraLevel */
37852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.paraLevel ^= 1;
37862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller//    cleanup2:
37872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* restore real text */
37882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.text = parmText;
37892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.length = saveLength;
37902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.originalLength = parmLength;
37912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.direction=saveDirection;
37922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.levels = saveLevels;
37932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.trailingWSStart = saveTrailingWSStart;
37942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (runCount > 1) {
37952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.direction = MIXED;
37962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
37972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller//    cleanup3:
37982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.reorderingMode = REORDER_RUNS_ONLY;
37992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
38002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
38012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
38022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Perform the Unicode Bidi algorithm. It is defined in the
3803fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <a href="http://www.unicode.org/reports/tr9/">Unicode Standard Annex #9</a>.
38042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3805fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <p>This method takes a piece of plain text containing one or more paragraphs,
38062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * with or without externally specified embedding levels from <i>styled</i>
3807fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * text and computes the left-right-directionality of each character.</p>
38082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3809fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <p>If the entire text is all of the same directionality, then
38102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the method may not perform all the steps described by the algorithm,
38112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * i.e., some levels may not be the same as if all steps were performed.
38122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is not relevant for unidirectional text.<br>
38132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For example, in pure LTR text with numbers the numbers would get
38142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a resolved level of 2 higher than the surrounding text according to
38152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the algorithm. This implementation may set all resolved levels to
3816fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * the same value in such a case.</p>
38172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3818fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <p>The text can be composed of multiple paragraphs. Occurrence of a block
38192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * separator in the text terminates a paragraph, and whatever comes next starts
38202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a new paragraph. The exception to this rule is when a Carriage Return (CR)
38212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is followed by a Line Feed (LF). Both CR and LF are block separators, but
38222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in that case, the pair of characters is considered as terminating the
38232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * preceding paragraph, and a new paragraph will be started by a character
38242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * coming after the LF.
38252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3826fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <p>Although the text is passed here as a <code>String</code>, it is
38272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * stored internally as an array of characters. Therefore the
38282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * documentation will refer to indexes of the characters in the text.
38292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
38302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param text contains the text that the Bidi algorithm will be performed
38312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        on. This text can be retrieved with <code>getText()</code> or
38322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>getTextAsString</code>.<br>
38332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
38342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param paraLevel specifies the default level for the text;
38352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        it is typically 0 (LTR) or 1 (RTL).
38362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        If the method shall determine the paragraph level from the text,
38372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        then <code>paraLevel</code> can be set to
38382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        either <code>LEVEL_DEFAULT_LTR</code>
38392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        or <code>LEVEL_DEFAULT_RTL</code>; if the text contains multiple
38402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        paragraphs, the paragraph level shall be determined separately for
38412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        each paragraph; if a paragraph does not include any strongly typed
38422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        character, then the desired default is used (0 for LTR or 1 for RTL).
38432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        Any other value between 0 and <code>MAX_EXPLICIT_LEVEL</code>
38442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        is also valid, with odd levels indicating RTL.
38452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
38462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param embeddingLevels (in) may be used to preset the embedding and override levels,
38472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        ignoring characters like LRE and PDF in the text.
38482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        A level overrides the directional property of its corresponding
38492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        (same index) character if the level has the
38502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>LEVEL_OVERRIDE</code> bit set.<br><br>
3851fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        Aside from that bit, it must be
3852bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     *        <code>paraLevel&lt;=embeddingLevels[]&lt;=MAX_EXPLICIT_LEVEL</code>,
3853fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        except that level 0 is always allowed.
3854fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        Level 0 for a paragraph separator prevents reordering of paragraphs;
3855fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        this only works reliably if <code>LEVEL_OVERRIDE</code>
3856fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        is also set for paragraph separators.
3857fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        Level 0 for other characters is treated as a wildcard
3858fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        and is lifted up to the resolved level of the surrounding paragraph.<br><br>
38592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <strong>Caution: </strong>A reference to this array, not a copy
38602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        of the levels, will be stored in the <code>Bidi</code> object;
38612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        the <code>embeddingLevels</code>
38622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        should not be modified to avoid unexpected results on subsequent
38632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        Bidi operations. However, the <code>setPara()</code> and
38642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>setLine()</code> methods may modify some or all of the
38652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        levels.<br><br>
38662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <strong>Note:</strong> the <code>embeddingLevels</code> array must
38672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        have one entry for each character in <code>text</code>.
38682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
38692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if the values in embeddingLevels are
38702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         not within the allowed range
38712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
38722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #LEVEL_DEFAULT_LTR
38732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #LEVEL_DEFAULT_RTL
38742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #LEVEL_OVERRIDE
38752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #MAX_EXPLICIT_LEVEL
38762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
38772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setPara(String text, byte paraLevel, byte[] embeddingLevels)
38782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
38792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (text == null) {
38802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            setPara(new char[0], paraLevel, embeddingLevels);
38812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
38822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            setPara(text.toCharArray(), paraLevel, embeddingLevels);
38832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
38842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
38852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
38862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
38872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Perform the Unicode Bidi algorithm. It is defined in the
3888fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <a href="http://www.unicode.org/reports/tr9/">Unicode Standard Annex #9</a>.
38892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3890fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <p>This method takes a piece of plain text containing one or more paragraphs,
38912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * with or without externally specified embedding levels from <i>styled</i>
3892fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * text and computes the left-right-directionality of each character.</p>
38932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3894fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <p>If the entire text is all of the same directionality, then
38952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the method may not perform all the steps described by the algorithm,
38962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * i.e., some levels may not be the same as if all steps were performed.
38972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is not relevant for unidirectional text.<br>
38982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For example, in pure LTR text with numbers the numbers would get
38992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a resolved level of 2 higher than the surrounding text according to
39002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the algorithm. This implementation may set all resolved levels to
3901fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * the same value in such a case.</p>
39022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3903fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <p>The text can be composed of multiple paragraphs. Occurrence of a block
39042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * separator in the text terminates a paragraph, and whatever comes next starts
39052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a new paragraph. The exception to this rule is when a Carriage Return (CR)
39062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is followed by a Line Feed (LF). Both CR and LF are block separators, but
39072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in that case, the pair of characters is considered as terminating the
39082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * preceding paragraph, and a new paragraph will be started by a character
39092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * coming after the LF.
39102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3911fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <p>The text is stored internally as an array of characters. Therefore the
39122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * documentation will refer to indexes of the characters in the text.
39132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
39142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param chars contains the text that the Bidi algorithm will be performed
39152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        on. This text can be retrieved with <code>getText()</code> or
39162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>getTextAsString</code>.<br>
39172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
39182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param paraLevel specifies the default level for the text;
39192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        it is typically 0 (LTR) or 1 (RTL).
39202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        If the method shall determine the paragraph level from the text,
39212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        then <code>paraLevel</code> can be set to
39222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        either <code>LEVEL_DEFAULT_LTR</code>
39232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        or <code>LEVEL_DEFAULT_RTL</code>; if the text contains multiple
39242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        paragraphs, the paragraph level shall be determined separately for
39252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        each paragraph; if a paragraph does not include any strongly typed
39262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        character, then the desired default is used (0 for LTR or 1 for RTL).
39272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        Any other value between 0 and <code>MAX_EXPLICIT_LEVEL</code>
39282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        is also valid, with odd levels indicating RTL.
39292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
39302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param embeddingLevels (in) may be used to preset the embedding and
39312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        override levels, ignoring characters like LRE and PDF in the text.
39322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        A level overrides the directional property of its corresponding
39332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        (same index) character if the level has the
39342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>LEVEL_OVERRIDE</code> bit set.<br><br>
3935fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        Aside from that bit, it must be
3936bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     *        <code>paraLevel&lt;=embeddingLevels[]&lt;=MAX_EXPLICIT_LEVEL</code>,
3937fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        except that level 0 is always allowed.
3938fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        Level 0 for a paragraph separator prevents reordering of paragraphs;
3939fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        this only works reliably if <code>LEVEL_OVERRIDE</code>
3940fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        is also set for paragraph separators.
3941fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        Level 0 for other characters is treated as a wildcard
3942fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *        and is lifted up to the resolved level of the surrounding paragraph.<br><br>
39432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <strong>Caution: </strong>A reference to this array, not a copy
39442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        of the levels, will be stored in the <code>Bidi</code> object;
39452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        the <code>embeddingLevels</code>
39462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        should not be modified to avoid unexpected results on subsequent
39472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        Bidi operations. However, the <code>setPara()</code> and
39482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>setLine()</code> methods may modify some or all of the
39492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        levels.<br><br>
39502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <strong>Note:</strong> the <code>embeddingLevels</code> array must
39512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        have one entry for each character in <code>text</code>.
39522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
39532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if the values in embeddingLevels are
39542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         not within the allowed range
39552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
39562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #LEVEL_DEFAULT_LTR
39572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #LEVEL_DEFAULT_RTL
39582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #LEVEL_OVERRIDE
39592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #MAX_EXPLICIT_LEVEL
39602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
39612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setPara(char[] chars, byte paraLevel, byte[] embeddingLevels)
39622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
39632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* check the argument values */
39642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (paraLevel < LEVEL_DEFAULT_LTR) {
39652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            verifyRange(paraLevel, 0, MAX_EXPLICIT_LEVEL + 1);
39662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
39672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (chars == null) {
39682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            chars = new char[0];
39692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
39702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
39712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* special treatment for RUNS_ONLY mode */
39722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (reorderingMode == REORDER_RUNS_ONLY) {
39732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            setParaRunsOnly(chars, paraLevel);
39742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
39752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
39762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
39772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* initialize the Bidi object */
39782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.paraBidi = null;          /* mark unfinished setPara */
39792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.text = chars;
39802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.length = this.originalLength = this.resultLength = text.length;
39812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.paraLevel = paraLevel;
39822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.direction = (byte)(paraLevel & 1);
39832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.paraCount = 1;
39842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
39852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* Allocate zero-length arrays instead of setting to null here; then
39862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * checks for null in various places can be eliminated.
39872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
39882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        dirProps = new byte[0];
39892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        levels = new byte[0];
39902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        runs = new BidiRun[0];
39912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        isGoodLogicalToVisualRunsMap = false;
39922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        insertPoints.size = 0;          /* clean up from last call */
39932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        insertPoints.confirmed = 0;     /* clean up from last call */
39942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
39952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*
39962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Save the original paraLevel if contextual; otherwise, set to 0.
39972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
39982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        defaultParaLevel = IsDefaultLevel(paraLevel) ? paraLevel : 0;
39992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (length == 0) {
40012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /*
40022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * For an empty paragraph, create a Bidi object with the paraLevel and
40032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * the flags and the direction set but without allocating zero-length arrays.
40042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * There is nothing more to do.
40052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             */
40062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (IsDefaultLevel(paraLevel)) {
40072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                this.paraLevel &= 1;
40082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                defaultParaLevel = 0;
40092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
40102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            flags = DirPropFlagLR(paraLevel);
40112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            runCount = 0;
40122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paraCount = 0;
40132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            setParaSuccess();
40142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
40152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
40162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        runCount = -1;
40182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*
40202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Get the directional properties,
40212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * the flags bit-set, and
40222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * determine the paragraph level if necessary.
40232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
40242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getDirPropsMemory(length);
40252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        dirProps = dirPropsMemory;
40262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getDirProps();
40272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* the processed length may have changed if OPTION_STREAMING is set */
40282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        trailingWSStart = length;  /* the levels[] will reflect the WS run */
40292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* are explicit levels specified? */
40312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (embeddingLevels == null) {
40322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* no: determine explicit levels according to the (Xn) rules */
40332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            getLevelsMemory(length);
40342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            levels = levelsMemory;
40352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            direction = resolveExplicitLevels();
40362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
40372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* set BN for all explicit codes, check that all levels are 0 or paraLevel..MAX_EXPLICIT_LEVEL */
40382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            levels = embeddingLevels;
40392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            direction = checkExplicitLevels();
40402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
40412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* allocate isolate memory */
40432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isolateCount > 0) {
40442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (isolates == null || isolates.length < isolateCount)
40452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                isolates = new Isolate[isolateCount + 3];   /* keep some reserve */
40462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
40472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        isolateCount = -1;              /* current isolates stack entry == none */
40482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*
40502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * The steps after (X9) in the Bidi algorithm are performed only if
40512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * the paragraph text has mixed directionality!
40522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
40532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (direction) {
40542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case LTR:
40552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* all levels are implicitly at paraLevel (important for getLevels()) */
40562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            trailingWSStart = 0;
40572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
40582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case RTL:
40592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* all levels are implicitly at paraLevel (important for getLevels()) */
40602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            trailingWSStart = 0;
40612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
40622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        default:
40632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /*
40642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             *  Choose the right implicit state table
40652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             */
40662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            switch(reorderingMode) {
40672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case REORDER_DEFAULT:
40682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                this.impTabPair = impTab_DEFAULT;
40692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
40702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case REORDER_NUMBERS_SPECIAL:
40712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                this.impTabPair = impTab_NUMBERS_SPECIAL;
40722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
40732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case REORDER_GROUP_NUMBERS_WITH_R:
40742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                this.impTabPair = impTab_GROUP_NUMBERS_WITH_R;
40752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
40762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case REORDER_RUNS_ONLY:
40772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* we should never get here */
40782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                throw new InternalError("Internal ICU error in setPara");
40792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* break; */
40802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case REORDER_INVERSE_NUMBERS_AS_L:
40812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                this.impTabPair = impTab_INVERSE_NUMBERS_AS_L;
40822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
40832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case REORDER_INVERSE_LIKE_DIRECT:
40842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ((reorderingOptions & OPTION_INSERT_MARKS) != 0) {
40852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    this.impTabPair = impTab_INVERSE_LIKE_DIRECT_WITH_MARKS;
40862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
40872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    this.impTabPair = impTab_INVERSE_LIKE_DIRECT;
40882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
40892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
40902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case REORDER_INVERSE_FOR_NUMBERS_SPECIAL:
40912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ((reorderingOptions & OPTION_INSERT_MARKS) != 0) {
40922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    this.impTabPair = impTab_INVERSE_FOR_NUMBERS_SPECIAL_WITH_MARKS;
40932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
40942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    this.impTabPair = impTab_INVERSE_FOR_NUMBERS_SPECIAL;
40952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
40962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
40972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
40982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /*
40992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * If there are no external levels specified and there
41002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * are no significant explicit level codes in the text,
41012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * then we can treat the entire paragraph as one run.
41022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * Otherwise, we need to perform the following rules on runs of
41032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * the text with the same embedding levels. (X10)
41042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * "Significant" explicit level codes are ones that actually
41052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * affect non-BN characters.
41062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * Examples for "insignificant" ones are empty embeddings
41072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * LRE-PDF, LRE-RLE-PDF-PDF, etc.
41082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             */
41092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (embeddingLevels == null && paraCount <= 1 &&
41102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                (flags & DirPropFlagMultiRuns) == 0) {
41112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                resolveImplicitLevels(0, length,
41122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        GetLRFromLevel(GetParaLevelAt(0)),
41132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        GetLRFromLevel(GetParaLevelAt(length - 1)));
41142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
41152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* sor, eor: start and end types of same-level-run */
41162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int start, limit = 0;
41172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                byte level, nextLevel;
41182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                short sor, eor;
41192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* determine the first sor and set eor to it because of the loop body (sor=eor there) */
41212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                level = GetParaLevelAt(0);
41222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                nextLevel = levels[0];
41232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (level < nextLevel) {
41242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    eor = GetLRFromLevel(nextLevel);
41252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
41262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    eor = GetLRFromLevel(level);
41272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
41282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                do {
41302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* determine start and limit of the run (end points just behind the run) */
41312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* the values for this run's start are the same as for the previous run's end */
41332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start = limit;
41342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    level = nextLevel;
41352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((start > 0) && (dirProps[start - 1] == B)) {
41362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        /* except if this is a new paragraph, then set sor = para level */
41372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        sor = GetLRFromLevel(GetParaLevelAt(start));
41382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
41392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        sor = eor;
41402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
41412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* search for the limit of this run */
41432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    while ((++limit < length) &&
41442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                           ((levels[limit] == level) ||
41452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            ((DirPropFlag(dirProps[limit]) & MASK_BN_EXPLICIT) != 0))) {}
41462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* get the correct level of the next run */
41482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (limit < length) {
41492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        nextLevel = levels[limit];
41502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
41512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        nextLevel = GetParaLevelAt(length - 1);
41522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
41532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* determine eor from max(level, nextLevel); sor is last run's eor */
41552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (NoOverride(level) < NoOverride(nextLevel)) {
41562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        eor = GetLRFromLevel(nextLevel);
41572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
41582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        eor = GetLRFromLevel(level);
41592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
41602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* if the run consists of overridden directional types, then there
41622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                       are no implicit types to be resolved */
41632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((level & LEVEL_OVERRIDE) == 0) {
41642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        resolveImplicitLevels(start, limit, sor, eor);
41652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
41662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        /* remove the LEVEL_OVERRIDE flags */
41672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        do {
41682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            levels[start++] &= ~LEVEL_OVERRIDE;
41692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        } while (start < limit);
41702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
41712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } while (limit  < length);
41722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
41732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* reset the embedding levels for some non-graphic characters (L1), (X9) */
41752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            adjustWSLevels();
41762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
41782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
41792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* add RLM for inverse Bidi with contextual orientation resolving
41802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * to RTL which would not round-trip otherwise
41812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
41822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((defaultParaLevel > 0) &&
41832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ((reorderingOptions & OPTION_INSERT_MARKS) != 0) &&
41842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ((reorderingMode == REORDER_INVERSE_LIKE_DIRECT) ||
41852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             (reorderingMode == REORDER_INVERSE_FOR_NUMBERS_SPECIAL))) {
41862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int start, last;
41872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            byte level;
41882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            byte dirProp;
41892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (int i = 0; i < paraCount; i++) {
41902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                last = paras_limit[i] - 1;
41912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                level = paras_level[i];
41922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (level == 0)
41932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    continue;           /* LTR paragraph */
41942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                start = i == 0 ? 0 : paras_limit[i - 1];
41952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for (int j = last; j >= start; j--) {
41962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    dirProp = dirProps[j];
41972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (dirProp == L) {
41982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (j < last) {
41992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            while (dirProps[last] == B) {
42002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                last--;
42012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
42022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
42032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        addPoint(last, RLM_BEFORE);
42042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        break;
42052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
42062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((DirPropFlag(dirProp) & MASK_R_AL) != 0) {
42072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        break;
42082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
42092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
42102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
42112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
42122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((reorderingOptions & OPTION_REMOVE_CONTROLS) != 0) {
42142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            resultLength -= controlCount;
42152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
42162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            resultLength += insertPoints.size;
42172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
42182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        setParaSuccess();
42192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
42202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
42222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Perform the Unicode Bidi algorithm on a given paragraph, as defined in the
42232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <a href="http://www.unicode.org/unicode/reports/tr9/">Unicode Standard Annex #9</a>,
42242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * version 13,
42252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * also described in The Unicode Standard, Version 4.0 .<p>
42262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
42272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method takes a paragraph of text and computes the
42282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * left-right-directionality of each character. The text should not
42292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * contain any Unicode block separators.<p>
42302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
42312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The RUN_DIRECTION attribute in the text, if present, determines the base
42322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * direction (left-to-right or right-to-left). If not present, the base
42332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * direction is computed using the Unicode Bidirectional Algorithm,
42342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * defaulting to left-to-right if there are no strong directional characters
42352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in the text. This attribute, if present, must be applied to all the text
42362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in the paragraph.<p>
42372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
42382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The BIDI_EMBEDDING attribute in the text, if present, represents
42392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * embedding level information. Negative values from -1 to -62 indicate
42402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * overrides at the absolute value of the level. Positive values from 1 to
42412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 62 indicate embeddings. Where values are zero or not defined, the base
42422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * embedding level as determined by the base direction is assumed.<p>
42432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
42442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The NUMERIC_SHAPING attribute in the text, if present, converts European
42452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * digits to other decimal digits before running the bidi algorithm. This
42462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * attribute, if present, must be applied to all the text in the paragraph.
42472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
42482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If the entire text is all of the same directionality, then
42492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the method may not perform all the steps described by the algorithm,
42502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * i.e., some levels may not be the same as if all steps were performed.
42512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is not relevant for unidirectional text.<br>
42522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For example, in pure LTR text with numbers the numbers would get
42532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a resolved level of 2 higher than the surrounding text according to
42542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the algorithm. This implementation may set all resolved levels to
42552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the same value in such a case.<p>
42562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
42572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param paragraph a paragraph of text with optional character and
42582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        paragraph attribute information
42592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
42602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setPara(AttributedCharacterIterator paragraph)
42612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
42622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte paraLvl;
42632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Boolean runDirection = (Boolean) paragraph.getAttribute(TextAttribute.RUN_DIRECTION);
42642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (runDirection == null) {
42652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paraLvl = LEVEL_DEFAULT_LTR;
42662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
42672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paraLvl = (runDirection.equals(TextAttribute.RUN_DIRECTION_LTR)) ?
42682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        LTR : RTL;
42692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
42702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte[] lvls = null;
42722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int len = paragraph.getEndIndex() - paragraph.getBeginIndex();
42732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte[] embeddingLevels = new byte[len];
42742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        char[] txt = new char[len];
42752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i = 0;
42762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        char ch = paragraph.first();
42772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (ch != AttributedCharacterIterator.DONE) {
42782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            txt[i] = ch;
42792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Integer embedding = (Integer) paragraph.getAttribute(TextAttribute.BIDI_EMBEDDING);
42802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (embedding != null) {
42812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                byte level = embedding.byteValue();
42822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (level == 0) {
42832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    /* no-op */
42842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else if (level < 0) {
42852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    lvls = embeddingLevels;
42862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    embeddingLevels[i] = (byte)((0 - level) | LEVEL_OVERRIDE);
42872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
42882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    lvls = embeddingLevels;
42892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    embeddingLevels[i] = level;
42902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
42912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
42922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ch = paragraph.next();
42932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ++i;
42942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
42952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        NumericShaper shaper = (NumericShaper) paragraph.getAttribute(TextAttribute.NUMERIC_SHAPING);
42972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (shaper != null) {
42982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            shaper.shape(txt, 0, len);
42992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
43002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        setPara(txt, paraLvl, lvls);
43012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
43022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
43042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Specify whether block separators must be allocated level zero,
43052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * so that successive paragraphs will progress from left to right.
43062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method must be called before <code>setPara()</code>.
43072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Paragraph separators (B) may appear in the text.  Setting them to level zero
43082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * means that all paragraph separators (including one possibly appearing
43092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in the last text position) are kept in the reordered text after the text
43102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * that they follow in the source text.
43112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * When this feature is not enabled, a paragraph separator at the last
43122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * position of the text before reordering will go to the first position
43132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of the reordered text when the paragraph level is odd.
43142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param ordarParaLTR specifies whether paragraph separators (B) must
43162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * receive level 0, so that successive paragraphs progress from left to right.
43172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setPara
43192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
43202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void orderParagraphsLTR(boolean ordarParaLTR) {
43212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        orderParagraphsLTR = ordarParaLTR;
43222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
43232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
43252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Is this <code>Bidi</code> object set to allocate level 0 to block
43262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * separators so that successive paragraphs progress from left to right?
43272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return <code>true</code> if the <code>Bidi</code> object is set to
43292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         allocate level 0 to block separators.
43302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
43312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean isOrderParagraphsLTR() {
43322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return orderParagraphsLTR;
43332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
43342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
43362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the directionality of the text.
43372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return a value of <code>LTR</code>, <code>RTL</code> or <code>MIXED</code>
43392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         that indicates if the entire text
43402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         represented by this object is unidirectional,
43412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         and which direction, or if it is mixed-directional.
43422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
43442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
43452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #LTR
43472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #RTL
43482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #MIXED
43492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
43502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public byte getDirection()
43512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
43522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
43532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return direction;
43542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
43552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
43572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the text.
43582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return A <code>String</code> containing the text that the
43602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>Bidi</code> object was created for.
43612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
43632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
43642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setPara
43662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setLine
43672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
43682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String getTextAsString()
43692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
43702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
43712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return new String(text);
43722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
43732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
43752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the text.
43762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return A <code>char</code> array containing the text that the
43782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>Bidi</code> object was created for.
43792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
43812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
43822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setPara
43842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setLine
43852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
43862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public char[] getText()
43872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
43882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
43892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return text;
43902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
43912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
43932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the length of the text.
43942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The length of the text that the <code>Bidi</code> object was
43962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         created for.
43972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
43992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
44002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
44012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getLength()
44022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
44032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
44042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return originalLength;
44052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
44062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
44082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the length of the source text processed by the last call to
44092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setPara()</code>. This length may be different from the length of
44102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the source text if option <code>OPTION_STREAMING</code> has been
44112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * set.
44122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <br>
44132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Note that whenever the length of the text affects the execution or the
44142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * result of a method, it is the processed length which must be considered,
44152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * except for <code>setPara</code> (which receives unprocessed source text)
44162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and <code>getLength</code> (which returns the original length of the
44172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * source text).<br>
44182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * In particular, the processed length is the one to consider in the
44192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * following cases:
44202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <ul>
44212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>maximum value of the <code>limit</code> argument of
44222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setLine</code></li>
44232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>maximum value of the <code>charIndex</code> argument of
44242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>getParagraph</code></li>
44252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>maximum value of the <code>charIndex</code> argument of
44262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>getLevelAt</code></li>
44272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>number of elements in the array returned by <code>getLevels</code>
44282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * </li>
44292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>maximum value of the <code>logicalStart</code> argument of
44302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>getLogicalRun</code></li>
44312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>maximum value of the <code>logicalIndex</code> argument of
44322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>getVisualIndex</code></li>
44332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>number of elements returned by <code>getLogicalMap</code></li>
44342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>length of text processed by <code>writeReordered</code></li>
44352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * </ul>
44362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
44372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The length of the part of the source text processed by
44382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         the last call to <code>setPara</code>.
44392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
44402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
44412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
44422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
44432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setPara
44442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_STREAMING
44452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
44462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getProcessedLength() {
44472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
44482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return length;
44492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
44502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
44522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the length of the reordered text resulting from the last call to
44532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setPara()</code>. This length may be different from the length
44542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of the source text if option <code>OPTION_INSERT_MARKS</code>
44552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * or option <code>OPTION_REMOVE_CONTROLS</code> has been set.
44562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <br>
44572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This resulting length is the one to consider in the following cases:
44582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <ul>
44592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>maximum value of the <code>visualIndex</code> argument of
44602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>getLogicalIndex</code></li>
44612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li>number of elements returned by <code>getVisualMap</code></li>
44622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * </ul>
44632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Note that this length stays identical to the source text length if
44642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Bidi marks are inserted or removed using option bits of
44652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>writeReordered</code>, or if option
44662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REORDER_INVERSE_NUMBERS_AS_L</code> has been set.
44672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
44682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The length of the reordered text resulting from
44692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         the last call to <code>setPara</code>.
44702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
44712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
44722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
44732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
44742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setPara
44752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_INSERT_MARKS
44762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_REMOVE_CONTROLS
44772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REORDER_INVERSE_NUMBERS_AS_L
44782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
44792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getResultLength() {
44802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
44812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return resultLength;
44822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
44832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* paragraphs API methods ------------------------------------------------- */
44852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
44872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the paragraph level of the text.
44882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
44892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The paragraph level. If there are multiple paragraphs, their
44902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         level may vary if the required paraLevel is LEVEL_DEFAULT_LTR or
44912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         LEVEL_DEFAULT_RTL.  In that case, the level of the first paragraph
44922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         is returned.
44932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
44942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
44952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
44962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
44972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #LEVEL_DEFAULT_LTR
44982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #LEVEL_DEFAULT_RTL
44992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getParagraph
45002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getParagraphByIndex
45012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
45022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public byte getParaLevel()
45032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
45042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
45052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return paraLevel;
45062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
45072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
45082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
45092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the number of paragraphs.
45102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
45112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The number of paragraphs.
45122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
45132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
45142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
45152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
45162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int countParagraphs()
45172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
45182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
45192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return paraCount;
45202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
45212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
45222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
45232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get a paragraph, given the index of this paragraph.
45242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
45252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method returns information about a paragraph.<p>
45262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
45272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param paraIndex is the number of the paragraph, in the
45282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        range <code>[0..countParagraphs()-1]</code>.
45292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
45302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return a BidiRun object with the details of the paragraph:<br>
45312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>start</code> will receive the index of the first character
45322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        of the paragraph in the text.<br>
45332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>limit</code> will receive the limit of the paragraph.<br>
45342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>embeddingLevel</code> will receive the level of the paragraph.
45352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
45362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
45372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
45382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if paraIndex is not in the range
45392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>[0..countParagraphs()-1]</code>
45402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
45412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see android.icu.text.BidiRun
45422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
45432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public BidiRun getParagraphByIndex(int paraIndex)
45442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
45452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
45462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(paraIndex, 0, paraCount);
45472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
45482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Bidi bidi = paraBidi;             /* get Para object if Line object */
45492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int paraStart;
45502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (paraIndex == 0) {
45512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paraStart = 0;
45522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
45532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paraStart = bidi.paras_limit[paraIndex - 1];
45542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
45552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        BidiRun bidiRun = new BidiRun();
45562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bidiRun.start = paraStart;
45572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bidiRun.limit = bidi.paras_limit[paraIndex];
45582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        bidiRun.level = GetParaLevelAt(paraStart);
45592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return bidiRun;
45602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
45612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
45622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
45632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get a paragraph, given a position within the text.
45642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method returns information about a paragraph.<br>
45652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Note: if the paragraph index is known, it is more efficient to
45662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * retrieve the paragraph information using getParagraphByIndex().<p>
45672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
45682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param charIndex is the index of a character within the text, in the
45692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        range <code>[0..getProcessedLength()-1]</code>.
45702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
45712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return a BidiRun object with the details of the paragraph:<br>
45722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>start</code> will receive the index of the first character
45732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        of the paragraph in the text.<br>
45742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>limit</code> will receive the limit of the paragraph.<br>
45752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>embeddingLevel</code> will receive the level of the paragraph.
45762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
45772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
45782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
45792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if charIndex is not within the legal range
45802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
45812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see android.icu.text.BidiRun
45822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getParagraphByIndex
45832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getProcessedLength
45842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
45852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public BidiRun getParagraph(int charIndex)
45862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
45872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
45882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Bidi bidi = paraBidi;             /* get Para object if Line object */
45892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(charIndex, 0, bidi.length);
45902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int paraIndex;
45912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (paraIndex = 0; charIndex >= bidi.paras_limit[paraIndex]; paraIndex++) {
45922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
45932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return getParagraphByIndex(paraIndex);
45942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
45952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
45962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
45972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the index of a paragraph, given a position within the text.<p>
45982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
45992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param charIndex is the index of a character within the text, in the
46002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        range <code>[0..getProcessedLength()-1]</code>.
46012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The index of the paragraph containing the specified position,
46032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         starting from 0.
46042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
46062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
46072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if charIndex is not within the legal range
46082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see android.icu.text.BidiRun
46102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getProcessedLength
46112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
46122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getParagraphIndex(int charIndex)
46132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
46142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
46152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Bidi bidi = paraBidi;             /* get Para object if Line object */
46162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(charIndex, 0, bidi.length);
46172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int paraIndex;
46182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (paraIndex = 0; charIndex >= bidi.paras_limit[paraIndex]; paraIndex++) {
46192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
46202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return paraIndex;
46212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
46222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
46232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
46242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Set a custom Bidi classifier used by the UBA implementation for Bidi
46252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * class determination.
46262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param classifier A new custom classifier. This can be null.
46282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getCustomClassifier
46302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
46312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setCustomClassifier(BidiClassifier classifier) {
46322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.customClassifier = classifier;
46332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
46342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
46352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
46362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Gets the current custom class classifier used for Bidi class
46372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * determination.
46382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return An instance of class <code>BidiClassifier</code>
46402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setCustomClassifier
46422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
46432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public BidiClassifier getCustomClassifier() {
46442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return this.customClassifier;
46452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
46462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
46472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
46482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Retrieves the Bidi class for a given code point.
46492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>If a <code>BidiClassifier</code> is defined and returns a value
4650f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * other than <code>CLASS_DEFAULT=UCharacter.getIntPropertyMaxValue(UProperty.BIDI_CLASS)+1</code>,
4651f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * that value is used; otherwise the default class determination mechanism is invoked.
46522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param c The code point to get a Bidi class for.
46542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The Bidi class for the character <code>c</code> that is in effect
46562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         for this <code>Bidi</code> instance.
46572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see BidiClassifier
46592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
46602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getCustomizedClass(int c) {
46612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int dir;
46622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
46632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (customClassifier == null ||
46642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                (dir = customClassifier.classify(c)) == Bidi.CLASS_DEFAULT) {
46652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            dir = bdp.getClass(c);
46662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
46672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (dir >= UCharacterDirection.CHAR_DIRECTION_COUNT)
46682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            dir = ON;
46692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return dir;
46702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
46712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
46722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
46732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setLine()</code> returns a <code>Bidi</code> object to
46742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * contain the reordering information, especially the resolved levels,
46752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * for all the characters in a line of text. This line of text is
46762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * specified by referring to a <code>Bidi</code> object representing
46772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * this information for a piece of text containing one or more paragraphs,
46782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and by specifying a range of indexes in this text.<p>
46792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * In the new line object, the indexes will range from 0 to <code>limit-start-1</code>.<p>
46802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is used after calling <code>setPara()</code>
46822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * for a piece of text, and after line-breaking on that text.
46832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It is not necessary if each paragraph is treated as a single line.<p>
46842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * After line-breaking, rules (L1) and (L2) for the treatment of
46862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * trailing WS and for reordering are performed on
46872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a <code>Bidi</code> object that represents a line.<p>
46882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <strong>Important: </strong>the line <code>Bidi</code> object may
46902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * reference data within the global text <code>Bidi</code> object.
46912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * You should not alter the content of the global text object until
46922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * you are finished using the line object.
46932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param start is the line's first index into the text.
46952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param limit is just behind the line's last index into the text
46972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        (its last index +1).
46982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
46992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return a <code>Bidi</code> object that will now represent a line of the text.
47002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
47022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code>
47032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if start and limit are not in the range
47042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>0&lt;=start&lt;limit&lt;=getProcessedLength()</code>,
47052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         or if the specified line crosses a paragraph boundary
47062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #setPara
47082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getProcessedLength
47092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
47102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Bidi setLine(int start, int limit)
47112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
47122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidPara();
47132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(start, 0, limit);
47142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(limit, 0, length+1);
47152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (getParagraphIndex(start) != getParagraphIndex(limit - 1)) {
47162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* the line crosses a paragraph boundary */
47172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException();
47182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
47192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return BidiLine.setLine(this, start, limit);
47202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
47212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
47222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
47232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the level for one character.
47242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param charIndex the index of a character.
47262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The level for the character at <code>charIndex</code>.
47282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
47302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
47312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if charIndex is not in the range
47322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>0&lt;=charIndex&lt;getProcessedLength()</code>
47332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getProcessedLength
47352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
47362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public byte getLevelAt(int charIndex)
47372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
47382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
47392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(charIndex, 0, length);
47402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return BidiLine.getLevelAt(this, charIndex);
47412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
47422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
47432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
47442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get an array of levels for each character.<p>
47452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Note that this method may allocate memory under some
47472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * circumstances, unlike <code>getLevelAt()</code>.
47482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The levels array for the text,
47502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         or <code>null</code> if an error occurs.
47512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
47532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
47542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
47552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public byte[] getLevels()
47562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
47572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
47582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (length <= 0) {
47592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return new byte[0];
47602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
47612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return BidiLine.getLevels(this);
47622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
47632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
47642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
47652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get a logical run.
47662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method returns information about a run and is used
47672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to retrieve runs in logical order.<p>
47682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is especially useful for line-breaking on a paragraph.
47692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param logicalPosition is a logical position within the source text.
47712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return a BidiRun object filled with <code>start</code> containing
47732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        the first character of the run, <code>limit</code> containing
47742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        the limit of the run, and <code>embeddingLevel</code> containing
47752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        the level of the run.
47762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
47782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
47792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if logicalPosition is not in the range
47802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>0&lt;=logicalPosition&lt;getProcessedLength()</code>
47812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
47822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see android.icu.text.BidiRun
47832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see android.icu.text.BidiRun#getStart()
47842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see android.icu.text.BidiRun#getLimit()
47852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see android.icu.text.BidiRun#getEmbeddingLevel()
47862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
47872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public BidiRun getLogicalRun(int logicalPosition)
47882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
47892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
47902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(logicalPosition, 0, length);
47912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return BidiLine.getLogicalRun(this, logicalPosition);
47922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
47932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
47942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
47952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the number of runs.
47962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method may invoke the actual reordering on the
47972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>Bidi</code> object, after <code>setPara()</code>
47982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * may have resolved only the levels of the text. Therefore,
47992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>countRuns()</code> may have to allocate memory,
48002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and may throw an exception if it fails to do so.
48012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
48022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The number of runs.
48032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
48042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
48052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
48062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
48072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int countRuns()
48082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
48092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
48102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        BidiLine.getRuns(this);
48112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return runCount;
48122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
48132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
48142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
48152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
48162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get a <code>BidiRun</code> object according to its index. BidiRun methods
48172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * may be used to retrieve the run's logical start, length and level,
48182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * which can be even for an LTR run or odd for an RTL run.
48192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * In an RTL run, the character at the logical start is
48202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * visually on the right of the displayed run.
48212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The length is the number of characters in the run.<p>
48222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>countRuns()</code> is normally called
48232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * before the runs are retrieved.
48242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
48252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
48262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  Example:
48272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <pre>
48282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  Bidi bidi = new Bidi();
48292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  String text = "abc 123 DEFG xyz";
48302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  bidi.setPara(text, Bidi.RTL, null);
48312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  int i, count=bidi.countRuns(), logicalStart, visualIndex=0, length;
48322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  BidiRun run;
48332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  for (i = 0; i &lt; count; ++i) {
48342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *      run = bidi.getVisualRun(i);
48352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *      logicalStart = run.getStart();
48362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *      length = run.getLength();
48372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *      if (Bidi.LTR == run.getEmbeddingLevel()) {
48382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *          do { // LTR
48392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *              show_char(text.charAt(logicalStart++), visualIndex++);
48402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *          } while (--length &gt; 0);
48412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *      } else {
48422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *          logicalStart += length;  // logicalLimit
48432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *          do { // RTL
48442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *              show_char(text.charAt(--logicalStart), visualIndex++);
48452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *          } while (--length &gt; 0);
48462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *      }
48472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  }
48482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * </pre>
48492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
48502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Note that in right-to-left runs, code like this places
48512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * second surrogates before first ones (which is generally a bad idea)
48522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and combining characters before base characters.
48532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
48542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Use of <code>{@link #writeReordered}</code>, optionally with the
48552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>{@link #KEEP_BASE_COMBINING}</code> option, can be considered in
48562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * order to avoid these issues.
48572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
48582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param runIndex is the number of the run in visual order, in the
48592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        range <code>[0..countRuns()-1]</code>.
48602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
48612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return a BidiRun object containing the details of the run. The
48622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         directionality of the run is
48632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>LTR==0</code> or <code>RTL==1</code>,
48642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         never <code>MIXED</code>.
48652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
48662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
48672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
48682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if <code>runIndex</code> is not in
48692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         the range <code>0&lt;=runIndex&lt;countRuns()</code>
48702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
48712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #countRuns()
48722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see android.icu.text.BidiRun
48732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see android.icu.text.BidiRun#getStart()
48742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see android.icu.text.BidiRun#getLength()
48752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see android.icu.text.BidiRun#getEmbeddingLevel()
48762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
48772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public BidiRun getVisualRun(int runIndex)
48782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
48792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
48802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        BidiLine.getRuns(this);
48812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(runIndex, 0, runCount);
48822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return BidiLine.getVisualRun(this, runIndex);
48832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
48842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
48852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
48862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the visual position from a logical text position.
48872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If such a mapping is used many times on the same
48882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>Bidi</code> object, then calling
48892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>getLogicalMap()</code> is more efficient.
48902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
48912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The value returned may be <code>MAP_NOWHERE</code> if there is no
48922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * visual position because the corresponding text character is a Bidi
48932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * control removed from output by the option
48942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>OPTION_REMOVE_CONTROLS</code>.
48952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
48962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * When the visual output is altered by using options of
48972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>writeReordered()</code> such as <code>INSERT_LRM_FOR_NUMERIC</code>,
48982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>KEEP_BASE_COMBINING</code>, <code>OUTPUT_REVERSE</code>,
48992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REMOVE_BIDI_CONTROLS</code>, the visual position returned may not
49002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * be correct. It is advised to use, when possible, reordering options
49012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * such as {@link #OPTION_INSERT_MARKS} and {@link #OPTION_REMOVE_CONTROLS}.
49022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
49032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Note that in right-to-left runs, this mapping places
49042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * second surrogates before first ones (which is generally a bad idea)
49052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and combining characters before base characters.
49062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Use of <code>{@link #writeReordered}</code>, optionally with the
49072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>{@link #KEEP_BASE_COMBINING}</code> option can be considered instead
49082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of using the mapping, in order to avoid these issues.
49092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
49102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param logicalIndex is the index of a character in the text.
49112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
49122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The visual position of this character.
49132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
49142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
49152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
49162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if <code>logicalIndex</code> is not in
49172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         the range <code>0&lt;=logicalIndex&lt;getProcessedLength()</code>
49182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
49192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getLogicalMap
49202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getLogicalIndex
49212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getProcessedLength
49222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #MAP_NOWHERE
49232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_REMOVE_CONTROLS
49242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #writeReordered
49252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
49262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getVisualIndex(int logicalIndex)
49272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
49282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
49292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(logicalIndex, 0, length);
49302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return BidiLine.getVisualIndex(this, logicalIndex);
49312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
49322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
49332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
49342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
49352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the logical text position from a visual position.
49362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If such a mapping is used many times on the same
49372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>Bidi</code> object, then calling
49382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>getVisualMap()</code> is more efficient.
49392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
49402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The value returned may be <code>MAP_NOWHERE</code> if there is no
49412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * logical position because the corresponding text character is a Bidi
49422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * mark inserted in the output by option
49432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>OPTION_INSERT_MARKS</code>.
49442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
49452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is the inverse method to <code>getVisualIndex()</code>.
49462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
49472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * When the visual output is altered by using options of
49482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>writeReordered()</code> such as <code>INSERT_LRM_FOR_NUMERIC</code>,
49492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>KEEP_BASE_COMBINING</code>, <code>OUTPUT_REVERSE</code>,
49502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REMOVE_BIDI_CONTROLS</code>, the logical position returned may not
49512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * be correct. It is advised to use, when possible, reordering options
49522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * such as {@link #OPTION_INSERT_MARKS} and {@link #OPTION_REMOVE_CONTROLS}.
49532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
49542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param visualIndex is the visual position of a character.
49552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
49562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The index of this character in the text.
49572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
49582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
49592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
49602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if <code>visualIndex</code> is not in
49612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         the range <code>0&lt;=visualIndex&lt;getResultLength()</code>
49622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
49632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getVisualMap
49642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getVisualIndex
49652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getResultLength
49662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #MAP_NOWHERE
49672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_INSERT_MARKS
49682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #writeReordered
49692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
49702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getLogicalIndex(int visualIndex)
49712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
49722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
49732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(visualIndex, 0, resultLength);
49742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* we can do the trivial cases without the runs array */
49752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (insertPoints.size == 0 && controlCount == 0) {
49762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (direction == LTR) {
49772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return visualIndex;
49782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
49792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            else if (direction == RTL) {
49802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return length - visualIndex - 1;
49812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
49822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
49832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        BidiLine.getRuns(this);
49842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return BidiLine.getLogicalIndex(this, visualIndex);
49852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
49862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
49872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
49882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get a logical-to-visual index map (array) for the characters in the
49892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>Bidi</code> (paragraph or line) object.
49902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
49912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Some values in the map may be <code>MAP_NOWHERE</code> if the
49922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * corresponding text characters are Bidi controls removed from the visual
49932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * output by the option <code>OPTION_REMOVE_CONTROLS</code>.
49942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
49952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * When the visual output is altered by using options of
49962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>writeReordered()</code> such as <code>INSERT_LRM_FOR_NUMERIC</code>,
49972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>KEEP_BASE_COMBINING</code>, <code>OUTPUT_REVERSE</code>,
49982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REMOVE_BIDI_CONTROLS</code>, the visual positions returned may not
49992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * be correct. It is advised to use, when possible, reordering options
50002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * such as {@link #OPTION_INSERT_MARKS} and {@link #OPTION_REMOVE_CONTROLS}.
50012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
50022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Note that in right-to-left runs, this mapping places
50032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * second surrogates before first ones (which is generally a bad idea)
50042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and combining characters before base characters.
50052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Use of <code>{@link #writeReordered}</code>, optionally with the
50062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>{@link #KEEP_BASE_COMBINING}</code> option can be considered instead
50072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of using the mapping, in order to avoid these issues.
50082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
50092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return an array of <code>getProcessedLength()</code>
50102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        indexes which will reflect the reordering of the characters.<br><br>
50112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        The index map will result in
50122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>indexMap[logicalIndex]==visualIndex</code>, where
50132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>indexMap</code> represents the returned array.
50142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
50152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
50162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
50172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
50182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getVisualMap
50192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getVisualIndex
50202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getProcessedLength
50212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #MAP_NOWHERE
50222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_REMOVE_CONTROLS
50232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #writeReordered
50242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
50252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int[] getLogicalMap()
50262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
50272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* countRuns() checks successful call to setPara/setLine */
50282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        countRuns();
50292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (length <= 0) {
50302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return new int[0];
50312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
50322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return BidiLine.getLogicalMap(this);
50332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
50342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
50352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
50362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get a visual-to-logical index map (array) for the characters in the
50372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>Bidi</code> (paragraph or line) object.
50382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
50392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Some values in the map may be <code>MAP_NOWHERE</code> if the
50402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * corresponding text characters are Bidi marks inserted in the visual
50412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * output by the option <code>OPTION_INSERT_MARKS</code>.
50422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>
50432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * When the visual output is altered by using options of
50442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>writeReordered()</code> such as <code>INSERT_LRM_FOR_NUMERIC</code>,
50452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>KEEP_BASE_COMBINING</code>, <code>OUTPUT_REVERSE</code>,
50462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>REMOVE_BIDI_CONTROLS</code>, the logical positions returned may not
50472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * be correct. It is advised to use, when possible, reordering options
50482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * such as {@link #OPTION_INSERT_MARKS} and {@link #OPTION_REMOVE_CONTROLS}.
50492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
50502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return an array of <code>getResultLength()</code>
50512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        indexes which will reflect the reordering of the characters.<br><br>
50522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        The index map will result in
50532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>indexMap[visualIndex]==logicalIndex</code>, where
50542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>indexMap</code> represents the returned array.
50552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
50562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
50572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
50582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
50592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getLogicalMap
50602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getLogicalIndex
50612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getResultLength
50622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #MAP_NOWHERE
50632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_INSERT_MARKS
50642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #writeReordered
50652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
50662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int[] getVisualMap()
50672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
50682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* countRuns() checks successful call to setPara/setLine */
50692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        countRuns();
50702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (resultLength <= 0) {
50712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return new int[0];
50722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
50732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return BidiLine.getVisualMap(this);
50742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
50752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
50762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
50772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is a convenience method that does not use a <code>Bidi</code> object.
50782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It is intended to be used for when an application has determined the levels
50792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of objects (character sequences) and just needs to have them reordered (L2).
50802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is equivalent to using <code>getLogicalMap()</code> on a
50812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>Bidi</code> object.
50822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
50832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param levels is an array of levels that have been determined by
50842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        the application.
50852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
50862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return an array of <code>levels.length</code>
50872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        indexes which will reflect the reordering of the characters.<p>
50882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        The index map will result in
50892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>indexMap[logicalIndex]==visualIndex</code>, where
50902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>indexMap</code> represents the returned array.
50912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
50922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static int[] reorderLogical(byte[] levels)
50932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
50942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return BidiLine.reorderLogical(levels);
50952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
50962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
50972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
50982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is a convenience method that does not use a <code>Bidi</code> object.
50992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It is intended to be used for when an application has determined the levels
51002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of objects (character sequences) and just needs to have them reordered (L2).
51012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is equivalent to using <code>getVisualMap()</code> on a
51022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>Bidi</code> object.
51032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
51042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param levels is an array of levels that have been determined by
51052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        the application.
51062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
51072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return an array of <code>levels.length</code>
51082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        indexes which will reflect the reordering of the characters.<p>
51092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        The index map will result in
51102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>indexMap[visualIndex]==logicalIndex</code>, where
51112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        <code>indexMap</code> represents the returned array.
51122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
51132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static int[] reorderVisual(byte[] levels)
51142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
51152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return BidiLine.reorderVisual(levels);
51162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
51172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
51182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
51192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Invert an index map.
51202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The index mapping of the argument map is inverted and returned as
51212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * an array of indexes that we will call the inverse map.
51222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
51232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param srcMap is an array whose elements define the original mapping
51242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * from a source array to a destination array.
51252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Some elements of the source array may have no mapping in the
51262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * destination array. In that case, their value will be
51272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the special value <code>MAP_NOWHERE</code>.
5128bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * All elements must be &gt;=0 or equal to <code>MAP_NOWHERE</code>.
51292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Some elements in the source map may have a value greater than the
51302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * srcMap.length if the destination array has more elements than the
51312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * source array.
51322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * There must be no duplicate indexes (two or more elements with the
51332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * same value except <code>MAP_NOWHERE</code>).
51342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
51352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return an array representing the inverse map.
51362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         This array has a number of elements equal to 1 + the highest
51372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         value in <code>srcMap</code>.
51382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         For elements of the result array which have no matching elements
51392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         in the source array, the corresponding elements in the inverse
51402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         map will receive a value equal to <code>MAP_NOWHERE</code>.
51412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         If element with index i in <code>srcMap</code> has a value k different
51422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         from <code>MAP_NOWHERE</code>, this means that element i of
51432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         the source array maps to element k in the destination array.
51442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         The inverse map will have value i in its k-th element.
51452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         For all elements of the destination array which do not map to
51462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         an element in the source array, the corresponding element in the
51472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         inverse map will have a value equal to <code>MAP_NOWHERE</code>.
51482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
51492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #MAP_NOWHERE
51502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
51512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static int[] invertMap(int[] srcMap)
51522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
51532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (srcMap == null) {
51542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return null;
51552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
51562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return BidiLine.invertMap(srcMap);
51572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
51582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
51592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
51602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
51612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Fields and methods for compatibility with java.text.bidi (Sun implementation)
51622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
51632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
51642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
51652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constant indicating base direction is left-to-right.
51662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
51672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIRECTION_LEFT_TO_RIGHT = LTR;
51682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
51692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
51702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constant indicating base direction is right-to-left.
51712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
51722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIRECTION_RIGHT_TO_LEFT = RTL;
51732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
51742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
51752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constant indicating that the base direction depends on the first strong
51762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * directional character in the text according to the Unicode Bidirectional
51772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Algorithm. If no strong directional character is present, the base
51782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * direction is left-to-right.
51792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
51802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = LEVEL_DEFAULT_LTR;
51812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
51822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
51832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constant indicating that the base direction depends on the first strong
51842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * directional character in the text according to the Unicode Bidirectional
51852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Algorithm. If no strong directional character is present, the base
51862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * direction is right-to-left.
51872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
51882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = LEVEL_DEFAULT_RTL;
51892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
51902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
51912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Create Bidi from the given paragraph of text and base direction.
51922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
51932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param paragraph a paragraph of text
51942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param flags a collection of flags that control the algorithm. The
51952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        algorithm understands the flags DIRECTION_LEFT_TO_RIGHT,
51962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        DIRECTION_RIGHT_TO_LEFT, DIRECTION_DEFAULT_LEFT_TO_RIGHT, and
51972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        DIRECTION_DEFAULT_RIGHT_TO_LEFT. Other values are reserved.
51982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #DIRECTION_LEFT_TO_RIGHT
51992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #DIRECTION_RIGHT_TO_LEFT
52002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #DIRECTION_DEFAULT_LEFT_TO_RIGHT
52012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #DIRECTION_DEFAULT_RIGHT_TO_LEFT
52022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
52032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Bidi(String paragraph, int flags)
52042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
52052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this(paragraph.toCharArray(), 0, null, 0, paragraph.length(), flags);
52062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
52072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
52082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
52092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Create Bidi from the given paragraph of text.<p>
52102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
52112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The RUN_DIRECTION attribute in the text, if present, determines the base
52122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * direction (left-to-right or right-to-left). If not present, the base
52132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * direction is computed using the Unicode Bidirectional Algorithm,
52142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * defaulting to left-to-right if there are no strong directional characters
52152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in the text. This attribute, if present, must be applied to all the text
52162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in the paragraph.<p>
52172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
52182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The BIDI_EMBEDDING attribute in the text, if present, represents
52192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * embedding level information. Negative values from -1 to -62 indicate
52202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * overrides at the absolute value of the level. Positive values from 1 to
52212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 62 indicate embeddings. Where values are zero or not defined, the base
52222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * embedding level as determined by the base direction is assumed.<p>
52232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
52242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The NUMERIC_SHAPING attribute in the text, if present, converts European
52252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * digits to other decimal digits before running the bidi algorithm. This
52262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * attribute, if present, must be applied to all the text in the paragraph.<p>
52272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
52282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Note: this constructor calls setPara() internally.
52292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
52302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param paragraph a paragraph of text with optional character and
52312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        paragraph attribute information
52322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
52332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Bidi(AttributedCharacterIterator paragraph)
52342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
52352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this();
52362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        setPara(paragraph);
52372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
52382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
52392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
52402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Create Bidi from the given text, embedding, and direction information.
52412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5242fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <p>The embeddings array may be null. If present, the values represent
5243fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * embedding level information.
5244fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * Negative values from -1 to -{@link #MAX_EXPLICIT_LEVEL}
5245fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * indicate overrides at the absolute value of the level.
5246fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * Positive values from 1 to {@link #MAX_EXPLICIT_LEVEL} indicate embeddings.
5247fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * Where values are zero, the base embedding level
5248fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * as determined by the base direction is assumed,
5249fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * except for paragraph separators which remain at 0 to prevent reordering of paragraphs.</p>
5250fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     *
5251fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * <p>Note: This constructor calls setPara() internally,
5252fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * after converting the java.text.Bidi-style embeddings with negative overrides
5253fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller     * into ICU-style embeddings with bit fields for {@link #LEVEL_OVERRIDE} and the level.
52542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
52552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param text an array containing the paragraph of text to process.
52562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param textStart the index into the text array of the start of the
52572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        paragraph.
52582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param embeddings an array containing embedding values for each character
52592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        in the paragraph. This can be null, in which case it is assumed
52602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        that there is no external embedding information.
52612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param embStart the index into the embedding array of the start of the
52622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        paragraph.
52632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param paragraphLength the length of the paragraph in the text and
52642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        embeddings arrays.
52652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param flags a collection of flags that control the algorithm. The
52662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        algorithm understands the flags DIRECTION_LEFT_TO_RIGHT,
52672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        DIRECTION_RIGHT_TO_LEFT, DIRECTION_DEFAULT_LEFT_TO_RIGHT, and
52682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        DIRECTION_DEFAULT_RIGHT_TO_LEFT. Other values are reserved.
52692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
52702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if the values in embeddings are
52712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         not within the allowed range
52722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
52732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #DIRECTION_LEFT_TO_RIGHT
52742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #DIRECTION_RIGHT_TO_LEFT
52752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #DIRECTION_DEFAULT_LEFT_TO_RIGHT
52762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #DIRECTION_DEFAULT_RIGHT_TO_LEFT
52772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
52782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Bidi(char[] text,
52792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int textStart,
52802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            byte[] embeddings,
52812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int embStart,
52822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int paragraphLength,
52832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int flags)
52842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
52852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this();
52862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte paraLvl;
52872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (flags) {
52882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case DIRECTION_LEFT_TO_RIGHT:
52892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        default:
52902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paraLvl = LTR;
52912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
52922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case DIRECTION_RIGHT_TO_LEFT:
52932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paraLvl = RTL;
52942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
52952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case DIRECTION_DEFAULT_LEFT_TO_RIGHT:
52962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paraLvl = LEVEL_DEFAULT_LTR;
52972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
52982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case DIRECTION_DEFAULT_RIGHT_TO_LEFT:
52992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paraLvl = LEVEL_DEFAULT_RTL;
53002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
53012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
53022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte[] paraEmbeddings;
53032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (embeddings == null) {
53042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paraEmbeddings = null;
53052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
5306fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            // Convert from java.text.Bidi embeddings to ICU setPara() levels:
5307fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            // Copy to the start of a new array and convert java.text negative overrides
5308fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            // to ICU bit-field-and-mask overrides.
5309fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            // A copy of the embeddings is always required because
5310fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller            // setPara() may modify its embeddings.
53112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            paraEmbeddings = new byte[paragraphLength];
53122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            byte lev;
53132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (int i = 0; i < paragraphLength; i++) {
53142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                lev = embeddings[i + embStart];
53152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (lev < 0) {
53162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    lev = (byte)((- lev) | LEVEL_OVERRIDE);
53172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
5318fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller                // setPara() lifts level 0 up to the resolved paragraph level.
53192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                paraEmbeddings[i] = lev;
53202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
53212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5322fdf7823ba3be2b03127dec2ae28706ab53e0927eNeil Fuller        if (textStart == 0 && paragraphLength == text.length) {
53232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            setPara(text, paraLvl, paraEmbeddings);
53242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
53252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char[] paraText = new char[paragraphLength];
53262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            System.arraycopy(text, textStart, paraText, 0, paragraphLength);
53272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            setPara(paraText, paraLvl, paraEmbeddings);
53282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
53292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
53302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
53312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
53322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Create a Bidi object representing the bidi information on a line of text
53332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * within the paragraph represented by the current Bidi. This call is not
53342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * required if the entire paragraph fits on one line.
53352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
53362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param lineStart the offset from the start of the paragraph to the start
53372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        of the line.
53382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param lineLimit the offset from the start of the paragraph to the limit
53392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        of the line.
53402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
53412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
53422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code>
53432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if lineStart and lineLimit are not in the range
53442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>0&lt;=lineStart&lt;lineLimit&lt;=getProcessedLength()</code>,
53452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         or if the specified line crosses a paragraph boundary
53462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
53472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Bidi createLineBidi(int lineStart, int lineLimit)
53482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
53492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return setLine(lineStart, lineLimit);
53502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
53512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
53522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
53532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return true if the line is not left-to-right or right-to-left. This means
53542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * it either has mixed runs of left-to-right and right-to-left text, or the
53552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * base direction differs from the direction of the only run of text.
53562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
53572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return true if the line is not left-to-right or right-to-left.
53582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
53592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
53602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code>
53612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
53622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean isMixed()
53632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
53642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (!isLeftToRight() && !isRightToLeft());
53652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
53662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
53672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
53682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return true if the line is all left-to-right text and the base direction
53692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is left-to-right.
53702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
53712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return true if the line is all left-to-right text and the base direction
53722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         is left-to-right.
53732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
53742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
53752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code>
53762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
53772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean isLeftToRight()
53782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
53792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (getDirection() == LTR && (paraLevel & 1) == 0);
53802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
53812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
53822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
53832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return true if the line is all right-to-left text, and the base direction
53842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is right-to-left
53852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
53862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return true if the line is all right-to-left text, and the base
53872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         direction is right-to-left
53882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
53892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
53902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code>
53912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
53922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean isRightToLeft()
53932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
53942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (getDirection() == RTL && (paraLevel & 1) == 1);
53952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
53962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
53972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
53982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return true if the base direction is left-to-right
53992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
54002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return true if the base direction is left-to-right
54012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
54022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
54032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
54042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
54052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean baseIsLeftToRight()
54062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
54072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (getParaLevel() == LTR);
54082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
54092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
54102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
54112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return the base level (0 if left-to-right, 1 if right-to-left).
54122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
54132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the base level
54142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
54152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
54162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
54172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
54182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getBaseLevel()
54192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
54202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return getParaLevel();
54212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
54222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
54232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
54242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return the number of level runs.
54252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
54262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the number of level runs
54272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
54282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
54292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
54302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
54312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getRunCount()
54322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
54332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return countRuns();
54342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
54352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
54362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
54372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Compute the logical to visual run mapping
54382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
54392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     void getLogicalToVisualRunsMap()
54402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     {
54412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isGoodLogicalToVisualRunsMap) {
54422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
54432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
54442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int count = countRuns();
54452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((logicalToVisualRunsMap == null) ||
54462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            (logicalToVisualRunsMap.length < count)) {
54472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            logicalToVisualRunsMap = new int[count];
54482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
54492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i;
54502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        long[] keys = new long[count];
54512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (i = 0; i < count; i++) {
54522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            keys[i] = ((long)(runs[i].start)<<32) + i;
54532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
54542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Arrays.sort(keys);
54552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (i = 0; i < count; i++) {
54562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            logicalToVisualRunsMap[i] = (int)(keys[i] & 0x00000000FFFFFFFF);
54572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
54582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        isGoodLogicalToVisualRunsMap = true;
54592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     }
54602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
54612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
54622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return the level of the nth logical run in this line.
54632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
54642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param run the index of the run, between 0 and <code>countRuns()-1</code>
54652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
54662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the level of the run
54672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
54682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
54692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
54702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if <code>run</code> is not in
54712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         the range <code>0&lt;=run&lt;countRuns()</code>
54722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
54732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getRunLevel(int run)
54742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
54752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
54762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        BidiLine.getRuns(this);
54772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(run, 0, runCount);
54782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getLogicalToVisualRunsMap();
54792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return runs[logicalToVisualRunsMap[run]].level;
54802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
54812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
54822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
54832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return the index of the character at the start of the nth logical run in
54842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * this line, as an offset from the start of the line.
54852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
54862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param run the index of the run, between 0 and <code>countRuns()</code>
54872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
54882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the start of the run
54892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
54902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
54912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
54922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if <code>run</code> is not in
54932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         the range <code>0&lt;=run&lt;countRuns()</code>
54942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
54952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getRunStart(int run)
54962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
54972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
54982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        BidiLine.getRuns(this);
54992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(run, 0, runCount);
55002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getLogicalToVisualRunsMap();
55012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return runs[logicalToVisualRunsMap[run]].start;
55022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
55032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
55042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
55052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return the index of the character past the end of the nth logical run in
55062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * this line, as an offset from the start of the line. For example, this
55072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * will return the length of the line for the last run on the line.
55082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
55092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param run the index of the run, between 0 and <code>countRuns()</code>
55102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
55112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the limit of the run
55122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
55132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
55142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
55152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if <code>run</code> is not in
55162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         the range <code>0&lt;=run&lt;countRuns()</code>
55172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
55182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getRunLimit(int run)
55192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
55202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
55212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        BidiLine.getRuns(this);
55222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyRange(run, 0, runCount);
55232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getLogicalToVisualRunsMap();
55242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int idx = logicalToVisualRunsMap[run];
55252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int len = idx == 0 ? runs[idx].limit :
55262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                runs[idx].limit - runs[idx-1].limit;
55272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return runs[idx].start + len;
55282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
55292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
55302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
55312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return true if the specified text requires bidi analysis. If this returns
55322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * false, the text will display left-to-right. Clients can then avoid
55332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * constructing a Bidi object. Text in the Arabic Presentation Forms area of
55342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Unicode is presumed to already be shaped and ordered for display, and so
55352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * will not cause this method to return true.
55362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
55372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param text the text containing the characters to test
55382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param start the start of the range of characters to test
55392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param limit the limit of the range of characters to test
55402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
55412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return true if the range of characters requires bidi analysis
55422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
55432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static boolean requiresBidi(char[] text,
55442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int start,
55452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int limit)
55462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
55472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        final int RTLMask = (1 << UCharacter.DIRECTIONALITY_RIGHT_TO_LEFT |
55482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                1 << UCharacter.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC |
55492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                1 << UCharacter.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING |
55502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                1 << UCharacter.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE |
55512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                1 << UCharacter.DIRECTIONALITY_ARABIC_NUMBER);
55522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
55532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = start; i < limit; ++i) {
55542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (((1 << UCharacter.getDirection(text[i])) & RTLMask) != 0) {
55552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return true;
55562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
55572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
55582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return false;
55592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
55602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
55612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
55622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Reorder the objects in the array into visual order based on their levels.
55632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is a utility method to use when you have a collection of objects
55642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * representing runs of text in logical order, each run containing text at a
55652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * single level. The elements at <code>index</code> from
55662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>objectStart</code> up to <code>objectStart + count</code> in the
55672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * objects array will be reordered into visual order assuming
55682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * each run of text has the level indicated by the corresponding element in
55692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the levels array (at <code>index - objectStart + levelStart</code>).
55702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
55712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param levels an array representing the bidi level of each object
55722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param levelStart the start position in the levels array
55732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param objects the array of objects to be reordered into visual order
55742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param objectStart the start position in the objects array
55752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param count the number of objects to reorder
55762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
55772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static void reorderVisually(byte[] levels,
55782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int levelStart,
55792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Object[] objects,
55802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int objectStart,
55812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int count)
55822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
55832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        byte[] reorderLevels = new byte[count];
55842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        System.arraycopy(levels, levelStart, reorderLevels, 0, count);
55852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] indexMap = reorderVisual(reorderLevels);
55862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Object[] temp = new Object[count];
55872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        System.arraycopy(objects, objectStart, temp, 0, count);
55882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < count; ++i) {
55892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            objects[objectStart + i] = temp[indexMap[i]];
55902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
55912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
55922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
55932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
55942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Take a <code>Bidi</code> object containing the reordering
55952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * information for a piece of text (one or more paragraphs) set by
55962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>setPara()</code> or for a line of text set by <code>setLine()</code>
55972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and return a string containing the reordered text.
55982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
55992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>The text may have been aliased (only a reference was stored
56002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * without copying the contents), thus it must not have been modified
5601bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin     * since the <code>setPara()</code> call.
56022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
56032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method preserves the integrity of characters with multiple
56042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * code units and (optionally) combining characters.
56052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Characters in RTL runs can be replaced by mirror-image characters
56062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in the returned string. Note that "real" mirroring has to be done in a
56072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * rendering engine by glyph selection and that for many "mirrored"
56082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * characters there are no Unicode characters as mirror-image equivalents.
56092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * There are also options to insert or remove Bidi control
56102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * characters; see the descriptions of the return value and the
56112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>options</code> parameter, and of the option bit flags.
56122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
56132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param options A bit set of options for the reordering that control
56142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                how the reordered text is written.
56152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                The options include mirroring the characters on a code
56162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                point basis and inserting LRM characters, which is used
56172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                especially for transforming visually stored text
56182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                to logically stored text (although this is still an
56192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                imperfect implementation of an "inverse Bidi" algorithm
56202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                because it uses the "forward Bidi" algorithm at its core).
56212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                The available options are:
56222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                <code>DO_MIRRORING</code>,
56232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                <code>INSERT_LRM_FOR_NUMERIC</code>,
56242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                <code>KEEP_BASE_COMBINING</code>,
56252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                <code>OUTPUT_REVERSE</code>,
56262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                <code>REMOVE_BIDI_CONTROLS</code>,
56272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                <code>STREAMING</code>
56282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
56292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The reordered text.
56302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         If the <code>INSERT_LRM_FOR_NUMERIC</code> option is set, then
56312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         the length of the returned string could be as large as
56322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>getLength()+2*countRuns()</code>.<br>
56332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         If the <code>REMOVE_BIDI_CONTROLS</code> option is set, then the
56342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         length of the returned string may be less than
56352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>getLength()</code>.<br>
56362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         If none of these options is set, then the length of the returned
56372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         string will be exactly <code>getProcessedLength()</code>.
56382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
56392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException if this call is not preceded by a successful
56402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         call to <code>setPara</code> or <code>setLine</code>
56412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
56422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #DO_MIRRORING
56432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #INSERT_LRM_FOR_NUMERIC
56442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #KEEP_BASE_COMBINING
56452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OUTPUT_REVERSE
56462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #REMOVE_BIDI_CONTROLS
56472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #OPTION_STREAMING
56482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #getProcessedLength
56492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
56502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String writeReordered(int options)
56512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
56522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        verifyValidParaOrLine();
56532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (length == 0) {
56542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* nothing to do */
56552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return "";
56562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
56572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return BidiWriter.writeReordered(this, options);
56582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
56592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
56602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
56612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Reverse a Right-To-Left run of Unicode text.
56622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
56632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method preserves the integrity of characters with multiple
56642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * code units and (optionally) combining characters.
56652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Characters can be replaced by mirror-image characters
56662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in the destination buffer. Note that "real" mirroring has
56672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to be done in a rendering engine by glyph selection
56682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and that for many "mirrored" characters there are no
56692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Unicode characters as mirror-image equivalents.
56702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * There are also options to insert or remove Bidi control
56712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * characters.
56722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
56732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method is the implementation for reversing RTL runs as part
56742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of <code>writeReordered()</code>. For detailed descriptions
56752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of the parameters, see there.
56762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Since no Bidi controls are inserted here, the output string length
56772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * will never exceed <code>src.length()</code>.
56782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
56792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see #writeReordered
56802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
56812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param src The RTL run text.
56822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
56832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param options A bit set of options for the reordering that control
56842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                how the reordered text is written.
56852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                See the <code>options</code> parameter in <code>writeReordered()</code>.
56862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
56872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The reordered text.
56882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         If the <code>REMOVE_BIDI_CONTROLS</code> option
56892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         is set, then the length of the returned string may be less than
56902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>src.length()</code>. If this option is not set,
56912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         then the length of the returned string will be exactly
56922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         <code>src.length()</code>.
56932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
56942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if <code>src</code> is null.
56952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
56962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static String writeReverse(String src, int options)
56972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
56982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* error checking */
56992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (src == null) {
57002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException();
57012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
57022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
57032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (src.length() > 0) {
57042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return BidiWriter.writeReverse(src, options);
57052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
57062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* nothing to do */
57072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return "";
57082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
57092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
57102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
57112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller}
5712