Path: blob/master/src/java.desktop/share/classes/sun/font/BidiUtils.java
41154 views
/*1* Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* (C) Copyright IBM Corp. 1999-2000 - All Rights Reserved27*28* The original version of this source code and documentation is29* copyrighted and owned by IBM. These materials are provided30* under terms of a License Agreement between IBM and Sun.31* This technology is protected by multiple US and International32* patents. This notice and attribution to IBM may not be removed.33*/3435package sun.font;3637import java.text.Bidi;3839public final class BidiUtils {40414243/**44* Return the level of each character into the levels array starting at start.45* This is a convenience method for clients who prefer to use an explicit levels46* array instead of iterating over the runs.47*48* @param levels the array to receive the character levels49* @param start the starting offset into the array50* @throws IndexOutOfBoundsException if {@code start} is less than 0 or51* {@code start + getLength()} is greater than {@code levels.length}.52*/53public static void getLevels(Bidi bidi, byte[] levels, int start) {54int limit = start + bidi.getLength();5556if (start < 0 || limit > levels.length) {57throw new IndexOutOfBoundsException("levels.length = " + levels.length +58" start: " + start + " limit: " + limit);59}6061int runCount = bidi.getRunCount();62int p = start;63for (int i = 0; i < runCount; ++i) {64int rlimit = start + bidi.getRunLimit(i);65byte rlevel = (byte)bidi.getRunLevel(i);6667while (p < rlimit) {68levels[p++] = rlevel;69}70}71}7273/**74* Return an array containing the resolved bidi level of each character, in logical order.75* @return an array containing the level of each character, in logical order.76*/77public static byte[] getLevels(Bidi bidi) {78byte[] levels = new byte[bidi.getLength()];79getLevels(bidi, levels, 0);80return levels;81}8283static final char NUMLEVELS = 62;8485/**86* Given level data, compute a a visual to logical mapping.87* The leftmost (or topmost) character is at visual index zero. The88* logical index of the character is derived from the visual index89* by the expression {@code li = map[vi];}.90* @param levels the levels array91* @return the mapping array from visual to logical92*/93public static int[] createVisualToLogicalMap(byte[] levels) {94int len = levels.length;95int[] mapping = new int[len];9697byte lowestOddLevel = (byte)(NUMLEVELS + 1);98byte highestLevel = 0;99100// initialize mapping and levels101102for (int i = 0; i < len; i++) {103mapping[i] = i;104105byte level = levels[i];106if (level > highestLevel) {107highestLevel = level;108}109110if ((level & 0x01) != 0 && level < lowestOddLevel) {111lowestOddLevel = level;112}113}114115while (highestLevel >= lowestOddLevel) {116int i = 0;117for (;;) {118while (i < len && levels[i] < highestLevel) {119i++;120}121int begin = i++;122123if (begin == levels.length) {124break; // no more runs at this level125}126127while (i < len && levels[i] >= highestLevel) {128i++;129}130int end = i - 1;131132while (begin < end) {133int temp = mapping[begin];134mapping[begin] = mapping[end];135mapping[end] = temp;136++begin;137--end;138}139}140141--highestLevel;142}143144return mapping;145}146147/**148* Return the inverse position map. The source array must map one-to-one (each value149* is distinct and the values run from zero to the length of the array minus one).150* For example, if {@code values[i] = j}, then {@code inverse[j] = i}.151* @param values the source ordering array152* @return the inverse array153*/154public static int[] createInverseMap(int[] values) {155if (values == null) {156return null;157}158159int[] result = new int[values.length];160for (int i = 0; i < values.length; i++) {161result[values[i]] = i;162}163164return result;165}166167168/**169* Return an array containing contiguous values from 0 to length170* having the same ordering as the source array. If this would be171* a canonical ltr ordering, return null. The data in values[] is NOT172* required to be a permutation, but elements in values are required173* to be distinct.174* @param values an array containing the discontiguous values175* @return the contiguous values176*/177public static int[] createContiguousOrder(int[] values) {178if (values != null) {179return computeContiguousOrder(values, 0, values.length);180}181182return null;183}184185/**186* Compute a contiguous order for the range start, limit.187*/188private static int[] computeContiguousOrder(int[] values, int start,189int limit) {190191int[] result = new int[limit-start];192for (int i=0; i < result.length; i++) {193result[i] = i + start;194}195196// now we'll sort result[], with the following comparison:197// result[i] lessthan result[j] iff values[result[i]] < values[result[j]]198199// selection sort for now; use more elaborate sorts if desired200for (int i=0; i < result.length-1; i++) {201int minIndex = i;202int currentValue = values[result[minIndex]];203for (int j=i; j < result.length; j++) {204if (values[result[j]] < currentValue) {205minIndex = j;206currentValue = values[result[minIndex]];207}208}209int temp = result[i];210result[i] = result[minIndex];211result[minIndex] = temp;212}213214// shift result by start:215if (start != 0) {216for (int i=0; i < result.length; i++) {217result[i] -= start;218}219}220221// next, check for canonical order:222int k;223for (k=0; k < result.length; k++) {224if (result[k] != k) {225break;226}227}228229if (k == result.length) {230return null;231}232233// now return inverse of result:234return createInverseMap(result);235}236237/**238* Return an array containing the data in the values array from start up to limit,239* normalized to fall within the range from 0 up to limit - start.240* If this would be a canonical ltr ordering, return null.241* NOTE: This method assumes that values[] is a logical to visual map242* generated from levels[].243* @param values the source mapping244* @param levels the levels corresponding to the values245* @param start the starting offset in the values and levels arrays246* @param limit the limiting offset in the values and levels arrays247* @return the normlized map248*/249public static int[] createNormalizedMap(int[] values, byte[] levels,250int start, int limit) {251252if (values != null) {253if (start != 0 || limit != values.length) {254// levels optimization255boolean copyRange, canonical;256byte primaryLevel;257258if (levels == null) {259primaryLevel = (byte) 0x0;260copyRange = true;261canonical = true;262}263else {264if (levels[start] == levels[limit-1]) {265primaryLevel = levels[start];266canonical = (primaryLevel & (byte)0x1) == 0;267268// scan for levels below primary269int i;270for (i=start; i < limit; i++) {271if (levels[i] < primaryLevel) {272break;273}274if (canonical) {275canonical = levels[i] == primaryLevel;276}277}278279copyRange = (i == limit);280}281else {282copyRange = false;283284// these don't matter; but the compiler cares:285primaryLevel = (byte) 0x0;286canonical = false;287}288}289290if (copyRange) {291if (canonical) {292return null;293}294295int[] result = new int[limit-start];296int baseValue;297298if ((primaryLevel & (byte)0x1) != 0) {299baseValue = values[limit-1];300} else {301baseValue = values[start];302}303304if (baseValue == 0) {305System.arraycopy(values, start, result, 0, limit-start);306}307else {308for (int j=0; j < result.length; j++) {309result[j] = values[j+start] - baseValue;310}311}312313return result;314}315else {316return computeContiguousOrder(values, start, limit);317}318}319else {320return values;321}322}323324return null;325}326327/**328* Reorder the objects in the array into visual order based on their levels.329* This is a utility function to use when you have a collection of objects330* representing runs of text in logical order, each run containing text331* at a single level. The elements in the objects array will be reordered332* into visual order assuming each run of text has the level provided333* by the corresponding element in the levels array.334* @param levels an array representing the bidi level of each object335* @param objects the array of objects to be reordered into visual order336*/337public static void reorderVisually(byte[] levels, Object[] objects) {338int len = levels.length;339340byte lowestOddLevel = (byte)(NUMLEVELS + 1);341byte highestLevel = 0;342343// initialize mapping and levels344345for (int i = 0; i < len; i++) {346byte level = levels[i];347if (level > highestLevel) {348highestLevel = level;349}350351if ((level & 0x01) != 0 && level < lowestOddLevel) {352lowestOddLevel = level;353}354}355356while (highestLevel >= lowestOddLevel) {357int i = 0;358for (;;) {359while (i < len && levels[i] < highestLevel) {360i++;361}362int begin = i++;363364if (begin == levels.length) {365break; // no more runs at this level366}367368while (i < len && levels[i] >= highestLevel) {369i++;370}371int end = i - 1;372373while (begin < end) {374Object temp = objects[begin];375objects[begin] = objects[end];376objects[end] = temp;377++begin;378--end;379}380}381382--highestLevel;383}384}385}386387388