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.
See Also:
See Also:
setReorderingMode
REORDER_DEFAULT
REORDER_NUMBERS_SPECIAL
REORDER_GROUP_NUMBERS_WITH_R
REORDER_RUNS_ONLY
REORDER_INVERSE_NUMBERS_AS_L
REORDER_INVERSE_LIKE_DIRECT
REORDER_INVERSE_FOR_NUMBERS_SPECIAL
See Also:
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);
}
}
Modifier and Type | Class and Description |
---|---|
public static interface | BidiBase.
Bidi Paired Bracket Type constants. |
pack-priv static class | |
private static class | |
pack-priv static class | |
pack-priv static class | |
pack-priv static class | |
private static class | |
private static class | BidiBase.
A class that provides access to java.awt.font.NumericShaper without creating a static dependency. |
pack-priv static class | |
pack-priv static class | |
private static class | BidiBase.
A class that provides access to constants defined by java.awt.font.TextAttribute without creating a static dependency. |
Modifier and Type | Field and Description |
---|---|
private static final short | |
private static final short | |
private static final short | |
private static final short | |
private static final short | |
private static final short | |
private static final short | |
private static final byte | |
private static final byte | |
pack-priv static final byte | |
pack-priv final UBiDiProps | |
public static final int | BIDI_PAIRED_BRACKET_TYPE
Enumerated property Bidi_Paired_Bracket_Type (new in Unicode 6.3). |
private static final byte | |
private static final int | |
pack-priv int | |
private static final char | |
private static final byte | |
pack-priv byte | |
pack-priv byte | |
public static final int | DIRECTION_DEFAULT_RIGHT_TO_LEFT
Constant indicating that the base direction depends on the first strong directional character in the text according to the Unicode Bidirectional Algorithm. |
pack-priv static final int[] | |
pack-priv static final int[] | |
pack-priv static final int | |
pack-priv static final int[] | |
pack-priv byte[] | |
pack-priv byte[] | |
public static final short | DO_MIRRORING
option bit for writeReordered(): replace characters with the "mirrored" property in RTL runs by their mirror-image mappings |
private static final byte | |
private static final byte | |
private static final byte | |
private static final byte | |
private static final byte | |
pack-priv static final int | |
pack-priv int | |
pack-priv static final byte | |
pack-priv static final byte | |
private static final byte | |
private static final short[] | |
private static final short[] | |
private static final short[] | |
private static final short[] | |
private static final short[] | |
private static final BidiBase. | |
private static final BidiBase. | |
private static final BidiBase. | |
private static final BidiBase. | |
private static final BidiBase. | |
private static final BidiBase. | |
private static final BidiBase. | |
private static final BidiBase. | |
private static final byte[][] | |
private static final byte[][] | |
private static final byte[][] | |
private static final byte[][] | |
private static final byte[][] | |
private static final byte[][] | |
private static final int | |
private static final int | |
pack-priv BidiBase. | |
private static final short[][] | |
private static final int | |
private static final int | |
private static final byte[][] | |
private static final byte[][] | |
private static final byte[][] | |
private static final byte[][] | |
private static final byte[][] | |
public static final short | INSERT_LRM_FOR_NUMERIC
option bit for writeReordered(): surround the run with LRMs if necessary; this is part of the approximate "inverse Bidi" algorithm This option does not imply corresponding adjustment of the index mappings. |
pack-priv BidiBase. | |
pack-priv boolean | |
pack-priv boolean | |
pack-priv static final int | |
pack-priv int | |
pack-priv BidiBase. | |
public static final short | KEEP_BASE_COMBINING
option bit for writeReordered(): keep combining characters after their base characters in RTL runs |
pack-priv static final byte | |
pack-priv int | |
public int | |
public static final byte | LEVEL_DEFAULT_LTR
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. |
public static final byte | LEVEL_DEFAULT_RTL
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. |
public static final byte | LEVEL_OVERRIDE
Bit flag for level input. |
pack-priv byte[] | |
pack-priv byte[] | |
private static final char | |
pack-priv int[] | |
pack-priv static final int | |
private static final byte | |
private static final byte | |
pack-priv static final int | |
pack-priv static final int | |
private static final byte | |
public static final byte | LTR
Left-to-right text. |
public static final int | MAP_NOWHERE
Special value which can be returned by the mapping methods when a logical index has no corresponding visual index or vice-versa. |
private static final int | |
private static final int | |
private static final int | |
private static final int | |
private static final int | |
pack-priv static final int | |
private static final int | |
pack-priv static final int | |
pack-priv static final int | |
pack-priv static final int | |
public static final byte | MAX_EXPLICIT_LEVEL
Maximum explicit embedding level. |
pack-priv boolean | |
pack-priv boolean | |
public static final byte | MIXED
Mixed-directional text. |
pack-priv static final int | |
private static final byte | |
private static final byte | |
pack-priv static final int | OPTION_INSERT_MARKS
Option bit for This option must be set or reset before calling
|
pack-priv static final int | OPTION_REMOVE_CONTROLS
Option bit for This option must be set or reset before calling
|
private static final int | OPTION_STREAMING
Option bit for This option must be set or reset before calling
|
pack-priv boolean | |
pack-priv int | |
public static final short | OUTPUT_REVERSE
option bit for writeReordered(): write the output in reverse order This has the same effect as calling |
pack-priv BidiBase | |
pack-priv int | |
pack-priv byte | |
pack-priv byte[] | |
pack-priv int[] | |
private static final byte | |
private static final byte | |
private static final byte | |
public static final short | REMOVE_BIDI_CONTROLS
option bit for writeReordered(): remove Bidi control characters (this does not affect INSERT_LRM_FOR_NUMERIC) This option does not imply corresponding adjustment of the index mappings. |
private static final short | REORDER_DEFAULT
Reordering mode: Regular Logical to Visual Bidi algorithm according to Unicode. |
private static final short | REORDER_GROUP_NUMBERS_WITH_R
Reordering mode: Logical to Visual algorithm grouping numbers with adjacent R characters (reversible algorithm). |
pack-priv static final short | REORDER_INVERSE_FOR_NUMBERS_SPECIAL
Reordering mode: Inverse Bidi (Visual to Logical) algorithm for the
|
pack-priv static final short | REORDER_INVERSE_LIKE_DIRECT
Reordering mode: Visual to Logical algorithm equivalent to the regular Logical to Visual algorithm. |
pack-priv static final short | REORDER_INVERSE_NUMBERS_AS_L
Reordering mode: Visual to Logical algorithm which handles numbers
like L (same algorithm as selected by |
private static final short | |
private static final short | REORDER_NUMBERS_SPECIAL
Reordering mode: Logical to Visual algorithm which handles numbers in a way which mimicks the behavior of Windows XP. |
pack-priv static final short | REORDER_RUNS_ONLY
Reordering mode: Reorder runs only to transform a Logical LTR string to the logical RTL string with the same display, or vice-versa. |
pack-priv int | |
pack-priv int | |
pack-priv int | |
private static final byte | |
private static final byte | |
pack-priv static final int | |
pack-priv static final int | |
private static final byte | |
public static final byte | RTL
Right-to-left text. |
pack-priv int | |
pack-priv BidiRun[] | |
pack-priv BidiRun[] | |
private static final byte | |
pack-priv static final int | |
pack-priv static final int | |
pack-priv static final int | |
pack-priv BidiRun[] | |
pack-priv char[] | |
pack-priv int | |
private static final byte |
Access | Constructor and Description |
---|---|
public | BidiBase(int
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. maxLength, int 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. maxRunCount)The number of runs depends on the actual text and maybe anywhere between 1 and maxLength . It is typically small.Allocate a |
public | BidiBase(char[]
an array containing the paragraph of text to process. text, int the index into the text array of the start of the
paragraph. textStart, byte[] 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. embeddings, int the index into the embedding array of the start of the
paragraph. embStart, int the length of the paragraph in the text and
embeddings arrays. paragraphLength, int 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. flags)Create Bidi from the given text, embedding, and direction information. |
Modifier and Type | Method and Description |
---|---|
private void | |
private void | |
public boolean | Returns: true if the base direction is left-to-rightReturn true if the base direction is left-to-right |
private int | |
private int | |
private void | |
private void | |
private void | |
private void | bracketProcessBoundary(BidiBase.
|
private void | |
private byte | |
private void | |
private void | |
private byte | |
private void | |
public int | |
private byte | |
pack-priv static final byte | |
pack-priv static int | |
pack-priv static final int | |
pack-priv static final int | |
pack-priv static final int | |
private void | |
private static short | |
private static short | |
public int | Returns: the base levelReturn the base level (0 if left-to-right, 1 if right-to-left). |
public int | Returns: The Bidi class for the characterc that is in effect
for this Bidi instance.The code point to get a Bidi class for. c)Retrieves the Bidi class for a given code point. |
public byte | Returns: a value ofLTR , RTL or MIXED
that indicates if the entire text
represented by this object is unidirectional,
and which direction, or if it is mixed-directional.Get the directionality of the text. |
private void | |
private void | |
pack-priv void | |
private void | |
private void | |
private void | |
public int | Returns: The length of the text that theBidi object was
created for.Get the length of the text. |
public byte | Returns: The level for the character atcharIndex .the index of a character. charIndex)Get the level for one character. |
pack-priv byte[] | Returns: The levels array for the text, ornull if an error occurs.Get an array of levels for each character. |
private void | |
pack-priv void | |
pack-priv void | |
private static byte | |
private Object | |
public byte | Returns: 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.Get the paragraph level of the text. |
pack-priv byte | |
public int | Returns: the level of the runthe index of the run, between 0 and run)countRuns()-1 Return the level of the nth logical run in this line. |
public int | Returns: the limit of the runthe index of the run, between 0 and run)countRuns() 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. |
private void | |
pack-priv void | |
public int | Returns: the start of the runthe index of the run, between 0 and run)countRuns() 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. |
private static short | |
private static short | |
private int[] | Returns: an array ofgetResultLength()
indexes which will reflect the reordering of the characters.The index map will result in indexMap[visualIndex]==logicalIndex , where
indexMap represents the returned array.Get a visual-to-logical index map (array) for the characters in the
|
pack-priv BidiRun | Returns: a BidiRun object containing the details of the run. The directionality of the run isLTR==0 or RTL==1 ,
never MIXED .is the number of the run in visual order, in the
range runIndex)[0..countRuns()-1] .Get a |
pack-priv static boolean | |
private static boolean | |
public boolean | Returns: true if the Bidi object is set to
perform the inverse Bidi algorithm by handling numbers as L.Is this |
public boolean | Returns: 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. |
public boolean | Returns: true if the line is not left-to-right or right-to-left.Return true if the line is not left-to-right or right-to-left. |
public boolean | Returns: true if the line is all right-to-left text, and the base direction is right-to-leftReturn true if the line is all right-to-left text, and the base direction is right-to-left |
pack-priv static final byte | |
public void | orderParagraphsLTR(boolean
specifies whether paragraph separators (B) must
receive level 0, so that successive paragraphs progress from left to right. ordarParaLTR)Specify whether block separators must be allocated level zero, so that successive paragraphs will progress from left to right. |
private void | |
private static int[] | Returns: an array oflevels.length
indexes which will reflect the reordering of the characters.
The index map will result in
is an array of levels that have been determined by
the application. levels)This is a convenience method that does not use a |
public static void | reorderVisually(byte[]
an array representing the bidi level of each object levels, int the start position in the levels array levelStart, Object[] the array of objects to be reordered into visual order objects, int the start position in the objects array objectStart, int the number of objects to reorder count)Reorder the objects in the array into visual order based on their levels. |
public static boolean | Returns: true if the range of characters requires bidi analysisthe text containing the characters to test text, int the start of the range of characters to test start, int the limit of the range of characters to test limit)Return true if the specified text requires bidi analysis. |
private byte | |
private void | |
private void | |
public Bidi | Returns: aBidi object that will now represent a line of the text.is the line's first index into the text. start, int is just behind the line's last index into the text
(its last index +1). limit)
|
pack-priv void | setPara(String
contains the text that the Bidi algorithm will be performed
on. This text can be retrieved with text, byte getText() or
getTextAsString .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, byte[] 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.(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
embeddingLevels)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 Perform the Unicode Bidi algorithm. |
pack-priv void | setPara(char[]
contains the text that the Bidi algorithm will be performed
on. This text can be retrieved with chars, byte getText() or
getTextAsString .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, byte[] 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.(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
embeddingLevels)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 Perform the Unicode Bidi algorithm. |
public void | setPara(AttributedCharacterIterator
a paragraph of text with optional character and
paragraph attribute information paragraph)Perform the Unicode Bidi algorithm on a given paragraph, as defined in the Unicode Standard Annex #9: Unicode Bidirectional Algorithm, version 13, also described in The Unicode Standard, Version 4.0 . |
pack-priv void | |
private void | |
pack-priv boolean | |
public String | |
pack-priv void | |
pack-priv void | |
pack-priv void | |
public String | Returns: The reordered text. If theINSERT_LRM_FOR_NUMERIC option is set, then
the length of the returned string could be as large as
getLength()+2*countRuns() .If the REMOVE_BIDI_CONTROLS option is set, then the
length of the returned string may be less than
getLength() .If none of these options is set, then the length of the returned string will be exactly getProcessedLength() .A bit set of options for the reordering that control
how the reordered text is written.
The options include mirroring the characters on a code
point basis and inserting LRM characters, which is used
especially for transforming visually stored text
to logically stored text (although this is still an
imperfect implementation of an "inverse Bidi" algorithm
because it uses the "forward Bidi" algorithm at its core).
The available options are:
options)DO_MIRRORING ,
INSERT_LRM_FOR_NUMERIC ,
KEEP_BASE_COMBINING ,
OUTPUT_REVERSE ,
REMOVE_BIDI_CONTROLS ,
STREAMING Take a |