PageRenderTime 60ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/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
  1. /*
  2. * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
  3. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4. *
  5. * This code is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License version 2 only, as
  7. * published by the Free Software Foundation. Oracle designates this
  8. * particular file as subject to the "Classpath" exception as provided
  9. * by Oracle in the LICENSE file that accompanied this code.
  10. *
  11. * This code is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * version 2 for more details (a copy is included in the LICENSE file that
  15. * accompanied this code).
  16. *
  17. * You should have received a copy of the GNU General Public License version
  18. * 2 along with this work; if not, write to the Free Software Foundation,
  19. * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20. *
  21. * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22. * or visit www.oracle.com if you need additional information or have any
  23. * questions.
  24. */
  25. /*
  26. * (C) Copyright IBM Corp. 1999-2000 - All Rights Reserved
  27. *
  28. * The original version of this source code and documentation is
  29. * copyrighted and owned by IBM. These materials are provided
  30. * under terms of a License Agreement between IBM and Sun.
  31. * This technology is protected by multiple US and International
  32. * patents. This notice and attribution to IBM may not be removed.
  33. */
  34. package sun.font;
  35. import java.text.Bidi;
  36. public final class BidiUtils {
  37. /**
  38. * Return the level of each character into the levels array starting at start.
  39. * This is a convenience method for clients who prefer to use an explicit levels
  40. * array instead of iterating over the runs.
  41. *
  42. * @param levels the array to receive the character levels
  43. * @param start the starting offset into the the array
  44. * @throws IndexOutOfBoundsException if <code>start</code> is less than 0 or
  45. * <code>start + getLength()</code> is greater than <code>levels.length</code>.
  46. */
  47. public static void getLevels(Bidi bidi, byte[] levels, int start) {
  48. int limit = start + bidi.getLength();
  49. if (start < 0 || limit > levels.length) {
  50. throw new IndexOutOfBoundsException("levels.length = " + levels.length +
  51. " start: " + start + " limit: " + limit);
  52. }
  53. int runCount = bidi.getRunCount();
  54. int p = start;
  55. for (int i = 0; i < runCount; ++i) {
  56. int rlimit = start + bidi.getRunLimit(i);
  57. byte rlevel = (byte)bidi.getRunLevel(i);
  58. while (p < rlimit) {
  59. levels[p++] = rlevel;
  60. }
  61. }
  62. }
  63. /**
  64. * Return an array containing the resolved bidi level of each character, in logical order.
  65. * @return an array containing the level of each character, in logical order.
  66. */
  67. public static byte[] getLevels(Bidi bidi) {
  68. byte[] levels = new byte[bidi.getLength()];
  69. getLevels(bidi, levels, 0);
  70. return levels;
  71. }
  72. static final char NUMLEVELS = 62;
  73. /**
  74. * Given level data, compute a a visual to logical mapping.
  75. * The leftmost (or topmost) character is at visual index zero. The
  76. * logical index of the character is derived from the visual index
  77. * by the expression <code>li = map[vi];</code>.
  78. * @param levels the levels array
  79. * @return the mapping array from visual to logical
  80. */
  81. public static int[] createVisualToLogicalMap(byte[] levels) {
  82. int len = levels.length;
  83. int[] mapping = new int[len];
  84. byte lowestOddLevel = (byte)(NUMLEVELS + 1);
  85. byte highestLevel = 0;
  86. // initialize mapping and levels
  87. for (int i = 0; i < len; i++) {
  88. mapping[i] = i;
  89. byte level = levels[i];
  90. if (level > highestLevel) {
  91. highestLevel = level;
  92. }
  93. if ((level & 0x01) != 0 && level < lowestOddLevel) {
  94. lowestOddLevel = level;
  95. }
  96. }
  97. while (highestLevel >= lowestOddLevel) {
  98. int i = 0;
  99. for (;;) {
  100. while (i < len && levels[i] < highestLevel) {
  101. i++;
  102. }
  103. int begin = i++;
  104. if (begin == levels.length) {
  105. break; // no more runs at this level
  106. }
  107. while (i < len && levels[i] >= highestLevel) {
  108. i++;
  109. }
  110. int end = i - 1;
  111. while (begin < end) {
  112. int temp = mapping[begin];
  113. mapping[begin] = mapping[end];
  114. mapping[end] = temp;
  115. ++begin;
  116. --end;
  117. }
  118. }
  119. --highestLevel;
  120. }
  121. return mapping;
  122. }
  123. /**
  124. * Return the inverse position map. The source array must map one-to-one (each value
  125. * is distinct and the values run from zero to the length of the array minus one).
  126. * For example, if <code>values[i] = j</code>, then <code>inverse[j] = i</code>.
  127. * @param values the source ordering array
  128. * @return the inverse array
  129. */
  130. public static int[] createInverseMap(int[] values) {
  131. if (values == null) {
  132. return null;
  133. }
  134. int[] result = new int[values.length];
  135. for (int i = 0; i < values.length; i++) {
  136. result[values[i]] = i;
  137. }
  138. return result;
  139. }
  140. /**
  141. * Return an array containing contiguous values from 0 to length
  142. * having the same ordering as the source array. If this would be
  143. * a canonical ltr ordering, return null. The data in values[] is NOT
  144. * required to be a permutation, but elements in values are required
  145. * to be distinct.
  146. * @param values an array containing the discontiguous values
  147. * @return the contiguous values
  148. */
  149. public static int[] createContiguousOrder(int[] values) {
  150. if (values != null) {
  151. return computeContiguousOrder(values, 0, values.length);
  152. }
  153. return null;
  154. }
  155. /**
  156. * Compute a contiguous order for the range start, limit.
  157. */
  158. private static int[] computeContiguousOrder(int[] values, int start,
  159. int limit) {
  160. int[] result = new int[limit-start];
  161. for (int i=0; i < result.length; i++) {
  162. result[i] = i + start;
  163. }
  164. // now we'll sort result[], with the following comparison:
  165. // result[i] lessthan result[j] iff values[result[i]] < values[result[j]]
  166. // selection sort for now; use more elaborate sorts if desired
  167. for (int i=0; i < result.length-1; i++) {
  168. int minIndex = i;
  169. int currentValue = values[result[minIndex]];
  170. for (int j=i; j < result.length; j++) {
  171. if (values[result[j]] < currentValue) {
  172. minIndex = j;
  173. currentValue = values[result[minIndex]];
  174. }
  175. }
  176. int temp = result[i];
  177. result[i] = result[minIndex];
  178. result[minIndex] = temp;
  179. }
  180. // shift result by start:
  181. if (start != 0) {
  182. for (int i=0; i < result.length; i++) {
  183. result[i] -= start;
  184. }
  185. }
  186. // next, check for canonical order:
  187. int k;
  188. for (k=0; k < result.length; k++) {
  189. if (result[k] != k) {
  190. break;
  191. }
  192. }
  193. if (k == result.length) {
  194. return null;
  195. }
  196. // now return inverse of result:
  197. return createInverseMap(result);
  198. }
  199. /**
  200. * Return an array containing the data in the values array from start up to limit,
  201. * normalized to fall within the range from 0 up to limit - start.
  202. * If this would be a canonical ltr ordering, return null.
  203. * NOTE: This method assumes that values[] is a logical to visual map
  204. * generated from levels[].
  205. * @param values the source mapping
  206. * @param levels the levels corresponding to the values
  207. * @param start the starting offset in the values and levels arrays
  208. * @param limit the limiting offset in the values and levels arrays
  209. * @return the normlized map
  210. */
  211. public static int[] createNormalizedMap(int[] values, byte[] levels,
  212. int start, int limit) {
  213. if (values != null) {
  214. if (start != 0 || limit != values.length) {
  215. // levels optimization
  216. boolean copyRange, canonical;
  217. byte primaryLevel;
  218. if (levels == null) {
  219. primaryLevel = (byte) 0x0;
  220. copyRange = true;
  221. canonical = true;
  222. }
  223. else {
  224. if (levels[start] == levels[limit-1]) {
  225. primaryLevel = levels[start];
  226. canonical = (primaryLevel & (byte)0x1) == 0;
  227. // scan for levels below primary
  228. int i;
  229. for (i=start; i < limit; i++) {
  230. if (levels[i] < primaryLevel) {
  231. break;
  232. }
  233. if (canonical) {
  234. canonical = levels[i] == primaryLevel;
  235. }
  236. }
  237. copyRange = (i == limit);
  238. }
  239. else {
  240. copyRange = false;
  241. // these don't matter; but the compiler cares:
  242. primaryLevel = (byte) 0x0;
  243. canonical = false;
  244. }
  245. }
  246. if (copyRange) {
  247. if (canonical) {
  248. return null;
  249. }
  250. int[] result = new int[limit-start];
  251. int baseValue;
  252. if ((primaryLevel & (byte)0x1) != 0) {
  253. baseValue = values[limit-1];
  254. } else {
  255. baseValue = values[start];
  256. }
  257. if (baseValue == 0) {
  258. System.arraycopy(values, start, result, 0, limit-start);
  259. }
  260. else {
  261. for (int j=0; j < result.length; j++) {
  262. result[j] = values[j+start] - baseValue;
  263. }
  264. }
  265. return result;
  266. }
  267. else {
  268. return computeContiguousOrder(values, start, limit);
  269. }
  270. }
  271. else {
  272. return values;
  273. }
  274. }
  275. return null;
  276. }
  277. /**
  278. * Reorder the objects in the array into visual order based on their levels.
  279. * This is a utility function to use when you have a collection of objects
  280. * representing runs of text in logical order, each run containing text
  281. * at a single level. The elements in the objects array will be reordered
  282. * into visual order assuming each run of text has the level provided
  283. * by the corresponding element in the levels array.
  284. * @param levels an array representing the bidi level of each object
  285. * @param objects the array of objects to be reordered into visual order
  286. */
  287. public static void reorderVisually(byte[] levels, Object[] objects) {
  288. int len = levels.length;
  289. byte lowestOddLevel = (byte)(NUMLEVELS + 1);
  290. byte highestLevel = 0;
  291. // initialize mapping and levels
  292. for (int i = 0; i < len; i++) {
  293. byte level = levels[i];
  294. if (level > highestLevel) {
  295. highestLevel = level;
  296. }
  297. if ((level & 0x01) != 0 && level < lowestOddLevel) {
  298. lowestOddLevel = level;
  299. }
  300. }
  301. while (highestLevel >= lowestOddLevel) {
  302. int i = 0;
  303. for (;;) {
  304. while (i < len && levels[i] < highestLevel) {
  305. i++;
  306. }
  307. int begin = i++;
  308. if (begin == levels.length) {
  309. break; // no more runs at this level
  310. }
  311. while (i < len && levels[i] >= highestLevel) {
  312. i++;
  313. }
  314. int end = i - 1;
  315. while (begin < end) {
  316. Object temp = objects[begin];
  317. objects[begin] = objects[end];
  318. objects[end] = temp;
  319. ++begin;
  320. --end;
  321. }
  322. }
  323. --highestLevel;
  324. }
  325. }
  326. }