1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ******************************************************************************* 5 * Copyright (C) 1996-2011, International Business Machines Corporation and * 6 * others. All Rights Reserved. * 7 ******************************************************************************* 8 */ 9 package com.ibm.icu.text; 10 11 import com.ibm.icu.impl.UCaseProps; 12 import com.ibm.icu.lang.UCharacter; 13 import com.ibm.icu.util.ULocale; 14 15 /** 16 * A transliterator that performs locale-sensitive toLower() 17 * case mapping. 18 */ 19 class LowercaseTransliterator extends Transliterator{ 20 21 /** 22 * Package accessible ID. 23 */ 24 static final String _ID = "Any-Lower"; 25 26 // TODO: Add variants for tr/az, lt, default = default locale: ICU ticket #12720 27 28 /** 29 * System registration hook. 30 */ 31 static void register() { 32 Transliterator.registerFactory(_ID, new Transliterator.Factory() { 33 @Override 34 public Transliterator getInstance(String ID) { 35 return new LowercaseTransliterator(ULocale.US); 36 } 37 }); 38 39 Transliterator.registerSpecialInverse("Lower", "Upper", true); 40 } 41 42 private final ULocale locale; 43 44 private final UCaseProps csp; 45 private ReplaceableContextIterator iter; 46 private StringBuilder result; 47 private int caseLocale; 48 49 /** 50 * Constructs a transliterator. 51 */ 52 53 public LowercaseTransliterator(ULocale loc) { 54 super(_ID, null); 55 locale = loc; 56 csp=UCaseProps.INSTANCE; 57 iter=new ReplaceableContextIterator(); 58 result = new StringBuilder(); 59 caseLocale = UCaseProps.getCaseLocale(locale); 60 } 61 62 /** 63 * Implements {@link Transliterator#handleTransliterate}. 64 */ 65 @Override 66 protected synchronized void handleTransliterate(Replaceable text, 67 Position offsets, boolean isIncremental) { 68 if(csp==null) { 69 return; 70 } 71 72 if(offsets.start >= offsets.limit) { 73 return; 74 } 75 76 iter.setText(text); 77 result.setLength(0); 78 int c, delta; 79 80 // Walk through original string 81 // If there is a case change, modify corresponding position in replaceable 82 83 iter.setIndex(offsets.start); 84 iter.setLimit(offsets.limit); 85 iter.setContextLimits(offsets.contextStart, offsets.contextLimit); 86 while((c=iter.nextCaseMapCP())>=0) { 87 c=csp.toFullLower(c, iter, result, caseLocale); 88 89 if(iter.didReachLimit() && isIncremental) { 90 // the case mapping function tried to look beyond the context limit 91 // wait for more input 92 offsets.start=iter.getCaseMapCPStart(); 93 return; 94 } 95 96 /* decode the result */ 97 if(c<0) { 98 /* c mapped to itself, no change */ 99 continue; 100 } else if(c<=UCaseProps.MAX_STRING_LENGTH) { 101 /* replace by the mapping string */ 102 delta=iter.replace(result.toString()); 103 result.setLength(0); 104 } else { 105 /* replace by single-code point mapping */ 106 delta=iter.replace(UTF16.valueOf(c)); 107 } 108 109 if(delta!=0) { 110 offsets.limit += delta; 111 offsets.contextLimit += delta; 112 } 113 } 114 offsets.start = offsets.limit; 115 } 116 117 // NOTE: normally this would be static, but because the results vary by locale.... 118 SourceTargetUtility sourceTargetUtility = null; 119 120 /* (non-Javadoc) 121 * @see com.ibm.icu.text.Transliterator#addSourceTargetSet(com.ibm.icu.text.UnicodeSet, com.ibm.icu.text.UnicodeSet, com.ibm.icu.text.UnicodeSet) 122 */ 123 @Override 124 public void addSourceTargetSet(UnicodeSet inputFilter, UnicodeSet sourceSet, UnicodeSet targetSet) { 125 synchronized (this) { 126 if (sourceTargetUtility == null) { 127 sourceTargetUtility = new SourceTargetUtility(new Transform<String,String>() { 128 @Override 129 public String transform(String source) { 130 return UCharacter.toLowerCase(locale, source); 131 } 132 }); 133 } 134 } 135 sourceTargetUtility.addSourceTargetSet(this, inputFilter, sourceSet, targetSet); 136 } 137 } 138