diff --git a/jdk/make/java/text/FILES_java.gmk b/jdk/make/java/text/FILES_java.gmk index 88dc12903cc..ada9bde7fee 100644 --- a/jdk/make/java/text/FILES_java.gmk +++ b/jdk/make/java/text/FILES_java.gmk @@ -76,6 +76,10 @@ FILES_java = \ sun/text/Normalizer.java \ sun/text/SupplementaryCharacterData.java \ sun/text/UCompactIntArray.java \ + sun/text/bidi/BidiBase.java \ + sun/text/bidi/BidiLine.java \ + sun/text/bidi/BidiRun.java \ + \ sun/text/normalizer/CharTrie.java \ sun/text/normalizer/CharacterIteratorWrapper.java \ sun/text/normalizer/ICUBinary.java \ diff --git a/jdk/make/sun/font/FILES_c.gmk b/jdk/make/sun/font/FILES_c.gmk index 2940ac78a08..84a78c289ab 100644 --- a/jdk/make/sun/font/FILES_c.gmk +++ b/jdk/make/sun/font/FILES_c.gmk @@ -24,10 +24,6 @@ # FILES_c_shared = \ - jbidi.c \ - ubidi.c \ - ubidiln.c \ - uchardir.c \ DrawGlyphList.c \ sunFont.c diff --git a/jdk/make/sun/font/Makefile b/jdk/make/sun/font/Makefile index 2663144a5f3..b81918de5c3 100644 --- a/jdk/make/sun/font/Makefile +++ b/jdk/make/sun/font/Makefile @@ -145,7 +145,6 @@ include $(BUILDDIR)/common/Library.gmk # Add to the ambient vpath to pick up files in subdirectories # vpath %.c $(PLATFORM_SRC)/native/$(PKGDIR) -vpath %.c $(SHARE_SRC)/native/$(PKGDIR)/bidi vpath %.cpp $(SHARE_SRC)/native/$(PKGDIR)/layout vpath %.cpp $(SHARE_SRC)/native/$(PKGDIR) @@ -187,7 +186,6 @@ endif # PLATFORM CPPFLAGS += -I$(SHARE_SRC)/native/$(PKGDIR) \ -I$(SHARE_SRC)/native/$(PKGDIR)/layout \ - -I$(SHARE_SRC)/native/$(PKGDIR)/bidi \ -I$(SHARE_SRC)/native/sun/awt/image/cvutils \ -I$(PLATFORM_SRC)/native/sun/awt \ -I$(SHARE_SRC)/native/sun/awt/debug \ diff --git a/jdk/make/sun/font/mapfile-vers b/jdk/make/sun/font/mapfile-vers index 1d1f003bf6a..8d1b6af9dca 100644 --- a/jdk/make/sun/font/mapfile-vers +++ b/jdk/make/sun/font/mapfile-vers @@ -31,8 +31,6 @@ SUNWprivate_1.1 { newLayoutTableCache; freeLayoutTableCache; isNullScalerContext; - Java_java_text_Bidi_nativeBidiChars; - Java_java_text_Bidi_nativeGetDirectionCode; Java_sun_font_NullFontScaler_getNullScalerContext; Java_sun_font_NullFontScaler_getGlyphImage; Java_sun_font_FontManager_getPlatformFontVar; diff --git a/jdk/make/sun/font/mapfile-vers.openjdk b/jdk/make/sun/font/mapfile-vers.openjdk index 55d5661bf24..2977f35dafe 100644 --- a/jdk/make/sun/font/mapfile-vers.openjdk +++ b/jdk/make/sun/font/mapfile-vers.openjdk @@ -33,8 +33,6 @@ SUNWprivate_1.1 { newLayoutTableCache; freeLayoutTableCache; isNullScalerContext; - Java_java_text_Bidi_nativeBidiChars; - Java_java_text_Bidi_nativeGetDirectionCode; Java_sun_font_NullFontScaler_getNullScalerContext; Java_sun_font_NullFontScaler_getGlyphImage; Java_sun_font_FontManager_getPlatformFontVar; diff --git a/jdk/src/share/classes/java/text/Bidi.java b/jdk/src/share/classes/java/text/Bidi.java index 80d7f6fa8f8..e4db4b2d086 100644 --- a/jdk/src/share/classes/java/text/Bidi.java +++ b/jdk/src/share/classes/java/text/Bidi.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,10 +35,7 @@ package java.text; -import java.awt.Toolkit; -import java.awt.font.TextAttribute; -import java.awt.font.NumericShaper; -import sun.text.CodePointIterator; +import sun.text.bidi.BidiBase; /** * This class implements the Unicode Bidirectional Algorithm. @@ -62,15 +59,6 @@ import sun.text.CodePointIterator; * @since 1.4 */ public final class Bidi { - byte dir; - byte baselevel; - int length; - int[] runs; - int[] cws; - - static { - sun.font.FontManagerNativeLibrary.load(); - } /** Constant indicating base direction is left-to-right. */ public static final int DIRECTION_LEFT_TO_RIGHT = 0; @@ -94,7 +82,7 @@ public final class Bidi { */ public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = -1; - private static final int DIR_MIXED = 2; + private BidiBase bidiBase; /** * Create Bidi from the given paragraph of text and base direction. @@ -109,7 +97,7 @@ public final class Bidi { throw new IllegalArgumentException("paragraph is null"); } - nativeBidiChars(this, paragraph.toCharArray(), 0, null, 0, paragraph.length(), flags); + bidiBase = new BidiBase(paragraph.toCharArray(), 0, null, 0, paragraph.length(), flags); } /** @@ -142,67 +130,8 @@ public final class Bidi { throw new IllegalArgumentException("paragraph is null"); } - int flags = DIRECTION_DEFAULT_LEFT_TO_RIGHT; - byte[] embeddings = null; - - int start = paragraph.getBeginIndex(); - int limit = paragraph.getEndIndex(); - int length = limit - start; - int n = 0; - char[] text = new char[length]; - for (char c = paragraph.first(); c != paragraph.DONE; c = paragraph.next()) { - text[n++] = c; - } - - paragraph.first(); - try { - Boolean runDirection = (Boolean)paragraph.getAttribute(TextAttribute.RUN_DIRECTION); - if (runDirection != null) { - if (TextAttribute.RUN_DIRECTION_LTR.equals(runDirection)) { - flags = DIRECTION_LEFT_TO_RIGHT; // clears default setting - } else { - flags = DIRECTION_RIGHT_TO_LEFT; - } - } - } - catch (ClassCastException e) { - } - - try { - NumericShaper shaper = (NumericShaper)paragraph.getAttribute(TextAttribute.NUMERIC_SHAPING); - if (shaper != null) { - shaper.shape(text, 0, text.length); - } - } - catch (ClassCastException e) { - } - - int pos = start; - do { - paragraph.setIndex(pos); - Object embeddingLevel = paragraph.getAttribute(TextAttribute.BIDI_EMBEDDING); - int newpos = paragraph.getRunLimit(TextAttribute.BIDI_EMBEDDING); - - if (embeddingLevel != null) { - try { - int intLevel = ((Integer)embeddingLevel).intValue(); - if (intLevel >= -61 && intLevel < 61) { - byte level = (byte)(intLevel < 0 ? (-intLevel | 0x80) : intLevel); - if (embeddings == null) { - embeddings = new byte[length]; - } - for (int i = pos - start; i < newpos - start; ++i) { - embeddings[i] = level; - } - } - } - catch (ClassCastException e) { - } - } - pos = newpos; - } while (pos < limit); - - nativeBidiChars(this, text, 0, embeddings, 0, text.length, flags); + bidiBase = new BidiBase(0, 0); + bidiBase.setPara(paragraph); } /** @@ -240,46 +169,7 @@ public final class Bidi { " for embeddings of length: " + text.length); } - if (embeddings != null) { - // native uses high bit to indicate override, not negative value, sigh - - for (int i = embStart, embLimit = embStart + paragraphLength; i < embLimit; ++i) { - if (embeddings[i] < 0) { - byte[] temp = new byte[paragraphLength]; - System.arraycopy(embeddings, embStart, temp, 0, paragraphLength); - - for (i -= embStart; i < paragraphLength; ++i) { - if (temp[i] < 0) { - temp[i] = (byte)(-temp[i] | 0x80); - } - } - - embeddings = temp; - embStart = 0; - break; - } - } - } - - nativeBidiChars(this, text, textStart, embeddings, embStart, paragraphLength, flags); - } - - /** - * Private constructor used by line bidi. - */ - private Bidi(int dir, int baseLevel, int length, int[] data, int[] cws) { - reset(dir, baseLevel, length, data, cws); - } - - /** - * Private mutator used by native code. - */ - private void reset(int dir, int baselevel, int length, int[] data, int[] cws) { - this.dir = (byte)dir; - this.baselevel = (byte)baselevel; - this.length = length; - this.runs = data; - this.cws = cws; + bidiBase = new BidiBase(text, textStart, embeddings, embStart, paragraphLength, flags); } /** @@ -290,96 +180,10 @@ public final class Bidi { * @param lineLimit the offset from the start of the paragraph to the limit of the line. */ public Bidi createLineBidi(int lineStart, int lineLimit) { - if (lineStart == 0 && lineLimit == length) { - return this; - } + AttributedString astr = new AttributedString(""); + Bidi newBidi = new Bidi(astr.getIterator()); - int lineLength = lineLimit - lineStart; - if (lineStart < 0 || - lineLimit < lineStart || - lineLimit > length) { - throw new IllegalArgumentException("range " + lineStart + - " to " + lineLimit + - " is invalid for paragraph of length " + length); - } - - if (runs == null) { - return new Bidi(dir, baselevel, lineLength, null, null); - } else { - int cwspos = -1; - int[] ncws = null; - if (cws != null) { - int cwss = 0; - int cwsl = cws.length; - while (cwss < cwsl) { - if (cws[cwss] >= lineStart) { - cwsl = cwss; - while (cwsl < cws.length && cws[cwsl] < lineLimit) { - cwsl++; - } - int ll = lineLimit-1; - while (cwsl > cwss && cws[cwsl-1] == ll) { - cwspos = ll; // record start of counter-directional whitespace - --cwsl; - --ll; - } - - if (cwspos == lineStart) { // entire line is cws, so ignore - return new Bidi(dir, baselevel, lineLength, null, null); - } - - int ncwslen = cwsl - cwss; - if (ncwslen > 0) { - ncws = new int[ncwslen]; - for (int i = 0; i < ncwslen; ++i) { - ncws[i] = cws[cwss+i] - lineStart; - } - } - break; - } - ++cwss; - } - } - - int[] nruns = null; - int nlevel = baselevel; - int limit = cwspos == -1 ? lineLimit : cwspos; - int rs = 0; - int rl = runs.length; - int ndir = dir; - for (; rs < runs.length; rs += 2) { - if (runs[rs] > lineStart) { - rl = rs; - while (rl < runs.length && runs[rl] < limit) { - rl += 2; - } - if ((rl > rs) || (runs[rs+1] != baselevel)) { - rl += 2; - - if (cwspos != -1 && rl > rs && runs[rl-1] != baselevel) { // add level for cws - nruns = new int[rl - rs + 2]; - nruns[rl - rs] = lineLength; - nruns[rl - rs + 1] = baselevel; - } else { - limit = lineLimit; - nruns = new int[rl - rs]; - } - - int n = 0; - for (int i = rs; i < rl; i += 2) { - nruns[n++] = runs[i] - lineStart; - nruns[n++] = runs[i+1]; - } - nruns[n-2] = limit - lineStart; - } else { - ndir = (runs[rs+1] & 0x1) == 0 ? DIRECTION_LEFT_TO_RIGHT : DIRECTION_RIGHT_TO_LEFT; - } - break; - } - } - - return new Bidi(ndir, baselevel, lineLength, nruns, ncws); - } + return bidiBase.setLine(this, bidiBase, newBidi, newBidi.bidiBase,lineStart, lineLimit); } /** @@ -388,7 +192,7 @@ public final class Bidi { * @return true if the line is not left-to-right or right-to-left. */ public boolean isMixed() { - return dir == DIR_MIXED; + return bidiBase.isMixed(); } /** @@ -396,7 +200,7 @@ public final class Bidi { * @return true if the line is all left-to-right text and the base direction is left-to-right */ public boolean isLeftToRight() { - return dir == DIRECTION_LEFT_TO_RIGHT; + return bidiBase.isLeftToRight(); } /** @@ -404,7 +208,7 @@ public final class Bidi { * @return true if the line is all right-to-left text, and the base direction is right-to-left */ public boolean isRightToLeft() { - return dir == DIRECTION_RIGHT_TO_LEFT; + return bidiBase.isRightToLeft(); } /** @@ -412,7 +216,7 @@ public final class Bidi { * @return the length of text in the line */ public int getLength() { - return length; + return bidiBase.getLength(); } /** @@ -420,7 +224,7 @@ public final class Bidi { * @return true if the base direction is left-to-right */ public boolean baseIsLeftToRight() { - return (baselevel & 0x1) == 0; + return bidiBase.baseIsLeftToRight(); } /** @@ -428,7 +232,7 @@ public final class Bidi { * @return the base level */ public int getBaseLevel() { - return baselevel; + return bidiBase.getParaLevel(); } /** @@ -438,17 +242,7 @@ public final class Bidi { * @return the resolved level of the character at offset */ public int getLevelAt(int offset) { - if (runs == null || offset < 0 || offset >= length) { - return baselevel; - } else { - int i = 0; - do { - if (offset < runs[i]) { - return runs[i+1]; - } - i += 2; - } while (true); - } + return bidiBase.getLevelAt(offset); } /** @@ -456,7 +250,7 @@ public final class Bidi { * @return the number of level runs */ public int getRunCount() { - return runs == null ? 1 : runs.length / 2; + return bidiBase.countRuns(); } /** @@ -465,7 +259,7 @@ public final class Bidi { * @return the level of the run */ public int getRunLevel(int run) { - return runs == null ? baselevel : runs[run * 2 + 1]; + return bidiBase.getRunLevel(run); } /** @@ -475,7 +269,7 @@ public final class Bidi { * @return the start of the run */ public int getRunStart(int run) { - return (runs == null || run == 0) ? 0 : runs[run * 2 - 2]; + return bidiBase.getRunStart(run); } /** @@ -486,7 +280,7 @@ public final class Bidi { * @return limit the limit of the run */ public int getRunLimit(int run) { - return runs == null ? length : runs[run * 2]; + return bidiBase.getRunLimit(run); } /** @@ -501,16 +295,7 @@ public final class Bidi { * @return true if the range of characters requires bidi analysis */ public static boolean requiresBidi(char[] text, int start, int limit) { - CodePointIterator cpi = CodePointIterator.create(text, start, limit); - for (int cp = cpi.next(); cp != CodePointIterator.DONE; cp = cpi.next()) { - if (cp > 0x0590) { - int dc = nativeGetDirectionCode(cp); - if ((RMASK & (1 << dc)) != 0) { - return true; - } - } - } - return false; + return BidiBase.requiresBidi(text, start, limit); } /** @@ -530,124 +315,14 @@ public final class Bidi { * @param count the number of objects to reorder */ public static void reorderVisually(byte[] levels, int levelStart, Object[] objects, int objectStart, int count) { - - if (count < 0) { - throw new IllegalArgumentException("count " + count + " must be >= 0"); - } - if (levelStart < 0 || levelStart + count > levels.length) { - throw new IllegalArgumentException("levelStart " + levelStart + " and count " + count + - " out of range [0, " + levels.length + "]"); - } - if (objectStart < 0 || objectStart + count > objects.length) { - throw new IllegalArgumentException("objectStart " + objectStart + " and count " + count + - " out of range [0, " + objects.length + "]"); - } - - byte lowestOddLevel = (byte)(NUMLEVELS + 1); - byte highestLevel = 0; - - // initialize mapping and levels - - int levelLimit = levelStart + count; - for (int i = levelStart; i < levelLimit; i++) { - byte level = levels[i]; - if (level > highestLevel) { - highestLevel = level; - } - - if ((level & 0x01) != 0 && level < lowestOddLevel) { - lowestOddLevel = level; - } - } - - int delta = objectStart - levelStart; - - while (highestLevel >= lowestOddLevel) { - int i = levelStart; - - for (;;) { - while (i < levelLimit && levels[i] < highestLevel) { - i++; - } - int begin = i++; - - if (begin == levelLimit) { - break; // no more runs at this level - } - - while (i < levelLimit && levels[i] >= highestLevel) { - i++; - } - int end = i - 1; - - begin += delta; - end += delta; - while (begin < end) { - Object temp = objects[begin]; - objects[begin] = objects[end]; - objects[end] = temp; - ++begin; - --end; - } - } - - --highestLevel; - } + BidiBase.reorderVisually(levels, levelStart, objects, objectStart, count); } - private static final char NUMLEVELS = 62; - - private static final int RMASK = - (1 << 1 /* U_RIGHT_TO_LEFT */) | - (1 << 5 /* U_ARABIC_NUMBER */) | - (1 << 13 /* U_RIGHT_TO_LEFT_ARABIC */) | - (1 << 14 /* U_RIGHT_TO_LEFT_EMBEDDING */) | - (1 << 15 /* U_RIGHT_TO_LEFT_OVERRIDE */); - - /** Access native bidi implementation. */ - private static native int nativeGetDirectionCode(int cp); - - /** Access native bidi implementation. */ - private static synchronized native void nativeBidiChars(Bidi bidi, char[] text, int textStart, - byte[] embeddings, int embeddingStart, - int length, int flags); - /** * Display the bidi internal state, used in debugging. */ public String toString() { - StringBuffer buf = new StringBuffer(super.toString()); - buf.append("[dir: " + dir); - buf.append(" baselevel: " + baselevel); - buf.append(" length: " + length); - if (runs == null) { - buf.append(" runs: null"); - } else { - buf.append(" runs: ["); - for (int i = 0; i < runs.length; i += 2) { - if (i != 0) { - buf.append(' '); - } - buf.append(runs[i]); // limit - buf.append('/'); - buf.append(runs[i+1]); // level - } - buf.append(']'); - } - if (cws == null) { - buf.append(" cws: null"); - } else { - buf.append(" cws: ["); - for (int i = 0; i < cws.length; ++i) { - if (i != 0) { - buf.append(' '); - } - buf.append(Integer.toHexString(cws[i])); - } - buf.append(']'); - } - buf.append(']'); - - return buf.toString(); + return bidiBase.toString(); } + } diff --git a/jdk/src/share/classes/sun/text/bidi/BidiBase.java b/jdk/src/share/classes/sun/text/bidi/BidiBase.java new file mode 100644 index 00000000000..be494ea3cc8 --- /dev/null +++ b/jdk/src/share/classes/sun/text/bidi/BidiBase.java @@ -0,0 +1,3444 @@ +/* + * Portions Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + ******************************************************************************* + * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * + * * + * The original version of this source code and documentation is copyrighted * + * and owned by IBM, These materials are provided under terms of a License * + * Agreement between IBM and Sun. This technology is protected by multiple * + * US and International patents. This notice and attribution to IBM may not * + * to removed. * + ******************************************************************************* + */ + +/* FOOD FOR THOUGHT: currently the reordering modes are a mixture of + * algorithm for direct BiDi, algorithm for inverse Bidi and the bizarre + * concept of RUNS_ONLY which is a double operation. + * It could be advantageous to divide this into 3 concepts: + * a) Operation: direct / inverse / RUNS_ONLY + * b) Direct algorithm: default / NUMBERS_SPECIAL / GROUP_NUMBERS_WITH_L + * c) Inverse algorithm: default / INVERSE_LIKE_DIRECT / NUMBERS_SPECIAL + * This would allow combinations not possible today like RUNS_ONLY with + * NUMBERS_SPECIAL. + * Also allow to set INSERT_MARKS for the direct step of RUNS_ONLY and + * REMOVE_CONTROLS for the inverse step. + * Not all combinations would be supported, and probably not all do make sense. + * This would need to document which ones are supported and what are the + * fallbacks for unsupported combinations. + */ + +package sun.text.bidi; + +import java.awt.font.TextAttribute; +import java.awt.font.NumericShaper; +import java.io.IOException; +import java.lang.reflect.Array; +import java.text.AttributedCharacterIterator; +import java.text.Bidi; +import java.util.Arrays; +import java.util.MissingResourceException; +import sun.text.normalizer.UBiDiProps; +import sun.text.normalizer.UCharacter; +import sun.text.normalizer.UTF16; + +/** + * + *
+ * + * Note: Libraries that perform a bidirectional algorithm and reorder strings + * accordingly are sometimes called "Storage Layout Engines". ICU's Bidi and + * shaping (ArabicShaping) classes can be used at the core of such "Storage + * Layout Engines". + * + *
+ * + * Some of the API methods provide access to "runs". Such a + * "run" is defined as a sequence of characters that are at the same + * embedding level after performing the Bidi algorithm. + *
+ * + *
Block Separator. For handling of
+ * paragraphs, see:
+ *
+ *
+ * Levels can be abstract values when used for the
+ * paraLevel and embeddingLevels
+ * arguments of setPara(); there:
+ *
embeddingLevels[]
+ * value indicates whether the using application is
+ * specifying the level of a character to override whatever the
+ * Bidi implementation would resolve it to.paraLevel can be set to the
+ * pseudo-level values LEVEL_DEFAULT_LTR
+ * and LEVEL_DEFAULT_RTL.The related constants are not real, valid level values.
+ * DEFAULT_XXX can be used to specify
+ * a default for the paragraph level for
+ * when the setPara() method
+ * shall determine it but there is no
+ * strongly typed character in the input.
+ *
+ * Note that the value for LEVEL_DEFAULT_LTR is even
+ * and the one for LEVEL_DEFAULT_RTL is odd,
+ * just like with normal LTR and RTL level values -
+ * these special values are designed that way. Also, the implementation
+ * assumes that MAX_EXPLICIT_LEVEL is odd.
+ *
+ *
+ * The basic assumptions are: + *
+ *
+ *
+ * package com.ibm.icu.dev.test.bidi;
+ *
+ * import com.ibm.icu.text.Bidi;
+ * import com.ibm.icu.text.BidiRun;
+ *
+ * public class Sample {
+ *
+ * static final int styleNormal = 0;
+ * static final int styleSelected = 1;
+ * static final int styleBold = 2;
+ * static final int styleItalics = 4;
+ * static final int styleSuper=8;
+ * static final int styleSub = 16;
+ *
+ * static class StyleRun {
+ * int limit;
+ * int style;
+ *
+ * public StyleRun(int limit, int style) {
+ * this.limit = limit;
+ * this.style = style;
+ * }
+ * }
+ *
+ * static class Bounds {
+ * int start;
+ * int limit;
+ *
+ * public Bounds(int start, int limit) {
+ * this.start = start;
+ * this.limit = limit;
+ * }
+ * }
+ *
+ * static int getTextWidth(String text, int start, int limit,
+ * StyleRun[] styleRuns, int styleRunCount) {
+ * // simplistic way to compute the width
+ * return limit - start;
+ * }
+ *
+ * // set limit and StyleRun limit for a line
+ * // from text[start] and from styleRuns[styleRunStart]
+ * // using Bidi.getLogicalRun(...)
+ * // returns line width
+ * static int getLineBreak(String text, Bounds line, Bidi para,
+ * StyleRun styleRuns[], Bounds styleRun) {
+ * // dummy return
+ * return 0;
+ * }
+ *
+ * // render runs on a line sequentially, always from left to right
+ *
+ * // prepare rendering a new line
+ * static void startLine(byte textDirection, int lineWidth) {
+ * System.out.println();
+ * }
+ *
+ * // render a run of text and advance to the right by the run width
+ * // the text[start..limit-1] is always in logical order
+ * static void renderRun(String text, int start, int limit,
+ * byte textDirection, int style) {
+ * }
+ *
+ * // We could compute a cross-product
+ * // from the style runs with the directional runs
+ * // and then reorder it.
+ * // Instead, here we iterate over each run type
+ * // and render the intersections -
+ * // with shortcuts in simple (and common) cases.
+ * // renderParagraph() is the main function.
+ *
+ * // render a directional run with
+ * // (possibly) multiple style runs intersecting with it
+ * static void renderDirectionalRun(String text, int start, int limit,
+ * byte direction, StyleRun styleRuns[],
+ * int styleRunCount) {
+ * int i;
+ *
+ * // iterate over style runs
+ * if (direction == Bidi.LTR) {
+ * int styleLimit;
+ * for (i = 0; i < styleRunCount; ++i) {
+ * styleLimit = styleRuns[i].limit;
+ * if (start < styleLimit) {
+ * if (styleLimit > limit) {
+ * styleLimit = limit;
+ * }
+ * renderRun(text, start, styleLimit,
+ * direction, styleRuns[i].style);
+ * if (styleLimit == limit) {
+ * break;
+ * }
+ * start = styleLimit;
+ * }
+ * }
+ * } else {
+ * int styleStart;
+ *
+ * for (i = styleRunCount-1; i >= 0; --i) {
+ * if (i > 0) {
+ * styleStart = styleRuns[i-1].limit;
+ * } else {
+ * styleStart = 0;
+ * }
+ * if (limit >= styleStart) {
+ * if (styleStart < start) {
+ * styleStart = start;
+ * }
+ * renderRun(text, styleStart, limit, direction,
+ * styleRuns[i].style);
+ * if (styleStart == start) {
+ * break;
+ * }
+ * limit = styleStart;
+ * }
+ * }
+ * }
+ * }
+ *
+ * // the line object represents text[start..limit-1]
+ * static void renderLine(Bidi line, String text, int start, int limit,
+ * StyleRun styleRuns[], int styleRunCount) {
+ * byte direction = line.getDirection();
+ * if (direction != Bidi.MIXED) {
+ * // unidirectional
+ * if (styleRunCount <= 1) {
+ * renderRun(text, start, limit, direction, styleRuns[0].style);
+ * } else {
+ * renderDirectionalRun(text, start, limit, direction,
+ * styleRuns, styleRunCount);
+ * }
+ * } else {
+ * // mixed-directional
+ * int count, i;
+ * BidiRun run;
+ *
+ * try {
+ * count = line.countRuns();
+ * } catch (IllegalStateException e) {
+ * e.printStackTrace();
+ * return;
+ * }
+ * if (styleRunCount <= 1) {
+ * int style = styleRuns[0].style;
+ *
+ * // iterate over directional runs
+ * for (i = 0; i < count; ++i) {
+ * run = line.getVisualRun(i);
+ * renderRun(text, run.getStart(), run.getLimit(),
+ * run.getDirection(), style);
+ * }
+ * } else {
+ * // iterate over both directional and style runs
+ * for (i = 0; i < count; ++i) {
+ * run = line.getVisualRun(i);
+ * renderDirectionalRun(text, run.getStart(),
+ * run.getLimit(), run.getDirection(),
+ * styleRuns, styleRunCount);
+ * }
+ * }
+ * }
+ * }
+ *
+ * static void renderParagraph(String text, byte textDirection,
+ * StyleRun styleRuns[], int styleRunCount,
+ * int lineWidth) {
+ * int length = text.length();
+ * Bidi para = new Bidi();
+ * try {
+ * para.setPara(text,
+ * textDirection != 0 ? Bidi.LEVEL_DEFAULT_RTL
+ * : Bidi.LEVEL_DEFAULT_LTR,
+ * null);
+ * } catch (Exception e) {
+ * e.printStackTrace();
+ * return;
+ * }
+ * byte paraLevel = (byte)(1 & para.getParaLevel());
+ * StyleRun styleRun = new StyleRun(length, styleNormal);
+ *
+ * if (styleRuns == null || styleRunCount <= 0) {
+ * styleRuns = new StyleRun[1];
+ * styleRunCount = 1;
+ * styleRuns[0] = styleRun;
+ * }
+ * // assume styleRuns[styleRunCount-1].limit>=length
+ *
+ * int width = getTextWidth(text, 0, length, styleRuns, styleRunCount);
+ * if (width <= lineWidth) {
+ * // everything fits onto one line
+ *
+ * // prepare rendering a new line from either left or right
+ * startLine(paraLevel, width);
+ *
+ * renderLine(para, text, 0, length, styleRuns, styleRunCount);
+ * } else {
+ * // we need to render several lines
+ * Bidi line = new Bidi(length, 0);
+ * int start = 0, limit;
+ * int styleRunStart = 0, styleRunLimit;
+ *
+ * for (;;) {
+ * limit = length;
+ * styleRunLimit = styleRunCount;
+ * width = getLineBreak(text, new Bounds(start, limit),
+ * para, styleRuns,
+ * new Bounds(styleRunStart, styleRunLimit));
+ * try {
+ * line = para.setLine(start, limit);
+ * } catch (Exception e) {
+ * e.printStackTrace();
+ * return;
+ * }
+ * // prepare rendering a new line
+ * // from either left or right
+ * startLine(paraLevel, width);
+ *
+ * if (styleRunStart > 0) {
+ * int newRunCount = styleRuns.length - styleRunStart;
+ * StyleRun[] newRuns = new StyleRun[newRunCount];
+ * System.arraycopy(styleRuns, styleRunStart, newRuns, 0,
+ * newRunCount);
+ * renderLine(line, text, start, limit, newRuns,
+ * styleRunLimit - styleRunStart);
+ * } else {
+ * renderLine(line, text, start, limit, styleRuns,
+ * styleRunLimit - styleRunStart);
+ * }
+ * if (limit == length) {
+ * break;
+ * }
+ * start = limit;
+ * styleRunStart = styleRunLimit - 1;
+ * if (start >= styleRuns[styleRunStart].limit) {
+ * ++styleRunStart;
+ * }
+ * }
+ * }
+ * }
+ *
+ * public static void main(String[] args)
+ * {
+ * renderParagraph("Some Latin text...", Bidi.LTR, null, 0, 80);
+ * renderParagraph("Some Hebrew text...", Bidi.RTL, null, 0, 60);
+ * }
+ * }
+ *
+ *
+ */
+
+public class BidiBase {
+
+ class Point {
+ int pos; /* position in text */
+ int flag; /* flag for LRM/RLM, before/after */
+ }
+
+ class InsertPoints {
+ int size;
+ int confirmed;
+ Point[] points = new Point[0];
+ }
+
+ /** Paragraph level setting+ * + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, + * then set the paragraph level to 0 (left-to-right).
+ *
+ * If this value is used in conjunction with reordering modes
+ * REORDER_INVERSE_LIKE_DIRECT or
+ * REORDER_INVERSE_FOR_NUMBERS_SPECIAL, the text to reorder
+ * is assumed to be visual LTR, and the text after reordering is required
+ * to be the corresponding logical string with appropriate contextual
+ * direction. The direction of the result string will be RTL if either
+ * the righmost or leftmost strong character of the source text is RTL
+ * or Arabic Letter, the direction will be LTR otherwise.
+ *
+ * If reordering option OPTION_INSERT_MARKS is set, an RLM may
+ * be added at the beginning of the result string to ensure round trip
+ * (that the result string, when reordered back to visual, will produce
+ * the original source text).
+ * @see #REORDER_INVERSE_LIKE_DIRECT
+ * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL
+ * @stable ICU 3.8
+ */
+ public static final byte INTERNAL_LEVEL_DEFAULT_LTR = (byte)0x7e;
+
+ /** Paragraph level setting
+ * + * Constant indicating that the base direction depends on the first strong + * directional character in the text according to the Unicode Bidirectional + * Algorithm. If no strong directional character is present, + * then set the paragraph level to 1 (right-to-left).
+ *
+ * If this value is used in conjunction with reordering modes
+ * REORDER_INVERSE_LIKE_DIRECT or
+ * REORDER_INVERSE_FOR_NUMBERS_SPECIAL, the text to reorder
+ * is assumed to be visual LTR, and the text after reordering is required
+ * to be the corresponding logical string with appropriate contextual
+ * direction. The direction of the result string will be RTL if either
+ * the righmost or leftmost strong character of the source text is RTL
+ * or Arabic Letter, or if the text contains no strong character;
+ * the direction will be LTR otherwise.
+ *
+ * If reordering option OPTION_INSERT_MARKS is set, an RLM may
+ * be added at the beginning of the result string to ensure round trip
+ * (that the result string, when reordered back to visual, will produce
+ * the original source text).
+ * @see #REORDER_INVERSE_LIKE_DIRECT
+ * @see #REORDER_INVERSE_FOR_NUMBERS_SPECIAL
+ * @stable ICU 3.8
+ */
+ public static final byte INTERNAL_LEVEL_DEFAULT_RTL = (byte)0x7f;
+
+ /**
+ * Maximum explicit embedding level.
+ * (The maximum resolved level can be up to MAX_EXPLICIT_LEVEL+1).
+ * @stable ICU 3.8
+ */
+ public static final byte MAX_EXPLICIT_LEVEL = 61;
+
+ /**
+ * Bit flag for level input.
+ * Overrides directional properties.
+ * @stable ICU 3.8
+ */
+ public static final byte INTERNAL_LEVEL_OVERRIDE = (byte)0x80;
+
+ /**
+ * Special value which can be returned by the mapping methods when a
+ * logical index has no corresponding visual index or vice-versa. This may
+ * happen for the logical-to-visual mapping of a Bidi control when option
+ * OPTION_REMOVE_CONTROLS is
+ * specified. This can also happen for the visual-to-logical mapping of a
+ * Bidi mark (LRM or RLM) inserted by option
+ * OPTION_INSERT_MARKS.
+ * @see #getVisualIndex
+ * @see #getVisualMap
+ * @see #getLogicalIndex
+ * @see #getLogicalMap
+ * @see #OPTION_INSERT_MARKS
+ * @see #OPTION_REMOVE_CONTROLS
+ * @stable ICU 3.8
+ */
+ public static final int MAP_NOWHERE = -1;
+
+ /**
+ * Mixed-directional text.
+ * @stable ICU 3.8
+ */
+ public static final byte MIXED = 2;
+
+ /**
+ * option bit for writeReordered():
+ * replace characters with the "mirrored" property in RTL runs
+ * by their mirror-image mappings
+ *
+ * @see #writeReordered
+ * @stable ICU 3.8
+ */
+ public static final short DO_MIRRORING = 2;
+
+ /** Reordering mode: Regular Logical to Visual Bidi algorithm according to Unicode.
+ * @see #setReorderingMode
+ * @stable ICU 3.8
+ */
+ private static final short REORDER_DEFAULT = 0;
+
+ /** Reordering mode: Logical to Visual algorithm which handles numbers in
+ * a way which mimicks the behavior of Windows XP.
+ * @see #setReorderingMode
+ * @stable ICU 3.8
+ */
+ private static final short REORDER_NUMBERS_SPECIAL = 1;
+
+ /** Reordering mode: Logical to Visual algorithm grouping numbers with
+ * adjacent R characters (reversible algorithm).
+ * @see #setReorderingMode
+ * @stable ICU 3.8
+ */
+ private static final short REORDER_GROUP_NUMBERS_WITH_R = 2;
+
+ /** Reordering mode: Reorder runs only to transform a Logical LTR string
+ * to the logical RTL string with the same display, or vice-versa.
+ * If this mode is set together with option
+ * OPTION_INSERT_MARKS, some Bidi controls in the source
+ * text may be removed and other controls may be added to produce the
+ * minimum combination which has the required display.
+ * @see #OPTION_INSERT_MARKS
+ * @see #setReorderingMode
+ * @stable ICU 3.8
+ */
+ private static final short REORDER_RUNS_ONLY = 3;
+
+ /** Reordering mode: Visual to Logical algorithm which handles numbers
+ * like L (same algorithm as selected by setInverse(true).
+ * @see #setInverse
+ * @see #setReorderingMode
+ * @stable ICU 3.8
+ */
+ private static final short REORDER_INVERSE_NUMBERS_AS_L = 4;
+
+ /** Reordering mode: Visual to Logical algorithm equivalent to the regular
+ * Logical to Visual algorithm.
+ * @see #setReorderingMode
+ * @stable ICU 3.8
+ */
+ private static final short REORDER_INVERSE_LIKE_DIRECT = 5;
+
+ /** Reordering mode: Inverse Bidi (Visual to Logical) algorithm for the
+ * REORDER_NUMBERS_SPECIAL Bidi algorithm.
+ * @see #setReorderingMode
+ * @stable ICU 3.8
+ */
+ private static final short REORDER_INVERSE_FOR_NUMBERS_SPECIAL = 6;
+
+ /* Reordering mode values must be ordered so that all the regular logical to
+ * visual modes come first, and all inverse Bidi modes come last.
+ */
+ private static final short REORDER_LAST_LOGICAL_TO_VISUAL =
+ REORDER_NUMBERS_SPECIAL;
+
+ /**
+ * Option bit for setReorderingOptions:
+ * insert Bidi marks (LRM or RLM) when needed to ensure correct result of
+ * a reordering to a Logical order
+ *
+ *
This option must be set or reset before calling
+ * setPara.
This option is significant only with reordering modes which generate + * a result with Logical order, specifically.
+ *REORDER_RUNS_ONLYREORDER_INVERSE_NUMBERS_AS_LREORDER_INVERSE_LIKE_DIRECTREORDER_INVERSE_FOR_NUMBERS_SPECIALIf this option is set in conjunction with reordering mode
+ * REORDER_INVERSE_NUMBERS_AS_L or with calling
+ * setInverse(true), it implies option
+ * INSERT_LRM_FOR_NUMERIC in calls to method
+ * writeReordered().
For other reordering modes, a minimum number of LRM or RLM characters
+ * will be added to the source text after reordering it so as to ensure
+ * round trip, i.e. when applying the inverse reordering mode on the
+ * resulting logical text with removal of Bidi marks
+ * (option OPTION_REMOVE_CONTROLS set before calling
+ * setPara() or option
+ * REMOVE_BIDI_CONTROLS in
+ * writeReordered), the result will be identical to the
+ * source text in the first transformation.
+ *
+ *
This option will be ignored if specified together with option
+ * OPTION_REMOVE_CONTROLS. It inhibits option
+ * REMOVE_BIDI_CONTROLS in calls to method
+ * writeReordered() and it implies option
+ * INSERT_LRM_FOR_NUMERIC in calls to method
+ * writeReordered() if the reordering mode is
+ * REORDER_INVERSE_NUMBERS_AS_L.
setReorderingOptions:
+ * remove Bidi control characters
+ *
+ * This option must be set or reset before calling
+ * setPara.
This option nullifies option
+ * OPTION_INSERT_MARKS. It inhibits option
+ * INSERT_LRM_FOR_NUMERIC in calls to method
+ * writeReordered() and it implies option
+ * REMOVE_BIDI_CONTROLS in calls to that method.
setReorderingOptions:
+ * process the output as part of a stream to be continued
+ *
+ * This option must be set or reset before calling
+ * setPara.
This option specifies that the caller is interested in processing + * large text object in parts. The results of the successive calls are + * expected to be concatenated by the caller. Only the call for the last + * part will have this option bit off.
+ * + *When this option bit is on, setPara() may process
+ * less than the full source text in order to truncate the text at a
+ * meaningful boundary. The caller should call
+ * getProcessedLength() immediately after calling
+ * setPara() in order to determine how much of the source
+ * text has been processed. Source text beyond that length should be
+ * resubmitted in following calls to setPara. The
+ * processed length may be less than the length of the source text if a
+ * character preceding the last character of the source text constitutes a
+ * reasonable boundary (like a block separator) for text to be continued.
+ * If the last character of the source text constitutes a reasonable
+ * boundary, the whole text will be processed at once.
+ * If nowhere in the source text there exists
+ * such a reasonable boundary, the processed length will be zero.
+ * The caller should check for such an occurrence and do one of the following:
+ *
OPTION_STREAMING.When the OPTION_STREAMING option is used, it is
+ * recommended to call orderParagraphsLTR() with argument
+ * orderParagraphsLTR set to true before calling
+ * setPara() so that later paragraphs may be concatenated to
+ * previous paragraphs on the right.
+ *
setPara, which may be shorter
+ * than the original length. Otherwise, it is identical to the original
+ * length.
+ */
+ public int length;
+
+ /* if option OPTION_REMOVE_CONTROLS is set, and/or Bidi
+ * marks are allowed to be inserted in one of the reordering modes, the
+ * length of the result string may be different from the processed length.
+ */
+ int resultLength;
+
+ /* indicators for whether memory may be allocated after construction */
+ boolean mayAllocateText;
+ boolean mayAllocateRuns;
+
+ /* arrays with one value per text-character */
+ byte[] dirPropsMemory = new byte[1];
+ byte[] levelsMemory = new byte[1];
+ byte[] dirProps;
+ byte[] levels;
+
+ /* must block separators receive level 0? */
+ boolean orderParagraphsLTR;
+
+ /* the paragraph level */
+ byte paraLevel;
+
+ /* original paraLevel when contextual */
+ /* must be one of DEFAULT_xxx or 0 if not contextual */
+ byte defaultParaLevel;
+
+ /* the following is set in setPara, used in processPropertySeq */
+
+ ImpTabPair impTabPair; /* reference to levels state table pair */
+
+ /* the overall paragraph or line directionality*/
+ byte direction;
+
+ /* flags is a bit set for which directional properties are in the text */
+ int flags;
+
+ /* lastArabicPos is index to the last AL in the text, -1 if none */
+ int lastArabicPos;
+
+ /* characters after trailingWSStart are WS and are */
+ /* implicitly at the paraLevel (rule (L1)) - levels may not reflect that */
+ int trailingWSStart;
+
+ /* fields for paragraph handling */
+ int paraCount; /* set in getDirProps() */
+ int[] parasMemory = new int[1];
+ int[] paras; /* limits of paragraphs, filled in
+ ResolveExplicitLevels() or CheckExplicitLevels() */
+
+ /* for single paragraph text, we only need a tiny array of paras (no allocation) */
+ int[] simpleParas = {0};
+
+ /* fields for line reordering */
+ int runCount; /* ==-1: runs not set up yet */
+ BidiRun[] runsMemory = new BidiRun[0];
+ BidiRun[] runs;
+
+ /* for non-mixed text, we only need a tiny array of runs (no allocation) */
+ BidiRun[] simpleRuns = {new BidiRun()};
+
+ /* mapping of runs in logical order to visual order */
+ int[] logicalToVisualRunsMap;
+
+ /* flag to indicate that the map has been updated */
+ boolean isGoodLogicalToVisualRunsMap;
+
+ /* for inverse Bidi with insertion of directional marks */
+ InsertPoints insertPoints = new InsertPoints();
+
+ /* for option OPTION_REMOVE_CONTROLS */
+ int controlCount;
+
+ /*
+ * Sometimes, bit values are more appropriate
+ * to deal with directionality properties.
+ * Abbreviations in these method names refer to names
+ * used in the Bidi algorithm.
+ */
+ static int DirPropFlag(byte dir) {
+ return (1 << dir);
+ }
+
+ /*
+ * The following bit is ORed to the property of characters in paragraphs
+ * with contextual RTL direction when paraLevel is contextual.
+ */
+ static final byte CONTEXT_RTL_SHIFT = 6;
+ static final byte CONTEXT_RTL = (byte)(1<Bidi object with preallocated memory
+ * for internal structures.
+ * This method provides a Bidi object like the default constructor
+ * but it also preallocates memory for internal structures
+ * according to the sizings supplied by the caller.
+ * The preallocation can be limited to some of the internal memory
+ * by setting some values to 0 here. That means that if, e.g.,
+ *
+ *
+ * This method takes a piece of plain text containing one or more paragraphs,
+ * with or without externally specified embedding levels from styled
+ * text and computes the left-right-directionality of each character.
+ *
+ * If the entire text is all of the same directionality, then
+ * the method may not perform all the steps described by the algorithm,
+ * i.e., some levels may not be the same as if all steps were performed.
+ * This is not relevant for unidirectional text.
+ *
+ * The text can be composed of multiple paragraphs. Occurrence of a block
+ * separator in the text terminates a paragraph, and whatever comes next starts
+ * a new paragraph. The exception to this rule is when a Carriage Return (CR)
+ * is followed by a Line Feed (LF). Both CR and LF are block separators, but
+ * in that case, the pair of characters is considered as terminating the
+ * preceding paragraph, and a new paragraph will be started by a character
+ * coming after the LF.
+ *
+ * Although the text is passed here as a
+ *
+ * This method takes a piece of plain text containing one or more paragraphs,
+ * with or without externally specified embedding levels from styled
+ * text and computes the left-right-directionality of each character.
+ *
+ * If the entire text is all of the same directionality, then
+ * the method may not perform all the steps described by the algorithm,
+ * i.e., some levels may not be the same as if all steps were performed.
+ * This is not relevant for unidirectional text.
+ *
+ * The text can be composed of multiple paragraphs. Occurrence of a block
+ * separator in the text terminates a paragraph, and whatever comes next starts
+ * a new paragraph. The exception to this rule is when a Carriage Return (CR)
+ * is followed by a Line Feed (LF). Both CR and LF are block separators, but
+ * in that case, the pair of characters is considered as terminating the
+ * preceding paragraph, and a new paragraph will be started by a character
+ * coming after the LF.
+ *
+ * The text is stored internally as an array of characters. Therefore the
+ * documentation will refer to indexes of the characters in the text.
+ *
+ * @param chars contains the text that the Bidi algorithm will be performed
+ * on. This text can be retrieved with
+ *
+ * This method takes a paragraph of text and computes the
+ * left-right-directionality of each character. The text should not
+ * contain any Unicode block separators.
+ *
+ * The RUN_DIRECTION attribute in the text, if present, determines the base
+ * direction (left-to-right or right-to-left). If not present, the base
+ * direction is computed using the Unicode Bidirectional Algorithm,
+ * defaulting to left-to-right if there are no strong directional characters
+ * in the text. This attribute, if present, must be applied to all the text
+ * in the paragraph.
+ *
+ * The BIDI_EMBEDDING attribute in the text, if present, represents
+ * embedding level information. Negative values from -1 to -62 indicate
+ * overrides at the absolute value of the level. Positive values from 1 to
+ * 62 indicate embeddings. Where values are zero or not defined, the base
+ * embedding level as determined by the base direction is assumed.
+ *
+ * The NUMERIC_SHAPING attribute in the text, if present, converts European
+ * digits to other decimal digits before running the bidi algorithm. This
+ * attribute, if present, must be applied to all the text in the paragraph.
+ *
+ * If the entire text is all of the same directionality, then
+ * the method may not perform all the steps described by the algorithm,
+ * i.e., some levels may not be the same as if all steps were performed.
+ * This is not relevant for unidirectional text.
+ *
+ * @param paragraph a paragraph of text with optional character and
+ * paragraph attribute information
+ * @stable ICU 3.8
+ */
+ public void setPara(AttributedCharacterIterator paragraph)
+ {
+ byte paraLvl;
+ Boolean runDirection = (Boolean) paragraph.getAttribute(TextAttribute.RUN_DIRECTION);
+ NumericShaper shaper = (NumericShaper) paragraph.getAttribute(TextAttribute.NUMERIC_SHAPING);
+ if (runDirection == null) {
+ paraLvl = INTERNAL_LEVEL_DEFAULT_LTR;
+ } else {
+ paraLvl = (runDirection.equals(TextAttribute.RUN_DIRECTION_LTR)) ?
+ (byte)Bidi.DIRECTION_LEFT_TO_RIGHT : (byte)Bidi.DIRECTION_RIGHT_TO_LEFT;
+ }
+
+ byte[] lvls = null;
+ int len = paragraph.getEndIndex() - paragraph.getBeginIndex();
+ byte[] embeddingLevels = new byte[len];
+ char[] txt = new char[len];
+ int i = 0;
+ char ch = paragraph.first();
+ while (ch != AttributedCharacterIterator.DONE) {
+ txt[i] = ch;
+ Integer embedding = (Integer) paragraph.getAttribute(TextAttribute.BIDI_EMBEDDING);
+ if (embedding != null) {
+ byte level = embedding.byteValue();
+ if (level == 0) {
+ /* no-op */
+ } else if (level < 0) {
+ lvls = embeddingLevels;
+ embeddingLevels[i] = (byte)((0 - level) | INTERNAL_LEVEL_OVERRIDE);
+ } else {
+ lvls = embeddingLevels;
+ embeddingLevels[i] = level;
+ }
+ }
+ ch = paragraph.next();
+ ++i;
+ }
+
+ if (shaper != null) {
+ shaper.shape(txt, 0, len);
+ }
+ setPara(txt, paraLvl, lvls);
+ }
+
+ /**
+ * Specify whether block separators must be allocated level zero,
+ * so that successive paragraphs will progress from left to right.
+ * This method must be called before
+ *
+ * @param charIndex is the index of a character within the text, in the
+ * range
+ * In the new line object, the indexes will range from 0 to
+ *
+ * This is used after calling
+ *
+ * After line-breaking, rules (L1) and (L2) for the treatment of
+ * trailing WS and for reordering are performed on
+ * a
+ *
+ * Important: the line
+ *
+ * Note that this method may allocate memory under some
+ * circumstances, unlike
+ * Some values in the map may be
+ * When the visual output is altered by using options of
+ *
+ * The index map will result in
+ *
+ *
+ * Note: this constructor calls setPara() internally.
+ *
+ * @param text an array containing the paragraph of text to process.
+ * @param textStart the index into the text array of the start of the
+ * paragraph.
+ * @param embeddings an array containing embedding values for each character
+ * in the paragraph. This can be null, in which case it is assumed
+ * that there is no external embedding information.
+ * @param embStart the index into the embedding array of the start of the
+ * paragraph.
+ * @param paragraphLength the length of the paragraph in the text and
+ * embeddings arrays.
+ * @param flags a collection of flags that control the algorithm. The
+ * algorithm understands the flags DIRECTION_LEFT_TO_RIGHT,
+ * DIRECTION_RIGHT_TO_LEFT, DIRECTION_DEFAULT_LEFT_TO_RIGHT, and
+ * DIRECTION_DEFAULT_RIGHT_TO_LEFT. Other values are reserved.
+ *
+ * @throws IllegalArgumentException if the values in embeddings are
+ * not within the allowed range
+ *
+ * @see #DIRECTION_LEFT_TO_RIGHT
+ * @see #DIRECTION_RIGHT_TO_LEFT
+ * @see #DIRECTION_DEFAULT_LEFT_TO_RIGHT
+ * @see #DIRECTION_DEFAULT_RIGHT_TO_LEFT
+ * @stable ICU 3.8
+ */
+ public BidiBase(char[] text,
+ int textStart,
+ byte[] embeddings,
+ int embStart,
+ int paragraphLength,
+ int flags)
+ {
+ this(0, 0);
+ byte paraLvl;
+ switch (flags) {
+ case Bidi.DIRECTION_LEFT_TO_RIGHT:
+ default:
+ paraLvl = Bidi.DIRECTION_LEFT_TO_RIGHT;
+ break;
+ case Bidi.DIRECTION_RIGHT_TO_LEFT:
+ paraLvl = Bidi.DIRECTION_RIGHT_TO_LEFT;
+ break;
+ case Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT:
+ paraLvl = INTERNAL_LEVEL_DEFAULT_LTR;
+ break;
+ case Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT:
+ paraLvl = INTERNAL_LEVEL_DEFAULT_RTL;
+ break;
+ }
+ byte[] paraEmbeddings;
+ if (embeddings == null) {
+ paraEmbeddings = null;
+ } else {
+ paraEmbeddings = new byte[paragraphLength];
+ byte lev;
+ for (int i = 0; i < paragraphLength; i++) {
+ lev = embeddings[i + embStart];
+ if (lev < 0) {
+ lev = (byte)((- lev) | INTERNAL_LEVEL_OVERRIDE);
+ } else if (lev == 0) {
+ lev = paraLvl;
+ if (paraLvl > MAX_EXPLICIT_LEVEL) {
+ lev &= 1;
+ }
+ }
+ paraEmbeddings[i] = lev;
+ }
+ }
+ if (textStart == 0 && embStart == 0 && paragraphLength == text.length) {
+ setPara(text, paraLvl, paraEmbeddings);
+ } else {
+ char[] paraText = new char[paragraphLength];
+ System.arraycopy(text, textStart, paraText, 0, paragraphLength);
+ setPara(paraText, paraLvl, paraEmbeddings);
+ }
+ }
+
+ /**
+ * Return true if the line is not left-to-right or right-to-left. This means
+ * it either has mixed runs of left-to-right and right-to-left text, or the
+ * base direction differs from the direction of the only run of text.
+ *
+ * @return true if the line is not left-to-right or right-to-left.
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to A BidiRun represents such a run by storing its essential properties,
+ * but does not duplicate the characters which form the run.
+ *
+ * The "limit" of the run is the position just after the
+ * last character, i.e., one more than that position.
+ *
+ * This class has no public constructor, and its members cannot be
+ * modified by users.
+ *
+ * @see com.ibm.icu.text.Bidi
+ */
+public class BidiRun {
+
+ int start; /* first logical position of the run */
+ int limit; /* last visual position of the run +1 */
+ int insertRemove; /* if >0, flags for inserting LRM/RLM before/after run,
+ if <0, count of bidi controls within run */
+ byte level;
+
+ /*
+ * Default constructor
+ *
+ * Note that members start and limit of a run instance have different
+ * meanings depending whether the run is part of the runs array of a Bidi
+ * object, or if it is a reference returned by getVisualRun() or
+ * getLogicalRun().
+ * For a member of the runs array of a Bidi object,
+ * - start is the first logical position of the run in the source text.
+ * - limit is one after the last visual position of the run.
+ * For a reference returned by getLogicalRun() or getVisualRun(),
+ * - start is the first logical position of the run in the source text.
+ * - limit is one after the last logical position of the run.
+ */
+ BidiRun()
+ {
+ this(0, 0, (byte)0);
+ }
+
+ /*
+ * Constructor
+ */
+ BidiRun(int start, int limit, byte embeddingLevel)
+ {
+ this.start = start;
+ this.limit = limit;
+ this.level = embeddingLevel;
+ }
+
+ /*
+ * Copy the content of a BidiRun instance
+ */
+ void copyFrom(BidiRun run)
+ {
+ this.start = run.start;
+ this.limit = run.limit;
+ this.level = run.level;
+ this.insertRemove = run.insertRemove;
+ }
+
+ /**
+ * Get level of run
+ */
+ public byte getEmbeddingLevel()
+ {
+ return level;
+ }
+
+ /**
+ * Check if run level is even
+ * @return true if the embedding level of this run is even, i.e. it is a
+ * left-to-right run.
+ */
+ boolean isEvenRun()
+ {
+ return (level & 1) == 0;
+ }
+
+}
diff --git a/jdk/src/share/classes/sun/text/normalizer/UCharacter.java b/jdk/src/share/classes/sun/text/normalizer/UCharacter.java
index 8225517f07c..4ff5695dd3e 100644
--- a/jdk/src/share/classes/sun/text/normalizer/UCharacter.java
+++ b/jdk/src/share/classes/sun/text/normalizer/UCharacter.java
@@ -1,5 +1,5 @@
/*
- * Portions Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Portions Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -355,7 +355,7 @@ public final class UCharacter
private static int getEuropeanDigit(int ch) {
if ((ch > 0x7a && ch < 0xff21)
|| ch < 0x41 || (ch > 0x5a && ch < 0x61)
- || ch > 0xff5a || (ch > 0xff31 && ch < 0xff41)) {
+ || ch > 0xff5a || (ch > 0xff3a && ch < 0xff41)) {
return -1;
}
if (ch <= 0x7a) {
diff --git a/jdk/src/share/native/sun/font/bidi/cmemory.h b/jdk/src/share/native/sun/font/bidi/cmemory.h
deleted file mode 100644
index 65245f7fc09..00000000000
--- a/jdk/src/share/native/sun/font/bidi/cmemory.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Portions Copyright 2000 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-/*
- * (C) Copyright IBM Corp. 1998, 1999 - All Rights Reserved
- *
- * The original version of this source code and documentation is
- * copyrighted and owned by IBM. These materials are provided
- * under terms of a License Agreement between IBM and Sun.
- * This technology is protected by multiple US and International
- * patents. This notice and attribution to IBM may not be removed.
- */
-
-/*
-* File CMEMORY.H
-*
-* Contains stdlib.h/string.h memory functions
-*
-* @author Bertrand A. Damiba
-*
-* Modification History:
-*
-* Date Name Description
-* 6/20/98 Bertrand Created.
-* 05/03/99 stephen Changed from functions to macros.
-*
-*******************************************************************************
-*/
-
-#ifndef CMEMORY_H
-#define CMEMORY_H
-
-#include
- *
- *
- *
- * The
- *
- * Some of the API functions provide access to
- *
- * @author Markus W. Scherer
- */
-DOCXX_TAG
-/*@{*/
-
-/**
- * UBiDiLevel is the type of the level values in this
- * BiDi implementation.
- * It holds an embedding level and indicates the visual direction
- * by its bit 0 (even/odd value).
- *
- * It can also hold non-level values for the
- * The related constants are not real, valid level values.
- *
- *
- * Note that the value for
- * This structure holds information about a paragraph of text
- * with BiDi-algorithm-related details, or about one line of
- * such a paragraph.
- * Reordering can be done on a line, or on a paragraph which is
- * then interpreted as one single line.
- */
-struct UBiDi;
-
-typedef struct UBiDi UBiDi;
-
-/**
- * Allocate a
- * This object can be reused for as long as it is not deallocated
- * by calling
- *
- * Subsequent functions will not allocate any more memory, and are thus
- * guaranteed not to fail because of lack of memory.
- * The preallocation can be limited to some of the internal memory
- * by setting some values to 0 here. That means that if, e.g.,
- *
- * The number of runs depends on the actual text and maybe anywhere between
- * 1 and
- *
- * @param pErrorCode must be a valid pointer to an error code value,
- * which must not indicate a failure before the function call.
- *
- * @return An empty
- *
- * Important:
- * If a
- *
- * This function takes a single plain text paragraph with or without
- * externally specified embedding levels from
- *
- * If the entire paragraph consists of text of only one direction, then
- * the function may not perform all the steps described by the algorithm,
- * i.e., some levels may not be the same as if all steps were performed.
- * This is not relevant for unidirectional text.
- *
- * The text must be externally split into separate paragraphs (rule P1).
- * Paragraph separators (B) should appear at most at the very end.
- *
- * @param pBiDi A
- * Except for that bit, it must be
- *
- * Caution: A copy of this pointer, not of the levels,
- * will be stored in the
- * After the
- * The
- * In the new line object, the indexes will range from 0 to
- *
- * This is used after calling
- *
- * After line-breaking, rules (L1) and (L2) for the treatment of
- * trailing WS and for reordering are performed on
- * a
- *
- * Important:
- *
- * Note that this function may allocate memory under some
- * circumstances, unlike
- * This is especially useful for line-breaking on a paragraph.
- *
- * @param pBiDi is the paragraph or line
- *
- *
- * Note that in right-to-left runs, this mapping places
- * modifier letters before base characters and second surrogates
- * before first ones.
- *
- * @param pBiDi is the paragraph or line
- *
- * This is the inverse function to
- * The index map will result in
- *
- * @param pErrorCode must be a valid pointer to an error code value,
- * which must not indicate a failure before the function call.
- *
- * @see ubidi_getVisualMap
- * @see ubidi_getVisualIndex
- */
-U_CAPI void U_EXPORT2
-ubidi_getLogicalMap(UBiDi *pBiDi, int32_t *indexMap, UErrorCode *pErrorCode);
-
-/**
- * Get a visual-to-logical index map (array) for the characters in the UBiDi
- * (paragraph or line) object.
- *
- * @param pBiDi is the paragraph or line
- * The index map will result in
- *
- * @param pErrorCode must be a valid pointer to an error code value,
- * which must not indicate a failure before the function call.
- *
- * @see ubidi_getLogicalMap
- * @see ubidi_getLogicalIndex
- */
-U_CAPI void U_EXPORT2
-ubidi_getVisualMap(UBiDi *pBiDi, int32_t *indexMap, UErrorCode *pErrorCode);
-
-/**
- * This is a convenience function that does not use a UBiDi object.
- * It is intended to be used for when an application has determined the levels
- * of objects (character sequences) and just needs to have them reordered (L2).
- * This is equivalent to using
- * The index map will result in
- * The index map will result in The basic assumptions are:
- * Returns the linguistic direction property of a character.
- * For example, 0x0041 (letter A) has the LEFT_TO_RIGHT directional
- * property.
- * @see UCharDirection
- */
-U_CAPI UCharDirection U_EXPORT2
-u_charDirection(UChar c);
-
-U_CAPI UCharDirection U_EXPORT2
-u_getDirection(uint32_t cp);
-
-U_CAPI UCharDirection U_EXPORT2
-u_surrogatePairDirection(UChar lead, UChar trail);
-
-#endif /*_UCHAR*/
-/*eof*/
diff --git a/jdk/src/share/native/sun/font/bidi/utypes.h b/jdk/src/share/native/sun/font/bidi/utypes.h
deleted file mode 100644
index 92cd4bed617..00000000000
--- a/jdk/src/share/native/sun/font/bidi/utypes.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Portions Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-/*
- * (C) Copyright Taligent, Inc., 1996, 1997 *
- * (C) Copyright IBM Corp. 1998-2003 - All Rights Reserved
- *
- * The original version of this source code and documentation is
- * copyrighted and owned by IBM. These materials are provided
- * under terms of a License Agreement between IBM and Sun.
- * This technology is protected by multiple US and International
- * patents. This notice and attribution to IBM may not be removed.
- */
-
-/*
-*
-* FILE NAME : UTYPES.H (formerly ptypes.h)
-*
-* Date Name Description
-* 12/11/96 helena Creation.
-* 02/27/97 aliu Added typedefs for UClassID, int8, int16, int32,
-* uint8, uint16, and uint32.
-* 04/01/97 aliu Added XP_CPLUSPLUS and modified to work under C as
-* well as C++.
-* Modified to use memcpy() for icu_arrayCopy() fns.
-* 04/14/97 aliu Added TPlatformUtilities.
-* 05/07/97 aliu Added import/export specifiers (replacing the old
-* broken EXT_CLASS). Added version number for our
-* code. Cleaned up header.
-* 6/20/97 helena Java class name change.
-* 08/11/98 stephen UErrorCode changed from typedef to enum
-* 08/12/98 erm Changed T_ANALYTIC_PACKAGE_VERSION to 3
-* 08/14/98 stephen Added icu_arrayCopy() for int8_t, int16_t, int32_t
-* 12/09/98 jfitz Added BUFFER_OVERFLOW_ERROR (bug 1100066)
-* 04/20/99 stephen Cleaned up & reworked for autoconf.
-* Renamed to utypes.h.
-* 05/05/99 stephen Changed to use maxRunCount cannot be reasonably predetermined and should not
+ * be set to maxLength (the only failproof value) to avoid
+ * wasting memory, then maxRunCount could be set to 0 here
+ * and the internal structures that are associated with it will be allocated
+ * on demand, just like with the default constructor.
+ *
+ * @param maxLength is the maximum text or line length that internal memory
+ * will be preallocated for. An attempt to associate this object with a
+ * longer text will fail, unless this value is 0, which leaves the allocation
+ * up to the implementation.
+ *
+ * @param maxRunCount is the maximum anticipated number of same-level runs
+ * that internal memory will be preallocated for. An attempt to access
+ * visual runs on an object that was not preallocated for as many runs
+ * as the text was actually resolved to will fail,
+ * unless this value is 0, which leaves the allocation up to the implementation.
+ * The number of runs depends on the actual text and maybe anywhere between
+ * 1 and maxLength. It is typically small.
+ *
+ * @throws IllegalArgumentException if maxLength or maxRunCount is less than 0
+ * @stable ICU 3.8
+ */
+ public BidiBase(int maxLength, int maxRunCount)
+ {
+ /* check the argument values */
+ if (maxLength < 0 || maxRunCount < 0) {
+ throw new IllegalArgumentException();
+ }
+
+ /* reset the object, all reference variables null, all flags false,
+ all sizes 0.
+ In fact, we don't need to do anything, since class members are
+ initialized as zero when an instance is created.
+ */
+ /*
+ mayAllocateText = false;
+ mayAllocateRuns = false;
+ orderParagraphsLTR = false;
+ paraCount = 0;
+ runCount = 0;
+ trailingWSStart = 0;
+ flags = 0;
+ paraLevel = 0;
+ defaultParaLevel = 0;
+ direction = 0;
+ */
+ /* get Bidi properties */
+ try {
+ bdp = UBiDiProps.getSingleton();
+ }
+ catch (IOException e) {
+ throw new MissingResourceException(e.getMessage(), "(BidiProps)", "");
+ }
+
+ /* allocate memory for arrays as requested */
+ if (maxLength > 0) {
+ getInitialDirPropsMemory(maxLength);
+ getInitialLevelsMemory(maxLength);
+ } else {
+ mayAllocateText = true;
+ }
+
+ if (maxRunCount > 0) {
+ // if maxRunCount == 1, use simpleRuns[]
+ if (maxRunCount > 1) {
+ getInitialRunsMemory(maxRunCount);
+ }
+ } else {
+ mayAllocateRuns = true;
+ }
+ }
+
+ /*
+ * We are allowed to allocate memory if object==null or
+ * mayAllocate==true for each array that we need.
+ *
+ * Assume sizeNeeded>0.
+ * If object != null, then assume size > 0.
+ */
+ private Object getMemory(String label, Object array, Class arrayClass,
+ boolean mayAllocate, int sizeNeeded)
+ {
+ int len = Array.getLength(array);
+
+ /* we have at least enough memory and must not allocate */
+ if (sizeNeeded == len) {
+ return array;
+ }
+ if (!mayAllocate) {
+ /* we must not allocate */
+ if (sizeNeeded <= len) {
+ return array;
+ }
+ throw new OutOfMemoryError("Failed to allocate memory for "
+ + label);
+ }
+ /* we may try to grow or shrink */
+ /* FOOD FOR THOUGHT: when shrinking it should be possible to avoid
+ the allocation altogether and rely on this.length */
+ try {
+ return Array.newInstance(arrayClass, sizeNeeded);
+ } catch (Exception e) {
+ throw new OutOfMemoryError("Failed to allocate memory for "
+ + label);
+ }
+ }
+
+ /* helper methods for each allocated array */
+ private void getDirPropsMemory(boolean mayAllocate, int len)
+ {
+ Object array = getMemory("DirProps", dirPropsMemory, Byte.TYPE, mayAllocate, len);
+ dirPropsMemory = (byte[]) array;
+ }
+
+ void getDirPropsMemory(int len)
+ {
+ getDirPropsMemory(mayAllocateText, len);
+ }
+
+ private void getLevelsMemory(boolean mayAllocate, int len)
+ {
+ Object array = getMemory("Levels", levelsMemory, Byte.TYPE, mayAllocate, len);
+ levelsMemory = (byte[]) array;
+ }
+
+ void getLevelsMemory(int len)
+ {
+ getLevelsMemory(mayAllocateText, len);
+ }
+
+ private void getRunsMemory(boolean mayAllocate, int len)
+ {
+ Object array = getMemory("Runs", runsMemory, BidiRun.class, mayAllocate, len);
+ runsMemory = (BidiRun[]) array;
+ }
+
+ void getRunsMemory(int len)
+ {
+ getRunsMemory(mayAllocateRuns, len);
+ }
+
+ /* additional methods used by constructor - always allow allocation */
+ private void getInitialDirPropsMemory(int len)
+ {
+ getDirPropsMemory(true, len);
+ }
+
+ private void getInitialLevelsMemory(int len)
+ {
+ getLevelsMemory(true, len);
+ }
+
+ private void getInitialParasMemory(int len)
+ {
+ Object array = getMemory("Paras", parasMemory, Integer.TYPE, true, len);
+ parasMemory = (int[]) array;
+ }
+
+ private void getInitialRunsMemory(int len)
+ {
+ getRunsMemory(true, len);
+ }
+
+/* perform (P2)..(P3) ------------------------------------------------------- */
+
+ private void getDirProps()
+ {
+ int i = 0, i0, i1;
+ flags = 0; /* collect all directionalities in the text */
+ int uchar;
+ byte dirProp;
+ byte paraDirDefault = 0; /* initialize to avoid compiler warnings */
+ boolean isDefaultLevel = IsDefaultLevel(paraLevel);
+ /* for inverse Bidi, the default para level is set to RTL if there is a
+ strong R or AL character at either end of the text */
+ lastArabicPos = -1;
+ controlCount = 0;
+
+ final int NOT_CONTEXTUAL = 0; /* 0: not contextual paraLevel */
+ final int LOOKING_FOR_STRONG = 1; /* 1: looking for first strong char */
+ final int FOUND_STRONG_CHAR = 2; /* 2: found first strong char */
+
+ int state;
+ int paraStart = 0; /* index of first char in paragraph */
+ byte paraDir; /* == CONTEXT_RTL within paragraphs
+ starting with strong R char */
+ byte lastStrongDir=0; /* for default level & inverse Bidi */
+ int lastStrongLTR=0; /* for STREAMING option */
+
+ if (isDefaultLevel) {
+ paraDirDefault = ((paraLevel & 1) != 0) ? CONTEXT_RTL : 0;
+ paraDir = paraDirDefault;
+ lastStrongDir = paraDirDefault;
+ state = LOOKING_FOR_STRONG;
+ } else {
+ state = NOT_CONTEXTUAL;
+ paraDir = 0;
+ }
+ /* count paragraphs and determine the paragraph level (P2..P3) */
+ /*
+ * see comment on constant fields:
+ * the LEVEL_DEFAULT_XXX values are designed so that
+ * their low-order bit alone yields the intended default
+ */
+
+ for (i = 0; i < originalLength; /* i is incremented in the loop */) {
+ i0 = i; /* index of first code unit */
+ uchar = UTF16.charAt(text, 0, originalLength, i);
+ i += Character.charCount(uchar);
+ i1 = i - 1; /* index of last code unit, gets the directional property */
+
+ dirProp = (byte)bdp.getClass(uchar);
+
+ flags |= DirPropFlag(dirProp);
+ dirProps[i1] = (byte)(dirProp | paraDir);
+ if (i1 > i0) { /* set previous code units' properties to BN */
+ flags |= DirPropFlag(BN);
+ do {
+ dirProps[--i1] = (byte)(BN | paraDir);
+ } while (i1 > i0);
+ }
+ if (state == LOOKING_FOR_STRONG) {
+ if (dirProp == L) {
+ state = FOUND_STRONG_CHAR;
+ if (paraDir != 0) {
+ paraDir = 0;
+ for (i1 = paraStart; i1 < i; i1++) {
+ dirProps[i1] &= ~CONTEXT_RTL;
+ }
+ }
+ continue;
+ }
+ if (dirProp == R || dirProp == AL) {
+ state = FOUND_STRONG_CHAR;
+ if (paraDir == 0) {
+ paraDir = CONTEXT_RTL;
+ for (i1 = paraStart; i1 < i; i1++) {
+ dirProps[i1] |= CONTEXT_RTL;
+ }
+ }
+ continue;
+ }
+ }
+ if (dirProp == L) {
+ lastStrongDir = 0;
+ lastStrongLTR = i; /* i is index to next character */
+ }
+ else if (dirProp == R) {
+ lastStrongDir = CONTEXT_RTL;
+ }
+ else if (dirProp == AL) {
+ lastStrongDir = CONTEXT_RTL;
+ lastArabicPos = i-1;
+ }
+ else if (dirProp == B) {
+ if (i < originalLength) { /* B not last char in text */
+ if (!((uchar == (int)CR) && (text[i] == (int)LF))) {
+ paraCount++;
+ }
+ if (isDefaultLevel) {
+ state=LOOKING_FOR_STRONG;
+ paraStart = i; /* i is index to next character */
+ paraDir = paraDirDefault;
+ lastStrongDir = paraDirDefault;
+ }
+ }
+ }
+ }
+ if (isDefaultLevel) {
+ paraLevel = GetParaLevelAt(0);
+ }
+
+ /* The following line does nothing new for contextual paraLevel, but is
+ needed for absolute paraLevel. */
+ flags |= DirPropFlagLR(paraLevel);
+
+ if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) {
+ flags |= DirPropFlag(L);
+ }
+ }
+
+ /* perform (X1)..(X9) ------------------------------------------------------- */
+
+ /* determine if the text is mixed-directional or single-directional */
+ private byte directionFromFlags() {
+ /* if the text contains AN and neutrals, then some neutrals may become RTL */
+ if (!((flags & MASK_RTL) != 0 ||
+ ((flags & DirPropFlag(AN)) != 0 &&
+ (flags & MASK_POSSIBLE_N) != 0))) {
+ return Bidi.DIRECTION_LEFT_TO_RIGHT;
+ } else if ((flags & MASK_LTR) == 0) {
+ return Bidi.DIRECTION_RIGHT_TO_LEFT;
+ } else {
+ return MIXED;
+ }
+ }
+
+ /*
+ * Resolve the explicit levels as specified by explicit embedding codes.
+ * Recalculate the flags to have them reflect the real properties
+ * after taking the explicit embeddings into account.
+ *
+ * The Bidi algorithm is designed to result in the same behavior whether embedding
+ * levels are externally specified (from "styled text", supposedly the preferred
+ * method) or set by explicit embedding codes (LRx, RLx, PDF) in the plain text.
+ * That is why (X9) instructs to remove all explicit codes (and BN).
+ * However, in a real implementation, this removal of these codes and their index
+ * positions in the plain text is undesirable since it would result in
+ * reallocated, reindexed text.
+ * Instead, this implementation leaves the codes in there and just ignores them
+ * in the subsequent processing.
+ * In order to get the same reordering behavior, positions with a BN or an
+ * explicit embedding code just get the same level assigned as the last "real"
+ * character.
+ *
+ * Some implementations, not this one, then overwrite some of these
+ * directionality properties at "real" same-level-run boundaries by
+ * L or R codes so that the resolution of weak types can be performed on the
+ * entire paragraph at once instead of having to parse it once more and
+ * perform that resolution on same-level-runs.
+ * This limits the scope of the implicit rules in effectively
+ * the same way as the run limits.
+ *
+ * Instead, this implementation does not modify these codes.
+ * On one hand, the paragraph has to be scanned for same-level-runs, but
+ * on the other hand, this saves another loop to reset these codes,
+ * or saves making and modifying a copy of dirProps[].
+ *
+ *
+ * Note that (Pn) and (Xn) changed significantly from version 4 of the Bidi algorithm.
+ *
+ *
+ * Handling the stack of explicit levels (Xn):
+ *
+ * With the Bidi stack of explicit levels,
+ * as pushed with each LRE, RLE, LRO, and RLO and popped with each PDF,
+ * the explicit level must never exceed MAX_EXPLICIT_LEVEL==61.
+ *
+ * In order to have a correct push-pop semantics even in the case of overflows,
+ * there are two overflow counters:
+ * - countOver60 is incremented with each LRx at level 60
+ * - from level 60, one RLx increases the level to 61
+ * - countOver61 is incremented with each LRx and RLx at level 61
+ *
+ * Popping levels with PDF must work in the opposite order so that level 61
+ * is correct at the correct point. Underflows (too many PDFs) must be checked.
+ *
+ * This implementation assumes that MAX_EXPLICIT_LEVEL is odd.
+ */
+ private byte resolveExplicitLevels() {
+ int i = 0;
+ byte dirProp;
+ byte level = GetParaLevelAt(0);
+
+ byte dirct;
+ int paraIndex = 0;
+
+ /* determine if the text is mixed-directional or single-directional */
+ dirct = directionFromFlags();
+
+ /* we may not need to resolve any explicit levels, but for multiple
+ paragraphs we want to loop on all chars to set the para boundaries */
+ if ((dirct != MIXED) && (paraCount == 1)) {
+ /* not mixed directionality: levels don't matter - trailingWSStart will be 0 */
+ } else if ((paraCount == 1) &&
+ ((flags & MASK_EXPLICIT) == 0)) {
+ /* mixed, but all characters are at the same embedding level */
+ /* or we are in "inverse Bidi" */
+ /* and we don't have contextual multiple paragraphs with some B char */
+ /* set all levels to the paragraph level */
+ for (i = 0; i < length; ++i) {
+ levels[i] = level;
+ }
+ } else {
+ /* continue to perform (Xn) */
+
+ /* (X1) level is set for all codes, embeddingLevel keeps track of the push/pop operations */
+ /* both variables may carry the LEVEL_OVERRIDE flag to indicate the override status */
+ byte embeddingLevel = level;
+ byte newLevel;
+ byte stackTop = 0;
+
+ byte[] stack = new byte[MAX_EXPLICIT_LEVEL]; /* we never push anything >=MAX_EXPLICIT_LEVEL */
+ int countOver60 = 0;
+ int countOver61 = 0; /* count overflows of explicit levels */
+
+ /* recalculate the flags */
+ flags = 0;
+
+ for (i = 0; i < length; ++i) {
+ dirProp = NoContextRTL(dirProps[i]);
+ switch(dirProp) {
+ case LRE:
+ case LRO:
+ /* (X3, X5) */
+ newLevel = (byte)((embeddingLevel+2) & ~(INTERNAL_LEVEL_OVERRIDE | 1)); /* least greater even level */
+ if (newLevel <= MAX_EXPLICIT_LEVEL) {
+ stack[stackTop] = embeddingLevel;
+ ++stackTop;
+ embeddingLevel = newLevel;
+ if (dirProp == LRO) {
+ embeddingLevel |= INTERNAL_LEVEL_OVERRIDE;
+ }
+ /* we don't need to set LEVEL_OVERRIDE off for LRE
+ since this has already been done for newLevel which is
+ the source for embeddingLevel.
+ */
+ } else if ((embeddingLevel & ~INTERNAL_LEVEL_OVERRIDE) == MAX_EXPLICIT_LEVEL) {
+ ++countOver61;
+ } else /* (embeddingLevel & ~INTERNAL_LEVEL_OVERRIDE) == MAX_EXPLICIT_LEVEL-1 */ {
+ ++countOver60;
+ }
+ flags |= DirPropFlag(BN);
+ break;
+ case RLE:
+ case RLO:
+ /* (X2, X4) */
+ newLevel=(byte)(((embeddingLevel & ~INTERNAL_LEVEL_OVERRIDE) + 1) | 1); /* least greater odd level */
+ if (newLevel<=MAX_EXPLICIT_LEVEL) {
+ stack[stackTop] = embeddingLevel;
+ ++stackTop;
+ embeddingLevel = newLevel;
+ if (dirProp == RLO) {
+ embeddingLevel |= INTERNAL_LEVEL_OVERRIDE;
+ }
+ /* we don't need to set LEVEL_OVERRIDE off for RLE
+ since this has already been done for newLevel which is
+ the source for embeddingLevel.
+ */
+ } else {
+ ++countOver61;
+ }
+ flags |= DirPropFlag(BN);
+ break;
+ case PDF:
+ /* (X7) */
+ /* handle all the overflow cases first */
+ if (countOver61 > 0) {
+ --countOver61;
+ } else if (countOver60 > 0 && (embeddingLevel & ~INTERNAL_LEVEL_OVERRIDE) != MAX_EXPLICIT_LEVEL) {
+ /* handle LRx overflows from level 60 */
+ --countOver60;
+ } else if (stackTop > 0) {
+ /* this is the pop operation; it also pops level 61 while countOver60>0 */
+ --stackTop;
+ embeddingLevel = stack[stackTop];
+ /* } else { (underflow) */
+ }
+ flags |= DirPropFlag(BN);
+ break;
+ case B:
+ stackTop = 0;
+ countOver60 = 0;
+ countOver61 = 0;
+ level = GetParaLevelAt(i);
+ if ((i + 1) < length) {
+ embeddingLevel = GetParaLevelAt(i+1);
+ if (!((text[i] == CR) && (text[i + 1] == LF))) {
+ paras[paraIndex++] = i+1;
+ }
+ }
+ flags |= DirPropFlag(B);
+ break;
+ case BN:
+ /* BN, LRE, RLE, and PDF are supposed to be removed (X9) */
+ /* they will get their levels set correctly in adjustWSLevels() */
+ flags |= DirPropFlag(BN);
+ break;
+ default:
+ /* all other types get the "real" level */
+ if (level != embeddingLevel) {
+ level = embeddingLevel;
+ if ((level & INTERNAL_LEVEL_OVERRIDE) != 0) {
+ flags |= DirPropFlagO(level) | DirPropFlagMultiRuns;
+ } else {
+ flags |= DirPropFlagE(level) | DirPropFlagMultiRuns;
+ }
+ }
+ if ((level & INTERNAL_LEVEL_OVERRIDE) == 0) {
+ flags |= DirPropFlag(dirProp);
+ }
+ break;
+ }
+
+ /*
+ * We need to set reasonable levels even on BN codes and
+ * explicit codes because we will later look at same-level runs (X10).
+ */
+ levels[i] = level;
+ }
+ if ((flags & MASK_EMBEDDING) != 0) {
+ flags |= DirPropFlagLR(paraLevel);
+ }
+ if (orderParagraphsLTR && (flags & DirPropFlag(B)) != 0) {
+ flags |= DirPropFlag(L);
+ }
+
+ /* subsequently, ignore the explicit codes and BN (X9) */
+
+ /* again, determine if the text is mixed-directional or single-directional */
+ dirct = directionFromFlags();
+ }
+
+ return dirct;
+ }
+
+ /*
+ * Use a pre-specified embedding levels array:
+ *
+ * Adjust the directional properties for overrides (->LEVEL_OVERRIDE),
+ * ignore all explicit codes (X9),
+ * and check all the preset levels.
+ *
+ * Recalculate the flags to have them reflect the real properties
+ * after taking the explicit embeddings into account.
+ */
+ private byte checkExplicitLevels() {
+ byte dirProp;
+ int i;
+ this.flags = 0; /* collect all directionalities in the text */
+ byte level;
+ int paraIndex = 0;
+
+ for (i = 0; i < length; ++i) {
+ if (levels[i] == 0) {
+ levels[i] = paraLevel;
+ }
+ if (MAX_EXPLICIT_LEVEL < (levels[i]&0x7f)) {
+ if ((levels[i] & INTERNAL_LEVEL_OVERRIDE) != 0) {
+ levels[i] = (byte)(paraLevel|INTERNAL_LEVEL_OVERRIDE);
+ } else {
+ levels[i] = paraLevel;
+ }
+ }
+ level = levels[i];
+ dirProp = NoContextRTL(dirProps[i]);
+ if ((level & INTERNAL_LEVEL_OVERRIDE) != 0) {
+ /* keep the override flag in levels[i] but adjust the flags */
+ level &= ~INTERNAL_LEVEL_OVERRIDE; /* make the range check below simpler */
+ flags |= DirPropFlagO(level);
+ } else {
+ /* set the flags */
+ flags |= DirPropFlagE(level) | DirPropFlag(dirProp);
+ }
+
+ if ((level < GetParaLevelAt(i) &&
+ !((0 == level) && (dirProp == B))) ||
+ (MAX_EXPLICIT_LEVEL = 0) {
+ addPoint(levState.startL2EN, LRM_BEFORE);
+ }
+ levState.startL2EN = -1; /* not within previous if since could also be -2 */
+ /* check if we had any relevant EN/AN after R/AL */
+ if ((insertPoints.points.length == 0) ||
+ (insertPoints.size <= insertPoints.confirmed)) {
+ /* nothing, just clean up */
+ levState.lastStrongRTL = -1;
+ /* check if we have a pending conditional segment */
+ level = (byte)impTab[oldStateSeq][IMPTABLEVELS_RES];
+ if ((level & 1) != 0 && levState.startON > 0) { /* after ON */
+ start = levState.startON; /* reset to basic run level */
+ }
+ if (_prop == _S) { /* add LRM before S */
+ addPoint(start0, LRM_BEFORE);
+ insertPoints.confirmed = insertPoints.size;
+ }
+ break;
+ }
+ /* reset previous RTL cont to level for LTR text */
+ for (k = levState.lastStrongRTL + 1; k < start0; k++) {
+ /* reset odd level, leave runLevel+2 as is */
+ levels[k] = (byte)((levels[k] - 2) & ~1);
+ }
+ /* mark insert points as confirmed */
+ insertPoints.confirmed = insertPoints.size;
+ levState.lastStrongRTL = -1;
+ if (_prop == _S) { /* add LRM before S */
+ addPoint(start0, LRM_BEFORE);
+ insertPoints.confirmed = insertPoints.size;
+ }
+ break;
+
+ case 4: /* R/AL after possible relevant EN/AN */
+ /* just clean up */
+ if (insertPoints.points.length > 0)
+ /* remove all non confirmed insert points */
+ insertPoints.size = insertPoints.confirmed;
+ levState.startON = -1;
+ levState.startL2EN = -1;
+ levState.lastStrongRTL = limit - 1;
+ break;
+
+ case 5: /* EN/AN after R/AL + possible cont */
+ /* check for real AN */
+ if ((_prop == _AN) && (NoContextRTL(dirProps[start0]) == AN)) {
+ /* real AN */
+ if (levState.startL2EN == -1) { /* if no relevant EN already found */
+ /* just note the righmost digit as a strong RTL */
+ levState.lastStrongRTL = limit - 1;
+ break;
+ }
+ if (levState.startL2EN >= 0) { /* after EN, no AN */
+ addPoint(levState.startL2EN, LRM_BEFORE);
+ levState.startL2EN = -2;
+ }
+ /* note AN */
+ addPoint(start0, LRM_BEFORE);
+ break;
+ }
+ /* if first EN/AN after R/AL */
+ if (levState.startL2EN == -1) {
+ levState.startL2EN = start0;
+ }
+ break;
+
+ case 6: /* note location of latest R/AL */
+ levState.lastStrongRTL = limit - 1;
+ levState.startON = -1;
+ break;
+
+ case 7: /* L after R+ON/EN/AN */
+ /* include possible adjacent number on the left */
+ for (k = start0-1; k >= 0 && ((levels[k] & 1) == 0); k--) {
+ }
+ if (k >= 0) {
+ addPoint(k, RLM_BEFORE); /* add RLM before */
+ insertPoints.confirmed = insertPoints.size; /* confirm it */
+ }
+ levState.startON = start0;
+ break;
+
+ case 8: /* AN after L */
+ /* AN numbers between L text on both sides may be trouble. */
+ /* tentatively bracket with LRMs; will be confirmed if followed by L */
+ addPoint(start0, LRM_BEFORE); /* add LRM before */
+ addPoint(start0, LRM_AFTER); /* add LRM after */
+ break;
+
+ case 9: /* R after L+ON/EN/AN */
+ /* false alert, infirm LRMs around previous AN */
+ insertPoints.size=insertPoints.confirmed;
+ if (_prop == _S) { /* add RLM before S */
+ addPoint(start0, RLM_BEFORE);
+ insertPoints.confirmed = insertPoints.size;
+ }
+ break;
+
+ case 10: /* L after L+ON/AN */
+ level = (byte)(levState.runLevel + addLevel);
+ for (k=levState.startON; k < start0; k++) {
+ if (levels[k] < level) {
+ levels[k] = level;
+ }
+ }
+ insertPoints.confirmed = insertPoints.size; /* confirm inserts */
+ levState.startON = start0;
+ break;
+
+ case 11: /* L after L+ON+EN/AN/ON */
+ level = (byte)levState.runLevel;
+ for (k = start0-1; k >= levState.startON; k--) {
+ if (levels[k] == level+3) {
+ while (levels[k] == level+3) {
+ levels[k--] -= 2;
+ }
+ while (levels[k] == level) {
+ k--;
+ }
+ }
+ if (levels[k] == level+2) {
+ levels[k] = level;
+ continue;
+ }
+ levels[k] = (byte)(level+1);
+ }
+ break;
+
+ case 12: /* R after L+ON+EN/AN/ON */
+ level = (byte)(levState.runLevel+1);
+ for (k = start0-1; k >= levState.startON; k--) {
+ if (levels[k] > level) {
+ levels[k] -= 2;
+ }
+ }
+ break;
+
+ default: /* we should never get here */
+ throw new IllegalStateException("Internal ICU error in processPropertySeq");
+ }
+ }
+ if ((addLevel) != 0 || (start < start0)) {
+ level = (byte)(levState.runLevel + addLevel);
+ for (k = start; k < limit; k++) {
+ levels[k] = level;
+ }
+ }
+ }
+
+ private void resolveImplicitLevels(int start, int limit, short sor, short eor)
+ {
+ LevState levState = new LevState();
+ int i, start1, start2;
+ short oldStateImp, stateImp, actionImp;
+ short gprop, resProp, cell;
+ short nextStrongProp = R;
+ int nextStrongPos = -1;
+
+
+ /* check for RTL inverse Bidi mode */
+ /* FOOD FOR THOUGHT: in case of RTL inverse Bidi, it would make sense to
+ * loop on the text characters from end to start.
+ * This would need a different properties state table (at least different
+ * actions) and different levels state tables (maybe very similar to the
+ * LTR corresponding ones.
+ */
+ /* initialize for levels state table */
+ levState.startL2EN = -1; /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */
+ levState.lastStrongRTL = -1; /* used for INVERSE_LIKE_DIRECT_WITH_MARKS */
+ levState.state = 0;
+ levState.runLevel = levels[start];
+ levState.impTab = impTabPair.imptab[levState.runLevel & 1];
+ levState.impAct = impTabPair.impact[levState.runLevel & 1];
+ processPropertySeq(levState, (short)sor, start, start);
+ /* initialize for property state table */
+ if (dirProps[start] == NSM) {
+ stateImp = (short)(1 + sor);
+ } else {
+ stateImp = 0;
+ }
+ start1 = start;
+ start2 = 0;
+
+ for (i = start; i <= limit; i++) {
+ if (i >= limit) {
+ gprop = eor;
+ } else {
+ short prop, prop1;
+ prop = NoContextRTL(dirProps[i]);
+ gprop = groupProp[prop];
+ }
+ oldStateImp = stateImp;
+ cell = impTabProps[oldStateImp][gprop];
+ stateImp = GetStateProps(cell); /* isolate the new state */
+ actionImp = GetActionProps(cell); /* isolate the action */
+ if ((i == limit) && (actionImp == 0)) {
+ /* there is an unprocessed sequence if its property == eor */
+ actionImp = 1; /* process the last sequence */
+ }
+ if (actionImp != 0) {
+ resProp = impTabProps[oldStateImp][IMPTABPROPS_RES];
+ switch (actionImp) {
+ case 1: /* process current seq1, init new seq1 */
+ processPropertySeq(levState, resProp, start1, i);
+ start1 = i;
+ break;
+ case 2: /* init new seq2 */
+ start2 = i;
+ break;
+ case 3: /* process seq1, process seq2, init new seq1 */
+ processPropertySeq(levState, resProp, start1, start2);
+ processPropertySeq(levState, _ON, start2, i);
+ start1 = i;
+ break;
+ case 4: /* process seq1, set seq1=seq2, init new seq2 */
+ processPropertySeq(levState, resProp, start1, start2);
+ start1 = start2;
+ start2 = i;
+ break;
+ default: /* we should never get here */
+ throw new IllegalStateException("Internal ICU error in resolveImplicitLevels");
+ }
+ }
+ }
+ /* flush possible pending sequence, e.g. ON */
+ processPropertySeq(levState, (short)eor, limit, limit);
+ }
+
+ /* perform (L1) and (X9) ---------------------------------------------------- */
+
+ /*
+ * Reset the embedding levels for some non-graphic characters (L1).
+ * This method also sets appropriate levels for BN, and
+ * explicit embedding types that are supposed to have been removed
+ * from the paragraph in (X9).
+ */
+ private void adjustWSLevels() {
+ int i;
+
+ if ((flags & MASK_WS) != 0) {
+ int flag;
+ i = trailingWSStart;
+ while (i > 0) {
+ /* reset a sequence of WS/BN before eop and B/S to the paragraph paraLevel */
+ while (i > 0 && ((flag = DirPropFlagNC(dirProps[--i])) & MASK_WS) != 0) {
+ if (orderParagraphsLTR && (flag & DirPropFlag(B)) != 0) {
+ levels[i] = 0;
+ } else {
+ levels[i] = GetParaLevelAt(i);
+ }
+ }
+
+ /* reset BN to the next character's paraLevel until B/S, which restarts above loop */
+ /* here, i+1 is guaranteed to be
+ * For example, in pure LTR text with numbers the numbers would get
+ * a resolved level of 2 higher than the surrounding text according to
+ * the algorithm. This implementation may set all resolved levels to
+ * the same value in such a case.String, it is
+ * stored internally as an array of characters. Therefore the
+ * documentation will refer to indexes of the characters in the text.
+ *
+ * @param text contains the text that the Bidi algorithm will be performed
+ * on. This text can be retrieved with getText() or
+ * getTextAsString.
+ *
+ * @param paraLevel specifies the default level for the text;
+ * it is typically 0 (LTR) or 1 (RTL).
+ * If the method shall determine the paragraph level from the text,
+ * then paraLevel can be set to
+ * either LEVEL_DEFAULT_LTR
+ * or LEVEL_DEFAULT_RTL; if the text contains multiple
+ * paragraphs, the paragraph level shall be determined separately for
+ * each paragraph; if a paragraph does not include any strongly typed
+ * character, then the desired default is used (0 for LTR or 1 for RTL).
+ * Any other value between 0 and MAX_EXPLICIT_LEVEL
+ * is also valid, with odd levels indicating RTL.
+ *
+ * @param embeddingLevels (in) may be used to preset the embedding and override levels,
+ * ignoring characters like LRE and PDF in the text.
+ * A level overrides the directional property of its corresponding
+ * (same index) character if the level has the
+ * LEVEL_OVERRIDE bit set.
+ * Except for that bit, it must be
+ * paraLevel<=embeddingLevels[]<=MAX_EXPLICIT_LEVEL,
+ * with one exception: a level of zero may be specified for a
+ * paragraph separator even if paraLevel>0 when multiple
+ * paragraphs are submitted in the same call to setPara().
+ * Caution: A reference to this array, not a copy
+ * of the levels, will be stored in the Bidi object;
+ * the embeddingLevels
+ * should not be modified to avoid unexpected results on subsequent
+ * Bidi operations. However, the setPara() and
+ * setLine() methods may modify some or all of the
+ * levels.
+ * Note: the embeddingLevels array must
+ * have one entry for each character in text.
+ *
+ * @throws IllegalArgumentException if the values in embeddingLevels are
+ * not within the allowed range
+ *
+ * @see #LEVEL_DEFAULT_LTR
+ * @see #LEVEL_DEFAULT_RTL
+ * @see #LEVEL_OVERRIDE
+ * @see #MAX_EXPLICIT_LEVEL
+ * @stable ICU 3.8
+ */
+ void setPara(String text, byte paraLevel, byte[] embeddingLevels)
+ {
+ if (text == null) {
+ setPara(new char[0], paraLevel, embeddingLevels);
+ } else {
+ setPara(text.toCharArray(), paraLevel, embeddingLevels);
+ }
+ }
+
+ /**
+ * Perform the Unicode Bidi algorithm. It is defined in the
+ * Unicode Standard Annex #9,
+ * version 13,
+ * also described in The Unicode Standard, Version 4.0 .
+ * For example, in pure LTR text with numbers the numbers would get
+ * a resolved level of 2 higher than the surrounding text according to
+ * the algorithm. This implementation may set all resolved levels to
+ * the same value in such a case.getText() or
+ * getTextAsString.
+ *
+ * @param paraLevel specifies the default level for the text;
+ * it is typically 0 (LTR) or 1 (RTL).
+ * If the method shall determine the paragraph level from the text,
+ * then paraLevel can be set to
+ * either LEVEL_DEFAULT_LTR
+ * or LEVEL_DEFAULT_RTL; if the text contains multiple
+ * paragraphs, the paragraph level shall be determined separately for
+ * each paragraph; if a paragraph does not include any strongly typed
+ * character, then the desired default is used (0 for LTR or 1 for RTL).
+ * Any other value between 0 and MAX_EXPLICIT_LEVEL
+ * is also valid, with odd levels indicating RTL.
+ *
+ * @param embeddingLevels (in) may be used to preset the embedding and
+ * override levels, ignoring characters like LRE and PDF in the text.
+ * A level overrides the directional property of its corresponding
+ * (same index) character if the level has the
+ * LEVEL_OVERRIDE bit set.
+ * Except for that bit, it must be
+ * paraLevel<=embeddingLevels[]<=MAX_EXPLICIT_LEVEL,
+ * with one exception: a level of zero may be specified for a
+ * paragraph separator even if paraLevel>0 when multiple
+ * paragraphs are submitted in the same call to setPara().
+ * Caution: A reference to this array, not a copy
+ * of the levels, will be stored in the Bidi object;
+ * the embeddingLevels
+ * should not be modified to avoid unexpected results on subsequent
+ * Bidi operations. However, the setPara() and
+ * setLine() methods may modify some or all of the
+ * levels.
+ * Note: the embeddingLevels array must
+ * have one entry for each character in text.
+ *
+ * @throws IllegalArgumentException if the values in embeddingLevels are
+ * not within the allowed range
+ *
+ * @see #LEVEL_DEFAULT_LTR
+ * @see #LEVEL_DEFAULT_RTL
+ * @see #LEVEL_OVERRIDE
+ * @see #MAX_EXPLICIT_LEVEL
+ * @stable ICU 3.8
+ */
+ public void setPara(char[] chars, byte paraLevel, byte[] embeddingLevels)
+ {
+ /* check the argument values */
+ if (paraLevel < INTERNAL_LEVEL_DEFAULT_LTR) {
+ verifyRange(paraLevel, 0, MAX_EXPLICIT_LEVEL + 1);
+ }
+ if (chars == null) {
+ chars = new char[0];
+ }
+
+ /* initialize the Bidi object */
+ this.paraBidi = null; /* mark unfinished setPara */
+ this.text = chars;
+ this.length = this.originalLength = this.resultLength = text.length;
+ this.paraLevel = paraLevel;
+ this.direction = Bidi.DIRECTION_LEFT_TO_RIGHT;
+ this.paraCount = 1;
+
+ /* Allocate zero-length arrays instead of setting to null here; then
+ * checks for null in various places can be eliminated.
+ */
+ dirProps = new byte[0];
+ levels = new byte[0];
+ runs = new BidiRun[0];
+ isGoodLogicalToVisualRunsMap = false;
+ insertPoints.size = 0; /* clean up from last call */
+ insertPoints.confirmed = 0; /* clean up from last call */
+
+ /*
+ * Save the original paraLevel if contextual; otherwise, set to 0.
+ */
+ if (IsDefaultLevel(paraLevel)) {
+ defaultParaLevel = paraLevel;
+ } else {
+ defaultParaLevel = 0;
+ }
+
+ if (length == 0) {
+ /*
+ * For an empty paragraph, create a Bidi object with the paraLevel and
+ * the flags and the direction set but without allocating zero-length arrays.
+ * There is nothing more to do.
+ */
+ if (IsDefaultLevel(paraLevel)) {
+ this.paraLevel &= 1;
+ defaultParaLevel = 0;
+ }
+ if ((this.paraLevel & 1) != 0) {
+ flags = DirPropFlag(R);
+ direction = Bidi.DIRECTION_RIGHT_TO_LEFT;
+ } else {
+ flags = DirPropFlag(L);
+ direction = Bidi.DIRECTION_LEFT_TO_RIGHT;
+ }
+
+ runCount = 0;
+ paraCount = 0;
+ paraBidi = this; /* mark successful setPara */
+ return;
+ }
+
+ runCount = -1;
+
+ /*
+ * Get the directional properties,
+ * the flags bit-set, and
+ * determine the paragraph level if necessary.
+ */
+ getDirPropsMemory(length);
+ dirProps = dirPropsMemory;
+ getDirProps();
+
+ /* the processed length may have changed if OPTION_STREAMING is set */
+ trailingWSStart = length; /* the levels[] will reflect the WS run */
+
+ /* allocate paras memory */
+ if (paraCount > 1) {
+ getInitialParasMemory(paraCount);
+ paras = parasMemory;
+ paras[paraCount - 1] = length;
+ } else {
+ /* initialize paras for single paragraph */
+ paras = simpleParas;
+ simpleParas[0] = length;
+ }
+
+ /* are explicit levels specified? */
+ if (embeddingLevels == null) {
+ /* no: determine explicit levels according to the (Xn) rules */
+ getLevelsMemory(length);
+ levels = levelsMemory;
+ direction = resolveExplicitLevels();
+ } else {
+ /* set BN for all explicit codes, check that all levels are 0 or paraLevel..MAX_EXPLICIT_LEVEL */
+ levels = embeddingLevels;
+ direction = checkExplicitLevels();
+ }
+
+ /*
+ * The steps after (X9) in the Bidi algorithm are performed only if
+ * the paragraph text has mixed directionality!
+ */
+ switch (direction) {
+ case Bidi.DIRECTION_LEFT_TO_RIGHT:
+ /* make sure paraLevel is even */
+ paraLevel = (byte)((paraLevel + 1) & ~1);
+
+ /* all levels are implicitly at paraLevel (important for getLevels()) */
+ trailingWSStart = 0;
+ break;
+ case Bidi.DIRECTION_RIGHT_TO_LEFT:
+ /* make sure paraLevel is odd */
+ paraLevel |= 1;
+
+ /* all levels are implicitly at paraLevel (important for getLevels()) */
+ trailingWSStart = 0;
+ break;
+ default:
+ this.impTabPair = impTab_DEFAULT;
+
+ /*
+ * If there are no external levels specified and there
+ * are no significant explicit level codes in the text,
+ * then we can treat the entire paragraph as one run.
+ * Otherwise, we need to perform the following rules on runs of
+ * the text with the same embedding levels. (X10)
+ * "Significant" explicit level codes are ones that actually
+ * affect non-BN characters.
+ * Examples for "insignificant" ones are empty embeddings
+ * LRE-PDF, LRE-RLE-PDF-PDF, etc.
+ */
+ if (embeddingLevels == null && paraCount <= 1 &&
+ (flags & DirPropFlagMultiRuns) == 0) {
+ resolveImplicitLevels(0, length,
+ GetLRFromLevel(GetParaLevelAt(0)),
+ GetLRFromLevel(GetParaLevelAt(length - 1)));
+ } else {
+ /* sor, eor: start and end types of same-level-run */
+ int start, limit = 0;
+ byte level, nextLevel;
+ short sor, eor;
+
+ /* determine the first sor and set eor to it because of the loop body (sor=eor there) */
+ level = GetParaLevelAt(0);
+ nextLevel = levels[0];
+ if (level < nextLevel) {
+ eor = GetLRFromLevel(nextLevel);
+ } else {
+ eor = GetLRFromLevel(level);
+ }
+
+ do {
+ /* determine start and limit of the run (end points just behind the run) */
+
+ /* the values for this run's start are the same as for the previous run's end */
+ start = limit;
+ level = nextLevel;
+ if ((start > 0) && (NoContextRTL(dirProps[start - 1]) == B)) {
+ /* except if this is a new paragraph, then set sor = para level */
+ sor = GetLRFromLevel(GetParaLevelAt(start));
+ } else {
+ sor = eor;
+ }
+
+ /* search for the limit of this run */
+ while (++limit < length && levels[limit] == level) {}
+
+ /* get the correct level of the next run */
+ if (limit < length) {
+ nextLevel = levels[limit];
+ } else {
+ nextLevel = GetParaLevelAt(length - 1);
+ }
+
+ /* determine eor from max(level, nextLevel); sor is last run's eor */
+ if ((level & ~INTERNAL_LEVEL_OVERRIDE) < (nextLevel & ~INTERNAL_LEVEL_OVERRIDE)) {
+ eor = GetLRFromLevel(nextLevel);
+ } else {
+ eor = GetLRFromLevel(level);
+ }
+
+ /* if the run consists of overridden directional types, then there
+ are no implicit types to be resolved */
+ if ((level & INTERNAL_LEVEL_OVERRIDE) == 0) {
+ resolveImplicitLevels(start, limit, sor, eor);
+ } else {
+ /* remove the LEVEL_OVERRIDE flags */
+ do {
+ levels[start++] &= ~INTERNAL_LEVEL_OVERRIDE;
+ } while (start < limit);
+ }
+ } while (limit < length);
+ }
+
+ /* reset the embedding levels for some non-graphic characters (L1), (X9) */
+ adjustWSLevels();
+
+ break;
+ }
+
+ resultLength += insertPoints.size;
+ paraBidi = this; /* mark successful setPara */
+ }
+
+ /**
+ * Perform the Unicode Bidi algorithm on a given paragraph, as defined in the
+ * Unicode Standard Annex #9,
+ * version 13,
+ * also described in The Unicode Standard, Version 4.0 .
+ * For example, in pure LTR text with numbers the numbers would get
+ * a resolved level of 2 higher than the surrounding text according to
+ * the algorithm. This implementation may set all resolved levels to
+ * the same value in such a case.setPara().
+ * Paragraph separators (B) may appear in the text. Setting them to level zero
+ * means that all paragraph separators (including one possibly appearing
+ * in the last text position) are kept in the reordered text after the text
+ * that they follow in the source text.
+ * When this feature is not enabled, a paragraph separator at the last
+ * position of the text before reordering will go to the first position
+ * of the reordered text when the paragraph level is odd.
+ *
+ * @param ordarParaLTR specifies whether paragraph separators (B) must
+ * receive level 0, so that successive paragraphs progress from left to right.
+ *
+ * @see #setPara
+ * @stable ICU 3.8
+ */
+ private void orderParagraphsLTR(boolean ordarParaLTR) {
+ orderParagraphsLTR = ordarParaLTR;
+ }
+
+ /**
+ * Get the directionality of the text.
+ *
+ * @return a value of LTR, RTL or MIXED
+ * that indicates if the entire text
+ * represented by this object is unidirectional,
+ * and which direction, or if it is mixed-directional.
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ *
+ * @see #LTR
+ * @see #RTL
+ * @see #MIXED
+ * @stable ICU 3.8
+ */
+ private byte getDirection()
+ {
+ verifyValidParaOrLine();
+ return direction;
+ }
+
+ /**
+ * Get the length of the text.
+ *
+ * @return The length of the text that the Bidi object was
+ * created for.
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ * @stable ICU 3.8
+ */
+ public int getLength()
+ {
+ verifyValidParaOrLine();
+ return originalLength;
+ }
+
+ /* paragraphs API methods ------------------------------------------------- */
+
+ /**
+ * Get the paragraph level of the text.
+ *
+ * @return The paragraph level. If there are multiple paragraphs, their
+ * level may vary if the required paraLevel is LEVEL_DEFAULT_LTR or
+ * LEVEL_DEFAULT_RTL. In that case, the level of the first paragraph
+ * is returned.
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ *
+ * @see #LEVEL_DEFAULT_LTR
+ * @see #LEVEL_DEFAULT_RTL
+ * @see #getParagraph
+ * @see #getParagraphByIndex
+ * @stable ICU 3.8
+ */
+ public byte getParaLevel()
+ {
+ verifyValidParaOrLine();
+ return paraLevel;
+ }
+
+ /**
+ * Get the index of a paragraph, given a position within the text.[0..getProcessedLength()-1].
+ *
+ * @return The index of the paragraph containing the specified position,
+ * starting from 0.
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ * @throws IllegalArgumentException if charIndex is not within the legal range
+ *
+ * @see com.ibm.icu.text.BidiRun
+ * @see #getProcessedLength
+ * @stable ICU 3.8
+ */
+ public int getParagraphIndex(int charIndex)
+ {
+ verifyValidParaOrLine();
+ BidiBase bidi = paraBidi; /* get Para object if Line object */
+ verifyRange(charIndex, 0, bidi.length);
+ int paraIndex;
+ for (paraIndex = 0; charIndex >= bidi.paras[paraIndex]; paraIndex++) {
+ }
+ return paraIndex;
+ }
+
+ /**
+ * setLine() returns a Bidi object to
+ * contain the reordering information, especially the resolved levels,
+ * for all the characters in a line of text. This line of text is
+ * specified by referring to a Bidi object representing
+ * this information for a piece of text containing one or more paragraphs,
+ * and by specifying a range of indexes in this text.limit-start-1.setPara()
+ * for a piece of text, and after line-breaking on that text.
+ * It is not necessary if each paragraph is treated as a single line.Bidi object that represents a line.Bidi object may
+ * reference data within the global text Bidi object.
+ * You should not alter the content of the global text object until
+ * you are finished using the line object.
+ *
+ * @param start is the line's first index into the text.
+ *
+ * @param limit is just behind the line's last index into the text
+ * (its last index +1).
+ *
+ * @return a Bidi object that will now represent a line of the text.
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara
+ * @throws IllegalArgumentException if start and limit are not in the range
+ * 0<=start<limit<=getProcessedLength(),
+ * or if the specified line crosses a paragraph boundary
+ *
+ * @see #setPara
+ * @see #getProcessedLength
+ * @stable ICU 3.8
+ */
+ public Bidi setLine(Bidi bidi, BidiBase bidiBase, Bidi newBidi, BidiBase newBidiBase, int start, int limit)
+ {
+ verifyValidPara();
+ verifyRange(start, 0, limit);
+ verifyRange(limit, 0, length+1);
+ if (getParagraphIndex(start) != getParagraphIndex(limit - 1)) {
+ /* the line crosses a paragraph boundary */
+ throw new IllegalArgumentException();
+ }
+
+ return BidiLine.setLine(bidi, this, newBidi, newBidiBase, start, limit);
+ }
+
+ /**
+ * Get the level for one character.
+ *
+ * @param charIndex the index of a character.
+ *
+ * @return The level for the character at charIndex.
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ * @throws IllegalArgumentException if charIndex is not in the range
+ * 0<=charIndex<getProcessedLength()
+ *
+ * @see #getProcessedLength
+ * @stable ICU 3.8
+ */
+ public byte getLevelAt(int charIndex)
+ {
+ if (charIndex < 0 || charIndex >= length) {
+ return (byte)getBaseLevel();
+ }
+ verifyValidParaOrLine();
+ verifyRange(charIndex, 0, length);
+ return BidiLine.getLevelAt(this, charIndex);
+ }
+
+ /**
+ * Get an array of levels for each character.getLevelAt().
+ *
+ * @return The levels array for the text,
+ * or null if an error occurs.
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ * @stable ICU 3.8
+ */
+ private byte[] getLevels()
+ {
+ verifyValidParaOrLine();
+ if (length <= 0) {
+ return new byte[0];
+ }
+ return BidiLine.getLevels(this);
+ }
+
+ /**
+ * Get the number of runs.
+ * This method may invoke the actual reordering on the
+ * Bidi object, after setPara()
+ * may have resolved only the levels of the text. Therefore,
+ * countRuns() may have to allocate memory,
+ * and may throw an exception if it fails to do so.
+ *
+ * @return The number of runs.
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ * @stable ICU 3.8
+ */
+ public int countRuns()
+ {
+ verifyValidParaOrLine();
+ BidiLine.getRuns(this);
+ return runCount;
+ }
+
+ /**
+ * Get a visual-to-logical index map (array) for the characters in the
+ * Bidi (paragraph or line) object.
+ * MAP_NOWHERE if the
+ * corresponding text characters are Bidi marks inserted in the visual
+ * output by the option OPTION_INSERT_MARKS.
+ * writeReordered() such as INSERT_LRM_FOR_NUMERIC,
+ * KEEP_BASE_COMBINING, OUTPUT_REVERSE,
+ * REMOVE_BIDI_CONTROLS, the logical positions returned may not
+ * be correct. It is advised to use, when possible, reordering options
+ * such as {@link #OPTION_INSERT_MARKS} and {@link #OPTION_REMOVE_CONTROLS}.
+ *
+ * @return an array of getResultLength()
+ * indexes which will reflect the reordering of the characters.
+ * The index map will result in
+ * indexMap[visualIndex]==logicalIndex, where
+ * indexMap represents the returned array.
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ *
+ * @see #getLogicalMap
+ * @see #getLogicalIndex
+ * @see #getResultLength
+ * @see #MAP_NOWHERE
+ * @see #OPTION_INSERT_MARKS
+ * @see #writeReordered
+ * @stable ICU 3.8
+ */
+ private int[] getVisualMap()
+ {
+ /* countRuns() checks successful call to setPara/setLine */
+ countRuns();
+ if (resultLength <= 0) {
+ return new int[0];
+ }
+ return BidiLine.getVisualMap(this);
+ }
+
+ /**
+ * This is a convenience method that does not use a Bidi object.
+ * It is intended to be used for when an application has determined the levels
+ * of objects (character sequences) and just needs to have them reordered (L2).
+ * This is equivalent to using getVisualMap() on a
+ * Bidi object.
+ *
+ * @param levels is an array of levels that have been determined by
+ * the application.
+ *
+ * @return an array of levels.length
+ * indexes which will reflect the reordering of the characters.indexMap[visualIndex]==logicalIndex, where
+ * indexMap represents the returned array.
+ *
+ * @stable ICU 3.8
+ */
+ private static int[] reorderVisual(byte[] levels)
+ {
+ return BidiLine.reorderVisual(levels);
+ }
+
+ /**
+ * Constant indicating that the base direction depends on the first strong
+ * directional character in the text according to the Unicode Bidirectional
+ * Algorithm. If no strong directional character is present, the base
+ * direction is left-to-right.
+ * @stable ICU 3.8
+ */
+ private static final int INTERNAL_DIRECTION_DEFAULT_LEFT_TO_RIGHT = 0x7e;
+
+ /**
+ * Constant indicating that the base direction depends on the first strong
+ * directional character in the text according to the Unicode Bidirectional
+ * Algorithm. If no strong directional character is present, the base
+ * direction is right-to-left.
+ * @stable ICU 3.8
+ */
+ private static final int INTERMAL_DIRECTION_DEFAULT_RIGHT_TO_LEFT = 0x7f;
+
+ /**
+ * Create Bidi from the given text, embedding, and direction information.
+ * The embeddings array may be null. If present, the values represent
+ * embedding level information. Negative values from -1 to -61 indicate
+ * overrides at the absolute value of the level. Positive values from 1 to
+ * 61 indicate embeddings. Where values are zero, the base embedding level
+ * as determined by the base direction is assumed.setPara
+ * @stable ICU 3.8
+ */
+ public boolean isMixed()
+ {
+ return (!isLeftToRight() && !isRightToLeft());
+ }
+
+ /**
+ * Return true if the line is all left-to-right text and the base direction
+ * is left-to-right.
+ *
+ * @return true if the line is all left-to-right text and the base direction
+ * is left-to-right.
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara
+ * @stable ICU 3.8
+ */
+ public boolean isLeftToRight()
+ {
+ return (getDirection() == Bidi.DIRECTION_LEFT_TO_RIGHT && (paraLevel & 1) == 0);
+ }
+
+ /**
+ * Return true if the line is all right-to-left text, and the base direction
+ * is right-to-left
+ *
+ * @return true if the line is all right-to-left text, and the base
+ * direction is right-to-left
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara
+ * @stable ICU 3.8
+ */
+ public boolean isRightToLeft()
+ {
+ return (getDirection() == Bidi.DIRECTION_RIGHT_TO_LEFT && (paraLevel & 1) == 1);
+ }
+
+ /**
+ * Return true if the base direction is left-to-right
+ *
+ * @return true if the base direction is left-to-right
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ *
+ * @stable ICU 3.8
+ */
+ public boolean baseIsLeftToRight()
+ {
+ return (getParaLevel() == Bidi.DIRECTION_LEFT_TO_RIGHT);
+ }
+
+ /**
+ * Return the base level (0 if left-to-right, 1 if right-to-left).
+ *
+ * @return the base level
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ *
+ * @stable ICU 3.8
+ */
+ public int getBaseLevel()
+ {
+ return getParaLevel();
+ }
+
+ /**
+ * Compute the logical to visual run mapping
+ */
+ private void getLogicalToVisualRunsMap()
+ {
+ if (isGoodLogicalToVisualRunsMap) {
+ return;
+ }
+ int count = countRuns();
+ if ((logicalToVisualRunsMap == null) ||
+ (logicalToVisualRunsMap.length < count)) {
+ logicalToVisualRunsMap = new int[count];
+ }
+ int i;
+ long[] keys = new long[count];
+ for (i = 0; i < count; i++) {
+ keys[i] = ((long)(runs[i].start)<<32) + i;
+ }
+ Arrays.sort(keys);
+ for (i = 0; i < count; i++) {
+ logicalToVisualRunsMap[i] = (int)(keys[i] & 0x00000000FFFFFFFF);
+ }
+ keys = null;
+ isGoodLogicalToVisualRunsMap = true;
+ }
+
+ /**
+ * Return the level of the nth logical run in this line.
+ *
+ * @param run the index of the run, between 0 and countRuns()-1
+ *
+ * @return the level of the run
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ * @throws IllegalArgumentException if run is not in
+ * the range 0<=run<countRuns()
+ * @stable ICU 3.8
+ */
+ public int getRunLevel(int run)
+ {
+ verifyValidParaOrLine();
+ BidiLine.getRuns(this);
+ if (runCount == 1) {
+ return getParaLevel();
+ }
+ verifyIndex(run, 0, runCount);
+ getLogicalToVisualRunsMap();
+ return runs[logicalToVisualRunsMap[run]].level;
+ }
+
+ /**
+ * Return the index of the character at the start of the nth logical run in
+ * this line, as an offset from the start of the line.
+ *
+ * @param run the index of the run, between 0 and countRuns()
+ *
+ * @return the start of the run
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ * @throws IllegalArgumentException if run is not in
+ * the range 0<=run<countRuns()
+ * @stable ICU 3.8
+ */
+ public int getRunStart(int run)
+ {
+ verifyValidParaOrLine();
+ BidiLine.getRuns(this);
+ if (runCount == 1) {
+ return 0;
+ } else if (run == runCount) {
+ return length;
+ }
+ verifyIndex(run, 0, runCount);
+ getLogicalToVisualRunsMap();
+ return runs[logicalToVisualRunsMap[run]].start;
+ }
+
+ /**
+ * Return the index of the character past the end of the nth logical run in
+ * this line, as an offset from the start of the line. For example, this
+ * will return the length of the line for the last run on the line.
+ *
+ * @param run the index of the run, between 0 and countRuns()
+ *
+ * @return the limit of the run
+ *
+ * @throws IllegalStateException if this call is not preceded by a successful
+ * call to setPara or setLine
+ * @throws IllegalArgumentException if run is not in
+ * the range 0<=run<countRuns()
+ * @stable ICU 3.8
+ */
+ public int getRunLimit(int run)
+ {
+ verifyValidParaOrLine();
+ BidiLine.getRuns(this);
+ if (runCount == 1) {
+ return length;
+ }
+ verifyIndex(run, 0, runCount);
+ getLogicalToVisualRunsMap();
+ int idx = logicalToVisualRunsMap[run];
+ int len = idx == 0 ? runs[idx].limit :
+ runs[idx].limit - runs[idx-1].limit;
+ return runs[idx].start + len;
+ }
+
+ /**
+ * Return true if the specified text requires bidi analysis. If this returns
+ * false, the text will display left-to-right. Clients can then avoid
+ * constructing a Bidi object. Text in the Arabic Presentation Forms area of
+ * Unicode is presumed to already be shaped and ordered for display, and so
+ * will not cause this method to return true.
+ *
+ * @param text the text containing the characters to test
+ * @param start the start of the range of characters to test
+ * @param limit the limit of the range of characters to test
+ *
+ * @return true if the range of characters requires bidi analysis
+ *
+ * @stable ICU 3.8
+ */
+ public static boolean requiresBidi(char[] text,
+ int start,
+ int limit)
+ {
+ final int RTLMask = (1 << Bidi.DIRECTION_RIGHT_TO_LEFT |
+ 1 << AL |
+ 1 << RLE |
+ 1 << RLO |
+ 1 << AN);
+
+ if (0 > start || start > limit || limit > text.length) {
+ throw new IllegalArgumentException("Value start " + start +
+ " is out of range 0 to " + limit);
+ }
+ for (int i = start; i < limit; ++i) {
+ if (Character.isHighSurrogate(text[i]) && i < (limit-1) &&
+ Character.isLowSurrogate(text[i+1])) {
+ if (((1 << UCharacter.getDirection(Character.codePointAt(text, i))) & RTLMask) != 0) {
+ return true;
+ }
+ } else if (((1 << UCharacter.getDirection(text[i])) & RTLMask) != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Reorder the objects in the array into visual order based on their levels.
+ * This is a utility method to use when you have a collection of objects
+ * representing runs of text in logical order, each run containing text at a
+ * single level. The elements at index from
+ * objectStart up to objectStart + count in the
+ * objects array will be reordered into visual order assuming
+ * each run of text has the level indicated by the corresponding element in
+ * the levels array (at index - objectStart + levelStart).
+ *
+ * @param levels an array representing the bidi level of each object
+ * @param levelStart the start position in the levels array
+ * @param objects the array of objects to be reordered into visual order
+ * @param objectStart the start position in the objects array
+ * @param count the number of objects to reorder
+ * @stable ICU 3.8
+ */
+ public static void reorderVisually(byte[] levels,
+ int levelStart,
+ Object[] objects,
+ int objectStart,
+ int count)
+ {
+ if (0 > levelStart || levels.length <= levelStart) {
+ throw new IllegalArgumentException("Value levelStart " +
+ levelStart + " is out of range 0 to " +
+ (levels.length-1));
+ }
+ if (0 > objectStart || objects.length <= objectStart) {
+ throw new IllegalArgumentException("Value objectStart " +
+ levelStart + " is out of range 0 to " +
+ (objects.length-1));
+ }
+ if (0 > count || objects.length < (objectStart+count)) {
+ throw new IllegalArgumentException("Value count " +
+ levelStart + " is out of range 0 to " +
+ (objects.length - objectStart));
+ }
+ byte[] reorderLevels = new byte[count];
+ System.arraycopy(levels, levelStart, reorderLevels, 0, count);
+ int[] indexMap = reorderVisual(reorderLevels);
+ Object[] temp = new Object[count];
+ System.arraycopy(objects, objectStart, temp, 0, count);
+ for (int i = 0; i < count; ++i) {
+ objects[objectStart + i] = temp[indexMap[i]];
+ }
+ }
+
+ /**
+ * Display the bidi internal state, used in debugging.
+ */
+ public String toString() {
+ StringBuffer buf = new StringBuffer(super.toString());
+
+ buf.append("[dir: " + direction);
+ buf.append(" baselevel: " + paraLevel);
+ buf.append(" length: " + length);
+ buf.append(" runs: ");
+ if (levels == null) {
+ buf.append("null");
+ } else {
+ buf.append('[');
+ buf.append(levels[0]);
+ for (int i = 0; i < levels.length; i++) {
+ buf.append(' ');
+ buf.append(levels[i]);
+ }
+ buf.append(']');
+ }
+ buf.append(" text: [0x");
+ buf.append(Integer.toHexString(text[0]));
+ for (int i = 0; i < text.length; i++) {
+ buf.append(" 0x");
+ buf.append(Integer.toHexString(text[i]));
+ }
+ buf.append(']');
+ buf.append(']');
+
+ return buf.toString();
+ }
+
+}
diff --git a/jdk/src/share/classes/sun/text/bidi/BidiLine.java b/jdk/src/share/classes/sun/text/bidi/BidiLine.java
new file mode 100644
index 00000000000..311cf3349cd
--- /dev/null
+++ b/jdk/src/share/classes/sun/text/bidi/BidiLine.java
@@ -0,0 +1,849 @@
+/*
+ * Portions Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+/*
+ *******************************************************************************
+ * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved *
+ * *
+ * The original version of this source code and documentation is copyrighted *
+ * and owned by IBM, These materials are provided under terms of a License *
+ * Agreement between IBM and Sun. This technology is protected by multiple *
+ * US and International patents. This notice and attribution to IBM may not *
+ * to removed. *
+ *******************************************************************************
+ */
+/* Written by Simon Montagu, Matitiahu Allouche
+ * (ported from C code written by Markus W. Scherer)
+ */
+
+package sun.text.bidi;
+
+import java.text.Bidi;
+import java.util.Arrays;
+
+public final class BidiLine {
+
+ /*
+ * General remarks about the functions in this file:
+ *
+ * These functions deal with the aspects of potentially mixed-directional
+ * text in a single paragraph or in a line of a single paragraph
+ * which has already been processed according to
+ * the Unicode 3.0 Bidi algorithm as defined in
+ * http://www.unicode.org/unicode/reports/tr9/ , version 13,
+ * also described in The Unicode Standard, Version 4.0.1 .
+ *
+ * This means that there is a Bidi object with a levels
+ * and a dirProps array.
+ * paraLevel and direction are also set.
+ * Only if the length of the text is zero, then levels==dirProps==NULL.
+ *
+ * The overall directionality of the paragraph
+ * or line is used to bypass the reordering steps if possible.
+ * Even purely RTL text does not need reordering there because
+ * the getLogical/VisualIndex() methods can compute the
+ * index on the fly in such a case.
+ *
+ * The implementation of the access to same-level-runs and of the reordering
+ * do attempt to provide better performance and less memory usage compared to
+ * a direct implementation of especially rule (L2) with an array of
+ * one (32-bit) integer per text character.
+ *
+ * Here, the levels array is scanned as soon as necessary, and a vector of
+ * same-level-runs is created. Reordering then is done on this vector.
+ * For each run of text positions that were resolved to the same level,
+ * only 8 bytes are stored: the first text position of the run and the visual
+ * position behind the run after reordering.
+ * One sign bit is used to hold the directionality of the run.
+ * This is inefficient if there are many very short runs. If the average run
+ * length is <2, then this uses more memory.
+ *
+ * In a further attempt to save memory, the levels array is never changed
+ * after all the resolution rules (Xn, Wn, Nn, In).
+ * Many methods have to consider the field trailingWSStart:
+ * if it is less than length, then there is an implicit trailing run
+ * at the paraLevel,
+ * which is not reflected in the levels array.
+ * This allows a line Bidi object to use the same levels array as
+ * its paragraph parent object.
+ *
+ * When a Bidi object is created for a line of a paragraph, then the
+ * paragraph's levels and dirProps arrays are reused by way of setting
+ * a pointer into them, not by copying. This again saves memory and forbids to
+ * change the now shared levels for (L1).
+ */
+
+ /* handle trailing WS (L1) -------------------------------------------------- */
+
+ /*
+ * setTrailingWSStart() sets the start index for a trailing
+ * run of WS in the line. This is necessary because we do not modify
+ * the paragraph's levels array that we just point into.
+ * Using trailingWSStart is another form of performing (L1).
+ *
+ * To make subsequent operations easier, we also include the run
+ * before the WS if it is at the paraLevel - we merge the two here.
+ *
+ * This method is called only from setLine(), so paraLevel is
+ * set correctly for the line even when contextual multiple paragraphs.
+ */
+
+ static void setTrailingWSStart(BidiBase bidiBase)
+ {
+ byte[] dirProps = bidiBase.dirProps;
+ byte[] levels = bidiBase.levels;
+ int start = bidiBase.length;
+ byte paraLevel = bidiBase.paraLevel;
+
+ /* If the line is terminated by a block separator, all preceding WS etc...
+ are already set to paragraph level.
+ Setting trailingWSStart to pBidi->length will avoid changing the
+ level of B chars from 0 to paraLevel in getLevels when
+ orderParagraphsLTR==TRUE
+ */
+ if (BidiBase.NoContextRTL(dirProps[start - 1]) == BidiBase.B) {
+ bidiBase.trailingWSStart = start; /* currently == bidiBase.length */
+ return;
+ }
+ /* go backwards across all WS, BN, explicit codes */
+ while (start > 0 &&
+ (BidiBase.DirPropFlagNC(dirProps[start - 1]) & BidiBase.MASK_WS) != 0) {
+ --start;
+ }
+
+ /* if the WS run can be merged with the previous run then do so here */
+ while (start > 0 && levels[start - 1] == paraLevel) {
+ --start;
+ }
+
+ bidiBase.trailingWSStart=start;
+ }
+
+ public static Bidi setLine(Bidi bidi, BidiBase paraBidi,
+ Bidi newBidi, BidiBase newBidiBase,
+ int start, int limit) {
+ int length;
+
+ BidiBase lineBidi = newBidiBase;
+
+ /* set the values in lineBidi from its paraBidi parent */
+ /* class members are already initialized to 0 */
+ // lineBidi.paraBidi = null; /* mark unfinished setLine */
+ // lineBidi.flags = 0;
+ // lineBidi.controlCount = 0;
+
+ length = lineBidi.length = lineBidi.originalLength =
+ lineBidi.resultLength = limit - start;
+
+ lineBidi.text = new char[length];
+ System.arraycopy(paraBidi.text, start, lineBidi.text, 0, length);
+ lineBidi.paraLevel = paraBidi.GetParaLevelAt(start);
+ lineBidi.paraCount = paraBidi.paraCount;
+ lineBidi.runs = new BidiRun[0];
+ if (paraBidi.controlCount > 0) {
+ int j;
+ for (j = start; j < limit; j++) {
+ if (BidiBase.IsBidiControlChar(paraBidi.text[j])) {
+ lineBidi.controlCount++;
+ }
+ }
+ lineBidi.resultLength -= lineBidi.controlCount;
+ }
+ /* copy proper subset of DirProps */
+ lineBidi.getDirPropsMemory(length);
+ lineBidi.dirProps = lineBidi.dirPropsMemory;
+ System.arraycopy(paraBidi.dirProps, start, lineBidi.dirProps, 0,
+ length);
+ /* copy proper subset of Levels */
+ lineBidi.getLevelsMemory(length);
+ lineBidi.levels = lineBidi.levelsMemory;
+ System.arraycopy(paraBidi.levels, start, lineBidi.levels, 0,
+ length);
+ lineBidi.runCount = -1;
+
+ if (paraBidi.direction != BidiBase.MIXED) {
+ /* the parent is already trivial */
+ lineBidi.direction = paraBidi.direction;
+
+ /*
+ * The parent's levels are all either
+ * implicitly or explicitly ==paraLevel;
+ * do the same here.
+ */
+ if (paraBidi.trailingWSStart <= start) {
+ lineBidi.trailingWSStart = 0;
+ } else if (paraBidi.trailingWSStart < limit) {
+ lineBidi.trailingWSStart = paraBidi.trailingWSStart - start;
+ } else {
+ lineBidi.trailingWSStart = length;
+ }
+ } else {
+ byte[] levels = lineBidi.levels;
+ int i, trailingWSStart;
+ byte level;
+
+ setTrailingWSStart(lineBidi);
+ trailingWSStart = lineBidi.trailingWSStart;
+
+ /* recalculate lineBidi.direction */
+ if (trailingWSStart == 0) {
+ /* all levels are at paraLevel */
+ lineBidi.direction = (byte)(lineBidi.paraLevel & 1);
+ } else {
+ /* get the level of the first character */
+ level = (byte)(levels[0] & 1);
+
+ /* if there is anything of a different level, then the line
+ is mixed */
+ if (trailingWSStart < length &&
+ (lineBidi.paraLevel & 1) != level) {
+ /* the trailing WS is at paraLevel, which differs from
+ levels[0] */
+ lineBidi.direction = BidiBase.MIXED;
+ } else {
+ /* see if levels[1..trailingWSStart-1] have the same
+ direction as levels[0] and paraLevel */
+ for (i = 1; ; i++) {
+ if (i == trailingWSStart) {
+ /* the direction values match those in level */
+ lineBidi.direction = level;
+ break;
+ } else if ((levels[i] & 1) != level) {
+ lineBidi.direction = BidiBase.MIXED;
+ break;
+ }
+ }
+ }
+ }
+
+ switch(lineBidi.direction) {
+ case Bidi.DIRECTION_LEFT_TO_RIGHT:
+ /* make sure paraLevel is even */
+ lineBidi.paraLevel = (byte)
+ ((lineBidi.paraLevel + 1) & ~1);
+
+ /* all levels are implicitly at paraLevel (important for
+ getLevels()) */
+ lineBidi.trailingWSStart = 0;
+ break;
+ case Bidi.DIRECTION_RIGHT_TO_LEFT:
+ /* make sure paraLevel is odd */
+ lineBidi.paraLevel |= 1;
+
+ /* all levels are implicitly at paraLevel (important for
+ getLevels()) */
+ lineBidi.trailingWSStart = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ newBidiBase.paraBidi = paraBidi; /* mark successful setLine */
+ return newBidi;
+ }
+
+ static byte getLevelAt(BidiBase bidiBase, int charIndex)
+ {
+ /* return paraLevel if in the trailing WS run, otherwise the real level */
+ if (bidiBase.direction != BidiBase.MIXED || charIndex >= bidiBase.trailingWSStart) {
+ return bidiBase.GetParaLevelAt(charIndex);
+ } else {
+ return bidiBase.levels[charIndex];
+ }
+ }
+
+ static byte[] getLevels(BidiBase bidiBase)
+ {
+ int start = bidiBase.trailingWSStart;
+ int length = bidiBase.length;
+
+ if (start != length) {
+ /* the current levels array does not reflect the WS run */
+ /*
+ * After the previous if(), we know that the levels array
+ * has an implicit trailing WS run and therefore does not fully
+ * reflect itself all the levels.
+ * This must be a Bidi object for a line, and
+ * we need to create a new levels array.
+ */
+ /* bidiBase.paraLevel is ok even if contextual multiple paragraphs,
+ since bidiBase is a line object */
+ Arrays.fill(bidiBase.levels, start, length, bidiBase.paraLevel);
+
+ /* this new levels array is set for the line and reflects the WS run */
+ bidiBase.trailingWSStart = length;
+ }
+ if (length < bidiBase.levels.length) {
+ byte[] levels = new byte[length];
+ System.arraycopy(bidiBase.levels, 0, levels, 0, length);
+ return levels;
+ }
+ return bidiBase.levels;
+ }
+
+ static BidiRun getLogicalRun(BidiBase bidiBase, int logicalPosition)
+ {
+ /* this is done based on runs rather than on levels since levels have
+ a special interpretation when REORDER_RUNS_ONLY
+ */
+ BidiRun newRun = new BidiRun(), iRun;
+ getRuns(bidiBase);
+ int runCount = bidiBase.runCount;
+ int visualStart = 0, logicalLimit = 0;
+ iRun = bidiBase.runs[0];
+
+ for (int i = 0; i < runCount; i++) {
+ iRun = bidiBase.runs[i];
+ logicalLimit = iRun.start + iRun.limit - visualStart;
+ if ((logicalPosition >= iRun.start) &&
+ (logicalPosition < logicalLimit)) {
+ break;
+ }
+ visualStart = iRun.limit;
+ }
+ newRun.start = iRun.start;
+ newRun.limit = logicalLimit;
+ newRun.level = iRun.level;
+ return newRun;
+ }
+
+ /* in trivial cases there is only one trivial run; called by getRuns() */
+ private static void getSingleRun(BidiBase bidiBase, byte level) {
+ /* simple, single-run case */
+ bidiBase.runs = bidiBase.simpleRuns;
+ bidiBase.runCount = 1;
+
+ /* fill and reorder the single run */
+ bidiBase.runs[0] = new BidiRun(0, bidiBase.length, level);
+ }
+
+ /* reorder the runs array (L2) ---------------------------------------------- */
+
+ /*
+ * Reorder the same-level runs in the runs array.
+ * Here, runCount>1 and maxLevel>=minLevel>=paraLevel.
+ * All the visualStart fields=logical start before reordering.
+ * The "odd" bits are not set yet.
+ *
+ * Reordering with this data structure lends itself to some handy shortcuts:
+ *
+ * Since each run is moved but not modified, and since at the initial maxLevel
+ * each sequence of same-level runs consists of only one run each, we
+ * don't need to do anything there and can predecrement maxLevel.
+ * In many simple cases, the reordering is thus done entirely in the
+ * index mapping.
+ * Also, reordering occurs only down to the lowest odd level that occurs,
+ * which is minLevel|1. However, if the lowest level itself is odd, then
+ * in the last reordering the sequence of the runs at this level or higher
+ * will be all runs, and we don't need the elaborate loop to search for them.
+ * This is covered by ++minLevel instead of minLevel|=1 followed
+ * by an extra reorder-all after the reorder-some loop.
+ * About a trailing WS run:
+ * Such a run would need special treatment because its level is not
+ * reflected in levels[] if this is not a paragraph object.
+ * Instead, all characters from trailingWSStart on are implicitly at
+ * paraLevel.
+ * However, for all maxLevel>paraLevel, this run will never be reordered
+ * and does not need to be taken into account. maxLevel==paraLevel is only reordered
+ * if minLevel==paraLevel is odd, which is done in the extra segment.
+ * This means that for the main reordering loop we don't need to consider
+ * this run and can --runCount. If it is later part of the all-runs
+ * reordering, then runCount is adjusted accordingly.
+ */
+ private static void reorderLine(BidiBase bidiBase, byte minLevel, byte maxLevel) {
+
+ /* nothing to do? */
+ if (maxLevel<=(minLevel|1)) {
+ return;
+ }
+
+ BidiRun[] runs;
+ BidiRun tempRun;
+ byte[] levels;
+ int firstRun, endRun, limitRun, runCount;
+
+ /*
+ * Reorder only down to the lowest odd level
+ * and reorder at an odd minLevel in a separate, simpler loop.
+ * See comments above for why minLevel is always incremented.
+ */
+ ++minLevel;
+
+ runs = bidiBase.runs;
+ levels = bidiBase.levels;
+ runCount = bidiBase.runCount;
+
+ /* do not include the WS run at paraLevel<=old minLevel except in the simple loop */
+ if (bidiBase.trailingWSStart < bidiBase.length) {
+ --runCount;
+ }
+
+ while (--maxLevel >= minLevel) {
+ firstRun = 0;
+
+ /* loop for all sequences of runs */
+ for ( ; ; ) {
+ /* look for a sequence of runs that are all at >=maxLevel */
+ /* look for the first run of such a sequence */
+ while (firstRun < runCount && levels[runs[firstRun].start] < maxLevel) {
+ ++firstRun;
+ }
+ if (firstRun >= runCount) {
+ break; /* no more such runs */
+ }
+
+ /* look for the limit run of such a sequence (the run behind it) */
+ for (limitRun = firstRun; ++limitRun < runCount &&
+ levels[runs[limitRun].start]>=maxLevel; ) {}
+
+ /* Swap the entire sequence of runs from firstRun to limitRun-1. */
+ endRun = limitRun - 1;
+ while (firstRun < endRun) {
+ tempRun = runs[firstRun];
+ runs[firstRun] = runs[endRun];
+ runs[endRun] = tempRun;
+ ++firstRun;
+ --endRun;
+ }
+
+ if (limitRun == runCount) {
+ break; /* no more such runs */
+ } else {
+ firstRun = limitRun + 1;
+ }
+ }
+ }
+
+ /* now do maxLevel==old minLevel (==odd!), see above */
+ if ((minLevel & 1) == 0) {
+ firstRun = 0;
+
+ /* include the trailing WS run in this complete reordering */
+ if (bidiBase.trailingWSStart == bidiBase.length) {
+ --runCount;
+ }
+
+ /* Swap the entire sequence of all runs. (endRun==runCount) */
+ while (firstRun < runCount) {
+ tempRun = runs[firstRun];
+ runs[firstRun] = runs[runCount];
+ runs[runCount] = tempRun;
+ ++firstRun;
+ --runCount;
+ }
+ }
+ }
+
+ /* compute the runs array --------------------------------------------------- */
+
+ static int getRunFromLogicalIndex(BidiBase bidiBase, int logicalIndex) {
+ BidiRun[] runs = bidiBase.runs;
+ int runCount = bidiBase.runCount, visualStart = 0, i, length, logicalStart;
+
+ for (i = 0; i < runCount; i++) {
+ length = runs[i].limit - visualStart;
+ logicalStart = runs[i].start;
+ if ((logicalIndex >= logicalStart) && (logicalIndex < (logicalStart+length))) {
+ return i;
+ }
+ visualStart += length;
+ }
+ /* we should never get here */
+ throw new IllegalStateException("Internal ICU error in getRunFromLogicalIndex");
+ }
+
+ /*
+ * Compute the runs array from the levels array.
+ * After getRuns() returns true, runCount is guaranteed to be >0
+ * and the runs are reordered.
+ * Odd-level runs have visualStart on their visual right edge and
+ * they progress visually to the left.
+ * If option OPTION_INSERT_MARKS is set, insertRemove will contain the
+ * sum of appropriate LRM/RLM_BEFORE/AFTER flags.
+ * If option OPTION_REMOVE_CONTROLS is set, insertRemove will contain the
+ * negative number of BiDi control characters within this run.
+ */
+ static void getRuns(BidiBase bidiBase) {
+ /*
+ * This method returns immediately if the runs are already set. This
+ * includes the case of length==0 (handled in setPara)..
+ */
+ if (bidiBase.runCount >= 0) {
+ return;
+ }
+ if (bidiBase.direction != BidiBase.MIXED) {
+ /* simple, single-run case - this covers length==0 */
+ /* bidiBase.paraLevel is ok even for contextual multiple paragraphs */
+ getSingleRun(bidiBase, bidiBase.paraLevel);
+ } else /* BidiBase.MIXED, length>0 */ {
+ /* mixed directionality */
+ int length = bidiBase.length, limit;
+ byte[] levels = bidiBase.levels;
+ int i, runCount;
+ byte level = BidiBase.INTERNAL_LEVEL_DEFAULT_LTR; /* initialize with no valid level */
+ /*
+ * If there are WS characters at the end of the line
+ * and the run preceding them has a level different from
+ * paraLevel, then they will form their own run at paraLevel (L1).
+ * Count them separately.
+ * We need some special treatment for this in order to not
+ * modify the levels array which a line Bidi object shares
+ * with its paragraph parent and its other line siblings.
+ * In other words, for the trailing WS, it may be
+ * levels[]!=paraLevel but we have to treat it like it were so.
+ */
+ limit = bidiBase.trailingWSStart;
+ /* count the runs, there is at least one non-WS run, and limit>0 */
+ runCount = 0;
+ for (i = 0; i < limit; ++i) {
+ /* increment runCount at the start of each run */
+ if (levels[i] != level) {
+ ++runCount;
+ level = levels[i];
+ }
+ }
+
+ /*
+ * We don't need to see if the last run can be merged with a trailing
+ * WS run because setTrailingWSStart() would have done that.
+ */
+ if (runCount == 1 && limit == length) {
+ /* There is only one non-WS run and no trailing WS-run. */
+ getSingleRun(bidiBase, levels[0]);
+ } else /* runCount>1 || limitrun
.
+ *
+ * dirProps;
- UBiDiLevel *levels=pBiDi->levels;
-
- int32_t i, next, neutralStart=-1;
- DirProp prevDirProp, dirProp, nextDirProp, lastStrong, beforeNeutral=L;
- UBiDiLevel numberLevel;
- uint8_t historyOfEN;
-
- /* initialize: current at sor, next at start (it is start
General remarks about the API:
- *
- * In functions with an error code parameter,
- * the pErrorCode pointer must be valid
- * and the value that it points to must not indicate a failure before
- * the function call. Otherwise, the function returns immediately.
- * After the function call, the value indicates success or failure.limit
of a sequence of characters is the position just after their
- * last character, i.e., one more than that position.runs
.
- * Such a run
is defined as a sequence of characters
- * that are at the same embedding level
- * after performing the BiDi algorithm.paraLevel and embeddingLevels
- * arguments of ubidi_setPara(); there:
- *
- *
embeddingLevels[]
- * value indicates whether the using application is
- * specifying the level of a character to override whatever the
- * BiDi implementation would resolve it to.paraLevel can be set to the
- * pesudo-level values UBIDI_DEFAULT_LTR
- * and UBIDI_DEFAULT_RTL.UBIDI_DEFAULT_XXX can be used to specify
- * a default for the paragraph level for
- * when the ubidi_setPara() function
- * shall determine it but there is no
- * strongly typed character in the input.UBIDI_DEFAULT_LTR is even
- * and the one for UBIDI_DEFAULT_RTL is odd,
- * just like with normal LTR and RTL level values -
- * these special values are designed that way. Also, the implementation
- * assumes that UBIDI_MAX_EXPLICIT_LEVEL is odd.
- *
- * @see UBIDI_DEFAULT_LTR
- * @see UBIDI_DEFAULT_RTL
- * @see UBIDI_LEVEL_OVERRIDE
- * @see UBIDI_MAX_EXPLICIT_LEVEL
- */
-typedef uint8_t UBiDiLevel;
-
-/** @memo If there is no strong character, then set the paragraph level to 0 (left-to-right). */
-#define UBIDI_DEFAULT_LTR 0xfe
-
-/** @memo If there is no strong character, then set the paragraph level to 1 (right-to-left). */
-#define UBIDI_DEFAULT_RTL 0xff
-
-/**
- * @memo Maximum explicit embedding level
- * (The maximum resolved level can be up to UBIDI_MAX_EXPLICIT_LEVEL+1).
- */
-#define UBIDI_MAX_EXPLICIT_LEVEL 61
-
-/** @memo Bit flag for level input: overrides directional properties. */
-#define UBIDI_LEVEL_OVERRIDE 0x80
-
-/**
- * @memo UBiDiDirection values indicate the text direction.
- */
-enum UBiDiDirection {
- /** @memo All left-to-right text. This is a 0 value. */
- UBIDI_LTR,
- /** @memo All right-to-left text. This is a 1 value. */
- UBIDI_RTL,
- /** @memo Mixed-directional text. */
- UBIDI_MIXED
-};
-
-typedef enum UBiDiDirection UBiDiDirection;
-
-/**
- * Forward declaration of the UBiDi structure for the declaration of
- * the API functions. Its fields are implementation-specific.UBiDi structure.
- * Such an object is initially empty. It is assigned
- * the BiDi properties of a paragraph by ubidi_setPara()
- * or the BiDi properties of a line of a paragraph by
- * ubidi_getLine().ubidi_close().ubidi_set() will allocate additional memory for
- * internal structures as necessary.
- *
- * @return An empty UBiDi object.
- */
-U_CAPI UBiDi * U_EXPORT2
-ubidi_open();
-
-/**
- * Allocate a UBiDi structure with preallocated memory
- * for internal structures.
- * This function provides a UBiDi object like ubidi_open()
- * with no arguments, but it also preallocates memory for internal structures
- * according to the sizings supplied by the caller.maxRunCount cannot be reasonably predetermined and should not
- * be set to maxLength (the only failproof value) to avoid
- * wasting memory, then maxRunCount could be set to 0 here
- * and the internal structures that are associated with it will be allocated
- * on demand, just like with ubidi_open().
- *
- * @param maxLength is the maximum paragraph or line length that internal memory
- * will be preallocated for. An attempt to associate this object with a
- * longer text will fail, unless this value is 0, which leaves the allocation
- * up to the implementation.
- *
- * @param maxRunCount is the maximum anticipated number of same-level runs
- * that internal memory will be preallocated for. An attempt to access
- * visual runs on an object that was not preallocated for as many runs
- * as the text was actually resolved to will fail,
- * unless this value is 0, which leaves the allocation up to the implementation.maxLength. It is typically small.UBiDi object with preallocated memory.
- */
-U_CAPI UBiDi * U_EXPORT2
-ubidi_openSized(int32_t maxLength, int32_t maxRunCount, UErrorCode *pErrorCode);
-
-/**
- * ubidi_close() must be called to free the memory
- * associated with a UBiDi object.UBiDi object is the child
- * of another one (its parent
), after calling
- * ubidi_setLine(), then the child object must
- * be destroyed (closed) or reused (by calling
- * ubidi_setPara() or ubidi_setLine())
- * before the parent object.
- *
- * @param pBiDi is a UBiDi object.
- *
- * @see ubidi_setPara
- * @see ubidi_setLine
- */
-U_CAPI void U_EXPORT2
-ubidi_close(UBiDi *pBiDi);
-
-/**
- * Perform the Unicode BiDi algorithm. It is defined in the
- * Unicode Technical Report 9,
- * version 5,
- * also described in The Unicode Standard, Version 3.0 .styled
text
- * and computes the left-right-directionality of each character.
- * For example, in pure LTR text with numbers the numbers would get
- * a resolved level of 2 higher than the surrounding text according to
- * the algorithm. This implementation may set all resolved levels to
- * the same value in such a case.UBiDi object allocated with ubidi_open()
- * which will be set to contain the reordering information,
- * especially the resolved levels for all the characters in text.
- *
- * @param text is a pointer to the single-paragraph text that the
- * BiDi algorithm will be performed on
- * (step (P1) of the algorithm is performed externally).
- * The text must be (at least) length long.
- *
- * @param length is the length of the text; if length==-1 then
- * the text must be zero-terminated.
- *
- * @param paraLevel specifies the default level for the paragraph;
- * it is typically 0 (LTR) or 1 (RTL).
- * If the function shall determine the paragraph level from the text,
- * then paraLevel can be set to
- * either UBIDI_DEFAULT_LTR
- * or UBIDI_DEFAULT_RTL;
- * if there is no strongly typed character, then
- * the desired default is used (0 for LTR or 1 for RTL).
- * Any other value between 0 and UBIDI_MAX_EXPLICIT_LEVEL is also valid,
- * with odd levels indicating RTL.
- *
- * @param embeddingLevels (in) may be used to preset the embedding and override levels,
- * ignoring characters like LRE and PDF in the text.
- * A level overrides the directional property of its corresponding
- * (same index) character if the level has the
- * UBIDI_LEVEL_OVERRIDE bit set.paraLevel<=embeddingLevels[]<=UBIDI_MAX_EXPLICIT_LEVEL.UBiDi object;
- * the embeddingLevels array must not be
- * deallocated before the UBiDi structure is destroyed or reused,
- * and the embeddingLevels
- * should not be modified to avoid unexpected results on subsequent BiDi operations.
- * However, the ubidi_setPara() and
- * ubidi_setLine() functions may modify some or all of the levels.UBiDi object is reused or destroyed, the caller
- * must take care of the deallocation of the embeddingLevels array.embeddingLevels array must be
- * at least length long.
- *
- * @param pErrorCode must be a valid pointer to an error code value,
- * which must not indicate a failure before the function call.
- */
-U_CAPI void U_EXPORT2
-ubidi_setPara(UBiDi *pBiDi, const UChar *text, int32_t length,
- UBiDiLevel paraLevel, UBiDiLevel *embeddingLevels,
- UErrorCode *pErrorCode);
-
-/**
- * ubidi_getLine() sets a UBiDi to
- * contain the reordering information, especially the resolved levels,
- * for all the characters in a line of text. This line of text is
- * specified by referring to a UBiDi object representing
- * this information for a paragraph of text, and by specifying
- * a range of indexes in this paragraph.limit-start.ubidi_setPara()
- * for a paragraph, and after line-breaking on that paragraph.
- * It is not necessary if the paragraph is treated as a single line.UBiDi object that represents a line.pLineBiDi shares data with
- * pParaBiDi.
- * You must destroy or reuse pLineBiDi before pParaBiDi.
- * In other words, you must destroy or reuse the UBiDi object for a line
- * before the object for its parent paragraph.
- *
- * @param pParaBiDi is the parent paragraph object.
- *
- * @param start is the line's first index into the paragraph text.
- *
- * @param limit is just behind the line's last index into the paragraph text
- * (its last index +1).
- * It must be 0<=start<=limit<=paragraph length.
- *
- * @param pLineBiDi is the object that will now represent a line of the paragraph.
- *
- * @param pErrorCode must be a valid pointer to an error code value,
- * which must not indicate a failure before the function call.
- *
- * @see ubidi_setPara
- */
-U_CAPI void U_EXPORT2
-ubidi_setLine(const UBiDi *pParaBiDi,
- int32_t start, int32_t limit,
- UBiDi *pLineBiDi,
- UErrorCode *pErrorCode);
-
-/**
- * Get the directionality of the text.
- *
- * @param pBiDi is the paragraph or line UBiDi object.
- *
- * @return A UBIDI_XXX value that indicates if the entire text
- * represented by this object is unidirectional,
- * and which direction, or if it is mixed-directional.
- *
- * @see UBiDiDirection
- */
-U_CAPI UBiDiDirection U_EXPORT2
-ubidi_getDirection(const UBiDi *pBiDi);
-
-/**
- * Get the length of the text.
- *
- * @param pBiDi is the paragraph or line UBiDi object.
- *
- * @return The length of the text that the UBiDi object was created for.
- */
-U_CAPI int32_t U_EXPORT2
-ubidi_getLength(const UBiDi *pBiDi);
-
-/**
- * Get the paragraph level of the text.
- *
- * @param pBiDi is the paragraph or line UBiDi object.
- *
- * @return The paragraph level.
- *
- * @see UBiDiLevel
- */
-U_CAPI UBiDiLevel U_EXPORT2
-ubidi_getParaLevel(const UBiDi *pBiDi);
-
-/**
- * Get the level for one character.
- *
- * @param pBiDi is the paragraph or line UBiDi object.
- *
- * @param charIndex the index of a character.
- *
- * @return The level for the character at charIndex.
- *
- * @see UBiDiLevel
- */
-U_CAPI UBiDiLevel U_EXPORT2
-ubidi_getLevelAt(const UBiDi *pBiDi, int32_t charIndex);
-
-/**
- * Get an array of levels for each character.ubidi_getLevelAt().
- *
- * @param pBiDi is the paragraph or line UBiDi object.
- *
- * @param pErrorCode must be a valid pointer to an error code value,
- * which must not indicate a failure before the function call.
- *
- * @return The levels array for the text,
- * or NULL if an error occurs.
- *
- * @see UBiDiLevel
- */
-U_CAPI const UBiDiLevel * U_EXPORT2
-ubidi_getLevels(UBiDi *pBiDi, UErrorCode *pErrorCode);
-
-/**
- * Get a logical run.
- * This function returns information about a run and is used
- * to retrieve runs in logical order.UBiDi object.
- *
- * @param logicalStart is the first character of the run.
- *
- * @param pLogicalLimit will receive the limit of the run.
- * The l-value that you point to here may be the
- * same expression (variable) as the one for
- * logicalStart.
- * This pointer can be NULL if this
- * value is not necessary.
- *
- * @param pLevel will receive the level of the run.
- * This pointer can be NULL if this
- * value is not necessary.
- */
-U_CAPI void U_EXPORT2
-ubidi_getLogicalRun(const UBiDi *pBiDi, int32_t logicalStart,
- int32_t *pLogicalLimit, UBiDiLevel *pLevel);
-
-/**
- * Get the number of runs.
- * This function may invoke the actual reordering on the
- * UBiDi object, after ubidi_setPara()
- * may have resolved only the levels of the text. Therefore,
- * ubidi_countRuns() may have to allocate memory,
- * and may fail doing so.
- *
- * @param pBiDi is the paragraph or line UBiDi object.
- *
- * @param pErrorCode must be a valid pointer to an error code value,
- * which must not indicate a failure before the function call.
- *
- * @return The number of runs.
- */
-U_CAPI int32_t U_EXPORT2
-ubidi_countRuns(UBiDi *pBiDi, UErrorCode *pErrorCode);
-
-/**
- * Get one run's logical start, length, and directionality,
- * which can be 0 for LTR or 1 for RTL.
- * In an RTL run, the character at the logical start is
- * visually on the right of the displayed run.
- * The length is the number of characters in the run.ubidi_countRuns() should be called
- * before the runs are retrieved.
- *
- * @param pBiDi is the paragraph or line UBiDi object.
- *
- * @param runIndex is the number of the run in visual order, in the
- * range [0..ubidi_countRuns(pBiDi)-1].
- *
- * @param pLogicalStart is the first logical character index in the text.
- * The pointer may be NULL if this index is not needed.
- *
- * @param pLength is the number of characters (at least one) in the run.
- * The pointer may be NULL if this is not needed.
- *
- * @return the directionality of the run,
- * UBIDI_LTR==0 or UBIDI_RTL==1,
- * never UBIDI_MIXED.
- *
- * @see ubidi_countRuns
- *
- * Example:
- *
- * int32_t i, count=ubidi_countRuns(pBiDi),
- * logicalStart, visualIndex=0, length;
- * for(i=0; i<count; ++i) {
- * if(UBIDI_LTR==ubidi_getVisualRun(pBiDi, i, &logicalStart, &length)) {
- * do { // LTR
- * show_char(text[logicalStart++], visualIndex++);
- * } while(--length>0);
- * } else {
- * logicalStart+=length; // logicalLimit
- * do { // RTL
- * show_char(text[--logicalStart], visualIndex++);
- * } while(--length>0);
- * }
- * }
- *
- *
- * Note that in right-to-left runs, code like this places
- * modifier letters before base characters and second surrogates
- * before first ones.
- */
-U_CAPI UBiDiDirection U_EXPORT2
-ubidi_getVisualRun(UBiDi *pBiDi, int32_t runIndex,
- int32_t *pLogicalStart, int32_t *pLength);
-
-/**
- * Get the visual position from a logical text position.
- * If such a mapping is used many times on the same
- * UBiDi object, then calling
- * ubidi_getLogicalMap() is more efficient.UBiDi object.
- *
- * @param logicalIndex is the index of a character in the text.
- *
- * @param pErrorCode must be a valid pointer to an error code value,
- * which must not indicate a failure before the function call.
- *
- * @return The visual position of this character.
- *
- * @see ubidi_getLogicalMap
- * @see ubidi_getLogicalIndex
- */
-U_CAPI int32_t U_EXPORT2
-ubidi_getVisualIndex(UBiDi *pBiDi, int32_t logicalIndex, UErrorCode *pErrorCode);
-
-/**
- * Get the logical text position from a visual position.
- * If such a mapping is used many times on the same
- * UBiDi object, then calling
- * ubidi_getVisualMap() is more efficient.ubidi_getVisualIndex().
- *
- * @param pBiDi is the paragraph or line UBiDi object.
- *
- * @param visualIndex is the visual position of a character.
- *
- * @param pErrorCode must be a valid pointer to an error code value,
- * which must not indicate a failure before the function call.
- *
- * @return The index of this character in the text.
- *
- * @see ubidi_getVisualMap
- * @see ubidi_getVisualIndex
- */
-U_CAPI int32_t U_EXPORT2
-ubidi_getLogicalIndex(UBiDi *pBiDi, int32_t visualIndex, UErrorCode *pErrorCode);
-
-/**
- * Get a logical-to-visual index map (array) for the characters in the UBiDi
- * (paragraph or line) object.
- *
- * @param pBiDi is the paragraph or line UBiDi object.
- *
- * @param indexMap is a pointer to an array of ubidi_getLength()
- * indexes which will reflect the reordering of the characters.
- * The array does not need to be initialized.indexMap[logicalIndex]==visualIndex.UBiDi object.
- *
- * @param indexMap is a pointer to an array of ubidi_getLength()
- * indexes which will reflect the reordering of the characters.
- * The array does not need to be initialized.indexMap[visualIndex]==logicalIndex.ubidi_getLogicalMap on a
- * UBiDi object.
- *
- * @param levels is an array with length levels that have been determined by
- * the application.
- *
- * @param length is the number of levels in the array, or, semantically,
- * the number of objects to be reordered.
- * It must be length>0.
- *
- * @param indexMap is a pointer to an array of length
- * indexes which will reflect the reordering of the characters.
- * The array does not need to be initialized.indexMap[logicalIndex]==visualIndex.
- */
-U_CAPI void U_EXPORT2
-ubidi_reorderLogical(const UBiDiLevel *levels, int32_t length, int32_t *indexMap);
-
-/**
- * This is a convenience function that does not use a UBiDi object.
- * It is intended to be used for when an application has determined the levels
- * of objects (character sequences) and just needs to have them reordered (L2).
- * This is equivalent to using ubidi_getVisualMap on a
- * UBiDi object.
- *
- * @param levels is an array with length levels that have been determined by
- * the application.
- *
- * @param length is the number of levels in the array, or, semantically,
- * the number of objects to be reordered.
- * It must be length>0.
- *
- * @param indexMap is a pointer to an array of length
- * indexes which will reflect the reordering of the characters.
- * The array does not need to be initialized.indexMap[visualIndex]==logicalIndex.
- */
-U_CAPI void U_EXPORT2
-ubidi_reorderVisual(const UBiDiLevel *levels, int32_t length, int32_t *indexMap);
-
-/**
- * Invert an index map.
- * The one-to-one index mapping of the first map is inverted and written to
- * the second one.
- *
- * @param srcMap is an array with length indexes
- * which define the original mapping.
- *
- * @param destMap is an array with length indexes
- * which will be filled with the inverse mapping.
- *
- * @param length is the length of each array.
- */
-U_CAPI void U_EXPORT2
-ubidi_invertMap(const int32_t *srcMap, int32_t *destMap, int32_t length);
-
-/**
- * @name Sample code for the ICU BiDi API
- *
- * Rendering a paragraph with the ICU BiDi API
- *
- * This is (hypothetical) sample code that illustrates
- * how the ICU BiDi API could be used to render a paragraph of text.
- * Rendering code depends highly on the graphics system,
- * therefore this sample code must make a lot of assumptions,
- * which may or may not match any existing graphics system's properties.
- *
- *
- *
- *
- *
- * #include "ubidi.h"
- *
- * typedef enum {
- * styleNormal=0, styleSelected=1,
- * styleBold=2, styleItalics=4,
- * styleSuper=8, styleSub=16
- * } Style;
- *
- * typedef struct { int32_t limit; Style style; } StyleRun;
- *
- * int getTextWidth(const UChar *text, int32_t start, int32_t limit,
- * const StyleRun *styleRuns, int styleRunCount);
- *
- * // set *pLimit and *pStyleRunLimit for a line
- * // from text[start] and from styleRuns[styleRunStart]
- * // using ubidi_getLogicalRun(para, ...)
- * void getLineBreak(const UChar *text, int32_t start, int32_t *pLimit,
- * UBiDi *para,
- * const StyleRun *styleRuns, int styleRunStart, int *pStyleRunLimit,
- * int *pLineWidth);
- *
- * // render runs on a line sequentially, always from left to right
- *
- * // prepare rendering a new line
- * void startLine(UBiDiDirection textDirection, int lineWidth);
- *
- * // render a run of text and advance to the right by the run width
- * // the text[start..limit-1] is always in logical order
- * void renderRun(const UChar *text, int32_t start, int32_t limit,
- * UBiDiDirection textDirection, Style style);
- *
- * // We could compute a cross-product
- * // from the style runs with the directional runs
- * // and then reorder it.
- * // Instead, here we iterate over each run type
- * // and render the intersections -
- * // with shortcuts in simple (and common) cases.
- * // renderParagraph() is the main function.
- *
- * // render a directional run with
- * // (possibly) multiple style runs intersecting with it
- * void renderDirectionalRun(const UChar *text,
- * int32_t start, int32_t limit,
- * UBiDiDirection direction,
- * const StyleRun *styleRuns, int styleRunCount) {
- * int i;
- *
- * // iterate over style runs
- * if(direction==UBIDI_LTR) {
- * int styleLimit;
- *
- * for(i=0; i<styleRunCount; ++i) {
- * styleLimit=styleRun[i].limit;
- * if(start<styleLimit) {
- * if(styleLimit>limit) { styleLimit=limit; }
- * renderRun(text, start, styleLimit,
- * direction, styleRun[i].style);
- * if(styleLimit==limit) { break; }
- * start=styleLimit;
- * }
- * }
- * } else {
- * int styleStart;
- *
- * for(i=styleRunCount-1; i>=0; --i) {
- * if(i>0) {
- * styleStart=styleRun[i-1].limit;
- * } else {
- * styleStart=0;
- * }
- * if(limit>=styleStart) {
- * if(styleStart<start) { styleStart=start; }
- * renderRun(text, styleStart, limit,
- * direction, styleRun[i].style);
- * if(styleStart==start) { break; }
- * limit=styleStart;
- * }
- * }
- * }
- * }
- *
- * // the line object represents text[start..limit-1]
- * void renderLine(UBiDi *line, const UChar *text,
- * int32_t start, int32_t limit,
- * const StyleRun *styleRuns, int styleRunCount) {
- * UBiDiDirection direction=ubidi_getDirection(line);
- * if(direction!=UBIDI_MIXED) {
- * // unidirectional
- * if(styleRunCount<=1) {
- * renderRun(text, start, limit, direction, styleRuns[0].style);
- * } else {
- * renderDirectionalRun(text, start, limit,
- * direction, styleRuns, styleRunCount);
- * }
- * } else {
- * // mixed-directional
- * int32_t count, i, length;
- * UBiDiLevel level;
- *
- * count=ubidi_countRuns(para, pErrorCode);
- * if(U_SUCCESS(*pErrorCode)) {
- * if(styleRunCount<=1) {
- * Style style=styleRuns[0].style;
- *
- * // iterate over directional runs
- * for(i=0; i<count; ++i) {
- * direction=ubidi_getVisualRun(para, i, &start, &length);
- * renderRun(text, start, start+length, direction, style);
- * }
- * } else {
- * int32_t j;
- *
- * // iterate over both directional and style runs
- * for(i=0; i<count; ++i) {
- * direction=ubidi_getVisualRun(line, i, &start, &length);
- * renderDirectionalRun(text, start, start+length,
- * direction, styleRuns, styleRunCount);
- * }
- * }
- * }
- * }
- * }
- *
- * void renderParagraph(const UChar *text, int32_t length,
- * UBiDiDirection textDirection,
- * const StyleRun *styleRuns, int styleRunCount,
- * int lineWidth,
- * UErrorCode *pErrorCode) {
- * UBiDi *para;
- *
- * if(pErrorCode==NULL || U_FAILURE(*pErrorCode) || length<=0) {
- * return;
- * }
- *
- * para=ubidi_openSized(length, 0, pErrorCode);
- * if(para==NULL) { return; }
- *
- * ubidi_setPara(para, text, length,
- * textDirection ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR,
- * NULL, pErrorCode);
- * if(U_SUCCESS(*pErrorCode)) {
- * UBiDiLevel paraLevel=1&ubidi_getParaLevel(para);
- * StyleRun styleRun={ length, styleNormal };
- * int width;
- *
- * if(styleRuns==NULL || styleRunCount<=0) {
- * styleRunCount=1;
- * styleRuns=&styleRun;
- * }
- *
- * // assume styleRuns[styleRunCount-1].limit>=length
- *
- * width=getTextWidth(text, 0, length, styleRuns, styleRunCount);
- * if(width<=lineWidth) {
- * // everything fits onto one line
- *
- * // prepare rendering a new line from either left or right
- * startLine(paraLevel, width);
- *
- * renderLine(para, text, 0, length,
- * styleRuns, styleRunCount);
- * } else {
- * UBiDi *line;
- *
- * // we need to render several lines
- * line=ubidi_openSized(length, 0, pErrorCode);
- * if(line!=NULL) {
- * int32_t start=0, limit;
- * int styleRunStart=0, styleRunLimit;
- *
- * for(;;) {
- * limit=length;
- * styleRunLimit=styleRunCount;
- * getLineBreak(text, start, &limit, para,
- * styleRuns, styleRunStart, &styleRunLimit,
- * &width);
- * ubidi_setLine(para, start, limit, line, pErrorCode);
- * if(U_SUCCESS(*pErrorCode)) {
- * // prepare rendering a new line
- * // from either left or right
- * startLine(paraLevel, width);
- *
- * renderLine(line, text, start, limit,
- * styleRuns+styleRunStart,
- * styleRunLimit-styleRunStart);
- * }
- * if(limit==length) { break; }
- * start=limit;
- * styleRunStart=styleRunLimit-1;
- * if(start>=styleRuns[styleRunStart].limit) {
- * ++styleRunStart;
- * }
- * }
- *
- * ubidi_close(line);
- * }
- * }
- * }
- *
- * ubidi_close(para);
- * }
- *
- */
-BIDI_SAMPLE_CODE
-/*@{*/
-/*@}*/
-
-/*@}*/
-
-#endif
diff --git a/jdk/src/share/native/sun/font/bidi/ubidiimp.h b/jdk/src/share/native/sun/font/bidi/ubidiimp.h
deleted file mode 100644
index e961aad84ec..00000000000
--- a/jdk/src/share/native/sun/font/bidi/ubidiimp.h
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Portions Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-/*
- * (C) Copyright IBM Corp. 1999-2003 - All Rights Reserved
- *
- * The original version of this source code and documentation is
- * copyrighted and owned by IBM. These materials are provided
- * under terms of a License Agreement between IBM and Sun.
- * This technology is protected by multiple US and International
- * patents. This notice and attribution to IBM may not be removed.
- */
-
-/*
-* file name: ubidiimp.h
-* encoding: US-ASCII
-* tab size: 8 (not used)
-* indentation:4
-*
-* created on: 1999aug06
-* created by: Markus W. Scherer
-*/
-
-#ifndef UBIDIIMP_H
-#define UBIDIIMP_H
-
-/* set import/export definitions */
-#ifdef U_COMMON_IMPLEMENTATION
-
-#include "utypes.h"
-#include "uchardir.h"
-
-/* miscellaneous definitions ---------------------------------------------- */
-
-typedef uint8_t DirProp;
-typedef uint32_t Flags;
-
-/* Comparing the description of the BiDi algorithm with this implementation
- is easier with the same names for the BiDi types in the code as there.
- See UCharDirection in uchar.h .
-*/
-enum {
- L= U_LEFT_TO_RIGHT,
- R= U_RIGHT_TO_LEFT,
- EN= U_EUROPEAN_NUMBER,
- ES= U_EUROPEAN_NUMBER_SEPARATOR,
- ET= U_EUROPEAN_NUMBER_TERMINATOR,
- AN= U_ARABIC_NUMBER,
- CS= U_COMMON_NUMBER_SEPARATOR,
- B= U_BLOCK_SEPARATOR,
- S= U_SEGMENT_SEPARATOR,
- WS= U_WHITE_SPACE_NEUTRAL,
- ON= U_OTHER_NEUTRAL,
- LRE=U_LEFT_TO_RIGHT_EMBEDDING,
- LRO=U_LEFT_TO_RIGHT_OVERRIDE,
- AL= U_RIGHT_TO_LEFT_ARABIC,
- RLE=U_RIGHT_TO_LEFT_EMBEDDING,
- RLO=U_RIGHT_TO_LEFT_OVERRIDE,
- PDF=U_POP_DIRECTIONAL_FORMAT,
- NSM=U_DIR_NON_SPACING_MARK,
- BN= U_BOUNDARY_NEUTRAL,
- dirPropCount
-};
-
-/*
- * Sometimes, bit values are more appropriate
- * to deal with directionality properties.
- * Abbreviations in these macro names refer to names
- * used in the BiDi algorithm.
- */
-#define DIRPROP_FLAG(dir) (1UL<<(dir))
-
-/* special flag for multiple runs from explicit embedding codes */
-#define DIRPROP_FLAG_MULTI_RUNS (1UL<<31)
-
-/* are there any characters that are LTR or RTL? */
-#define MASK_LTR (DIRPROP_FLAG(L)|DIRPROP_FLAG(EN)|DIRPROP_FLAG(AN)|DIRPROP_FLAG(LRE)|DIRPROP_FLAG(LRO))
-#define MASK_RTL (DIRPROP_FLAG(R)|DIRPROP_FLAG(AL)|DIRPROP_FLAG(RLE)|DIRPROP_FLAG(RLO))
-
-/* explicit embedding codes */
-#define MASK_LRX (DIRPROP_FLAG(LRE)|DIRPROP_FLAG(LRO))
-#define MASK_RLX (DIRPROP_FLAG(RLE)|DIRPROP_FLAG(RLO))
-#define MASK_OVERRIDE (DIRPROP_FLAG(LRO)|DIRPROP_FLAG(RLO))
-
-#define MASK_EXPLICIT (MASK_LRX|MASK_RLX|DIRPROP_FLAG(PDF))
-#define MASK_BN_EXPLICIT (DIRPROP_FLAG(BN)|MASK_EXPLICIT)
-
-/* paragraph and segment separators */
-#define MASK_B_S (DIRPROP_FLAG(B)|DIRPROP_FLAG(S))
-
-/* all types that are counted as White Space or Neutral in some steps */
-#define MASK_WS (MASK_B_S|DIRPROP_FLAG(WS)|MASK_BN_EXPLICIT)
-#define MASK_N (DIRPROP_FLAG(ON)|MASK_WS)
-
-/* all types that are included in a sequence of European Terminators for (W5) */
-#define MASK_ET_NSM_BN (DIRPROP_FLAG(ET)|DIRPROP_FLAG(NSM)|MASK_BN_EXPLICIT)
-
-/* types that are neutrals or could becomes neutrals in (Wn) */
-#define MASK_POSSIBLE_N (DIRPROP_FLAG(CS)|DIRPROP_FLAG(ES)|DIRPROP_FLAG(ET)|MASK_N)
-
-/*
- * These types may be changed to "e",
- * the embedding type (L or R) of the run,
- * in the BiDi algorithm (N2)
- */
-#define MASK_EMBEDDING (DIRPROP_FLAG(NSM)|MASK_POSSIBLE_N)
-
-/* the dirProp's L and R are defined to 0 and 1 values in UCharDirection */
-#define GET_LR_FROM_LEVEL(level) ((DirProp)((level)&1))
-
-#define IS_DEFAULT_LEVEL(level) (((level)&0xfe)==0xfe)
-
-/* handle surrogate pairs --------------------------------------------------- */
-/* Note: dlf added for java */
-#define IS_FIRST_SURROGATE(uchar) (((uchar)&0xfc00)==0xd800)
-#define IS_SECOND_SURROGATE(uchar) (((uchar)&0xfc00)==0xdc00)
-
-/* get the UTF-32 value directly from the surrogate pseudo-characters */
-#define SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
-#define GET_UTF_32(first, second) (((first)<<10UL)+(second)-SURROGATE_OFFSET)
-
-/* Run structure for reordering --------------------------------------------- */
-
-typedef struct Run {
- int32_t logicalStart, /* first character of the run; b31 indicates even/odd level */
- visualLimit; /* last visual position of the run +1 */
-} Run;
-
-/* in a Run, logicalStart will get this bit set if the run level is odd */
-#define INDEX_ODD_BIT (1UL<<31)
-
-#define MAKE_INDEX_ODD_PAIR(index, level) (index|((uint32_t)level<<31))
-#define ADD_ODD_BIT_FROM_LEVEL(x, level) ((x)|=((uint32_t)level<<31))
-#define REMOVE_ODD_BIT(x) ((x)&=~INDEX_ODD_BIT)
-
-#define GET_INDEX(x) (x&~INDEX_ODD_BIT)
-#define GET_ODD_BIT(x) ((uint32_t)x>>31)
-#define IS_ODD_RUN(x) ((x&INDEX_ODD_BIT)!=0)
-#define IS_EVEN_RUN(x) ((x&INDEX_ODD_BIT)==0)
-
-U_CFUNC bool_t
-ubidi_getRuns(UBiDi *pBiDi);
-
-/* UBiDi structure ----------------------------------------------------------- */
-
-struct UBiDi {
- /* alias pointer to the current text */
- const UChar *text;
-
- /* length of the current text */
- int32_t length;
-
- /* memory sizes in bytes */
- int32_t dirPropsSize, levelsSize, runsSize;
-
- /* allocated memory */
- DirProp *dirPropsMemory;
- UBiDiLevel *levelsMemory;
- Run *runsMemory;
-
- /* indicators for whether memory may be allocated after ubidi_open() */
- bool_t mayAllocateText, mayAllocateRuns;
-
- /* arrays with one value per text-character */
- const DirProp *dirProps;
- UBiDiLevel *levels;
-
- /* are we performing an approximation of the "inverse BiDi" algorithm? */
- bool_t isInverse;
-
- /* the paragraph level */
- UBiDiLevel paraLevel;
-
- /* the overall paragraph or line directionality - see UBiDiDirection */
- UBiDiDirection direction;
-
- /* flags is a bit set for which directional properties are in the text */
- Flags flags;
-
- /* characters after trailingWSStart are WS and are */
- /* implicitly at the paraLevel (rule (L1)) - levels may not reflect that */
- int32_t trailingWSStart;
-
- /* fields for line reordering */
- int32_t runCount; /* ==-1: runs not set up yet */
- Run *runs;
-
- /* for non-mixed text, we only need a tiny array of runs (no malloc()) */
- Run simpleRuns[1];
-};
-
-/* helper function to (re)allocate memory if allowed */
-extern bool_t
-ubidi_getMemory(void **pMemory, int32_t *pSize, bool_t mayAllocate, int32_t sizeNeeded);
-
-/* helper macros for each allocated array in UBiDi */
-#define getDirPropsMemory(pBiDi, length) \
- ubidi_getMemory((void **)&(pBiDi)->dirPropsMemory, &(pBiDi)->dirPropsSize, \
- (pBiDi)->mayAllocateText, (length))
-
-#define getLevelsMemory(pBiDi, length) \
- ubidi_getMemory((void **)&(pBiDi)->levelsMemory, &(pBiDi)->levelsSize, \
- (pBiDi)->mayAllocateText, (length))
-
-#define getRunsMemory(pBiDi, length) \
- ubidi_getMemory((void **)&(pBiDi)->runsMemory, &(pBiDi)->runsSize, \
- (pBiDi)->mayAllocateRuns, (length)*sizeof(Run))
-
-/* additional macros used by ubidi_open() - always allow allocation */
-#define getInitialDirPropsMemory(pBiDi, length) \
- ubidi_getMemory((void **)&(pBiDi)->dirPropsMemory, &(pBiDi)->dirPropsSize, \
- TRUE, (length))
-
-#define getInitialLevelsMemory(pBiDi, length) \
- ubidi_getMemory((void **)&(pBiDi)->levelsMemory, &(pBiDi)->levelsSize, \
- TRUE, (length))
-
-#define getInitialRunsMemory(pBiDi, length) \
- ubidi_getMemory((void **)&(pBiDi)->runsMemory, &(pBiDi)->runsSize, \
- TRUE, (length)*sizeof(Run))
-
-#endif
-
-#endif
diff --git a/jdk/src/share/native/sun/font/bidi/ubidiln.c b/jdk/src/share/native/sun/font/bidi/ubidiln.c
deleted file mode 100644
index 538c492404b..00000000000
--- a/jdk/src/share/native/sun/font/bidi/ubidiln.c
+++ /dev/null
@@ -1,996 +0,0 @@
-/*
- * Portions Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-/*
- * (C) Copyright IBM Corp. 1999-2003 - All Rights Reserved
- *
- * The original version of this source code and documentation is
- * copyrighted and owned by IBM. These materials are provided
- * under terms of a License Agreement between IBM and Sun.
- * This technology is protected by multiple US and International
- * patents. This notice and attribution to IBM may not be removed.
- */
-
-/*
-* file name: ubidiln.c
-* encoding: US-ASCII
-* tab size: 8 (not used)
-* indentation:4
-*
-* created on: 1999aug06
-* created by: Markus W. Scherer
-*/
-
-/* set import/export definitions */
-#ifndef U_COMMON_IMPLEMENTATION
-# define U_COMMON_IMPLEMENTATION
-#endif
-
-#include "cmemory.h"
-#include "utypes.h"
-#include "uchardir.h"
-#include "ubidi.h"
-#include "ubidiimp.h"
-
-/*
- * General remarks about the functions in this file:
- *
- * These functions deal with the aspects of potentially mixed-directional
- * text in a single paragraph or in a line of a single paragraph
- * which has already been processed according to
- * the Unicode 3.0 BiDi algorithm as defined in
- * http://www.unicode.org/unicode/reports/tr9/ , version 5,
- * also described in The Unicode Standard, Version 3.0 .
- *
- * This means that there is a UBiDi object with a levels
- * and a dirProps array.
- * paraLevel and direction are also set.
- * Only if the length of the text is zero, then levels==dirProps==NULL.
- *
- * The overall directionality of the paragraph
- * or line is used to bypass the reordering steps if possible.
- * Even purely RTL text does not need reordering there because
- * the ubidi_getLogical/VisualIndex() functions can compute the
- * index on the fly in such a case.
- *
- * The implementation of the access to same-level-runs and of the reordering
- * do attempt to provide better performance and less memory usage compared to
- * a direct implementation of especially rule (L2) with an array of
- * one (32-bit) integer per text character.
- *
- * Here, the levels array is scanned as soon as necessary, and a vector of
- * same-level-runs is created. Reordering then is done on this vector.
- * For each run of text positions that were resolved to the same level,
- * only 8 bytes are stored: the first text position of the run and the visual
- * position behind the run after reordering.
- * One sign bit is used to hold the directionality of the run.
- * This is inefficient if there are many very short runs. If the average run
- * length is <2, then this uses more memory.
- *
- * In a further attempt to save memory, the levels array is never changed
- * after all the resolution rules (Xn, Wn, Nn, In).
- * Many functions have to consider the field trailingWSStart:
- * if it is less than length, then there is an implicit trailing run
- * at the paraLevel,
- * which is not reflected in the levels array.
- * This allows a line UBiDi object to use the same levels array as
- * its paragraph parent object.
- *
- * When a UBiDi object is created for a line of a paragraph, then the
- * paragraph's levels and dirProps arrays are reused by way of setting
- * a pointer into them, not by copying. This again saves memory and forbids to
- * change the now shared levels for (L1).
- */
-
-/* prototypes --------------------------------------------------------------- */
-
-static void
-setTrailingWSStart(UBiDi *pBiDi);
-
-static void
-getSingleRun(UBiDi *pBiDi, UBiDiLevel level);
-
-static void
-reorderLine(UBiDi *pBiDi, UBiDiLevel minLevel, UBiDiLevel maxLevel);
-
-static bool_t
-prepareReorder(const UBiDiLevel *levels, int32_t length,
- int32_t *indexMap,
- UBiDiLevel *pMinLevel, UBiDiLevel *pMaxLevel);
-
-/* ubidi_setLine ------------------------------------------------------------ */
-
-U_CAPI void U_EXPORT2
-ubidi_setLine(const UBiDi *pParaBiDi,
- int32_t start, int32_t limit,
- UBiDi *pLineBiDi,
- UErrorCode *pErrorCode) {
- int32_t length;
-
- /* check the argument values */
- if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
- return;
- } else if(pParaBiDi==NULL || pLineBiDi==NULL) {
- *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
- return;
- } else if(start<0 || start>limit || limit>pParaBiDi->length) {
- *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
- return;
- }
-
- /* set the values in pLineBiDi from its pParaBiDi parent */
- pLineBiDi->text=pParaBiDi->text+start;
- length=pLineBiDi->length=limit-start;
- pLineBiDi->paraLevel=pParaBiDi->paraLevel;
-
- pLineBiDi->runs=NULL;
- pLineBiDi->flags=0;
-
- if(length>0) {
- pLineBiDi->dirProps=pParaBiDi->dirProps+start;
- pLineBiDi->levels=pParaBiDi->levels+start;
- pLineBiDi->runCount=-1;
-
- if(pParaBiDi->direction!=UBIDI_MIXED) {
- /* the parent is already trivial */
- pLineBiDi->direction=pParaBiDi->direction;
-
- /*
- * The parent's levels are all either
- * implicitly or explicitly ==paraLevel;
- * do the same here.
- */
- if(pParaBiDi->trailingWSStart<=start) {
- pLineBiDi->trailingWSStart=0;
- } else if(pParaBiDi->trailingWSStart