📄 bidiorder.java
字号:
//
// Although the scan proceeds left to right, and changes the type values
// in a way that would appear to affect the computations later in the scan,
// there is actually no problem. A change in the current value can only
// affect the value to its immediate right, and only affect it if it is
// ES or CS. But the current value can only change if the value to its
// right is not ES or CS. Thus either the current value will not change,
// or its change will have no effect on the remainder of the analysis.
for (int i = start + 1; i < limit - 1; ++i) {
if (resultTypes[i] == ES || resultTypes[i] == CS) {
byte prevSepType = resultTypes[i-1];
byte succSepType = resultTypes[i+1];
if (prevSepType == EN && succSepType == EN) {
resultTypes[i] = EN;
} else if (resultTypes[i] == CS && prevSepType == AN && succSepType == AN) {
resultTypes[i] = AN;
}
}
}
// Rule W5.
for (int i = start; i < limit; ++i) {
if (resultTypes[i] == ET) {
// locate end of sequence
int runstart = i;
int runlimit = findRunLimit(runstart, limit, new byte[] { ET });
// check values at ends of sequence
byte t = runstart == start ? sor : resultTypes[runstart - 1];
if (t != EN) {
t = runlimit == limit ? eor : resultTypes[runlimit];
}
if (t == EN) {
setTypes(runstart, runlimit, EN);
}
// continue at end of sequence
i = runlimit;
}
}
// Rule W6.
for (int i = start; i < limit; ++i) {
byte t = resultTypes[i];
if (t == ES || t == ET || t == CS) {
resultTypes[i] = ON;
}
}
// Rule W7.
for (int i = start; i < limit; ++i) {
if (resultTypes[i] == EN) {
// set default if we reach start of run
byte prevStrongType = sor;
for (int j = i - 1; j >= start; --j) {
byte t = resultTypes[j];
if (t == L || t == R) { // AL's have been removed
prevStrongType = t;
break;
}
}
if (prevStrongType == L) {
resultTypes[i] = L;
}
}
}
}
/**
* 6) resolving neutral types
* Rules N1-N2.
*/
private void resolveNeutralTypes(int start, int limit, byte level, byte sor, byte eor) {
for (int i = start; i < limit; ++i) {
byte t = resultTypes[i];
if (t == WS || t == ON || t == B || t == S) {
// find bounds of run of neutrals
int runstart = i;
int runlimit = findRunLimit(runstart, limit, new byte[] {B, S, WS, ON});
// determine effective types at ends of run
byte leadingType;
byte trailingType;
if (runstart == start) {
leadingType = sor;
} else {
leadingType = resultTypes[runstart - 1];
if (leadingType == L || leadingType == R) {
// found the strong type
} else if (leadingType == AN) {
leadingType = R;
} else if (leadingType == EN) {
// Since EN's with previous strong L types have been changed
// to L in W7, the leadingType must be R.
leadingType = R;
}
}
if (runlimit == limit) {
trailingType = eor;
} else {
trailingType = resultTypes[runlimit];
if (trailingType == L || trailingType == R) {
// found the strong type
} else if (trailingType == AN) {
trailingType = R;
} else if (trailingType == EN) {
trailingType = R;
}
}
byte resolvedType;
if (leadingType == trailingType) {
// Rule N1.
resolvedType = leadingType;
} else {
// Rule N2.
// Notice the embedding level of the run is used, not
// the paragraph embedding level.
resolvedType = typeForLevel(level);
}
setTypes(runstart, runlimit, resolvedType);
// skip over run of (former) neutrals
i = runlimit;
}
}
}
/**
* 7) resolving implicit embedding levels
* Rules I1, I2.
*/
private void resolveImplicitLevels(int start, int limit, byte level, byte sor, byte eor) {
if ((level & 1) == 0) { // even level
for (int i = start; i < limit; ++i) {
byte t = resultTypes[i];
// Rule I1.
if (t == L ) {
// no change
} else if (t == R) {
resultLevels[i] += 1;
} else { // t == AN || t == EN
resultLevels[i] += 2;
}
}
} else { // odd level
for (int i = start; i < limit; ++i) {
byte t = resultTypes[i];
// Rule I2.
if (t == R) {
// no change
} else { // t == L || t == AN || t == EN
resultLevels[i] += 1;
}
}
}
}
//
// Output
//
public byte[] getLevels() {
return getLevels(new int[]{textLength});
}
/**
* Return levels array breaking lines at offsets in linebreaks. <br>
* Rule L1.
* <p>
* The returned levels array contains the resolved level for each
* bidi code passed to the constructor.
* <p>
* The linebreaks array must include at least one value.
* The values must be in strictly increasing order (no duplicates)
* between 1 and the length of the text, inclusive. The last value
* must be the length of the text.
*
* @param linebreaks the offsets at which to break the paragraph
* @return the resolved levels of the text
*/
public byte[] getLevels(int[] linebreaks) {
// Note that since the previous processing has removed all
// P, S, and WS values from resultTypes, the values referred to
// in these rules are the initial types, before any processing
// has been applied (including processing of overrides).
//
// This example implementation has reinserted explicit format codes
// and BN, in order that the levels array correspond to the
// initial text. Their final placement is not normative.
// These codes are treated like WS in this implementation,
// so they don't interrupt sequences of WS.
validateLineBreaks(linebreaks, textLength);
byte[] result = (byte[])resultLevels.clone(); // will be returned to caller
// don't worry about linebreaks since if there is a break within
// a series of WS values preceeding S, the linebreak itself
// causes the reset.
for (int i = 0; i < result.length; ++i) {
byte t = initialTypes[i];
if (t == B || t == S) {
// Rule L1, clauses one and two.
result[i] = paragraphEmbeddingLevel;
// Rule L1, clause three.
for (int j = i - 1; j >= 0; --j) {
if (isWhitespace(initialTypes[j])) { // including format codes
result[j] = paragraphEmbeddingLevel;
} else {
break;
}
}
}
}
// Rule L1, clause four.
int start = 0;
for (int i = 0; i < linebreaks.length; ++i) {
int limit = linebreaks[i];
for (int j = limit - 1; j >= start; --j) {
if (isWhitespace(initialTypes[j])) { // including format codes
result[j] = paragraphEmbeddingLevel;
} else {
break;
}
}
start = limit;
}
return result;
}
/**
* Return reordering array breaking lines at offsets in linebreaks.
* <p>
* The reordering array maps from a visual index to a logical index.
* Lines are concatenated from left to right. So for example, the
* fifth character from the left on the third line is
* <pre> getReordering(linebreaks)[linebreaks[1] + 4]</pre>
* (linebreaks[1] is the position after the last character of the
* second line, which is also the index of the first character on the
* third line, and adding four gets the fifth character from the left).
* <p>
* The linebreaks array must include at least one value.
* The values must be in strictly increasing order (no duplicates)
* between 1 and the length of the text, inclusive. The last value
* must be the length of the text.
*
* @param linebreaks the offsets at which to break the paragraph.
*/
public int[] getReordering(int[] linebreaks) {
validateLineBreaks(linebreaks, textLength);
byte[] levels = getLevels(linebreaks);
return computeMultilineReordering(levels, linebreaks);
}
/**
* Return multiline reordering array for a given level array.
* Reordering does not occur across a line break.
*/
private static int[] computeMultilineReordering(byte[] levels, int[] linebreaks) {
int[] result = new int[levels.length];
int start = 0;
for (int i = 0; i < linebreaks.length; ++i) {
int limit = linebreaks[i];
byte[] templevels = new byte[limit - start];
System.arraycopy(levels, start, templevels, 0, templevels.length);
int[] temporder = computeReordering(templevels);
for (int j = 0; j < temporder.length; ++j) {
result[start + j] = temporder[j] + start;
}
start = limit;
}
return result;
}
/**
* Return reordering array for a given level array. This reorders a single line.
* The reordering is a visual to logical map. For example,
* the leftmost char is string.charAt(order[0]).
* Rule L2.
*/
private static int[] computeReordering(byte[] levels) {
int lineLength = levels.length;
int[] result = new int[lineLength];
// initialize order
for (int i = 0; i < lineLength; ++i) {
result[i] = i;
}
// locate highest level found on line.
// Note the rules say text, but no reordering across line bounds is performed,
// so this is sufficient.
byte highestLevel = 0;
byte lowestOddLevel = 63;
for (int i = 0; i < lineLength; ++i) {
byte level = levels[i];
if (level > highestLevel) {
highestLevel = level;
}
if (((level & 1) != 0) && level < lowestOddLevel) {
lowestOddLevel = level;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -