blob: 85a5f491bf129c08b1d7b2583629863aa272f70f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Ilya S. Okomin
* @version $Revision$
*/
package java.awt.font;
import java.io.IOException;
import java.io.Serializable;
/**
* The Class NumericShaper provides methods to convert latin character codes
* to unicode character codes.
* For tables of the character codes used,
* see <a href="http://www.unicode.org/Public/UNIDATA/">unicode.org</a>.
*/
public final class NumericShaper implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = -8022764705923730308L;
/**
* The Constant EUROPEAN indicates the latin and extended range,
* and latin decimal base.
*/
public static final int EUROPEAN = 1;
/** The Constant ARABIC indicates the ARABIC range and decimal base. */
public static final int ARABIC = 2;
/**
* The Constant EASTERN_ARABIC indicates the ARABIC range and
* ARABIC_EXTENDED decimal base.
*/
public static final int EASTERN_ARABIC = 4;
/**
* The Constant DEVANAGARI indicates the DEVANAGARI range and
* decimal base.
*/
public static final int DEVANAGARI = 8;
/** The Constant BENGALI indicates the BENGALI range and decimal base. */
public static final int BENGALI = 16;
/** The Constant GURMUKHI indicates the GURMUKHI range and decimal base. */
public static final int GURMUKHI = 32;
/** The Constant GUJARATI indicates the GUJARATI range and decimal base. */
public static final int GUJARATI = 64;
/** The Constant ORIYA indicates the ORIYA range and decimal base. */
public static final int ORIYA = 128;
/** The Constant TAMIL indicates the TAMIL range and decimal base. */
public static final int TAMIL = 256;
/** The Constant TELUGU indicates the TELUGU range and decimal base. */
public static final int TELUGU = 512;
/** The Constant KANNADA indicates the KANNADA range and decimal base. */
public static final int KANNADA = 1024;
/**
* The Constant MALAYALAM indicates the MALAYALAM range and decimal base.
*/
public static final int MALAYALAM = 2048;
/** The Constant THAI indicates the THAI range and decimal base. */
public static final int THAI = 4096;
/** The Constant LAO indicates the LAO range and decimal base. */
public static final int LAO = 8192;
/** The Constant TIBETAN indicates the TIBETAN range and decimal base. */
public static final int TIBETAN = 16384;
/** The Constant MYANMAR indicates the MYANMAR range and decimal base. */
public static final int MYANMAR = 32768;
/**
* The Constant ETHIOPIC indicates the ETHIOPIC range and decimal base.
*/
public static final int ETHIOPIC = 65536;
/** The Constant KHMER indicates the KHMER range and decimal base. */
public static final int KHMER = 131072;
/**
* The Constant MONGOLIAN indicates the MONGOLIAN range and
* decimal base.
*/
public static final int MONGOLIAN = 262144;
/** The Constant ALL_RANGES indicates all ranges. */
public static final int ALL_RANGES = 524287;
/* Further one can find the set of script indices.
* Index is the power you need the 2 to raise to to get corresponding
* range constant value. Also script ranges, context names and digits low
* ranges are indexed with these indices.
*/
// Index of the EUROPEAN range
/** The Constant INDEX_EUROPEAN. */
private static final int INDEX_EUROPEAN = 0;
// Index of the ARABIC range
/** The Constant INDEX_ARABIC. */
private static final int INDEX_ARABIC = 1;
// Index of the EASTERN_ARABIC range
/** The Constant INDEX_EASTERN_ARABIC. */
private static final int INDEX_EASTERN_ARABIC = 2;
// Index of the DEVANAGARI range
/** The Constant INDEX_DEVANAGARI. */
private static final int INDEX_DEVANAGARI = 3;
// Index of the BENGALI range
/** The Constant INDEX_BENGALI. */
private static final int INDEX_BENGALI = 4;
// Index of the GURMUKHI range
/** The Constant INDEX_GURMUKHI. */
private static final int INDEX_GURMUKHI = 5;
// Index of the GUJARTI range
/** The Constant INDEX_GUJARATI. */
private static final int INDEX_GUJARATI = 6;
// Index of the ORIYA range
/** The Constant INDEX_ORIYA. */
private static final int INDEX_ORIYA = 7;
// Index of the TAMIL range
/** The Constant INDEX_TAMIL. */
private static final int INDEX_TAMIL = 8;
// Index of the TELUGU range
/** The Constant INDEX_TELUGU. */
private static final int INDEX_TELUGU = 9;
// Index of the KANNADA range
/** The Constant INDEX_KANNADA. */
private static final int INDEX_KANNADA = 10;
// Index of the MALAYALAM range
/** The Constant INDEX_MALAYALAM. */
private static final int INDEX_MALAYALAM = 11;
// Index of the THAI range
/** The Constant INDEX_THAI. */
private static final int INDEX_THAI = 12;
// Index of the LAO range
/** The Constant INDEX_LAO. */
private static final int INDEX_LAO = 13;
// Index of the TIBETAN range
/** The Constant INDEX_TIBETAN. */
private static final int INDEX_TIBETAN = 14;
// Index of the MYANMAR range
/** The Constant INDEX_MYANMAR. */
private static final int INDEX_MYANMAR = 15;
// Index of the ETHIOPIC range
/** The Constant INDEX_ETHIOPIC. */
private static final int INDEX_ETHIOPIC = 16;
// Index of the KHMER range
/** The Constant INDEX_KHMER. */
private static final int INDEX_KHMER = 17;
// Index of the MONGOLIAN range
/** The Constant INDEX_MONGOLIAN. */
private static final int INDEX_MONGOLIAN = 18;
// Maximum index that range can't exceed
/** The Constant MAX_INDEX. */
private static final int MAX_INDEX = 19;
/*
* Scripts ranges array. Array represents ranges as pairs of
* lowest and highest range bounds.
* Data is taken from the UnicodeData.txt file from
* http://www.unicode.org/Public/UNIDATA/
*/
/** The scripts ranges. */
private final int[] scriptsRanges = {
0x0000, 0x024F, // EUROPEAN (basic latin + latin-1 + extended)
0x0600, 0x06FF, // ARABIC
0x0600, 0x06FF, // EASTERN_ARABIC (XXX: diff with ARABIC ? )
0x0900, 0x097F, // DEVANAGARI
0x0980, 0x09FF, // BENGALI
0x0A00, 0x0A7F, // GURMUKHI
0x0A80, 0x0AFF, // GUJARATI
0x0B00, 0x0B7F, // ORIYA
0x0B80, 0x0BFF, // TAMIL
0x0C00, 0x0C7F, // TELUGU
0x0C80, 0x0CFF, // KANNADA
0x0D00, 0x0D7F, // MALAYALAM
0x0E00, 0x0E7F, // THAI
0x0E80, 0x0EFF, // LAO
0x0F00, 0x0FFF, // TIBETAN
0x1000, 0x109F, // MYANMAR
0x1200, 0x137F, // ETHIOPIC
0x1780, 0x17FF, // KHMER
0x1800, 0x18AF // MONGOLIAN
};
/*
* Digit low ranges values decreased by 0x0030. Each low range
* value decreased by 0x0030 for easy obtaing unicode value of the
* context dependent digit. European digits starts from 0x0030 hence
* context dependent unicode digit value equals to
* digitsLowRanges[script index] + european digit char unicode value.
* !! the only exception is ETHIOPIC script where there is no '0' digit
* Data is taken from the UnicodeData.txt file from
* http://www.unicode.org/Public/UNIDATA/
*/
/** The digits low ranges. */
private final int[] digitsLowRanges = {
0x0000, // EUROPEAN
0x0630, // ARABIC
0x0630, // EASTERN_ARABIC
0x0936, // DEVANAGARI
0x09B6, // BENGALI
0x0A36, // GURMUKHI
0x0AB6, // GUJARATI
0x0B36, // ORIYA
0x0BB6, // TAMIL
0x0C36, // TELUGU
0x0CB6, // KANNADA
0x0D36, // MALAYALAM
0x0E20, // THAI
0x0EA0, // LAO
0x0EF0, // TIBETAN
0x1010, // MYANMAR
0x1338, // ETHIOPIC - (low range-1) no ETHIOPIC '0' DIGIT!
0x17B0, // KHMER
0x17E0 // MONGOLIAN
};
// Set of context names used in toString method
/** The contexts. */
private final String[] contexts = {
"EUROPEAN",
"ARABIC",
"EASTERN_ARABIC",
"DEVANAGARI",
"BENGALI",
"GURMUKHI",
"GUJARATI",
"ORIYA",
"TAMIL",
"TELUGU",
"KANNADA",
"MALAYALAM",
"THAI",
"LAO",
"TIBETAN",
"MYANMAR",
"ETHIOPIC",
"KHMER",
"MONGOLIAN"
};
/*
* Strong characters flags array is to determine if the
* unicode bidirectional category of the character is strong,
* according to Unicode specification. If the bit with index equals to
* character's unicode value is 1 - the character is strong.
* This array was generated using UnicodeData.txt file from
* http://www.unicode.org/Public/UNIDATA/
*/
/** The Constant STRONG_TEXT_FLAGS. */
private static final int[] STRONG_TEXT_FLAGS = { 0, 0, 134217726, 134217726,
0, 69207040, -8388609, -8388609, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -65533, -1, -1, -100663297, 196611, 16415, 0, 0, 0,
67108864, -10432, -5, -32769, -4194305, -1, -1, -1, -1, -1017, -1,
-32769, 67108863, 65535, -131072, -25165825, -2, 767, 1073741824,
-65463, 2033663, -939513841, 134217726, 2047, -73728, -1, -1,
541065215, -67059616, -180225, 65535, -8192, 16383, -1, 131135, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, -8, -469762049, -16703999, 537001971,
-417812, -473563649, -1333765759, 133431235, -423960, -1016201729,
1577058305, 1900480, -278552, -470942209, 72193, 65475, -417812,
1676541439, -1333782143, 262083, -700594200, -1006647528, 8396230,
524224, -139282, 66059775, 30, 65475, -139284, -470811137,
1080036831, 65475, -139284, -1006633473, 8396225, 65475, -58720276,
805044223, -16547713, 1835008, -2, 917503, 268402815, 0, -17816170,
537783470, 872349791, 0, -50331649, -1050673153, -257, -2147481601,
3872, -1073741824, 237503, 0, -1, 16914171, 16777215, 0, 0, -1,
-65473, 536870911, -1, -1, -2080374785, -1, -1, -249, -1, 67108863,
-1, -1, 1031749119, -1, -49665, 2134769663, -8388803, -1,
-12713985, -1, 134217727, 536870911, 65535, -1, -1, 2097151, -2,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 8388607, 134217726, -1, -1, 131071, 253951, 6553599, 262143,
122879, -1, -1065353217, 401605055, 1023, 67043328, -1, -1,
16777215, -1, 511, 0, 0, 536870911, 33226872, -64, 2047999, -1,
-64513, 67044351, 0, -830472193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0,
-1, -1, -1, -1, 268435455, -1, -1, 67108863, 1061158911, -1,
-1426112705, 1073741823, -1, 1608515583, 265232348, 534519807,
49152, 27648, 0, -2147352576, 2031616, 0, 0, 0, 1043332228,
-201605808, 992, -1, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-4194304, -1, 134217727, 2097152, 0, 0, 0, 0, 0, 0, 0, -268435456,
-1, -1, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4096, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1,
-32769, 2147483647, 0, -1, -1, -1, 31, -1, -65473, -1, 32831,
8388607, 2139062143, 2139062143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 224, 524157950, -2, -1, -528482305, -2, -1,
-134217729, -32, -122881, -1, -1, -32769, 16777215, 0, -65536,
536870911, -1, 15, -1879048193, -1, 131071, -61441, 2147483647, -1,
-1, -1, -125829121, -1, -1, 1073741823, 2147483647, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 2097152, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
134217728, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, 8191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2117, 159, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 8, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2147483648, 1, 0, 0, -2147483648,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, -2147483648, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2147483648, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -49153, -1, -63489, -1, -1, 67108863, 0,
-1594359681, 1602223615, -37, -1, -1, 262143, -524288, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, 1073741823, -65536, -1, -196609, -1,
255, 536805376, 0, 0, 0, -2162688, -1, -1, -1, 536870911, 0,
134217726, 134217726, -64, -1, 2147483647, 486341884, 0
};
// index of context range (Serialization support)
/** The key. */
private int key;
// flag, true if shaping contextual (Serialization support)
/** The mask. */
private int mask;
// ranges to be shaped
/** The ranges. */
private int fRanges;
// index of the default context
/** The default context index. */
private int fDefaultContextIndex;
// flag if NumericShaper shapes contextually
/** The contextual. */
private boolean fContextual;
// uses for non-context dependent case only
/** The single range index. */
private int fSingleRangeIndex;
/**
* Creates NumericShaper with specified parameters.
*
* @param ranges specified ranges to be shaped
* @param defaultContext default context range
* @param isContextual specifies if the instance is contextual
*/
private NumericShaper(int ranges, int defaultContext, boolean isContextual){
this.fRanges = ranges;
this.fDefaultContextIndex = getIndexFromRange(defaultContext);
this.fContextual = isContextual;
if (!fContextual){
fSingleRangeIndex = getIndexFromRange(ranges);
}
}
/**
* Returns script index of the specified context range.
*
* @param range specified range
*
* @return one of the script indices according to the specified range.
*/
private int getIndexFromRange(int range){
if (range == 0) {
throw rangeException(range);
}
int index = 0;
while (index < MAX_INDEX){
if (range == (1 << index)){
return index;
}
index++;
}
throw rangeException(range);
}
/**
* Returns range corresponding to the specified script index.
*
* @param index specified script index
*
* @return one of the range constants according to the specified script index.
*/
private int getRangeFromIndex(int index){
if (index < 0 || index >= MAX_INDEX){
throw rangeException(index);
}
return 1 << index;
}
private static IllegalArgumentException rangeException(int value) {
throw new IllegalArgumentException("Illegal range argument value: " + value);
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + fRanges;
result = 31 * result + fDefaultContextIndex;
result = 31 * result + (fContextual ? 1 : 0);
return result;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
try {
NumericShaper ns = (NumericShaper)obj;
return (fRanges == ns.fRanges &&
fDefaultContextIndex == ns.fDefaultContextIndex &&
fContextual == ns.fContextual);
} catch (ClassCastException e){
}
return false;
}
@Override
public String toString() {
/* !! There is no description in the documentation what this method must
* return. Thus format of toString method is based on 1.5 release
* behavior and can be obtained using next test sample:
*
* // Simple shapers toString format
* System.out.println(NumericShaper.getShaper(NumericShaper.EASTERN_ARABIC));
*
* // Context shapers with default context toString format
* System.out.println(NumericShaper.getContextualShaper(
* NumericShaper.ARABIC | NumericShaper.TAMIL));
*
* // Context shapers with context
* System.out.println(NumericShaper.getContextualShaper(
* NumericShaper.ARABIC | NumericShaper.TAMIL,
* NumericShaper.EASTERN_ARABIC));
*/
StringBuilder sb = new StringBuilder(super.toString());
sb.append("[contextual:");
sb.append(fContextual);
if (fContextual){
sb.append(", context:");
sb.append(contexts[fDefaultContextIndex]);
}
sb.append(", range(s): ");
if (fContextual) {
int index = 0;
boolean isFirst = true;
while (index < MAX_INDEX){
if ((fRanges & (1 << index)) != 0){
if (isFirst){
isFirst = false;
} else {
sb.append(", ");
}
sb.append(contexts[index]);
}
index++;
}
} else {
sb.append(contexts[fSingleRangeIndex]);
}
sb.append("]");
return sb.toString();
}
/**
* Gets the NumericShaper for the specified unicode ranges
* and default unicode range. The defaultContext parameter
* is used as the starting context (which indicates the
* language/script being used). The OR logical operation
* should be used for multiple ranges:
* NumericShaper.DEVANAGARI | NumericShaper.BENGALI.
* The NumericShaper returned by this method is contextual
* in that it supports multiple character ranges, depending
* on the context.
*
* @param ranges the unicode ranges.
* @param defaultContext the default, starting context.
*
* @return the NumericShaper for the specified ranges.
*/
public static NumericShaper getContextualShaper(int ranges,
int defaultContext) {
ranges &= ALL_RANGES;
defaultContext &= ALL_RANGES;
return new NumericShaper(ranges, defaultContext, true);
}
/**
* Gets the NumericShaper for the specified unicode ranges.
* The OR logical operation should be used for multiple ranges:
* NumericShaper.DEVANAGARI | NumericShaper.BENGALI.
* The NumericShaper returned by this method is contextual
* in that it supports multiple character ranges, depending
* on the context.
*
* @param ranges the unicode ranges.
*
* @return the NumericShaper for the specified ranges.
*/
public static NumericShaper getContextualShaper(int ranges) {
ranges &= ALL_RANGES;
return new NumericShaper(ranges, EUROPEAN, true);
}
/**
* Gets the masks for all of the ranges supported by this NumericShaper,
* packed into an int value using the logical OR logical operation
* for multiple ranges:
* NumericShaper.DEVANAGARI | NumericShaper.BENGALI.
*
* @return all ranges of this NumericShaper.
*/
public int getRanges() {
return fRanges;
}
/**
* Gets a NumericShaper for the specified unicode range.
* The NumericShaper supports only a single range and
* hence is not contextual.
*
* @param singleRange the specified unicode single range.
*
* @return the NumericShaper for the specified unicode range.
*/
public static NumericShaper getShaper(int singleRange) {
singleRange &= ALL_RANGES;
return new NumericShaper(singleRange, EUROPEAN, false);
}
/**
* Checks if this NumericShaper is contextual (supporting
* multiple script ranges) or not.
*
* @return true, if this NumericShaper is contextual, false otherwise.
*/
public boolean isContextual() {
return fContextual;
}
/**
* Transforms the encoding of the text, starting from the character
* at index start and transforming count characters,
* using the specified context.
*
* @param text the text to be shaped.
* @param start the start offset of the text.
* @param count the number of characters to be shaped.
* @param context the context to be used for shaping.
*/
public void shape(char[] text, int start, int count, int context) {
if (isContextual()){
contextualShape(text, start, count, getIndexFromRange(context));
} else {
nonContextualShape(text, start, count);
}
}
/**
* Transforms the encoding of the text, starting from the character
* at index start and transforming count characters.
*
* @param text the text to be shaped.
* @param start the start offset of the text.
* @param count the number of characters to be shaped.
*/
public void shape(char[] text, int start, int count) {
if (isContextual()){
contextualShape(text, start, count, fDefaultContextIndex);
} else {
nonContextualShape(text, start, count);
}
}
/**
* Converts count of digits of the given array of characters from the start
* index using specified context. This method is applied for the contextual
* shaping, if the shaper instance is not contextual use nonContextualShape
* method.
*
* @param text an array of chars
* @param start index of the first character to convert
* @param count a number of characters to convert
* @param contextIndex index of the script index to use in shaper
*/
private void contextualShape(char[] text, int start, int count,
int contextIndex){
char maxDigit = (char)0x0039;
char minDigit = (char)0x0030;
int currIndex;
if (((1 << contextIndex) & fRanges) == 0 ){
currIndex = INDEX_EUROPEAN;
} else {
currIndex = contextIndex;
}
for (int ind = start; ind < start + count; ind++){
if (minDigit <= text[ind] && text[ind] <= maxDigit){
if (currIndex != INDEX_ETHIOPIC || text[ind] != '0'){
text[ind] = (char)(digitsLowRanges[currIndex] + text[ind]);
}
} else {
if(isCharStrong(text[ind])){
int index = getCharIndex(text[ind]);
if (currIndex != index){
if (((1 << index) & fRanges) != 0){
currIndex = index;
} else {
currIndex = INDEX_EUROPEAN;
}
}
}
}
}
}
/**
* Converts count of digits of the given array of characters from the start
* index. Method is applied for non-contextual shaper.
*
* @param text an array of chars
* @param start index of the first character to convert
* @param count a number of characters to convert
*/
private void nonContextualShape(char[] text, int start, int count){
char maxDigit = (char)0x0039;
char minDigit = (char)((fRanges == ETHIOPIC) ? 0x0031 : 0x0030);
for (int ind = start; ind < start + count; ind++){
if (minDigit <= text[ind] && text[ind] <= maxDigit){
text[ind] = (char)(digitsLowRanges[fSingleRangeIndex] + text[ind]);
}
}
}
/**
* Returns the index of the script of the specified char.
*
* @param ch specified unicode character
*
* @return script index corresponding to the given char
*/
private int getCharIndex(char ch){
int index = INDEX_EUROPEAN;
for (int i=0; i < MAX_INDEX; i++){
int j = i * 2;
if (scriptsRanges[j] <= ch && ch <= scriptsRanges[j+1]){
return i;
}
}
return index;
}
/**
* Returns true if the bidirectional category of the character
* is strong.
*
* @param chr the chr
*
* @return true, if the character is strong, false otherwise
*/
private boolean isCharStrong(int chr) {
return (STRONG_TEXT_FLAGS[chr >> 5] & (1 << (chr % 32))) != 0;
}
/**
* Updates all private serialized fields for object to be correctly serialized
* according to the serialized form of this class mentioned in the
* documentation.
*/
private void updateRangesFields(){
fRanges = (mask & ~(1 << 31));
fContextual = ((mask &(1 << 31)) != 0);
if (fContextual){
fRanges = (mask & ~(1 << 31));
fDefaultContextIndex = key;
} else {
fRanges = mask;
fSingleRangeIndex = key;
}
}
/**
* Updates private fields for object after deserialization
* according to the serialized form of this class mentioned in the
* documentation.
*/
private void updateKeyMaskFields(){
mask = fRanges;
if (fContextual){
mask |= (1 << 31);
key = fDefaultContextIndex;
} else{
key = fSingleRangeIndex;
}
}
/**
* Write object.
*
* @param out the out
*
* @throws IOException Signals that an I/O exception has occurred.
*/
private void writeObject(java.io.ObjectOutputStream out)
throws IOException{
updateKeyMaskFields();
out.defaultWriteObject();
}
/**
* Read object.
*
* @param in the in
*
* @throws IOException Signals that an I/O exception has occurred.
* @throws ClassNotFoundException the class not found exception
*/
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException{
in.defaultReadObject();
updateRangesFields();
}
}