]> granicus.if.org Git - icu/commitdiff
ICU-10681 Lazily get and cache BreakIterator for titlecasing; lazily get contextTrans...
authorPeter Edberg <pedberg@unicode.org>
Sun, 2 Mar 2014 00:44:35 +0000 (00:44 +0000)
committerPeter Edberg <pedberg@unicode.org>
Sun, 2 Mar 2014 00:44:35 +0000 (00:44 +0000)
X-SVN-Rev: 35287

icu4c/source/i18n/locdspnm.cpp
icu4c/source/i18n/rbnf.cpp
icu4c/source/i18n/reldtfmt.cpp
icu4c/source/i18n/reldtfmt.h
icu4c/source/i18n/smpdtfmt.cpp
icu4c/source/i18n/unicode/rbnf.h
icu4c/source/i18n/unicode/smpdtfmt.h
icu4c/source/test/intltest/locnmtst.cpp

index 7731463ac1aa17ac3f01696fa3280082204c5756..d99964ebbd98f2d39b329bf8f2a541d7476abb75 100644 (file)
@@ -12,6 +12,7 @@
 #include "unicode/locdspnm.h"
 #include "unicode/msgfmt.h"
 #include "unicode/ures.h"
+#include "unicode/udisplaycontext.h" 
 #include "unicode/brkiter.h"
 
 #include "cmemory.h"
