]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/uprops.cpp
ICU-64252.0.1.tar.gz
[apple/icu.git] / icuSources / common / uprops.cpp
index 81818b75859e8b1274d4d86edd5c05e4413eec55..546c82898888e8f7732f5a8353de008170c1d258 100644 (file)
@@ -1,12 +1,14 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 *******************************************************************************
 *
-*   Copyright (C) 2002-2010, International Business Machines
+*   Copyright (C) 2002-2016, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *
 *******************************************************************************
 *   file name:  uprops.cpp
-*   encoding:   US-ASCII
+*   encoding:   UTF-8
 *   tab size:   8 (not used)
 *   indentation:4
 *
 
 #include "unicode/utypes.h"
 #include "unicode/uchar.h"
+#include "unicode/ucptrie.h"
+#include "unicode/udata.h"
 #include "unicode/unorm2.h"
 #include "unicode/uscript.h"
 #include "unicode/ustring.h"
 #include "cstring.h"
+#include "mutex.h"
 #include "normalizer2impl.h"
-#include "ucln_cmn.h"
 #include "umutex.h"
 #include "ubidi_props.h"
 #include "uprops.h"
 #include "ucase.h"
+#include "ucln_cmn.h"
+#include "ulayout_props.h"
 #include "ustr_imp.h"
 
-#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
-
 U_NAMESPACE_USE
 
-#define GET_BIDI_PROPS() ubidi_getSingleton()
+// Unicode text layout properties data -----------------------------------------
+
+namespace {
+
+icu::UInitOnce gLayoutInitOnce = U_INITONCE_INITIALIZER;
+UDataMemory *gLayoutMemory = nullptr;
+
+UCPTrie *gInpcTrie = nullptr;  // Indic_Positional_Category
+UCPTrie *gInscTrie = nullptr;  // Indic_Syllabic_Category
+UCPTrie *gVoTrie = nullptr;  // Vertical_Orientation
+
+int32_t gMaxInpcValue = 0;
+int32_t gMaxInscValue = 0;
+int32_t gMaxVoValue = 0;
+
+UBool U_CALLCONV uprops_cleanup() {
+    udata_close(gLayoutMemory);
+    gLayoutMemory = nullptr;
+
+    ucptrie_close(gInpcTrie);
+    gInpcTrie = nullptr;
+    ucptrie_close(gInscTrie);
+    gInscTrie = nullptr;
+    ucptrie_close(gVoTrie);
+    gVoTrie = nullptr;
+
+    gMaxInpcValue = 0;
+    gMaxInscValue = 0;
+    gMaxVoValue = 0;
+
+    gLayoutInitOnce.reset();
+    return TRUE;
+}
+
+UBool U_CALLCONV
+ulayout_isAcceptable(void * /*context*/,
+                     const char * /* type */, const char * /*name*/,
+                     const UDataInfo *pInfo) {
+    return pInfo->size >= 20 &&
+        pInfo->isBigEndian == U_IS_BIG_ENDIAN &&
+        pInfo->charsetFamily == U_CHARSET_FAMILY &&
+        pInfo->dataFormat[0] == ULAYOUT_FMT_0 &&
+        pInfo->dataFormat[1] == ULAYOUT_FMT_1 &&
+        pInfo->dataFormat[2] == ULAYOUT_FMT_2 &&
+        pInfo->dataFormat[3] == ULAYOUT_FMT_3 &&
+        pInfo->formatVersion[0] == 1;
+}
+
+// UInitOnce singleton initialization function
+void U_CALLCONV ulayout_load(UErrorCode &errorCode) {
+    gLayoutMemory = udata_openChoice(
+        nullptr, ULAYOUT_DATA_TYPE, ULAYOUT_DATA_NAME,
+        ulayout_isAcceptable, nullptr, &errorCode);
+    if (U_FAILURE(errorCode)) { return; }
+
+    const uint8_t *inBytes = (const uint8_t *)udata_getMemory(gLayoutMemory);
+    const int32_t *inIndexes = (const int32_t *)inBytes;
+    int32_t indexesLength = inIndexes[ULAYOUT_IX_INDEXES_LENGTH];
+    if (indexesLength < 12) {
+        errorCode = U_INVALID_FORMAT_ERROR;  // Not enough indexes.
+        return;
+    }
+    int32_t offset = indexesLength * 4;
+    int32_t top = inIndexes[ULAYOUT_IX_INPC_TRIE_TOP];
+    int32_t trieSize = top - offset;
+    if (trieSize >= 16) {
+        gInpcTrie = ucptrie_openFromBinary(
+            UCPTRIE_TYPE_ANY, UCPTRIE_VALUE_BITS_ANY,
+            inBytes + offset, trieSize, nullptr, &errorCode);
+    }
+    offset = top;
+    top = inIndexes[ULAYOUT_IX_INSC_TRIE_TOP];
+    trieSize = top - offset;
+    if (trieSize >= 16) {
+        gInscTrie = ucptrie_openFromBinary(
+            UCPTRIE_TYPE_ANY, UCPTRIE_VALUE_BITS_ANY,
+            inBytes + offset, trieSize, nullptr, &errorCode);
+    }
+    offset = top;
+    top = inIndexes[ULAYOUT_IX_VO_TRIE_TOP];
+    trieSize = top - offset;
+    if (trieSize >= 16) {
+        gVoTrie = ucptrie_openFromBinary(
+            UCPTRIE_TYPE_ANY, UCPTRIE_VALUE_BITS_ANY,
+            inBytes + offset, trieSize, nullptr, &errorCode);
+    }
+
+    uint32_t maxValues = inIndexes[ULAYOUT_IX_MAX_VALUES];
+    gMaxInpcValue = maxValues >> ULAYOUT_MAX_INPC_SHIFT;
+    gMaxInscValue = (maxValues >> ULAYOUT_MAX_INSC_SHIFT) & 0xff;
+    gMaxVoValue = (maxValues >> ULAYOUT_MAX_VO_SHIFT) & 0xff;
+
+    ucln_common_registerCleanup(UCLN_COMMON_UPROPS, uprops_cleanup);
+}
+
+UBool ulayout_ensureData(UErrorCode &errorCode) {
+    if (U_FAILURE(errorCode)) { return FALSE; }
+    umtx_initOnce(gLayoutInitOnce, &ulayout_load, errorCode);
+    return U_SUCCESS(errorCode);
+}
+
+UBool ulayout_ensureData() {
+    UErrorCode errorCode = U_ZERO_ERROR;
+    return ulayout_ensureData(errorCode);
+}
+
+}  // namespace
 
 /* general properties API functions ----------------------------------------- */
 
