tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RelativeTimeFormat.cpp (5190B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 #include "mozilla/intl/RelativeTimeFormat.h"
      5 #include "mozilla/FloatingPoint.h"
      6 
      7 #include "unicode/unum.h"
      8 
      9 #include "NumberFormatFields.h"
     10 #include "ICU4CGlue.h"
     11 #include "ScopedICUObject.h"
     12 
     13 namespace mozilla::intl {
     14 
     15 /*static*/ Result<UniquePtr<RelativeTimeFormat>, ICUError>
     16 RelativeTimeFormat::TryCreate(const char* aLocale,
     17                              const RelativeTimeFormatOptions& aOptions) {
     18  UErrorCode status = U_ZERO_ERROR;
     19 
     20  UFormattedRelativeDateTime* formattedRelativeDateTime =
     21      ureldatefmt_openResult(&status);
     22  if (U_FAILURE(status)) {
     23    return Err(ToICUError(status));
     24  }
     25  ScopedICUObject<UFormattedRelativeDateTime, ureldatefmt_closeResult>
     26      closeFormattedRelativeDate(formattedRelativeDateTime);
     27 
     28  UNumberFormat* nf =
     29      unum_open(UNUM_DECIMAL, nullptr, 0, IcuLocale(aLocale), nullptr, &status);
     30  if (U_FAILURE(status)) {
     31    return Err(ToICUError(status));
     32  }
     33  ScopedICUObject<UNumberFormat, unum_close> closeNumberFormatter(nf);
     34 
     35  // Use the default values as if a new Intl.NumberFormat had been constructed.
     36  unum_setAttribute(nf, UNUM_MIN_INTEGER_DIGITS, 1);
     37  unum_setAttribute(nf, UNUM_MIN_FRACTION_DIGITS, 0);
     38  unum_setAttribute(nf, UNUM_MAX_FRACTION_DIGITS, 3);
     39  unum_setAttribute(nf, UNUM_GROUPING_USED, true);
     40  unum_setAttribute(nf, UNUM_MINIMUM_GROUPING_DIGITS,
     41                    UNUM_MINIMUM_GROUPING_DIGITS_AUTO);
     42 
     43  UDateRelativeDateTimeFormatterStyle relDateTimeStyle;
     44  switch (aOptions.style) {
     45    case RelativeTimeFormatOptions::Style::Short:
     46      relDateTimeStyle = UDAT_STYLE_SHORT;
     47      break;
     48    case RelativeTimeFormatOptions::Style::Narrow:
     49      relDateTimeStyle = UDAT_STYLE_NARROW;
     50      break;
     51    case RelativeTimeFormatOptions::Style::Long:
     52      relDateTimeStyle = UDAT_STYLE_LONG;
     53      break;
     54  }
     55 
     56  URelativeDateTimeFormatter* formatter =
     57      ureldatefmt_open(IcuLocale(aLocale), nf, relDateTimeStyle,
     58                       UDISPCTX_CAPITALIZATION_FOR_STANDALONE, &status);
     59 
     60  if (U_FAILURE(status)) {
     61    return Err(ToICUError(status));
     62  }
     63 
     64  // Ownership was transferred to mFormatter.
     65  closeNumberFormatter.forget();
     66 
     67  UniquePtr<RelativeTimeFormat> rtf = MakeUnique<RelativeTimeFormat>(
     68      aOptions.numeric, formatter, formattedRelativeDateTime);
     69 
     70  // Ownership was transferred to rtf.
     71  closeFormattedRelativeDate.forget();
     72  return rtf;
     73 }
     74 
     75 RelativeTimeFormat::RelativeTimeFormat(
     76    RelativeTimeFormatOptions::Numeric aNumeric,
     77    URelativeDateTimeFormatter* aFormatter,
     78    UFormattedRelativeDateTime* aFormattedRelativeDateTime)
     79    : mNumeric(aNumeric),
     80      mFormatter(aFormatter),
     81      mFormattedRelativeDateTime(aFormattedRelativeDateTime) {}
     82 
     83 RelativeTimeFormat::~RelativeTimeFormat() {
     84  if (mFormattedRelativeDateTime) {
     85    ureldatefmt_closeResult(mFormattedRelativeDateTime);
     86    mFormattedRelativeDateTime = nullptr;
     87  }
     88 
     89  if (mFormatter) {
     90    ureldatefmt_close(mFormatter);
     91    mFormatter = nullptr;
     92  }
     93 }
     94 
     95 URelativeDateTimeUnit RelativeTimeFormat::ToURelativeDateTimeUnit(
     96    FormatUnit unit) const {
     97  switch (unit) {
     98    case FormatUnit::Second:
     99      return UDAT_REL_UNIT_SECOND;
    100    case FormatUnit::Minute:
    101      return UDAT_REL_UNIT_MINUTE;
    102    case FormatUnit::Hour:
    103      return UDAT_REL_UNIT_HOUR;
    104    case FormatUnit::Day:
    105      return UDAT_REL_UNIT_DAY;
    106    case FormatUnit::Week:
    107      return UDAT_REL_UNIT_WEEK;
    108    case FormatUnit::Month:
    109      return UDAT_REL_UNIT_MONTH;
    110    case FormatUnit::Quarter:
    111      return UDAT_REL_UNIT_QUARTER;
    112    case FormatUnit::Year:
    113      return UDAT_REL_UNIT_YEAR;
    114  };
    115  MOZ_ASSERT_UNREACHABLE();
    116  return UDAT_REL_UNIT_SECOND;
    117 }
    118 
    119 Result<Span<const char16_t>, ICUError> RelativeTimeFormat::formatToParts(
    120    double aNumber, FormatUnit aUnit, NumberPartVector& aParts) const {
    121  UErrorCode status = U_ZERO_ERROR;
    122 
    123  if (mNumeric == RelativeTimeFormatOptions::Numeric::Auto) {
    124    ureldatefmt_formatToResult(mFormatter, aNumber,
    125                               ToURelativeDateTimeUnit(aUnit),
    126                               mFormattedRelativeDateTime, &status);
    127  } else {
    128    ureldatefmt_formatNumericToResult(mFormatter, aNumber,
    129                                      ToURelativeDateTimeUnit(aUnit),
    130                                      mFormattedRelativeDateTime, &status);
    131  }
    132  if (U_FAILURE(status)) {
    133    return Err(ToICUError(status));
    134  }
    135 
    136  const UFormattedValue* formattedValue =
    137      ureldatefmt_resultAsValue(mFormattedRelativeDateTime, &status);
    138  if (U_FAILURE(status)) {
    139    return Err(ToICUError(status));
    140  }
    141 
    142  bool isNegative = !std::isnan(aNumber) && IsNegative(aNumber);
    143 
    144  // Necessary until all of intl is using Span (Bug 1709880)
    145  return FormatResultToParts(formattedValue, Nothing(), isNegative,
    146                             false /*formatForUnit*/, aParts)
    147      .andThen([](std::u16string_view result)
    148                   -> Result<Span<const char16_t>, ICUError> {
    149        return Span<const char16_t>(result.data(), result.length());
    150      });
    151 }
    152 
    153 }  // namespace mozilla::intl