/java-1.7.0-openjdk/openjdk/jdk/src/share/classes/sun/font/BidiUtils.java
Java | 386 lines | 219 code | 60 blank | 107 comment | 78 complexity | 821e1c44442744775bbb34cef9b1a1f8 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, LGPL-3.0, LGPL-2.0
- /*
- * Copyright (c) 2000, 2003, Oracle and/or its affiliates. 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
- /*
- * (C) Copyright IBM Corp. 1999-2000 - 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.
- */
- package sun.font;
- import java.text.Bidi;
- public final class BidiUtils {
- /**
- * Return the level of each character into the levels array starting at start.
- * This is a convenience method for clients who prefer to use an explicit levels
- * array instead of iterating over the runs.
- *
- * @param levels the array to receive the character levels
- * @param start the starting offset into the the array
- * @throws IndexOutOfBoundsException if <code>start</code> is less than 0 or
- * <code>start + getLength()</code> is greater than <code>levels.length</code>.
- */
- public static void getLevels(Bidi bidi, byte[] levels, int start) {
- int limit = start + bidi.getLength();
- if (start < 0 || limit > levels.length) {
- throw new IndexOutOfBoundsException("levels.length = " + levels.length +
- " start: " + start + " limit: " + limit);
- }
- int runCount = bidi.getRunCount();
- int p = start;
- for (int i = 0; i < runCount; ++i) {
- int rlimit = start + bidi.getRunLimit(i);
- byte rlevel = (byte)bidi.getRunLevel(i);
- while (p < rlimit) {
- levels[p++] = rlevel;
- }
- }
- }
- /**
- * Return an array containing the resolved bidi level of each character, in logical order.
- * @return an array containing the level of each character, in logical order.
- */
- public static byte[] getLevels(Bidi bidi) {
- byte[] levels = new byte[bidi.getLength()];
- getLevels(bidi, levels, 0);
- return levels;
- }
- static final char NUMLEVELS = 62;
- /**
- * Given level data, compute a a visual to logical mapping.
- * The leftmost (or topmost) character is at visual index zero. The
- * logical index of the character is derived from the visual index
- * by the expression <code>li = map[vi];</code>.
- * @param levels the levels array
- * @return the mapping array from visual to logical
- */
- public static int[] createVisualToLogicalMap(byte[] levels) {
- int len = levels.length;
- int[] mapping = new int[len];
- byte lowestOddLevel = (byte)(NUMLEVELS + 1);
- byte highestLevel = 0;
- // initialize mapping and levels
- for (int i = 0; i < len; i++) {
- mapping[i] = i;
- byte level = levels[i];
- if (level > highestLevel) {
- highestLevel = level;
- }
- if ((level & 0x01) != 0 && level < lowestOddLevel) {
- lowestOddLevel = level;
- }
- }
- while (highestLevel >= lowestOddLevel) {
- int i = 0;
- for (;;) {
- while (i < len && levels[i] < highestLevel) {
- i++;
- }
- int begin = i++;
- if (begin == levels.length) {
- break; // no more runs at this level
- }
- while (i < len && levels[i] >= highestLevel) {
- i++;
- }
- int end = i - 1;
- while (begin < end) {
- int temp = mapping[begin];
- mapping[begin] = mapping[end];
- mapping[end] = temp;
- ++begin;
- --end;
- }
- }
- --highestLevel;
- }
- return mapping;
- }
- /**
- * Return the inverse position map. The source array must map one-to-one (each value
- * is distinct and the values run from zero to the length of the array minus one).
- * For example, if <code>values[i] = j</code>, then <code>inverse[j] = i</code>.
- * @param values the source ordering array
- * @return the inverse array
- */
- public static int[] createInverseMap(int[] values) {
- if (values == null) {
- return null;
- }
- int[] result = new int[values.length];
- for (int i = 0; i < values.length; i++) {
- result[values[i]] = i;
- }
- return result;
- }
- /**
- * Return an array containing contiguous values from 0 to length
- * having the same ordering as the source array. If this would be
- * a canonical ltr ordering, return null. The data in values[] is NOT
- * required to be a permutation, but elements in values are required
- * to be distinct.
- * @param values an array containing the discontiguous values
- * @return the contiguous values
- */
- public static int[] createContiguousOrder(int[] values) {
- if (values != null) {
- return computeContiguousOrder(values, 0, values.length);
- }
- return null;
- }
- /**
- * Compute a contiguous order for the range start, limit.
- */
- private static int[] computeContiguousOrder(int[] values, int start,
- int limit) {
- int[] result = new int[limit-start];
- for (int i=0; i < result.length; i++) {
- result[i] = i + start;
- }
- // now we'll sort result[], with the following comparison:
- // result[i] lessthan result[j] iff values[result[i]] < values[result[j]]
- // selection sort for now; use more elaborate sorts if desired
- for (int i=0; i < result.length-1; i++) {
- int minIndex = i;
- int currentValue = values[result[minIndex]];
- for (int j=i; j < result.length; j++) {
- if (values[result[j]] < currentValue) {
- minIndex = j;
- currentValue = values[result[minIndex]];
- }
- }
- int temp = result[i];
- result[i] = result[minIndex];
- result[minIndex] = temp;
- }
- // shift result by start:
- if (start != 0) {
- for (int i=0; i < result.length; i++) {
- result[i] -= start;
- }
- }
- // next, check for canonical order:
- int k;
- for (k=0; k < result.length; k++) {
- if (result[k] != k) {
- break;
- }
- }
- if (k == result.length) {
- return null;
- }
- // now return inverse of result:
- return createInverseMap(result);
- }
- /**
- * Return an array containing the data in the values array from start up to limit,
- * normalized to fall within the range from 0 up to limit - start.
- * If this would be a canonical ltr ordering, return null.
- * NOTE: This method assumes that values[] is a logical to visual map
- * generated from levels[].
- * @param values the source mapping
- * @param levels the levels corresponding to the values
- * @param start the starting offset in the values and levels arrays
- * @param limit the limiting offset in the values and levels arrays
- * @return the normlized map
- */
- public static int[] createNormalizedMap(int[] values, byte[] levels,
- int start, int limit) {
- if (values != null) {
- if (start != 0 || limit != values.length) {
- // levels optimization
- boolean copyRange, canonical;
- byte primaryLevel;
- if (levels == null) {
- primaryLevel = (byte) 0x0;
- copyRange = true;
- canonical = true;
- }
- else {
- if (levels[start] == levels[limit-1]) {
- primaryLevel = levels[start];
- canonical = (primaryLevel & (byte)0x1) == 0;
- // scan for levels below primary
- int i;
- for (i=start; i < limit; i++) {
- if (levels[i] < primaryLevel) {
- break;
- }
- if (canonical) {
- canonical = levels[i] == primaryLevel;
- }
- }
- copyRange = (i == limit);
- }
- else {
- copyRange = false;
- // these don't matter; but the compiler cares:
- primaryLevel = (byte) 0x0;
- canonical = false;
- }
- }
- if (copyRange) {
- if (canonical) {
- return null;
- }
- int[] result = new int[limit-start];
- int baseValue;
- if ((primaryLevel & (byte)0x1) != 0) {
- baseValue = values[limit-1];
- } else {
- baseValue = values[start];
- }
- if (baseValue == 0) {
- System.arraycopy(values, start, result, 0, limit-start);
- }
- else {
- for (int j=0; j < result.length; j++) {
- result[j] = values[j+start] - baseValue;
- }
- }
- return result;
- }
- else {
- return computeContiguousOrder(values, start, limit);
- }
- }
- else {
- return values;
- }
- }
- return null;
- }
- /**
- * Reorder the objects in the array into visual order based on their levels.
- * This is a utility function 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 in the objects array will be reordered
- * into visual order assuming each run of text has the level provided
- * by the corresponding element in the levels array.
- * @param levels an array representing the bidi level of each object
- * @param objects the array of objects to be reordered into visual order
- */
- public static void reorderVisually(byte[] levels, Object[] objects) {
- int len = levels.length;
- byte lowestOddLevel = (byte)(NUMLEVELS + 1);
- byte highestLevel = 0;
- // initialize mapping and levels
- for (int i = 0; i < len; i++) {
- byte level = levels[i];
- if (level > highestLevel) {
- highestLevel = level;
- }
- if ((level & 0x01) != 0 && level < lowestOddLevel) {
- lowestOddLevel = level;
- }
- }
- while (highestLevel >= lowestOddLevel) {
- int i = 0;
- for (;;) {
- while (i < len && levels[i] < highestLevel) {
- i++;
- }
- int begin = i++;
- if (begin == levels.length) {
- break; // no more runs at this level
- }
- while (i < len && levels[i] >= highestLevel) {
- i++;
- }
- int end = i - 1;
- while (begin < end) {
- Object temp = objects[begin];
- objects[begin] = objects[end];
- objects[end] = temp;
- ++begin;
- --end;
- }
- }
- --highestLevel;
- }
- }
- }