72 * NumericShaper.getContextualShaper(NumericShaper.ARABIC |
73 * NumericShaper.TAMIL,
74 * NumericShaper.EUROPEAN);
75 * shaper.shape(text, start, count);
76 * </pre></blockquote>
77 *
78 * <p><b>Bit mask- and enum-based Unicode ranges</b></p>
79 *
80 * <p>This class supports two different programming interfaces to
81 * represent Unicode ranges for script-specific digits: bit
82 * mask-based ones, such as {@link #ARABIC NumericShaper.ARABIC}, and
83 * enum-based ones, such as {@link NumericShaper.Range#ARABIC}.
84 * Multiple ranges can be specified by ORing bit mask-based constants,
85 * such as:
86 * <blockquote><pre>
87 * NumericShaper.ARABIC | NumericShaper.TAMIL
88 * </pre></blockquote>
89 * or creating a {@code Set} with the {@link NumericShaper.Range}
90 * constants, such as:
91 * <blockquote><pre>
92 * EnumSet.of(NumericShaper.Scirpt.ARABIC, NumericShaper.Range.TAMIL)
93 * </pre></blockquote>
94 * The enum-based ranges are a super set of the bit mask-based ones.
95 *
96 * <p>If the two interfaces are mixed (including serialization),
97 * Unicode range values are mapped to their counterparts where such
98 * mapping is possible, such as {@code NumericShaper.Range.ARABIC}
99 * from/to {@code NumericShaper.ARABIC}. If any unmappable range
100 * values are specified, such as {@code NumericShaper.Range.BALINESE},
101 * those ranges are ignored.
102 *
103 * <p><b>Decimal Digits Precedence</b></p>
104 *
105 * <p>A Unicode range may have more than one set of decimal digits. If
106 * multiple decimal digits sets are specified for the same Unicode
107 * range, one of the sets will take precedence as follows.
108 *
109 * <table border=1 cellspacing=3 cellpadding=0 summary="NumericShaper constants precedence.">
110 * <tr>
111 * <th class="TableHeadingColor">Unicode Range</th>
112 * <th class="TableHeadingColor"><code>NumericShaper</code> Constants</th>
458 public static final int LAO = 1<<13;
459
460 /** Identifies the TIBETAN range and decimal base. */
461 public static final int TIBETAN = 1<<14;
462
463 /** Identifies the MYANMAR range and decimal base. */
464 public static final int MYANMAR = 1<<15;
465
466 /** Identifies the ETHIOPIC range and decimal base. */
467 public static final int ETHIOPIC = 1<<16;
468
469 /** Identifies the KHMER range and decimal base. */
470 public static final int KHMER = 1<<17;
471
472 /** Identifies the MONGOLIAN range and decimal base. */
473 public static final int MONGOLIAN = 1<<18;
474
475 /** Identifies all ranges, for full contextual shaping.
476 *
477 * <p>This constant specifies all of the bit mask-based
478 * ranges. Use {@code EmunSet.allOf(NumericShaper.Range.class)} to
479 * specify all of the enum-based ranges.
480 */
481 public static final int ALL_RANGES = 0x0007ffff;
482
483 private static final int EUROPEAN_KEY = 0;
484 private static final int ARABIC_KEY = 1;
485 private static final int EASTERN_ARABIC_KEY = 2;
486 private static final int DEVANAGARI_KEY = 3;
487 private static final int BENGALI_KEY = 4;
488 private static final int GURMUKHI_KEY = 5;
489 private static final int GUJARATI_KEY = 6;
490 private static final int ORIYA_KEY = 7;
491 private static final int TAMIL_KEY = 8;
492 private static final int TELUGU_KEY = 9;
493 private static final int KANNADA_KEY = 10;
494 private static final int MALAYALAM_KEY = 11;
495 private static final int THAI_KEY = 12;
496 private static final int LAO_KEY = 13;
497 private static final int TIBETAN_KEY = 14;
498 private static final int MYANMAR_KEY = 15;
1051 if (defaultContext == null) {
1052 throw new NullPointerException();
1053 }
1054 NumericShaper shaper = new NumericShaper(defaultContext, ranges);
1055 shaper.mask = CONTEXTUAL_MASK;
1056 return shaper;
1057 }
1058
1059 /**
1060 * Private constructor.
1061 */
1062 private NumericShaper(int key, int mask) {
1063 this.key = key;
1064 this.mask = mask;
1065 }
1066
1067 private NumericShaper(Range defaultContext, Set<Range> ranges) {
1068 shapingRange = defaultContext;
1069 rangeSet = EnumSet.copyOf(ranges); // throws NPE if ranges is null.
1070
1071 // Give precedance to EASTERN_ARABIC if both ARABIC and
1072 // EASTERN_ARABIC are specified.
1073 if (rangeSet.contains(Range.EASTERN_ARABIC)
1074 && rangeSet.contains(Range.ARABIC)) {
1075 rangeSet.remove(Range.ARABIC);
1076 }
1077
1078 // As well as the above case, give precedance to TAI_THAM_THAM if both
1079 // TAI_THAM_HORA and TAI_THAM_THAM are specified.
1080 if (rangeSet.contains(Range.TAI_THAM_THAM)
1081 && rangeSet.contains(Range.TAI_THAM_HORA)) {
1082 rangeSet.remove(Range.TAI_THAM_HORA);
1083 }
1084
1085 rangeArray = rangeSet.toArray(new Range[rangeSet.size()]);
1086 if (rangeArray.length > BSEARCH_THRESHOLD) {
1087 // sort rangeArray for binary search
1088 Arrays.sort(rangeArray,
1089 new Comparator<Range>() {
1090 public int compare(Range s1, Range s2) {
1091 return s1.base > s2.base ? 1 : s1.base == s2.base ? 0 : -1;
1092 }
1093 });
1094 }
1095 }
1096
1097 /**
1098 * Converts the digits in the text that occur between start and
|
72 * NumericShaper.getContextualShaper(NumericShaper.ARABIC |
73 * NumericShaper.TAMIL,
74 * NumericShaper.EUROPEAN);
75 * shaper.shape(text, start, count);
76 * </pre></blockquote>
77 *
78 * <p><b>Bit mask- and enum-based Unicode ranges</b></p>
79 *
80 * <p>This class supports two different programming interfaces to
81 * represent Unicode ranges for script-specific digits: bit
82 * mask-based ones, such as {@link #ARABIC NumericShaper.ARABIC}, and
83 * enum-based ones, such as {@link NumericShaper.Range#ARABIC}.
84 * Multiple ranges can be specified by ORing bit mask-based constants,
85 * such as:
86 * <blockquote><pre>
87 * NumericShaper.ARABIC | NumericShaper.TAMIL
88 * </pre></blockquote>
89 * or creating a {@code Set} with the {@link NumericShaper.Range}
90 * constants, such as:
91 * <blockquote><pre>
92 * EnumSet.of(NumericShaper.Range.ARABIC, NumericShaper.Range.TAMIL)
93 * </pre></blockquote>
94 * The enum-based ranges are a super set of the bit mask-based ones.
95 *
96 * <p>If the two interfaces are mixed (including serialization),
97 * Unicode range values are mapped to their counterparts where such
98 * mapping is possible, such as {@code NumericShaper.Range.ARABIC}
99 * from/to {@code NumericShaper.ARABIC}. If any unmappable range
100 * values are specified, such as {@code NumericShaper.Range.BALINESE},
101 * those ranges are ignored.
102 *
103 * <p><b>Decimal Digits Precedence</b></p>
104 *
105 * <p>A Unicode range may have more than one set of decimal digits. If
106 * multiple decimal digits sets are specified for the same Unicode
107 * range, one of the sets will take precedence as follows.
108 *
109 * <table border=1 cellspacing=3 cellpadding=0 summary="NumericShaper constants precedence.">
110 * <tr>
111 * <th class="TableHeadingColor">Unicode Range</th>
112 * <th class="TableHeadingColor"><code>NumericShaper</code> Constants</th>
458 public static final int LAO = 1<<13;
459
460 /** Identifies the TIBETAN range and decimal base. */
461 public static final int TIBETAN = 1<<14;
462
463 /** Identifies the MYANMAR range and decimal base. */
464 public static final int MYANMAR = 1<<15;
465
466 /** Identifies the ETHIOPIC range and decimal base. */
467 public static final int ETHIOPIC = 1<<16;
468
469 /** Identifies the KHMER range and decimal base. */
470 public static final int KHMER = 1<<17;
471
472 /** Identifies the MONGOLIAN range and decimal base. */
473 public static final int MONGOLIAN = 1<<18;
474
475 /** Identifies all ranges, for full contextual shaping.
476 *
477 * <p>This constant specifies all of the bit mask-based
478 * ranges. Use {@code EnumSet.allOf(NumericShaper.Range.class)} to
479 * specify all of the enum-based ranges.
480 */
481 public static final int ALL_RANGES = 0x0007ffff;
482
483 private static final int EUROPEAN_KEY = 0;
484 private static final int ARABIC_KEY = 1;
485 private static final int EASTERN_ARABIC_KEY = 2;
486 private static final int DEVANAGARI_KEY = 3;
487 private static final int BENGALI_KEY = 4;
488 private static final int GURMUKHI_KEY = 5;
489 private static final int GUJARATI_KEY = 6;
490 private static final int ORIYA_KEY = 7;
491 private static final int TAMIL_KEY = 8;
492 private static final int TELUGU_KEY = 9;
493 private static final int KANNADA_KEY = 10;
494 private static final int MALAYALAM_KEY = 11;
495 private static final int THAI_KEY = 12;
496 private static final int LAO_KEY = 13;
497 private static final int TIBETAN_KEY = 14;
498 private static final int MYANMAR_KEY = 15;
1051 if (defaultContext == null) {
1052 throw new NullPointerException();
1053 }
1054 NumericShaper shaper = new NumericShaper(defaultContext, ranges);
1055 shaper.mask = CONTEXTUAL_MASK;
1056 return shaper;
1057 }
1058
1059 /**
1060 * Private constructor.
1061 */
1062 private NumericShaper(int key, int mask) {
1063 this.key = key;
1064 this.mask = mask;
1065 }
1066
1067 private NumericShaper(Range defaultContext, Set<Range> ranges) {
1068 shapingRange = defaultContext;
1069 rangeSet = EnumSet.copyOf(ranges); // throws NPE if ranges is null.
1070
1071 // Give precedence to EASTERN_ARABIC if both ARABIC and
1072 // EASTERN_ARABIC are specified.
1073 if (rangeSet.contains(Range.EASTERN_ARABIC)
1074 && rangeSet.contains(Range.ARABIC)) {
1075 rangeSet.remove(Range.ARABIC);
1076 }
1077
1078 // As well as the above case, give precedence to TAI_THAM_THAM if both
1079 // TAI_THAM_HORA and TAI_THAM_THAM are specified.
1080 if (rangeSet.contains(Range.TAI_THAM_THAM)
1081 && rangeSet.contains(Range.TAI_THAM_HORA)) {
1082 rangeSet.remove(Range.TAI_THAM_HORA);
1083 }
1084
1085 rangeArray = rangeSet.toArray(new Range[rangeSet.size()]);
1086 if (rangeArray.length > BSEARCH_THRESHOLD) {
1087 // sort rangeArray for binary search
1088 Arrays.sort(rangeArray,
1089 new Comparator<Range>() {
1090 public int compare(Range s1, Range s2) {
1091 return s1.base > s2.base ? 1 : s1.base == s2.base ? 0 : -1;
1092 }
1093 });
1094 }
1095 }
1096
1097 /**
1098 * Converts the digits in the text that occur between start and
|