📄 bidi.java
字号:
} /** * An internal method to resolve implicit levels. * This implements rules I1 and I2. */ private void resolveImplicitLevels() { // This implements rules I1 and I2. for (int i = 0; i < length; ++i) { if ((levels[i] & 1) == 0) { if (types[i] == Character.DIRECTIONALITY_RIGHT_TO_LEFT) ++levels[i]; else if (types[i] == Character.DIRECTIONALITY_ARABIC_NUMBER || types[i] == Character.DIRECTIONALITY_EUROPEAN_NUMBER) levels[i] += 2; } else { if (types[i] == Character.DIRECTIONALITY_LEFT_TO_RIGHT || types[i] == Character.DIRECTIONALITY_ARABIC_NUMBER || types[i] == Character.DIRECTIONALITY_EUROPEAN_NUMBER) ++levels[i]; } // Update the result flags. resultFlags |= 1 << (levels[i] & 1); } // One final update of the result flags, using the base level. resultFlags |= 1 << baseEmbedding; } /** * This reinserts the formatting codes that we removed early on. * Actually it does not insert formatting codes per se, but rather * simply inserts new levels at the appropriate locations in the * 'levels' array. */ private void reinsertFormattingCodes() { if (formatterIndices == null) return; int input = length; int output = levels.length; // Process from the end as we are copying the array over itself here. for (int index = formatterIndices.size() - 1; index >= 0; --index) { int nextFmt = ((Integer) formatterIndices.get(index)).intValue(); // nextFmt points to a location in the original array. So, // nextFmt+1 is the target of our copying. output is the location // to which we last copied, thus we can derive the length of the // copy from it. int len = output - nextFmt - 1; output = nextFmt; input -= len; // Note that we no longer need 'types' at this point, so we // only edit 'levels'. if (nextFmt + 1 < levels.length) System.arraycopy(levels, input, levels, nextFmt + 1, len); // Now set the level at the reinsertion point. int rightLevel; if (output == levels.length - 1) rightLevel = baseEmbedding; else rightLevel = levels[output + 1]; int leftLevel; if (input == 0) leftLevel = baseEmbedding; else leftLevel = levels[input]; levels[output] = (byte) Math.max(leftLevel, rightLevel); } length = levels.length; } /** * This is the main internal entry point. After a constructor * has initialized the appropriate local state, it will call * this method to do all the work. */ private void runBidi() { computeTypes(); baseEmbedding = computeParagraphEmbeddingLevel(); computeExplicitLevels(); computeRuns(); resolveWeakTypes(); resolveNeutralTypes(); resolveImplicitLevels(); // We're done with the types. Let the GC clean up. types = null; reinsertFormattingCodes(); // After resolving the implicit levels, the number // of runs may have changed. computeRuns(); } /** * Return true if the paragraph base embedding is left-to-right, * false otherwise. */ public boolean baseIsLeftToRight() { return baseEmbedding == DIRECTION_LEFT_TO_RIGHT; } /** * Create a new Bidi object for a single line of text, taken * from the text used when creating the current Bidi object. * @param start the index of the first character of the line * @param end the index of the final character of the line * @return a new Bidi object for the indicated line of text */ public Bidi createLineBidi(int start, int end) { // This isn't the most efficient implementation possible. // This probably does not matter, so we choose simplicity instead. int level = getLevelAt(start); int flag = (((level % 2) == 0) ? DIRECTION_LEFT_TO_RIGHT : DIRECTION_RIGHT_TO_LEFT); return new Bidi(text, textOffset + start, embeddings, embeddingOffset + start, end - start, flag); } /** * Return the base embedding level of the paragraph. */ public int getBaseLevel() { return baseEmbedding; } /** * Return the length of the paragraph, in characters. */ public int getLength() { return length; } /** * Return the level at the indicated character. If the * supplied index is less than zero or greater than the length * of the text, then the paragraph's base embedding level will * be returned. * @param offset the character to examine * @return the level of that character */ public int getLevelAt(int offset) { if (offset < 0 || offset >= length) return getBaseLevel(); return levels[offset]; } /** * Return the number of runs in the result. A run is * a sequence of characters at the same embedding level. */ public int getRunCount() { return runs.length; } /** * Return the level of the indicated run. * @param which the run to examine * @return the level of that run */ public int getRunLevel(int which) { return levels[runs[which]]; } /** * Return the index of the character just following the end * of the indicated run. * @param which the run to examine * @return the index of the character after the final character * of the run */ public int getRunLimit(int which) { if (which == runs.length - 1) return length; return runs[which + 1]; } /** * Return the index of the first character in the indicated run. * @param which the run to examine * @return the index of the first character of the run */ public int getRunStart(int which) { return runs[which]; } /** * Return true if the text is entirely left-to-right, and the * base embedding is also left-to-right. */ public boolean isLeftToRight() { return resultFlags == LTOR; } /** * Return true if the text consists of mixed left-to-right and * right-to-left runs, or if the text consists of one kind of run * which differs from the base embedding direction. */ public boolean isMixed() { return resultFlags == (LTOR | RTOL); } /** * Return true if the text is entirely right-to-left, and the * base embedding is also right-to-left. */ public boolean isRightToLeft() { return resultFlags == RTOL; } /** * Return a String describing the internal state of this object. * This is only useful for debugging. */ public String toString() { return "Bidi Bidi Bidi I like you, Buck!"; } /** * Reorder objects according to the levels passed in. This implements * reordering as defined by the Unicode bidirectional layout specification. * The levels are integers from 0 to 62; even numbers represent left-to-right * runs, and odd numbers represent right-to-left runs. * * @param levels the levels associated with each object * @param levelOffset the index of the first level to use * @param objs the objects to reorder according to the levels * @param objOffset the index of the first object to use * @param count the number of objects (and levels) to manipulate */ public static void reorderVisually(byte[] levels, int levelOffset, Object[] objs, int objOffset, int count) { // We need a copy of the 'levels' array, as we are going to modify it. // This is unfortunate but difficult to avoid. byte[] levelCopy = new byte[count]; // Do this explicitly so we can also find the maximum depth at the // same time. int max = 0; int lowestOdd = 63; for (int i = 0; i < count; ++i) { levelCopy[i] = levels[levelOffset + i]; max = Math.max(levelCopy[i], max); if (levelCopy[i] % 2 != 0) lowestOdd = Math.min(lowestOdd, levelCopy[i]); } // Reverse the runs starting with the deepest. for (int depth = max; depth >= lowestOdd; --depth) { int start = 0; while (start < count) { // Find the start of a run >= DEPTH. while (start < count && levelCopy[start] < depth) ++start; if (start == count) break; // Find the end of the run. int end = start + 1; while (end < count && levelCopy[end] >= depth) ++end; // Reverse this run. for (int i = 0; i < (end - start) / 2; ++i) { byte tmpb = levelCopy[end - i - 1]; levelCopy[end - i - 1] = levelCopy[start + i]; levelCopy[start + i] = tmpb; Object tmpo = objs[objOffset + end - i - 1]; objs[objOffset + end - i - 1] = objs[objOffset + start + i]; objs[objOffset + start + i] = tmpo; } // Handle the next run. start = end + 1; } } } /** * Returns false if all characters in the text between start and end * are all left-to-right text. This implementation is just calls * <code>Character.getDirectionality(char)</code> on all characters * and makes sure all characters are either explicitly left-to-right * or neutral in directionality (character types L, EN, ES, ET, AN, * CS, S and WS). */ public static boolean requiresBidi(char[] text, int start, int end) { for (int i = start; i < end; i++) { byte dir = Character.getDirectionality(text[i]); if (dir != Character.DIRECTIONALITY_LEFT_TO_RIGHT && dir != Character.DIRECTIONALITY_EUROPEAN_NUMBER && dir != Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR && dir != Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR && dir != Character.DIRECTIONALITY_ARABIC_NUMBER && dir != Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR && dir != Character.DIRECTIONALITY_SEGMENT_SEPARATOR && dir != Character.DIRECTIONALITY_WHITESPACE) return true; } return false; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -