diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 7c1b96a165f970a09ed239bb4fb3f1b0d8f2a407 (patch) | |
tree | df5a6539447324de36e95b057d6b9f0361b7a250 /libs/utils/Unicode.cpp | |
download | frameworks_native-7c1b96a165f970a09ed239bb4fb3f1b0d8f2a407.zip frameworks_native-7c1b96a165f970a09ed239bb4fb3f1b0d8f2a407.tar.gz frameworks_native-7c1b96a165f970a09ed239bb4fb3f1b0d8f2a407.tar.bz2 |
Initial Contribution
Diffstat (limited to 'libs/utils/Unicode.cpp')
-rw-r--r-- | libs/utils/Unicode.cpp | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/libs/utils/Unicode.cpp b/libs/utils/Unicode.cpp new file mode 100644 index 0000000..33f535f --- /dev/null +++ b/libs/utils/Unicode.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed 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. + */ + +#include "utils/AndroidUnicode.h" +#include "characterData.h" + +#define LOG_TAG "Unicode" +#include "utils/Log.h" + +// ICU headers for using macros +#include <unicode/utf16.h> + +#define MIN_RADIX 2 +#define MAX_RADIX 36 + +#define TYPE_SHIFT 0 +#define TYPE_MASK ((1<<5)-1) + +#define DIRECTION_SHIFT (TYPE_SHIFT+5) +#define DIRECTION_MASK ((1<<5)-1) + +#define MIRRORED_SHIFT (DIRECTION_SHIFT+5) +#define MIRRORED_MASK ((1<<1)-1) + +#define TOUPPER_SHIFT (MIRRORED_SHIFT+1) +#define TOUPPER_MASK ((1<<6)-1) + +#define TOLOWER_SHIFT (TOUPPER_SHIFT+6) +#define TOLOWER_MASK ((1<<6)-1) + +#define TOTITLE_SHIFT (TOLOWER_SHIFT+6) +#define TOTITLE_MASK ((1<<2)-1) + +#define MIRROR_SHIFT (TOTITLE_SHIFT+2) +#define MIRROR_MASK ((1<<5)-1) + +#define NUMERIC_SHIFT (TOTITLE_SHIFT+2) +#define NUMERIC_MASK ((1<<7)-1) + +#define DECOMPOSITION_SHIFT (11) +#define DECOMPOSITION_MASK ((1<<5)-1) + +/* + * Returns the value stored in the CharacterData tables that contains + * an index into the packed data table and the decomposition type. + */ +static uint16_t findCharacterValue(UChar32 c) +{ + LOG_ASSERT(c >= 0 && c <= 0x10FFFF, "findCharacterValue received an invalid codepoint"); + if (c < 256) + return CharacterData::LATIN1_DATA[c]; + + // Rotate the bits because the tables are separated into even and odd codepoints + c = (c >> 1) | ((c & 1) << 20); + + CharacterData::Range search = CharacterData::FULL_DATA[c >> 16]; + const uint32_t* array = search.array; + + // This trick is so that that compare in the while loop does not + // need to shift the array entry down by 16 + c <<= 16; + c |= 0xFFFF; + + int high = (int)search.length - 1; + int low = 0; + + if (high < 0) + return 0; + + while (low < high - 1) + { + int probe = (high + low) >> 1; + + // The entries contain the codepoint in the high 16 bits and the index + // into PACKED_DATA in the low 16. + if (array[probe] > (unsigned)c) + high = probe; + else + low = probe; + } + + LOG_ASSERT((array[low] <= (unsigned)c), "A suitable range was not found"); + return array[low] & 0xFFFF; +} + +uint32_t android::Unicode::getPackedData(UChar32 c) +{ + // findCharacterValue returns a 16-bit value with the top 5 bits containing a decomposition type + // and the remaining bits containing an index. + return CharacterData::PACKED_DATA[findCharacterValue(c) & 0x7FF]; +} + +android::Unicode::CharType android::Unicode::getType(UChar32 c) +{ + if (c < 0 || c >= 0x10FFFF) + return CHARTYPE_UNASSIGNED; + return (CharType)((getPackedData(c) >> TYPE_SHIFT) & TYPE_MASK); +} + +android::Unicode::DecompositionType android::Unicode::getDecompositionType(UChar32 c) +{ + // findCharacterValue returns a 16-bit value with the top 5 bits containing a decomposition type + // and the remaining bits containing an index. + return (DecompositionType)((findCharacterValue(c) >> DECOMPOSITION_SHIFT) & DECOMPOSITION_MASK); +} + +int android::Unicode::getDigitValue(UChar32 c, int radix) +{ + if (radix < MIN_RADIX || radix > MAX_RADIX) + return -1; + + int tempValue = radix; + + if (c >= '0' && c <= '9') + tempValue = c - '0'; + else if (c >= 'a' && c <= 'z') + tempValue = c - 'a' + 10; + else if (c >= 'A' && c <= 'Z') + tempValue = c - 'A' + 10; + + return tempValue < radix ? tempValue : -1; +} + +int android::Unicode::getNumericValue(UChar32 c) +{ + if (isMirrored(c)) + return -1; + + return (int) CharacterData::NUMERICS[((getPackedData(c) >> NUMERIC_SHIFT) & NUMERIC_MASK)]; +} + +UChar32 android::Unicode::toLower(UChar32 c) +{ + return c + CharacterData::LCDIFF[(getPackedData(c) >> TOLOWER_SHIFT) & TOLOWER_MASK]; +} + +UChar32 android::Unicode::toUpper(UChar32 c) +{ + return c + CharacterData::UCDIFF[(getPackedData(c) >> TOUPPER_SHIFT) & TOUPPER_MASK]; +} + +android::Unicode::Direction android::Unicode::getDirectionality(UChar32 c) +{ + uint32_t data = getPackedData(c); + + if (0 == data) + return DIRECTIONALITY_UNDEFINED; + + Direction d = (Direction) ((data >> DIRECTION_SHIFT) & DIRECTION_MASK); + + if (DIRECTION_MASK == d) + return DIRECTIONALITY_UNDEFINED; + + return d; +} + +bool android::Unicode::isMirrored(UChar32 c) +{ + return ((getPackedData(c) >> MIRRORED_SHIFT) & MIRRORED_MASK) != 0; +} + +UChar32 android::Unicode::toMirror(UChar32 c) +{ + if (!isMirrored(c)) + return c; + + return c + CharacterData::MIRROR_DIFF[(getPackedData(c) >> MIRROR_SHIFT) & MIRROR_MASK]; +} + +UChar32 android::Unicode::toTitle(UChar32 c) +{ + int32_t diff = CharacterData::TCDIFF[(getPackedData(c) >> TOTITLE_SHIFT) & TOTITLE_MASK]; + + if (TOTITLE_MASK == diff) + return toUpper(c); + + return c + diff; +} + + |