@@ -59,19 +169,19 @@ static UBool defaultContains(const BinaryProperty &prop, UChar32 c, UProperty /*
 }
 
 static UBool caseBinaryPropertyContains(const BinaryProperty &/*prop*/, UChar32 c, UProperty which) {
-    return ucase_hasBinaryProperty(c, which);
+    return static_cast<UBool>(ucase_hasBinaryProperty(c, which));
 }
 
 static UBool isBidiControl(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
-    return ubidi_isBidiControl(GET_BIDI_PROPS(), c);
+    return ubidi_isBidiControl(c);
 }
 
 static UBool isMirrored(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
-    return ubidi_isMirrored(GET_BIDI_PROPS(), c);
+    return ubidi_isMirrored(c);
 }
 
 static UBool isJoinControl(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
-    return ubidi_isJoinControl(GET_BIDI_PROPS(), c);
+    return ubidi_isJoinControl(c);
 }
 
 #if UCONFIG_NO_NORMALIZATION
@@ -109,7 +219,7 @@ static UBool changesWhenCasefolded(const BinaryProperty &, UChar32, UProperty) {
 static UBool changesWhenCasefolded(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
     UnicodeString nfd;
     UErrorCode errorCode=U_ZERO_ERROR;
-    const Normalizer2 *nfcNorm2=Normalizer2Factory::getNFCInstance(errorCode);
+    const Normalizer2 *nfcNorm2=Normalizer2::getNFCInstance(errorCode);
     if(U_FAILURE(errorCode)) {
         return FALSE;
     }
@@ -129,14 +239,13 @@ static UBool changesWhenCasefolded(const BinaryProperty &/*prop*/, UChar32 c, UP
     }
     if(c>=0) {
         /* single code point */
-        const UCaseProps *csp=ucase_getSingleton();
         const UChar *resultString;
-        return (UBool)(ucase_toFullFolding(csp, c, &resultString, U_FOLD_CASE_DEFAULT)>=0);
+        return (UBool)(ucase_toFullFolding(c, &resultString, U_FOLD_CASE_DEFAULT)>=0);
     } else {
         /* guess some large but stack-friendly capacity */
         UChar dest[2*UCASE_MAX_STRING_LENGTH];
         int32_t destLength;
-        destLength=u_strFoldCase(dest, LENGTHOF(dest),
+        destLength=u_strFoldCase(dest, UPRV_LENGTHOF(dest),
                                   nfd.getBuffer(), nfd.length(),
                                   U_FOLD_CASE_DEFAULT, &errorCode);
         return (UBool)(U_SUCCESS(errorCode) &&
@@ -208,13 +317,18 @@ static UBool isPOSIX_xdigit(const BinaryProperty &/*prop*/, UChar32 c, UProperty
     return u_isxdigit(c);
 }
 
+static UBool isRegionalIndicator(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    // Property starts are a subset of lb=RI etc.
+    return 0x1F1E6<=c && c<=0x1F1FF;
+}
+
 static const BinaryProperty binProps[UCHAR_BINARY_LIMIT]={
     /*
      * column and mask values for binary properties from u_getUnicodeProperties().
      * Must be in order of corresponding UProperty,
      * and there must be exactly one entry per binary UProperty.
      *
-     * Properties with mask==0 and contains==NULL are handled in code.
+     * Properties with mask==0 are handled in code.
      * For them, column is the UPropertySource value.
      */
     { 1,                U_MASK(UPROPS_ALPHABETIC), defaultContains },
@@ -273,7 +387,15 @@ static const BinaryProperty binProps[UCHAR_BINARY_LIMIT]={
     { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CHANGES_WHEN_TITLECASED
     { UPROPS_SRC_CASE_AND_NORM,  0, changesWhenCasefolded },
     { UPROPS_SRC_CASE,  0, caseBinaryPropertyContains },  // UCHAR_CHANGES_WHEN_CASEMAPPED
-    { UPROPS_SRC_NFKC_CF, 0, changesWhenNFKC_Casefolded }
+    { UPROPS_SRC_NFKC_CF, 0, changesWhenNFKC_Casefolded },
+    { 2,                U_MASK(UPROPS_2_EMOJI), defaultContains },
+    { 2,                U_MASK(UPROPS_2_EMOJI_PRESENTATION), defaultContains },
+    { 2,                U_MASK(UPROPS_2_EMOJI_MODIFIER), defaultContains },
+    { 2,                U_MASK(UPROPS_2_EMOJI_MODIFIER_BASE), defaultContains },
+    { 2,                U_MASK(UPROPS_2_EMOJI_COMPONENT), defaultContains },
+    { 2,                0, isRegionalIndicator },
+    { 1,                U_MASK(UPROPS_PREPENDED_CONCATENATION_MARK), defaultContains },
+    { 2,                U_MASK(UPROPS_2_EXTENDED_PICTOGRAPHIC), defaultContains },
 };
 
 U_CAPI UBool U_EXPORT2
@@ -288,32 +410,13 @@ u_hasBinaryProperty(UChar32 c, UProperty which) {
     }
 }
 
-#if !UCONFIG_NO_NORMALIZATION
-
-U_CAPI uint8_t U_EXPORT2
-u_getCombiningClass(UChar32 c) {
-    UErrorCode errorCode=U_ZERO_ERROR;
-    const Normalizer2Impl *impl=Normalizer2Factory::getNFCImpl(errorCode);
-    if(U_SUCCESS(errorCode)) {
-        return impl->getCC(impl->getNorm16(c));
-    } else {
-        return 0;
-    }
-}
-
-static uint16_t
-getFCD16(UChar32 c) {
-    UErrorCode errorCode=U_ZERO_ERROR;
-    const UTrie2 *trie=Normalizer2Factory::getFCDTrie(errorCode);
-    if(U_SUCCESS(errorCode)) {
-        return UTRIE2_GET16(trie, c);
-    } else {
-        return 0;
-    }
+// Apple-only specific version of the above
+U_CAPI UBool U_EXPORT2
+u_isEmoji(UChar32 c) {
+    const BinaryProperty &prop=binProps[UCHAR_EMOJI];
+    return prop.contains(prop, c, UCHAR_EMOJI);
 }
 
-#endif
-
 struct IntProperty;
 
 typedef int32_t IntPropertyGetValue(const IntProperty &prop, UChar32 c, UProperty which);
@@ -344,8 +447,12 @@ static int32_t getBiDiClass(const IntProperty &/*prop*/, UChar32 c, UProperty /*
     return (int32_t)u_charDirection(c);
 }
 
+static int32_t getBiDiPairedBracketType(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
+    return (int32_t)ubidi_getPairedBracketType(c);
+}
+
 static int32_t biDiGetMaxValue(const IntProperty &/*prop*/, UProperty which) {
-    return ubidi_getMaxValue(GET_BIDI_PROPS(), which);
+    return ubidi_getMaxValue(which);
 }
 
 #if UCONFIG_NO_NORMALIZATION
@@ -363,15 +470,15 @@ static int32_t getGeneralCategory(const IntProperty &/*prop*/, UChar32 c, UPrope
 }
 
 static int32_t getJoiningGroup(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
-    return ubidi_getJoiningGroup(GET_BIDI_PROPS(), c);
+    return ubidi_getJoiningGroup(c);
 }
 
 static int32_t getJoiningType(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
-    return ubidi_getJoiningType(GET_BIDI_PROPS(), c);
+    return ubidi_getJoiningType(c);
 }
 
 static int32_t getNumericType(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
-    int32_t ntv=(int32_t)GET_NUMERIC_TYPE_VALUE(u_getUnicodeProperties(c, -1));
+    int32_t ntv=(int32_t)GET_NUMERIC_TYPE_VALUE(u_getMainProperties(c));
     return UPROPS_NTV_GET_TYPE(ntv);
 }
 
@@ -404,7 +511,7 @@ static const UHangulSyllableType gcbToHst[]={
 static int32_t getHangulSyllableType(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
     /* see comments on gcbToHst[] above */
     int32_t gcb=(int32_t)(u_getUnicodeProperties(c, 2)&UPROPS_GCB_MASK)>>UPROPS_GCB_SHIFT;
-    if(gcb<LENGTHOF(gcbToHst)) {
+    if(gcb<UPRV_LENGTHOF(gcbToHst)) {
         return gcbToHst[gcb];
     } else {
         return U_HST_NOT_APPLICABLE;
@@ -427,7 +534,7 @@ static int32_t getLeadCombiningClass(const IntProperty &, UChar32, UProperty) {
 }
 #else
 static int32_t getLeadCombiningClass(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
-    return getFCD16(c)>>8;
+    return unorm_getFCD16(c)>>8;
 }
 #endif
 
@@ -437,17 +544,43 @@ static int32_t getTrailCombiningClass(const IntProperty &, UChar32, UProperty) {
 }
 #else
 static int32_t getTrailCombiningClass(const IntProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
-    return getFCD16(c)&0xff;
+    return unorm_getFCD16(c)&0xff;
 }
 #endif
 
+static int32_t getInPC(const IntProperty &, UChar32 c, UProperty) {
+    return ulayout_ensureData() && gInpcTrie != nullptr ? ucptrie_get(gInpcTrie, c) : 0;
+}
+
+static int32_t getInSC(const IntProperty &, UChar32 c, UProperty) {
+    return ulayout_ensureData() && gInscTrie != nullptr ? ucptrie_get(gInscTrie, c) : 0;
+}
+
+static int32_t getVo(const IntProperty &, UChar32 c, UProperty) {
+    return ulayout_ensureData() && gVoTrie != nullptr ? ucptrie_get(gVoTrie, c) : 0;
+}
+
+static int32_t layoutGetMaxValue(const IntProperty &/*prop*/, UProperty which) {
+    if (!ulayout_ensureData()) { return 0; }
+    switch (which) {
+    case UCHAR_INDIC_POSITIONAL_CATEGORY:
+        return gMaxInpcValue;
+    case UCHAR_INDIC_SYLLABIC_CATEGORY:
+        return gMaxInscValue;
+    case UCHAR_VERTICAL_ORIENTATION:
+        return gMaxVoValue;
+    default:
+        return 0;
+    }
+}
+
 static const IntProperty intProps[UCHAR_INT_LIMIT-UCHAR_INT_START]={
     /*
      * column, mask and shift values for int-value properties from u_getUnicodeProperties().
      * Must be in order of corresponding UProperty,
      * and there must be exactly one entry per int UProperty.
      *
-     * Properties with mask==0 and getValue==NULL are handled in code.
+     * Properties with mask==0 are handled in code.
      * For them, column is the UPropertySource value.
      */
     { UPROPS_SRC_BIDI,  0, 0,                               getBiDiClass, biDiGetMaxValue },
@@ -474,7 +607,11 @@ static const IntProperty intProps[UCHAR_INT_LIMIT-UCHAR_INT_START]={
     { UPROPS_SRC_NFC,   0, 0xff,                            getTrailCombiningClass, getMaxValueFromShift },
     { 2,                UPROPS_GCB_MASK, UPROPS_GCB_SHIFT,  defaultGetValue, defaultGetMaxValue },
     { 2,                UPROPS_SB_MASK, UPROPS_SB_SHIFT,    defaultGetValue, defaultGetMaxValue },
-    { 2,                UPROPS_WB_MASK, UPROPS_WB_SHIFT,    defaultGetValue, defaultGetMaxValue }
+    { 2,                UPROPS_WB_MASK, UPROPS_WB_SHIFT,    defaultGetValue, defaultGetMaxValue },
+    { UPROPS_SRC_BIDI,  0, 0,                               getBiDiPairedBracketType, biDiGetMaxValue },
+    { UPROPS_SRC_INPC,  0, 0,                               getInPC, layoutGetMaxValue },
+    { UPROPS_SRC_INSC,  0, 0,                               getInSC, layoutGetMaxValue },
+    { UPROPS_SRC_VO,    0, 0,                               getVo, layoutGetMaxValue },
 };
 
 U_CAPI int32_t U_EXPORT2
@@ -576,6 +713,39 @@ uprops_getSource(UProperty which) {
     }
 }
 
+U_CFUNC void U_EXPORT2
+uprops_addPropertyStarts(UPropertySource src, const USetAdder *sa, UErrorCode *pErrorCode) {
+    if (!ulayout_ensureData(*pErrorCode)) { return; }
+    const UCPTrie *trie;
+    switch (src) {
+    case UPROPS_SRC_INPC:
+        trie = gInpcTrie;
+        break;
+    case UPROPS_SRC_INSC:
+        trie = gInscTrie;
+        break;
+    case UPROPS_SRC_VO:
+        trie = gVoTrie;
+        break;
+    default:
+        *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    if (trie == nullptr) {
+        *pErrorCode = U_MISSING_RESOURCE_ERROR;
+        return;
+    }
+
+    // Add the start code point of each same-value range of the trie.
+    UChar32 start = 0, end;
+    while ((end = ucptrie_getRange(trie, start, UCPMAP_RANGE_NORMAL, 0,
+                                   nullptr, nullptr, nullptr)) >= 0) {
+        sa->add(sa->set, start);
+        start = end + 1;
+    }
+}
+
 #if !UCONFIG_NO_NORMALIZATION
 
 U_CAPI int32_t U_EXPORT2
@@ -593,15 +763,14 @@ u_getFC_NFKC_Closure(UChar32 c, UChar *dest, int32_t destCapacity, UErrorCode *p
     // (What could be useful is a custom normalization table that combines
     // case folding and NFKC.)
     // For the derivation, see Unicode's DerivedNormalizationProps.txt.
-    const Normalizer2 *nfkc=Normalizer2Factory::getNFKCInstance(*pErrorCode);
-    const UCaseProps *csp=ucase_getSingleton();
+    const Normalizer2 *nfkc=Normalizer2::getNFKCInstance(*pErrorCode);
     if(U_FAILURE(*pErrorCode)) {
         return 0;
     }
     // first: b = NFKC(Fold(a))
     UnicodeString folded1String;
     const UChar *folded1;
-    int32_t folded1Length=ucase_toFullFolding(csp, c, &folded1, U_FOLD_CASE_DEFAULT);
+    int32_t folded1Length=ucase_toFullFolding(c, &folded1, U_FOLD_CASE_DEFAULT);
     if(folded1Length<0) {
         const Normalizer2Impl *nfkcImpl=Normalizer2Factory::getImpl(nfkc);
         if(nfkcImpl->getCompQuickCheck(nfkcImpl->getNorm16(c))!=UNORM_NO) {