Bug 1746711 Part 2: Ensure the enqueued surface has a color space. r=gfx-reviewers...
[gecko.git] / intl / components / src / NumberRangeFormat.h
blob60de8399ec4cbc1c8e1c1b63e66730e0ea62cfeb
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 #ifndef intl_components_NumberRangeFormat_h_
5 #define intl_components_NumberRangeFormat_h_
7 #include "mozilla/FloatingPoint.h"
8 #include "mozilla/intl/ICUError.h"
9 #include "mozilla/intl/NumberFormat.h"
10 #include "mozilla/Result.h"
11 #include "mozilla/UniquePtr.h"
13 #include <stdint.h>
14 #include <string_view>
16 #include "unicode/utypes.h"
18 struct UFormattedNumberRange;
19 struct UNumberRangeFormatter;
20 struct UPluralRules;
22 namespace mozilla::intl {
24 /**
25 * NumberRangeFormatOptions supports the same set of options as
26 * NumberFormatOptions and additionally allows to control how to display ranges.
28 struct MOZ_STACK_CLASS NumberRangeFormatOptions : public NumberFormatOptions {
29 /**
30 * Controls if and how to collapse identical parts in a range.
32 enum class RangeCollapse {
33 /**
34 * Apply locale-specific heuristics.
36 Auto,
38 /**
39 * Never collapse identical parts.
41 None,
43 /**
44 * Collapse identical unit parts.
46 Unit,
48 /**
49 * Collapse all identical parts.
51 All,
52 } mRangeCollapse = RangeCollapse::Auto;
54 /**
55 * Controls how to display identical numbers.
57 enum class RangeIdentityFallback {
58 /**
59 * Display the range as a single value.
61 SingleValue,
63 /**
64 * Display the range as a single value if both numbers were equal before
65 * rounding. Otherwise display with a locale-sensitive approximation
66 * pattern.
68 ApproximatelyOrSingleValue,
70 /**
71 * Display with a locale-sensitive approximation pattern.
73 Approximately,
75 /**
76 * Display as a range expression.
78 Range,
79 } mRangeIdentityFallback = RangeIdentityFallback::SingleValue;
82 /**
83 * A NumberRangeFormat implementation that roughly mirrors the API provided by
84 * the ECMA-402 Intl.NumberFormat object for formatting number ranges.
86 * https://tc39.es/ecma402/#numberformat-objects
88 class NumberRangeFormat final {
89 public:
90 /**
91 * Initialize a new NumberRangeFormat for the provided locale and using the
92 * provided options.
94 * https://tc39.es/ecma402/#sec-initializenumberformat
96 static Result<UniquePtr<NumberRangeFormat>, ICUError> TryCreate(
97 std::string_view aLocale, const NumberRangeFormatOptions& aOptions);
99 NumberRangeFormat() = default;
100 NumberRangeFormat(const NumberRangeFormat&) = delete;
101 NumberRangeFormat& operator=(const NumberRangeFormat&) = delete;
103 ~NumberRangeFormat();
106 * Formats a double range to a utf-16 string. The string view is valid until
107 * another number range is formatted. Accessing the string view after this
108 * event is undefined behavior.
110 * https://tc39.es/ecma402/#sec-formatnumericrange
112 Result<std::u16string_view, ICUError> format(double start, double end) const {
113 if (!formatInternal(start, end)) {
114 return Err(ICUError::InternalError);
117 return formatResult();
121 * Formats a double range to a utf-16 string, and fills the provided parts
122 * vector. The string view is valid until another number is formatted.
123 * Accessing the string view after this event is undefined behavior.
125 * https://tc39.es/ecma402/#sec-partitionnumberrangepattern
127 Result<std::u16string_view, ICUError> formatToParts(
128 double start, double end, NumberPartVector& parts) const {
129 if (!formatInternal(start, end)) {
130 return Err(ICUError::InternalError);
133 bool isNegativeStart = !IsNaN(start) && IsNegative(start);
134 bool isNegativeEnd = !IsNaN(end) && IsNegative(end);
136 return formatResultToParts(Some(start), isNegativeStart, Some(end),
137 isNegativeEnd, parts);
141 * Formats a decimal number range to a utf-16 string. The string view is valid
142 * until another number range is formatted. Accessing the string view after
143 * this event is undefined behavior.
145 * https://tc39.es/ecma402/#sec-formatnumericrange
147 Result<std::u16string_view, ICUError> format(std::string_view start,
148 std::string_view end) const {
149 if (!formatInternal(start, end)) {
150 return Err(ICUError::InternalError);
153 return formatResult();
157 * Formats a string encoded decimal number range to a utf-16 string, and fills
158 * the provided parts vector. The string view is valid until another number is
159 * formatted. Accessing the string view after this event is undefined
160 * behavior.
162 * https://tc39.es/ecma402/#sec-partitionnumberrangepattern
164 Result<std::u16string_view, ICUError> formatToParts(
165 std::string_view start, std::string_view end,
166 NumberPartVector& parts) const {
167 if (!formatInternal(start, end)) {
168 return Err(ICUError::InternalError);
171 Maybe<double> numStart = Nothing();
172 if (start == "Infinity" || start == "+Infinity") {
173 numStart.emplace(PositiveInfinity<double>());
174 } else if (start == "-Infinity") {
175 numStart.emplace(NegativeInfinity<double>());
176 } else {
177 // Not currently expected, so we assert here.
178 MOZ_ASSERT(start != "NaN");
181 Maybe<double> numEnd = Nothing();
182 if (end == "Infinity" || end == "+Infinity") {
183 numEnd.emplace(PositiveInfinity<double>());
184 } else if (end == "-Infinity") {
185 numEnd.emplace(NegativeInfinity<double>());
186 } else {
187 // Not currently expected, so we assert here.
188 MOZ_ASSERT(end != "NaN");
191 bool isNegativeStart = !start.empty() && start[0] == '-';
192 bool isNegativeEnd = !end.empty() && end[0] == '-';
194 return formatResultToParts(numStart, isNegativeStart, numEnd, isNegativeEnd,
195 parts);
199 * Formats the number range and selects the keyword by using a provided
200 * UPluralRules object.
202 * https://tc39.es/ecma402/#sec-intl.pluralrules.prototype.selectrange
204 * TODO(1713917) This is necessary because both PluralRules and
205 * NumberRangeFormat have a shared dependency on the raw UFormattedNumberRange
206 * type. Once we transition to using ICU4X, the FFI calls should no
207 * longer require such shared dependencies. At that time, this
208 * functionality should be removed from NumberRangeFormat and invoked
209 * solely from PluralRules.
211 Result<int32_t, ICUError> selectForRange(
212 double start, double end, char16_t* keyword, int32_t keywordSize,
213 const UPluralRules* pluralRules) const;
215 private:
216 UNumberRangeFormatter* mNumberRangeFormatter = nullptr;
217 UFormattedNumberRange* mFormattedNumberRange = nullptr;
218 bool mFormatForUnit = false;
220 Result<Ok, ICUError> initialize(std::string_view aLocale,
221 const NumberRangeFormatOptions& aOptions);
223 [[nodiscard]] bool formatInternal(double start, double end) const;
225 [[nodiscard]] bool formatInternal(std::string_view start,
226 std::string_view end) const;
228 Result<std::u16string_view, ICUError> formatResult() const;
230 Result<std::u16string_view, ICUError> formatResultToParts(
231 Maybe<double> start, bool startIsNegative, Maybe<double> end,
232 bool endIsNegative, NumberPartVector& parts) const;
235 } // namespace mozilla::intl
237 #endif