@@ -275,6 +276,7 @@ class LocaleDisplayNamesImpl : public LocaleDisplayNames {
     MessageFormat *format;
     MessageFormat *keyTypeFormat;
     UDisplayContext capitalizationContext;
+    BreakIterator* capitalizationBrkIter; 
     UnicodeString formatOpenParen;
     UnicodeString formatReplaceOpenParen;
     UnicodeString formatCloseParen;
@@ -290,10 +292,9 @@ class LocaleDisplayNamesImpl : public LocaleDisplayNames {
         kCapContextUsageKeyValue,
         kCapContextUsageCount
     };
-    // Capitalization transforms. For each usage type, the first array element indicates
-    // whether to titlecase for uiListOrMenu context, the second indicates whether to
-    // titlecase for stand-alone context.
-     UBool fCapitalization[kCapContextUsageCount][2];
+    // Capitalization transforms. For each usage type, indicates whether to titlecase for
+    // the context specified in capitalizationContext (which we know at construction time)
+     UBool fCapitalization[kCapContextUsageCount];
 
 public:
     // constructor
@@ -341,6 +342,7 @@ LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale,
     , format(NULL)
     , keyTypeFormat(NULL)
     , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
+    , capitalizationBrkIter(NULL)
 {
     initialize();
 }
@@ -354,6 +356,7 @@ LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale,
     , format(NULL)
     , keyTypeFormat(NULL)
     , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
+    , capitalizationBrkIter(NULL)
 {
     while (length-- > 0) {
         UDisplayContext value = *contexts++;
@@ -429,35 +432,52 @@ LocaleDisplayNamesImpl::initialize(void) {
         { "variant",    kCapContextUsageVariant },
         { NULL,         (CapContextUsage)0 },
     };
-    int32_t len = 0;
-    UResourceBundle *localeBundle = ures_open(NULL, locale.getName(), &status);
-    if (U_SUCCESS(status)) {
-        UResourceBundle *contextTransforms = ures_getByKeyWithFallback(localeBundle, "contextTransforms", NULL, &status);
+    // Only get the context data if we need it! This is a const object so we know now...
+    // Also check whether we will need a break iterator (depends on the data)
+    UBool needBrkIter = FALSE;
+    if (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_STANDALONE) {
+        int32_t len = 0;
+        UResourceBundle *localeBundle = ures_open(NULL, locale.getName(), &status);
         if (U_SUCCESS(status)) {
-            UResourceBundle *contextTransformUsage;
-            while ( (contextTransformUsage = ures_getNextResource(contextTransforms, NULL, &status)) != NULL ) {
-                const int32_t * intVector = ures_getIntVector(contextTransformUsage, &len, &status);
-                if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
-                    const char* usageKey = ures_getKey(contextTransformUsage);
-                    if (usageKey != NULL) {
-                        const ContextUsageNameToEnum * typeMapPtr = contextUsageTypeMap;
-                        int32_t compResult = 0;
-                        // linear search; list is short and we cannot be sure that bsearch is available
-                        while ( typeMapPtr->usageName != NULL && (compResult = uprv_strcmp(usageKey, typeMapPtr->usageName)) > 0 ) {
-                            ++typeMapPtr;
-                        }
-                        if (typeMapPtr->usageName != NULL && compResult == 0) {
-                            fCapitalization[typeMapPtr->usageEnum][0] = intVector[0];
-                            fCapitalization[typeMapPtr->usageEnum][1] = intVector[1];
+            UResourceBundle *contextTransforms = ures_getByKeyWithFallback(localeBundle, "contextTransforms", NULL, &status);
+            if (U_SUCCESS(status)) {
+                UResourceBundle *contextTransformUsage;
+                while ( (contextTransformUsage = ures_getNextResource(contextTransforms, NULL, &status)) != NULL ) {
+                    const int32_t * intVector = ures_getIntVector(contextTransformUsage, &len, &status);
+                    if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
+                        const char* usageKey = ures_getKey(contextTransformUsage);
+                        if (usageKey != NULL) {
+                            const ContextUsageNameToEnum * typeMapPtr = contextUsageTypeMap;
+                            int32_t compResult = 0;
+                            // linear search; list is short and we cannot be sure that bsearch is available
+                            while ( typeMapPtr->usageName != NULL && (compResult = uprv_strcmp(usageKey, typeMapPtr->usageName)) > 0 ) {
+                                ++typeMapPtr;
+                            }
+                            if (typeMapPtr->usageName != NULL && compResult == 0) {
+                                int32_t titlecaseInt = (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU)? intVector[0]: intVector[1];
+                                if (titlecaseInt != 0) {
+                                    fCapitalization[typeMapPtr->usageEnum] = TRUE;;
+                                    needBrkIter = TRUE;
+                                }
+                            }
                         }
                     }
+                    status = U_ZERO_ERROR;
+                    ures_close(contextTransformUsage);
                 }
-                status = U_ZERO_ERROR;
-                ures_close(contextTransformUsage);
+                ures_close(contextTransforms);
             }
-            ures_close(contextTransforms);
+            ures_close(localeBundle);
+        }
+    }
+    // Get a sentence break iterator if we will need it
+    if (needBrkIter || capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE) {
+        status = U_ZERO_ERROR;
+        capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status);
+        if (U_FAILURE(status)) {
+            delete capitalizationBrkIter;
+            capitalizationBrkIter = NULL;
         }
-        ures_close(localeBundle);
     }
 #endif
 }
@@ -466,6 +486,7 @@ LocaleDisplayNamesImpl::~LocaleDisplayNamesImpl() {
     delete separatorFormat;
     delete format;
     delete keyTypeFormat;
+    delete capitalizationBrkIter;
  }
 
 const Locale&
@@ -496,51 +517,10 @@ LocaleDisplayNamesImpl::adjustForUsageAndContext(CapContextUsage usage,
                                                 UnicodeString& result) const {
 #if !UCONFIG_NO_BREAK_ITERATION
     // check to see whether we need to titlecase result
-    UBool titlecase = FALSE;
-    switch (capitalizationContext) {
-        case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
-            titlecase = TRUE;
-            break;
-        case UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU:
-            titlecase = fCapitalization[usage][0];
-            break;
-        case UDISPCTX_CAPITALIZATION_FOR_STANDALONE:
-            titlecase = fCapitalization[usage][1];
-            break;
-        default:
-            // titlecase = FALSE;
-            break;
-    }
-    if (titlecase) {
-        // TODO: Fix this titlecase hack when we figure out something better to do.
-        // We don't want to titlecase the whole text, only something like the first word,
-        // of the first segment long enough to have a complete cluster, whichever is
-        // shorter. We could have keep a word break iterator around, but I am not sure
-        // that will do the ight thing for the purposes here. For now we assume that in
-        // languages for which titlecasing makes a difference, we can stop at non-letter
-        // characters in 0x0000-0x00FF and only titlecase up to the first occurrence of
-        // any of those, or to a small number of chars, whichever comes first.
-        int32_t stopPos, stopPosLimit = 8, len = result.length();
-        if ( stopPosLimit > len ) {
-            stopPosLimit = len;
-        }
-        for ( stopPos = 0; stopPos < stopPosLimit; stopPos++ ) {
-            UChar32 ch = result.char32At(stopPos);
-            if ( (ch < 0x41) || (ch > 0x5A && ch < 0x61) || (ch > 0x7A && ch < 0xC0) ) {
-                break;
-            }
-            if (ch >= 0x10000) {
-                stopPos++;
-            }
-        }
-        if ( stopPos > 0 && stopPos < len ) {
-            UnicodeString firstWord(result, 0, stopPos);
-            firstWord.toTitle(NULL, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
-            result.replaceBetween(0, stopPos, firstWord);
-        } else {
-            // no stopPos, titlecase the whole text
-            result.toTitle(NULL, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
-        }
+    if ( result.length() > 0 && u_islower(result.char32At(0)) && capitalizationBrkIter!= NULL &&
+          ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || fCapitalization[usage] ) ) {
+        // note fCapitalization[usage] won't be set unless capitalizationContext is UI_LIST_OR_MENU or STANDALONE
+        result.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
     }
 #endif
     return result;
index a82b52acf37bedd7eebfb4b02b09297430512bec..37c28866702da08cf3d8f702f18b5728ea360c55 100644 (file)
@@ -1519,6 +1519,10 @@ RuleBasedNumberFormat::setContext(UDisplayContext value, UErrorCode& status)
                 (value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
             UErrorCode status = U_ZERO_ERROR;
             capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status);
+            if (U_FAILURE(status)) {
+                delete capitalizationBrkIter;
+                capitalizationBrkIter = NULL;
+            }
         }
 #endif
     }
index e3a126d35707b09341a29cd46dd2954150b02098..5cbb295553b1e1595917eaf2b43417b4e53113e0 100644 (file)
@@ -17,6 +17,7 @@
 #include "unicode/msgfmt.h"
 #include "unicode/udisplaycontext.h"
 #include "unicode/uchar.h"
+#include "unicode/brkiter.h"
 
 #include "gregoimp.h" // for CalendarData
 #include "cmemory.h"
@@ -45,7 +46,11 @@ RelativeDateFormat::RelativeDateFormat(const RelativeDateFormat& other) :
  fDateStyle(other.fDateStyle), fLocale(other.fLocale),
  fDayMin(other.fDayMin), fDayMax(other.fDayMax),
  fDatesLen(other.fDatesLen), fDates(NULL),
- fCombinedHasDateAtStart(other.fCombinedHasDateAtStart)
+ fCombinedHasDateAtStart(other.fCombinedHasDateAtStart),
+ fCapitalizationInfoSet(other.fCapitalizationInfoSet),
+ fCapitalizationOfRelativeUnitsForUIListMenu(other.fCapitalizationOfRelativeUnitsForUIListMenu),
+ fCapitalizationOfRelativeUnitsForStandAlone(other.fCapitalizationOfRelativeUnitsForStandAlone),
+ fCapitalizationBrkIter(NULL)
 {
     if(other.fDateTimeFormatter != NULL) {
         fDateTimeFormatter = (SimpleDateFormat*)other.fDateTimeFormatter->clone();
@@ -57,15 +62,18 @@ RelativeDateFormat::RelativeDateFormat(const RelativeDateFormat& other) :
         fDates = (URelativeString*) uprv_malloc(sizeof(fDates[0])*fDatesLen);
         uprv_memcpy(fDates, other.fDates, sizeof(fDates[0])*fDatesLen);
     }
-    fCapitalizationForRelativeUnits[0] = other.fCapitalizationForRelativeUnits[0];
-    fCapitalizationForRelativeUnits[1] = other.fCapitalizationForRelativeUnits[1];
+    if (other.fCapitalizationBrkIter != NULL) {
+        fCapitalizationBrkIter = (other.fCapitalizationBrkIter)->clone();
+    }
 }
 
 RelativeDateFormat::RelativeDateFormat( UDateFormatStyle timeStyle, UDateFormatStyle dateStyle,
                                         const Locale& locale, UErrorCode& status) :
  DateFormat(), fDateTimeFormatter(NULL), fDatePattern(), fTimePattern(), fCombinedFormat(NULL),
  fDateStyle(dateStyle), fLocale(locale), fDayMin(0), fDayMax(0), fDatesLen(0), fDates(NULL),
- fCombinedHasDateAtStart(FALSE)
+ fCombinedHasDateAtStart(FALSE), fCapitalizationInfoSet(FALSE),
+ fCapitalizationOfRelativeUnitsForUIListMenu(FALSE), fCapitalizationOfRelativeUnitsForStandAlone(FALSE),
+ fCapitalizationBrkIter(NULL)
 {
     if(U_FAILURE(status) ) {
         return;
@@ -116,6 +124,7 @@ RelativeDateFormat::~RelativeDateFormat() {
     delete fDateTimeFormatter;
     delete fCombinedFormat;
     uprv_free(fDates);
+    delete fCapitalizationBrkIter;
 }
 
 
@@ -125,6 +134,8 @@ Format* RelativeDateFormat::clone(void) const {
 
 UBool RelativeDateFormat::operator==(const Format& other) const {
     if(DateFormat::operator==(other)) {
+        // The DateFormat::operator== check for fCapitalizationContext equality above
+        //   is sufficient to check equality of all derived context-related data.
         // DateFormat::operator== guarantees following cast is safe
         RelativeDateFormat* that = (RelativeDateFormat*)&other;
         return (fDateStyle==that->fDateStyle   &&
@@ -158,34 +169,16 @@ UnicodeString& RelativeDateFormat::format(  Calendar& cal,
 
     if ( relativeDayString.length() > 0 && !fDatePattern.isEmpty() && 
          (fTimePattern.isEmpty() || fCombinedFormat == NULL || fCombinedHasDateAtStart)) {
+#if !UCONFIG_NO_BREAK_ITERATION
         // capitalize relativeDayString according to context for relative, set formatter no context
-        if ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
-             (capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && fCapitalizationForRelativeUnits[0]) ||
-             (capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && fCapitalizationForRelativeUnits[1]) ) {
-            // titlecase first word of relativeDayString, do like LocaleDisplayNamesImpl::adjustForUsageAndContext
-            int32_t stopPos, stopPosLimit = 8;
-            if ( stopPosLimit > len ) {
-                stopPosLimit = len;
-            }
-            for ( stopPos = 0; stopPos < stopPosLimit; stopPos++ ) {
-                UChar32 ch = relativeDayString.char32At(stopPos);
-                int32_t wb = u_getIntPropertyValue(ch, UCHAR_WORD_BREAK);
-                if (!(u_islower(ch) || wb==U_WB_EXTEND || wb==U_WB_SINGLE_QUOTE || wb==U_WB_MIDNUMLET || wb==U_WB_MIDLETTER)) {
-                    break;
-                }
-                if (ch >= 0x10000) {
-                    stopPos++;
-                }
-            }
-            if ( stopPos > 0 && stopPos < len ) {
-                UnicodeString firstWord(relativeDayString, 0, stopPos);
-                firstWord.toTitle(NULL, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
-                relativeDayString.replaceBetween(0, stopPos, firstWord);
-            } else {
-                // no stopPos, titlecase the whole text
-                relativeDayString.toTitle(NULL, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
-            }
+        if ( u_islower(relativeDayString.char32At(0)) && fCapitalizationBrkIter!= NULL &&
+             ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
+               (capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && fCapitalizationOfRelativeUnitsForUIListMenu) ||
+               (capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && fCapitalizationOfRelativeUnitsForStandAlone) ) ) {
+            // titlecase first word of relativeDayString
+            relativeDayString.toTitle(fCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
         }
+#endif
         fDateTimeFormatter->setContext(UDISPCTX_CAPITALIZATION_NONE, status);
     } else {
         // set our context for the formatter
@@ -427,6 +420,54 @@ RelativeDateFormat::getDateFormatSymbols() const
     return fDateTimeFormatter->getDateFormatSymbols();
 }
 
+// override the DateFormat implementation in order to
+// lazily initialize relevant items
+void
+RelativeDateFormat::setContext(UDisplayContext value, UErrorCode& status)
+{
+    DateFormat::setContext(value, status);
+    if (U_SUCCESS(status)) {
+        if (!fCapitalizationInfoSet &&
+                (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE)) {
+            initCapitalizationContextInfo(fLocale);
+            fCapitalizationInfoSet = TRUE;
+        }
+#if !UCONFIG_NO_BREAK_ITERATION
+        if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
+                (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && fCapitalizationOfRelativeUnitsForUIListMenu) ||
+                (value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && fCapitalizationOfRelativeUnitsForStandAlone)) ) {
+            UErrorCode status = U_ZERO_ERROR;
+            fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
+            if (U_FAILURE(status)) {
+                delete fCapitalizationBrkIter;
+                fCapitalizationBrkIter = NULL;
+            }
+        }
+#endif
+    }
+}
+
+void
+RelativeDateFormat::initCapitalizationContextInfo(const Locale& thelocale)
+{
+#if !UCONFIG_NO_BREAK_ITERATION
+    const char * localeID = (thelocale != NULL)? thelocale.getBaseName(): NULL;
+    UErrorCode status = U_ZERO_ERROR;
+    UResourceBundle *rb = ures_open(NULL, localeID, &status);
+    rb = ures_getByKeyWithFallback(rb, "contextTransforms", rb, &status);
+    rb = ures_getByKeyWithFallback(rb, "relative", rb, &status);
+    if (U_SUCCESS(status) && rb != NULL) {
+        int32_t len = 0;
+        const int32_t * intVector = ures_getIntVector(rb, &len, &status);
+        if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
+            fCapitalizationOfRelativeUnitsForUIListMenu = intVector[0];
+            fCapitalizationOfRelativeUnitsForStandAlone = intVector[1];
+        }
+    }
+    ures_close(rb);
+#endif
+}
+
 static const UChar patItem1[] = {0x7B,0x31,0x7D}; // "{1}"
 static const int32_t patItem1Len = 3;
 
@@ -473,35 +514,21 @@ void RelativeDateFormat::loadDates(UErrorCode &status) {
         }
     }
 
-    fCapitalizationForRelativeUnits[0] = fCapitalizationForRelativeUnits[1] = FALSE;
-    UResourceBundle *lb = ures_open(NULL, fLocale.getBaseName(), &status);
-    tempStatus = status;
-    UResourceBundle *rb = ures_getByKeyWithFallback(lb, "contextTransforms", NULL, &tempStatus);
-    UResourceBundle *sb = ures_getByKeyWithFallback(rb, "relative", NULL, &tempStatus);
-    if (U_SUCCESS(tempStatus) && sb != NULL) {
-        int32_t len = 0;
-        const int32_t * intVector = ures_getIntVector(sb, &len, &tempStatus);
-        if (U_SUCCESS(tempStatus) && intVector != NULL && len >= 2) {
-            fCapitalizationForRelativeUnits[0] = intVector[0];
-            fCapitalizationForRelativeUnits[1] = intVector[1];
-        }
-    }
-    sb = ures_getByKeyWithFallback(lb, "fields", sb, &status);
-    rb = ures_getByKeyWithFallback(sb, "day", rb, &status);
-    sb = ures_getByKeyWithFallback(rb, "relative", sb, &status);
-    ures_close(rb);
-    ures_close(lb);
+    UResourceBundle *rb = ures_open(NULL, fLocale.getBaseName(), &status);
+    rb = ures_getByKeyWithFallback(rb, "fields", rb, &status);
+    rb = ures_getByKeyWithFallback(rb, "day", rb, &status);
+    rb = ures_getByKeyWithFallback(rb, "relative", rb, &status);
     // set up min/max 
     fDayMin=-1;
     fDayMax=1;
 
     if(U_FAILURE(status)) {
         fDatesLen=0;
-        ures_close(sb);
+        ures_close(rb);
         return;
     }
 
-    fDatesLen = ures_getSize(sb);
+    fDatesLen = ures_getSize(rb);
     fDates = (URelativeString*) uprv_malloc(sizeof(fDates[0])*fDatesLen);
 
     // Load in each item into the array...
@@ -509,8 +536,8 @@ void RelativeDateFormat::loadDates(UErrorCode &status) {
 
     UResourceBundle *subString = NULL;
     
-    while(ures_hasNext(sb) && U_SUCCESS(status)) {  // iterate over items
-        subString = ures_getNextResource(sb, subString, &status);
+    while(ures_hasNext(rb) && U_SUCCESS(status)) {  // iterate over items
+        subString = ures_getNextResource(rb, subString, &status);
         
         if(U_FAILURE(status) || (subString==NULL)) break;
         
@@ -542,7 +569,7 @@ void RelativeDateFormat::loadDates(UErrorCode &status) {
         n++;
     }
     ures_close(subString);
-    ures_close(sb);
+    ures_close(rb);
     
     // the fDates[] array could be sorted here, for direct access.
 }
index dc277a41d20a43f70511e1b6d905d43b45fb5f1c..67539e043b29446f4984252286bd692c16fd4917 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "unicode/datefmt.h"
 #include "unicode/smpdtfmt.h"
+#include "unicode/brkiter.h"
 
 U_NAMESPACE_BEGIN
 
@@ -232,6 +233,19 @@ public:
      */
     virtual const DateFormatSymbols* getDateFormatSymbols(void) const;
 
+    /* Cannot use #ifndef U_HIDE_DRAFT_API for the following draft method since it is virtual */
+    /**
+     * Set a particular UDisplayContext value in the formatter, such as
+     * UDISPCTX_CAPITALIZATION_FOR_STANDALONE. Note: For getContext, see
+     * DateFormat.
+     * @param value The UDisplayContext value to set.
+     * @param status Input/output status. If at entry this indicates a failure
+     *               status, the function will do nothing; otherwise this will be
+     *               updated with any new status from the function. 
+     * @internal ICU 53
+     */
+    virtual void setContext(UDisplayContext value, UErrorCode& status);
+
 private:
     SimpleDateFormat *fDateTimeFormatter;
     UnicodeString fDatePattern;
@@ -246,8 +260,11 @@ private:
     int32_t fDatesLen;    // Length of array
     URelativeString *fDates; // array of strings
 
-    UBool fCapitalizationForRelativeUnits[2];
     UBool fCombinedHasDateAtStart;
+    UBool fCapitalizationInfoSet;
+    UBool fCapitalizationOfRelativeUnitsForUIListMenu;
+    UBool fCapitalizationOfRelativeUnitsForStandAlone;
+    BreakIterator* fCapitalizationBrkIter;
 
     /**
      * Get the string at a specific offset.
@@ -262,6 +279,11 @@ private:
      */
     void loadDates(UErrorCode &status);
 
+    /**
+     * Set fCapitalizationOfRelativeUnitsForUIListMenu, fCapitalizationOfRelativeUnitsForStandAlone
+     */
+    void initCapitalizationContextInfo(const Locale& thelocale);
+
     /**
      * @return the number of days in "until-now"
      */
index cdfd9f4e903c19b4cfd00aa28602246815a0bb58..086a7462288150bb9d1858c4eb2e1162e574ad52 100644 (file)
@@ -49,6 +49,7 @@
 #include "unicode/utf16.h"
 #include "unicode/vtzone.h"
 #include "unicode/udisplaycontext.h"
+#include "unicode/brkiter.h"
 #include "olsontz.h"
 #include "patternprops.h"
 #include "fphdlimp.h"
@@ -236,6 +237,8 @@ SimpleDateFormat::~SimpleDateFormat()
         delete cur->nf;
         uprv_free(cur);
     }
+    
+    delete fCapitalizationBrkIter;
 }
 
 //----------------------------------------------------------------------
@@ -245,7 +248,8 @@ SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
       fSymbols(NULL),
       fTimeZoneFormat(NULL),
       fNumberFormatters(NULL),
-      fOverrideList(NULL)
+      fOverrideList(NULL),
+      fCapitalizationBrkIter(NULL)
 {
     initializeBooleanAttributes();
     construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status);
@@ -261,7 +265,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
     fSymbols(NULL),
     fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fCapitalizationBrkIter(NULL)
 {
     fDateOverride.setToBogus();
     fTimeOverride.setToBogus();
@@ -281,7 +286,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
     fSymbols(NULL),
     fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fCapitalizationBrkIter(NULL)
 {
     fDateOverride.setTo(override);
     fTimeOverride.setToBogus();
@@ -303,7 +309,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
     fLocale(locale),
     fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fCapitalizationBrkIter(NULL)
 {
 
     fDateOverride.setToBogus();
@@ -325,7 +332,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
     fLocale(locale),
     fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fCapitalizationBrkIter(NULL)
 {
 
     fDateOverride.setTo(override);
@@ -350,7 +358,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
     fSymbols(symbolsToAdopt),
     fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fCapitalizationBrkIter(NULL)
 {
 
     fDateOverride.setToBogus();
@@ -372,7 +381,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
     fSymbols(new DateFormatSymbols(symbols)),
     fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fCapitalizationBrkIter(NULL)
 {
 
     fDateOverride.setToBogus();
@@ -395,7 +405,8 @@ SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,
     fSymbols(NULL),
     fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fCapitalizationBrkIter(NULL)
 {
     initializeBooleanAttributes();
     construct(timeStyle, dateStyle, fLocale, status);
@@ -418,7 +429,8 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale,
     fSymbols(NULL),
     fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fCapitalizationBrkIter(NULL)
 {
     if (U_FAILURE(status)) return;
     initializeBooleanAttributes();
@@ -453,7 +465,8 @@ SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
     fSymbols(NULL),
     fTimeZoneFormat(NULL),
     fNumberFormatters(NULL),
-    fOverrideList(NULL)
+    fOverrideList(NULL),
+    fCapitalizationBrkIter(NULL)
 {
     initializeBooleanAttributes();
     *this = other;
@@ -486,6 +499,10 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
         fTimeZoneFormat = NULL; // forces lazy instantiation with the other locale
         fLocale = other.fLocale;
     }
+    
+    if (other.fCapitalizationBrkIter != NULL) {
+        fCapitalizationBrkIter = (other.fCapitalizationBrkIter)->clone();
+    }
 
     return *this;
 }
@@ -504,6 +521,8 @@ UBool
 SimpleDateFormat::operator==(const Format& other) const
 {
     if (DateFormat::operator==(other)) {
+        // The DateFormat::operator== check for fCapitalizationContext equality above
+        //   is sufficient to check equality of all derived context-related data.
         // DateFormat::operator== guarantees following cast is safe
         SimpleDateFormat* that = (SimpleDateFormat*)&other;
         return (fPattern             == that->fPattern &&
@@ -1591,8 +1610,8 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
         break;
     }
 #if !UCONFIG_NO_BREAK_ITERATION
-    if (fieldNum == 0) {
-        // first field, check to see whether we need to titlecase it
+    // if first field, check to see whether we need to and are able to titlecase it
+    if (fieldNum == 0 && u_islower(appendTo.char32At(beginOffset)) && fCapitalizationBrkIter != NULL) {
         UBool titlecase = FALSE;
         switch (capitalizationContext) {
             case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
@@ -1610,7 +1629,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
         }
         if (titlecase) {
             UnicodeString firstField(appendTo, beginOffset);
-            firstField.toTitle(NULL, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
+            firstField.toTitle(fCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
             appendTo.replaceBetween(beginOffset, appendTo.length(), firstField);
         }
     }
@@ -3275,6 +3294,31 @@ void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
 //----------------------------------------------------------------------
 
 
+// override the DateFormat implementation in order to
+// lazily initialize fCapitalizationBrkIter
+void
+SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status)
+{
+    DateFormat::setContext(value, status);
+#if !UCONFIG_NO_BREAK_ITERATION
+    if (U_SUCCESS(status)) {
+        if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
+                value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE) ) {
+            UErrorCode status = U_ZERO_ERROR;
+            fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
+            if (U_FAILURE(status)) {
+                delete fCapitalizationBrkIter;
+                fCapitalizationBrkIter = NULL;
+            }
+        }
+    }
+#endif
+}
+
+
+//----------------------------------------------------------------------
+
+
 UBool
 SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const {
     return isFieldUnitIgnored(fPattern, field);
index d376a644a184dac5b2ade8ab60ecd0d52a6733ef..5e4f3b33148e4965ee3cea21feb09b853a51fa1a 100644 (file)
@@ -981,11 +981,7 @@ private:
     UBool capitalizationInfoSet;
     UBool capitalizationForUIListMenu;
     UBool capitalizationForStandAlone;
-#if !UCONFIG_NO_BREAK_ITERATION
     BreakIterator* capitalizationBrkIter;
-#else
-    void* capitalizationBrkIter;
-#endif
 };
 
 // ---------------
index a84eddc30a4135ef903d406ecee77aebac887e12..1e54dc3248835895a13b0049ae01162e446e990a 100644 (file)
@@ -36,6 +36,7 @@
 #include "unicode/datefmt.h"
 #include "unicode/udisplaycontext.h"
 #include "unicode/tzfmt.h"  /* for UTimeZoneFormatTimeType */
+#include "unicode/brkiter.h"
 
 U_NAMESPACE_BEGIN
 
@@ -1108,6 +1109,19 @@ public:
      */
     virtual const TimeZoneFormat* getTimeZoneFormat(void) const;
 
+    /* Cannot use #ifndef U_HIDE_DRAFT_API for the following draft method since it is virtual */
+    /**
+     * Set a particular UDisplayContext value in the formatter, such as
+     * UDISPCTX_CAPITALIZATION_FOR_STANDALONE. Note: For getContext, see
+     * DateFormat.
+     * @param value The UDisplayContext value to set.
+     * @param status Input/output status. If at entry this indicates a failure
+     *               status, the function will do nothing; otherwise this will be
+     *               updated with any new status from the function. 
+     * @draft ICU 53
+     */
+    virtual void setContext(UDisplayContext value, UErrorCode& status);
+
 #ifndef U_HIDE_INTERNAL_API
     /**
      * This is for ICU internal use only. Please do not use.
@@ -1516,6 +1530,8 @@ private:
     NSOverride      *fOverrideList;
 
     UBool fHaveDefaultCentury;
+
+    BreakIterator* fCapitalizationBrkIter;
 };
 
 inline UDate
index 1c98ee8dc658af0b21abcda3e43f96c8ef91f2d8..d2d7fbde6c6eaaaeb7ab8359813a4d539262fe5b 100644 (file)
@@ -1,6 +1,6 @@
 /*********************************************************************
  * COPYRIGHT:
- * Copyright (c) 2010-2013, International Business Machines Corporation and
+ * Copyright (c) 2010-2014, International Business Machines Corporation and
  * others. All Rights Reserved.
  *********************************************************************/
 
@@ -294,14 +294,21 @@ static const LocNameDispContextItem ctxtItems[] = {
     { "da", UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, en_US, daFor_en_US_DT },
     { "es", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, en,    esFor_en_T },
     { "es", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, en_US, esFor_en_US_T },
-    { "es", UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       en_US, esFor_en_US_DT },
+    { "es", UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, en_US, esFor_en_US_DT },
 
     { "da", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       en,    daFor_en_T },
     { "da", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       en_US, daFor_en_US_T },
     { "da", UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       en_US, daFor_en_US_DT },
     { "es", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       en,    esFor_en_T },
     { "es", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       en_US, esFor_en_US_T },
-    { "es", UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, en_US, esFor_en_US_DT },
+    { "es", UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       en_US, esFor_en_US_DT },
+
+    { "da", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_STANDALONE,            en,    daFor_en   },
+    { "da", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_STANDALONE,            en_US, daFor_en_US   },
+    { "da", UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_STANDALONE,            en_US, daFor_en_US_D  },
+    { "es", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_STANDALONE,            en,    esFor_en_T },
+    { "es", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_STANDALONE,            en_US, esFor_en_US_T },
+    { "es", UDISPCTX_DIALECT_NAMES,  UDISPCTX_CAPITALIZATION_FOR_STANDALONE,            en_US, esFor_en_US_DT },
  #endif /* #if !UCONFIG_NO_BREAK_ITERATION */
     { NULL, (UDisplayContext)0,      (UDisplayContext)0,                                NULL,  NULL }
 };