1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17/** 18 * @author Ilya S. Okomin 19 * @version $Revision$ 20 */ 21package java.awt.font; 22 23import java.io.IOException; 24import java.io.Serializable; 25 26// BEGIN android-deleted 27//import org.apache.harmony.awt.internal.nls.Messages; 28// END android-deleted 29import org.apache.harmony.misc.HashCode; 30 31 32/** 33 * The Class NumericShaper provides methods to convert latin character codes 34 * to unicode character codes. 35 * For tables of the character codes used, 36 * see <a href="http://www.unicode.org/Public/UNIDATA/">unicode.org</a>. 37 */ 38public final class NumericShaper implements Serializable { 39 40 /** The Constant serialVersionUID. */ 41 private static final long serialVersionUID = -8022764705923730308L; 42 43 /** 44 * The Constant EUROPEAN indicates the latin and extended range, 45 * and latin decimal base. 46 */ 47 public static final int EUROPEAN = 1; 48 49 /** The Constant ARABIC indicates the ARABIC range and decimal base. */ 50 public static final int ARABIC = 2; 51 52 /** 53 * The Constant EASTERN_ARABIC indicates the ARABIC range and 54 * ARABIC_EXTENDED decimal base. 55 */ 56 public static final int EASTERN_ARABIC = 4; 57 58 /** 59 * The Constant DEVANAGARI indicates the DEVANAGARI range and 60 * decimal base. 61 */ 62 public static final int DEVANAGARI = 8; 63 64 /** The Constant BENGALI indicates the BENGALI range and decimal base. */ 65 public static final int BENGALI = 16; 66 67 /** The Constant GURMUKHI indicates the GURMUKHI range and decimal base. */ 68 public static final int GURMUKHI = 32; 69 70 /** The Constant GUJARATI indicates the GUJARATI range and decimal base. */ 71 public static final int GUJARATI = 64; 72 73 /** The Constant ORIYA indicates the ORIYA range and decimal base. */ 74 public static final int ORIYA = 128; 75 76 /** The Constant TAMIL indicates the TAMIL range and decimal base. */ 77 public static final int TAMIL = 256; 78 79 /** The Constant TELUGU indicates the TELUGU range and decimal base. */ 80 public static final int TELUGU = 512; 81 82 /** The Constant KANNADA indicates the KANNADA range and decimal base. */ 83 public static final int KANNADA = 1024; 84 85 /** 86 * The Constant MALAYALAM indicates the MALAYALAM range and decimal base. 87 */ 88 public static final int MALAYALAM = 2048; 89 90 /** The Constant THAI indicates the THAI range and decimal base. */ 91 public static final int THAI = 4096; 92 93 /** The Constant LAO indicates the LAO range and decimal base. */ 94 public static final int LAO = 8192; 95 96 /** The Constant TIBETAN indicates the TIBETAN range and decimal base. */ 97 public static final int TIBETAN = 16384; 98 99 /** The Constant MYANMAR indicates the MYANMAR range and decimal base. */ 100 public static final int MYANMAR = 32768; 101 102 /** 103 * The Constant ETHIOPIC indicates the ETHIOPIC range and decimal base. 104 */ 105 public static final int ETHIOPIC = 65536; 106 107 /** The Constant KHMER indicates the KHMER range and decimal base. */ 108 public static final int KHMER = 131072; 109 110 /** 111 * The Constant MONGOLIAN indicates the MONGOLIAN range and 112 * decimal base. 113 */ 114 public static final int MONGOLIAN = 262144; 115 116 /** The Constant ALL_RANGES indicates all ranges. */ 117 public static final int ALL_RANGES = 524287; 118 119 /* Further one can find the set of script indices. 120 * Index is the power you need the 2 to raise to to get corresponding 121 * range constant value. Also script ranges, context names and digits low 122 * ranges are indexed with these indices. 123 */ 124 125 // Index of the EUROPEAN range 126 /** The Constant INDEX_EUROPEAN. */ 127 private static final int INDEX_EUROPEAN = 0; 128 129 // Index of the ARABIC range 130 /** The Constant INDEX_ARABIC. */ 131 private static final int INDEX_ARABIC = 1; 132 133 // Index of the EASTERN_ARABIC range 134 /** The Constant INDEX_EASTERN_ARABIC. */ 135 private static final int INDEX_EASTERN_ARABIC = 2; 136 137 // Index of the DEVANAGARI range 138 /** The Constant INDEX_DEVANAGARI. */ 139 private static final int INDEX_DEVANAGARI = 3; 140 141 // Index of the BENGALI range 142 /** The Constant INDEX_BENGALI. */ 143 private static final int INDEX_BENGALI = 4; 144 145 // Index of the GURMUKHI range 146 /** The Constant INDEX_GURMUKHI. */ 147 private static final int INDEX_GURMUKHI = 5; 148 149 // Index of the GUJARTI range 150 /** The Constant INDEX_GUJARATI. */ 151 private static final int INDEX_GUJARATI = 6; 152 153 // Index of the ORIYA range 154 /** The Constant INDEX_ORIYA. */ 155 private static final int INDEX_ORIYA = 7; 156 157 // Index of the TAMIL range 158 /** The Constant INDEX_TAMIL. */ 159 private static final int INDEX_TAMIL = 8; 160 161 // Index of the TELUGU range 162 /** The Constant INDEX_TELUGU. */ 163 private static final int INDEX_TELUGU = 9; 164 165 // Index of the KANNADA range 166 /** The Constant INDEX_KANNADA. */ 167 private static final int INDEX_KANNADA = 10; 168 169 // Index of the MALAYALAM range 170 /** The Constant INDEX_MALAYALAM. */ 171 private static final int INDEX_MALAYALAM = 11; 172 173 // Index of the THAI range 174 /** The Constant INDEX_THAI. */ 175 private static final int INDEX_THAI = 12; 176 177 // Index of the LAO range 178 /** The Constant INDEX_LAO. */ 179 private static final int INDEX_LAO = 13; 180 181 // Index of the TIBETAN range 182 /** The Constant INDEX_TIBETAN. */ 183 private static final int INDEX_TIBETAN = 14; 184 185 // Index of the MYANMAR range 186 /** The Constant INDEX_MYANMAR. */ 187 private static final int INDEX_MYANMAR = 15; 188 189 // Index of the ETHIOPIC range 190 /** The Constant INDEX_ETHIOPIC. */ 191 private static final int INDEX_ETHIOPIC = 16; 192 193 // Index of the KHMER range 194 /** The Constant INDEX_KHMER. */ 195 private static final int INDEX_KHMER = 17; 196 197 // Index of the MONGOLIAN range 198 /** The Constant INDEX_MONGOLIAN. */ 199 private static final int INDEX_MONGOLIAN = 18; 200 201 // Maximum index that range can't exceed 202 /** The Constant MAX_INDEX. */ 203 private static final int MAX_INDEX = 19; 204 205 /* 206 * Scripts ranges array. Array represents ranges as pairs of 207 * lowest and highest range bounds. 208 * Data is taken from the UnicodeData.txt file from 209 * http://www.unicode.org/Public/UNIDATA/ 210 */ 211 /** The scripts ranges. */ 212 private final int[] scriptsRanges = { 213 0x0000, 0x024F, // EUROPEAN (basic latin + latin-1 + extended) 214 0x0600, 0x06FF, // ARABIC 215 0x0600, 0x06FF, // EASTERN_ARABIC (XXX: diff with ARABIC ? ) 216 0x0900, 0x097F, // DEVANAGARI 217 0x0980, 0x09FF, // BENGALI 218 0x0A00, 0x0A7F, // GURMUKHI 219 0x0A80, 0x0AFF, // GUJARATI 220 0x0B00, 0x0B7F, // ORIYA 221 0x0B80, 0x0BFF, // TAMIL 222 0x0C00, 0x0C7F, // TELUGU 223 0x0C80, 0x0CFF, // KANNADA 224 0x0D00, 0x0D7F, // MALAYALAM 225 0x0E00, 0x0E7F, // THAI 226 0x0E80, 0x0EFF, // LAO 227 0x0F00, 0x0FFF, // TIBETAN 228 0x1000, 0x109F, // MYANMAR 229 0x1200, 0x137F, // ETHIOPIC 230 0x1780, 0x17FF, // KHMER 231 0x1800, 0x18AF // MONGOLIAN 232 }; 233 234 /* 235 * Digit low ranges values decreased by 0x0030. Each low range 236 * value decreased by 0x0030 for easy obtaing unicode value of the 237 * context dependent digit. European digits starts from 0x0030 hence 238 * context dependent unicode digit value equals to 239 * digitsLowRanges[script index] + european digit char unicode value. 240 * !! the only exception is ETHIOPIC script where there is no '0' digit 241 * Data is taken from the UnicodeData.txt file from 242 * http://www.unicode.org/Public/UNIDATA/ 243 */ 244 /** The digits low ranges. */ 245 private final int[] digitsLowRanges = { 246 0x0000, // EUROPEAN 247 0x0630, // ARABIC 248 0x0630, // EASTERN_ARABIC 249 0x0936, // DEVANAGARI 250 0x09B6, // BENGALI 251 0x0A36, // GURMUKHI 252 0x0AB6, // GUJARATI 253 0x0B36, // ORIYA 254 0x0BB6, // TAMIL 255 0x0C36, // TELUGU 256 0x0CB6, // KANNADA 257 0x0D36, // MALAYALAM 258 0x0E20, // THAI 259 0x0EA0, // LAO 260 0x0EF0, // TIBETAN 261 0x1010, // MYANMAR 262 0x1338, // ETHIOPIC - (low range-1) no ETHIOPIC '0' DIGIT! 263 0x17B0, // KHMER 264 0x17E0 // MONGOLIAN 265 }; 266 267 // Set of context names used in toString method 268 /** The contexts. */ 269 private final String[] contexts = { 270 "EUROPEAN", //$NON-NLS-1$ 271 "ARABIC", //$NON-NLS-1$ 272 "EASTERN_ARABIC", //$NON-NLS-1$ 273 "DEVANAGARI", //$NON-NLS-1$ 274 "BENGALI", //$NON-NLS-1$ 275 "GURMUKHI", //$NON-NLS-1$ 276 "GUJARATI", //$NON-NLS-1$ 277 "ORIYA", //$NON-NLS-1$ 278 "TAMIL", //$NON-NLS-1$ 279 "TELUGU", //$NON-NLS-1$ 280 "KANNADA", //$NON-NLS-1$ 281 "MALAYALAM", //$NON-NLS-1$ 282 "THAI", //$NON-NLS-1$ 283 "LAO", //$NON-NLS-1$ 284 "TIBETAN", //$NON-NLS-1$ 285 "MYANMAR", //$NON-NLS-1$ 286 "ETHIOPIC", //$NON-NLS-1$ 287 "KHMER", //$NON-NLS-1$ 288 "MONGOLIAN" //$NON-NLS-1$ 289 }; 290 291 /* 292 * Strong characters flags array is to determine if the 293 * unicode bidirectional category of the character is strong, 294 * according to Unicode specification. If the bit with index equals to 295 * character's unicode value is 1 - the character is strong. 296 * This array was generated using UnicodeData.txt file from 297 * http://www.unicode.org/Public/UNIDATA/ 298 */ 299 300 /** The Constant STRONG_TEXT_FLAGS. */ 301 private static final int[] STRONG_TEXT_FLAGS = { 0, 0, 134217726, 134217726, 302 0, 69207040, -8388609, -8388609, -1, -1, -1, -1, -1, -1, -1, -1, 303 -1, -1, -65533, -1, -1, -100663297, 196611, 16415, 0, 0, 0, 304 67108864, -10432, -5, -32769, -4194305, -1, -1, -1, -1, -1017, -1, 305 -32769, 67108863, 65535, -131072, -25165825, -2, 767, 1073741824, 306 -65463, 2033663, -939513841, 134217726, 2047, -73728, -1, -1, 307 541065215, -67059616, -180225, 65535, -8192, 16383, -1, 131135, 0, 308 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, -469762049, -16703999, 537001971, 309 -417812, -473563649, -1333765759, 133431235, -423960, -1016201729, 310 1577058305, 1900480, -278552, -470942209, 72193, 65475, -417812, 311 1676541439, -1333782143, 262083, -700594200, -1006647528, 8396230, 312 524224, -139282, 66059775, 30, 65475, -139284, -470811137, 313 1080036831, 65475, -139284, -1006633473, 8396225, 65475, -58720276, 314 805044223, -16547713, 1835008, -2, 917503, 268402815, 0, -17816170, 315 537783470, 872349791, 0, -50331649, -1050673153, -257, -2147481601, 316 3872, -1073741824, 237503, 0, -1, 16914171, 16777215, 0, 0, -1, 317 -65473, 536870911, -1, -1, -2080374785, -1, -1, -249, -1, 67108863, 318 -1, -1, 1031749119, -1, -49665, 2134769663, -8388803, -1, 319 -12713985, -1, 134217727, 536870911, 65535, -1, -1, 2097151, -2, 320 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 321 -1, 8388607, 134217726, -1, -1, 131071, 253951, 6553599, 262143, 322 122879, -1, -1065353217, 401605055, 1023, 67043328, -1, -1, 323 16777215, -1, 511, 0, 0, 536870911, 33226872, -64, 2047999, -1, 324 -64513, 67044351, 0, -830472193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 325 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, 326 -1, -1, -1, -1, 268435455, -1, -1, 67108863, 1061158911, -1, 327 -1426112705, 1073741823, -1, 1608515583, 265232348, 534519807, 328 49152, 27648, 0, -2147352576, 2031616, 0, 0, 0, 1043332228, 329 -201605808, 992, -1, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 330 -4194304, -1, 134217727, 2097152, 0, 0, 0, 0, 0, 0, 0, -268435456, 331 -1, -1, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4096, 0, 0, 0, 332 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 333 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 334 -32769, 2147483647, 0, -1, -1, -1, 31, -1, -65473, -1, 32831, 335 8388607, 2139062143, 2139062143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 336 0, 0, 0, 0, 0, 0, 224, 524157950, -2, -1, -528482305, -2, -1, 337 -134217729, -32, -122881, -1, -1, -32769, 16777215, 0, -65536, 338 536870911, -1, 15, -1879048193, -1, 131071, -61441, 2147483647, -1, 339 -1, -1, -125829121, -1, -1, 1073741823, 2147483647, 1, 0, 0, 0, 0, 340 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 341 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 342 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 344 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 345 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 347 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 349 0, 0, 2097152, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 353 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 354 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 355 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 359 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 378 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 379 134217728, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 380 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 381 -1, -1, -1, -1, -1, -1, -1, 8191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2117, 159, 0, 0, 383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 384 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 387 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 390 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 391 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 392 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 393 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 394 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 395 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 396 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 397 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 398 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 399 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 400 0, 0, 0, 8, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 401 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2147483648, 1, 0, 0, -2147483648, 402 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 403 0, 0, 0, 0, 0, 0, 0, 0, 0, -2147483648, 1, 0, 0, 0, 0, 0, 0, 0, 0, 404 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 405 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 406 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 407 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 408 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 409 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 410 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 411 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 412 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2147483648, -1, -1, -1, 413 -1, -1, -1, -1, -1, -1, -49153, -1, -63489, -1, -1, 67108863, 0, 414 -1594359681, 1602223615, -37, -1, -1, 262143, -524288, -1, -1, -1, 415 -1, -1, -1, -1, -1, -1, -1, 1073741823, -65536, -1, -196609, -1, 416 255, 536805376, 0, 0, 0, -2162688, -1, -1, -1, 536870911, 0, 417 134217726, 134217726, -64, -1, 2147483647, 486341884, 0 418 419 }; 420 421 // index of context range (Serialization support) 422 /** The key. */ 423 private int key; 424 425 // flag, true if shaping contextual (Serialization support) 426 /** The mask. */ 427 private int mask; 428 429 // ranges to be shaped 430 /** The ranges. */ 431 private int fRanges; 432 433 // index of the default context 434 /** The default context index. */ 435 private int fDefaultContextIndex; 436 437 // flag if NumericShaper shapes contextually 438 /** The contextual. */ 439 private boolean fContextual; 440 441 // uses for non-context dependent case only 442 /** The single range index. */ 443 private int fSingleRangeIndex; 444 445 /** 446 * Creates NumericShaper with specified parameters. 447 * 448 * @param ranges specified ranges to be shaped 449 * @param defaultContext default context range 450 * @param isContextual specifies if the instance is contextual 451 */ 452 private NumericShaper(int ranges, int defaultContext, boolean isContextual){ 453 this.fRanges = ranges; 454 this.fDefaultContextIndex = getIndexFromRange(defaultContext); 455 this.fContextual = isContextual; 456 457 if (!fContextual){ 458 fSingleRangeIndex = getIndexFromRange(ranges); 459 } 460 } 461 462 /** 463 * Returns script index of the specified context range. 464 * 465 * @param range specified range 466 * 467 * @return one of the script indices according to the specified range. 468 */ 469 private int getIndexFromRange(int range){ 470 if (range == 0){ 471 // BEGIN android-changed 472 throwRange(range); 473 // END android-changed 474 } 475 476 int index = 0; 477 while (index < MAX_INDEX){ 478 if (range == (1 << index)){ 479 return index; 480 } 481 index++; 482 } 483 484 // BEGIN android-changed 485 throwRange(range); 486 return -1; // Never executed; quiets the compiler. 487 // END android-changed 488 } 489 490 /** 491 * Returns range corresponding to the specified script index. 492 * 493 * @param index specified script index 494 * 495 * @return one of the range constants according to the specified script index. 496 */ 497 private int getRangeFromIndex(int index){ 498 if (index < 0 || index >= MAX_INDEX){ 499 // BEGIN android-changed 500 throwRange(index); 501 // END android-changed 502 } 503 504 return 1 << index; 505 } 506 507 // BEGIN android-added 508 /** 509 * Throws a standard "out of range" exception. 510 * 511 * @param value the bogus value 512 */ 513 private static void throwRange(int value) { 514 throw new IllegalArgumentException( 515 "Illegal range argument value: " + value); 516 } 517 // END android-added 518 519 /** 520 * Returns a hash code of this NumericShaper. 521 * 522 * @return a hash code of this NumericShaper. 523 */ 524 @Override 525 public int hashCode() { 526 HashCode hash = new HashCode(); 527 528 hash.append(fRanges); 529 hash.append(fDefaultContextIndex); 530 hash.append(fContextual); 531 532 return hash.hashCode(); 533 534 } 535 536 /** 537 * Compares this NumericShaper object with the specified Object. 538 * 539 * @param obj the Object to be compared. 540 * 541 * @return true, if this NumericShaper object is equal to 542 * the specified Object, false otherwise. 543 */ 544 @Override 545 public boolean equals(Object obj) { 546 if (obj == null) { 547 return false; 548 } 549 550 if (obj == this) { 551 return true; 552 } 553 554 try { 555 NumericShaper ns = (NumericShaper)obj; 556 return (fRanges == ns.fRanges && 557 fDefaultContextIndex == ns.fDefaultContextIndex && 558 fContextual == ns.fContextual); 559 } catch (ClassCastException e){ 560 } 561 562 return false; 563 } 564 565 /** 566 * Returns a string representation of this NumericShaper. 567 * 568 * @return the string representation of this NumericShaper. 569 */ 570 @Override 571 public String toString() { 572 /* !! There is no description in the documentation what this method must 573 * return. Thus format of toString method is based on 1.5 release 574 * behavior and can be obtained using next test sample: 575 * 576 * // Simple shapers toString format 577 * System.out.println(NumericShaper.getShaper(NumericShaper.EASTERN_ARABIC)); 578 * 579 * // Context shapers with default context toString format 580 * System.out.println(NumericShaper.getContextualShaper( 581 * NumericShaper.ARABIC | NumericShaper.TAMIL)); 582 * 583 * // Context shapers with context 584 * System.out.println(NumericShaper.getContextualShaper( 585 * NumericShaper.ARABIC | NumericShaper.TAMIL, 586 * NumericShaper.EASTERN_ARABIC)); 587 */ 588 StringBuffer sb = new StringBuffer(super.toString()); 589 590 sb.append("[contextual:"); //$NON-NLS-1$ 591 sb.append(fContextual); 592 593 if (fContextual){ 594 sb.append(", context:"); //$NON-NLS-1$ 595 sb.append(contexts[fDefaultContextIndex]); 596 } 597 598 sb.append(", range(s): "); //$NON-NLS-1$ 599 if (fContextual) { 600 int index = 0; 601 boolean isFirst = true; 602 while (index < MAX_INDEX){ 603 if ((fRanges & (1 << index)) != 0){ 604 if (isFirst){ 605 isFirst = false; 606 } else { 607 sb.append(", "); //$NON-NLS-1$ 608 } 609 sb.append(contexts[index]); 610 } 611 index++; 612 } 613 } else { 614 sb.append(contexts[fSingleRangeIndex]); 615 } 616 sb.append("]"); //$NON-NLS-1$ 617 618 return sb.toString(); 619 } 620 621 /** 622 * Gets the NumericShaper for the specified unicode ranges 623 * and default unicode range. The defaultContext parameter 624 * is used as the starting context (which indicates the 625 * language/script being used). The OR logical operation 626 * should be used for multiple ranges: 627 * NumericShaper.DEVANAGARI | NumericShaper.BENGALI. 628 * The NumericShaper returned by this method is contextual 629 * in that it supports multiple character ranges, depending 630 * on the context. 631 * 632 * @param ranges the unicode ranges. 633 * @param defaultContext the default, starting context. 634 * 635 * @return the NumericShaper for the specified ranges. 636 */ 637 public static NumericShaper getContextualShaper(int ranges, 638 int defaultContext) { 639 ranges &= ALL_RANGES; 640 defaultContext &= ALL_RANGES; 641 return new NumericShaper(ranges, defaultContext, true); 642 } 643 644 /** 645 * Gets the NumericShaper for the specified unicode ranges. 646 * The OR logical operation should be used for multiple ranges: 647 * NumericShaper.DEVANAGARI | NumericShaper.BENGALI. 648 * The NumericShaper returned by this method is contextual 649 * in that it supports multiple character ranges, depending 650 * on the context. 651 * 652 * @param ranges the unicode ranges. 653 * 654 * @return the NumericShaper for the specified ranges. 655 */ 656 public static NumericShaper getContextualShaper(int ranges) { 657 ranges &= ALL_RANGES; 658 return new NumericShaper(ranges, EUROPEAN, true); 659 } 660 661 /** 662 * Gets the masks for all of the ranges supported by this NumericShaper, 663 * packed into an int value using the logical OR logical operation 664 * for multiple ranges: 665 * NumericShaper.DEVANAGARI | NumericShaper.BENGALI. 666 * 667 * @return all ranges of this NumericShaper. 668 */ 669 public int getRanges() { 670 return fRanges; 671 } 672 673 /** 674 * Gets a NumericShaper for the specified unicode range. 675 * The NumericShaper supports only a single range and 676 * hence is not contextual. 677 * 678 * @param singleRange the specified unicode single range. 679 * 680 * @return the NumericShaper for the specified unicode range. 681 */ 682 public static NumericShaper getShaper(int singleRange) { 683 singleRange &= ALL_RANGES; 684 return new NumericShaper(singleRange, EUROPEAN, false); 685 } 686 687 /** 688 * Checks if this NumericShaper is contextual (supporting 689 * multiple script ranges) or not. 690 * 691 * @return true, if this NumericShaper is contextual, false otherwise. 692 */ 693 public boolean isContextual() { 694 return fContextual; 695 } 696 697 /** 698 * Transforms the encoding of the text, starting from the character 699 * at index start and transforming count characters, 700 * using the specified context. 701 * 702 * @param text the text to be shaped. 703 * @param start the start offset of the text. 704 * @param count the number of characters to be shaped. 705 * @param context the context to be used for shaping. 706 */ 707 public void shape(char[] text, int start, int count, int context) { 708 if (isContextual()){ 709 contextualShape(text, start, count, getIndexFromRange(context)); 710 } else { 711 nonContextualShape(text, start, count); 712 } 713 } 714 715 /** 716 * Transforms the encoding of the text, starting from the character 717 * at index start and transforming count characters. 718 * 719 * @param text the text to be shaped. 720 * @param start the start offset of the text. 721 * @param count the number of characters to be shaped. 722 */ 723 public void shape(char[] text, int start, int count) { 724 if (isContextual()){ 725 contextualShape(text, start, count, fDefaultContextIndex); 726 } else { 727 nonContextualShape(text, start, count); 728 } 729 } 730 731 /** 732 * Converts count of digits of the given array of characters from the start 733 * index using specified context. This method is applied for the contextual 734 * shaping, if the shaper instance is not contextual use nonContextualShape 735 * method. 736 * 737 * @param text an array of chars 738 * @param start index of the first character to convert 739 * @param count a number of characters to convert 740 * @param contextIndex index of the script index to use in shaper 741 */ 742 private void contextualShape(char[] text, int start, int count, 743 int contextIndex){ 744 char maxDigit = (char)0x0039; 745 char minDigit = (char)0x0030; 746 747 int currIndex; 748 if (((1 << contextIndex) & fRanges) == 0 ){ 749 currIndex = INDEX_EUROPEAN; 750 } else { 751 currIndex = contextIndex; 752 } 753 754 for (int ind = start; ind < start + count; ind++){ 755 if (minDigit <= text[ind] && text[ind] <= maxDigit){ 756 if (currIndex != INDEX_ETHIOPIC || text[ind] != '0'){ 757 text[ind] = (char)(digitsLowRanges[currIndex] + text[ind]); 758 } 759 } else { 760 if(isCharStrong(text[ind])){ 761 int index = getCharIndex(text[ind]); 762 if (currIndex != index){ 763 if (((1 << index) & fRanges) != 0){ 764 currIndex = index; 765 } else { 766 currIndex = INDEX_EUROPEAN; 767 } 768 } 769 } 770 } 771 } 772 773 } 774 775 /** 776 * Converts count of digits of the given array of characters from the start 777 * index. Method is applied for non-contextual shaper. 778 * 779 * @param text an array of chars 780 * @param start index of the first character to convert 781 * @param count a number of characters to convert 782 */ 783 private void nonContextualShape(char[] text, int start, int count){ 784 char maxDigit = (char)0x0039; 785 char minDigit = (char)((fRanges == ETHIOPIC) ? 0x0031 : 0x0030); 786 for (int ind = start; ind < start + count; ind++){ 787 if (minDigit <= text[ind] && text[ind] <= maxDigit){ 788 text[ind] = (char)(digitsLowRanges[fSingleRangeIndex] + text[ind]); 789 } 790 } 791 792 } 793 794 /** 795 * Returns the index of the script of the specified char. 796 * 797 * @param ch specified unicode character 798 * 799 * @return script index corresponding to the given char 800 */ 801 private int getCharIndex(char ch){ 802 int index = INDEX_EUROPEAN; 803 for (int i=0; i < MAX_INDEX; i++){ 804 int j = i * 2; 805 if (scriptsRanges[j] <= ch && ch <= scriptsRanges[j+1]){ 806 return i; 807 } 808 } 809 810 return index; 811 } 812 813 /** 814 * Returns true if the bidirectional category of the character 815 * is strong. 816 * 817 * @param chr the chr 818 * 819 * @return true, if the character is strong, false otherwise 820 */ 821 private boolean isCharStrong(int chr) { 822 return (STRONG_TEXT_FLAGS[chr >> 5] & (1 << (chr % 32))) != 0; 823 } 824 825 /** 826 * Updates all private serialized fields for object to be correctly serialized 827 * according to the serialized form of this class mentioned in the 828 * documentation. 829 */ 830 private void updateRangesFields(){ 831 fRanges = (mask & ~(1 << 31)); 832 fContextual = ((mask &(1 << 31)) != 0); 833 if (fContextual){ 834 fRanges = (mask & ~(1 << 31)); 835 fDefaultContextIndex = key; 836 } else { 837 fRanges = mask; 838 fSingleRangeIndex = key; 839 } 840 } 841 842 /** 843 * Updates private fields for object after deserialization 844 * according to the serialized form of this class mentioned in the 845 * documentation. 846 */ 847 private void updateKeyMaskFields(){ 848 mask = fRanges; 849 if (fContextual){ 850 mask |= (1 << 31); 851 key = fDefaultContextIndex; 852 } else{ 853 key = fSingleRangeIndex; 854 } 855 } 856 857 /** 858 * Write object. 859 * 860 * @param out the out 861 * 862 * @throws IOException Signals that an I/O exception has occurred. 863 */ 864 private void writeObject(java.io.ObjectOutputStream out) 865 throws IOException{ 866 updateKeyMaskFields(); 867 out.defaultWriteObject(); 868 } 869 870 /** 871 * Read object. 872 * 873 * @param in the in 874 * 875 * @throws IOException Signals that an I/O exception has occurred. 876 * @throws ClassNotFoundException the class not found exception 877 */ 878 private void readObject(java.io.ObjectInputStream in) 879 throws IOException, ClassNotFoundException{ 880 in.defaultReadObject(); 881 updateRangesFields(); 882 } 883 884} 885 886