Line data Source code
1 : // Copyright 2013 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_INTL_SUPPORT
6 : #error Internationalization is expected to be enabled.
7 : #endif // V8_INTL_SUPPORT
8 :
9 : #ifndef V8_OBJECTS_INTL_OBJECTS_H_
10 : #define V8_OBJECTS_INTL_OBJECTS_H_
11 :
12 : #include <map>
13 : #include <set>
14 : #include <string>
15 :
16 : #include "src/base/timezone-cache.h"
17 : #include "src/contexts.h"
18 : #include "src/objects.h"
19 : #include "src/objects/managed.h"
20 : #include "unicode/locid.h"
21 : #include "unicode/uversion.h"
22 :
23 : #define V8_MINIMUM_ICU_VERSION 64
24 :
25 : namespace U_ICU_NAMESPACE {
26 : class BreakIterator;
27 : class Collator;
28 : class DecimalFormat;
29 : class SimpleDateFormat;
30 : class UnicodeString;
31 : }
32 :
33 : namespace v8 {
34 : namespace internal {
35 :
36 : template <typename T>
37 : class Handle;
38 : class JSCollator;
39 :
40 : class Intl {
41 : public:
42 : enum class BoundFunctionContextSlot {
43 : kBoundFunction = Context::MIN_CONTEXT_SLOTS,
44 : kLength
45 : };
46 :
47 : // Build a set of ICU locales from a list of Locales. If there is a locale
48 : // with a script tag then the locales also include a locale without the
49 : // script; eg, pa_Guru_IN (language=Panjabi, script=Gurmukhi, country-India)
50 : // would include pa_IN.
51 : static std::set<std::string> BuildLocaleSet(
52 : const icu::Locale* icu_available_locales, int32_t count);
53 :
54 : static Maybe<std::string> ToLanguageTag(const icu::Locale& locale);
55 :
56 : // Get the name of the numbering system from locale.
57 : // ICU doesn't expose numbering system in any way, so we have to assume that
58 : // for given locale NumberingSystem constructor produces the same digits as
59 : // NumberFormat/Calendar would.
60 : static std::string GetNumberingSystem(const icu::Locale& icu_locale);
61 :
62 : static V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> SupportedLocalesOf(
63 : Isolate* isolate, const char* method,
64 : const std::set<std::string>& available_locales, Handle<Object> locales_in,
65 : Handle<Object> options_in);
66 :
67 : // ECMA402 9.2.10. GetOption( options, property, type, values, fallback)
68 : // ecma402/#sec-getoption
69 : //
70 : // This is specialized for the case when type is string.
71 : //
72 : // Instead of passing undefined for the values argument as the spec
73 : // defines, pass in an empty vector.
74 : //
75 : // Returns true if options object has the property and stores the
76 : // result in value. Returns false if the value is not found. The
77 : // caller is required to use fallback value appropriately in this
78 : // case.
79 : //
80 : // service is a string denoting the type of Intl object; used when
81 : // printing the error message.
82 : V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Maybe<bool> GetStringOption(
83 : Isolate* isolate, Handle<JSReceiver> options, const char* property,
84 : std::vector<const char*> values, const char* service,
85 : std::unique_ptr<char[]>* result);
86 :
87 : // A helper template to get string from option into a enum.
88 : // The enum in the enum_values is the corresponding value to the strings
89 : // in the str_values. If the option does not contains name,
90 : // default_value will be return.
91 : template <typename T>
92 50268 : V8_WARN_UNUSED_RESULT static Maybe<T> GetStringOption(
93 : Isolate* isolate, Handle<JSReceiver> options, const char* name,
94 : const char* method, const std::vector<const char*>& str_values,
95 : const std::vector<T>& enum_values, T default_value) {
96 : DCHECK_EQ(str_values.size(), enum_values.size());
97 50268 : std::unique_ptr<char[]> cstr;
98 100536 : Maybe<bool> found = Intl::GetStringOption(isolate, options, name,
99 50268 : str_values, method, &cstr);
100 50268 : MAYBE_RETURN(found, Nothing<T>());
101 49890 : if (found.FromJust()) {
102 : DCHECK_NOT_NULL(cstr.get());
103 10521 : for (size_t i = 0; i < str_values.size(); i++) {
104 14202 : if (strcmp(cstr.get(), str_values[i]) == 0) {
105 : return Just(enum_values[i]);
106 : }
107 : }
108 0 : UNREACHABLE();
109 : }
110 : return Just(default_value);
111 : }
112 :
113 : // ECMA402 9.2.10. GetOption( options, property, type, values, fallback)
114 : // ecma402/#sec-getoption
115 : //
116 : // This is specialized for the case when type is boolean.
117 : //
118 : // Returns true if options object has the property and stores the
119 : // result in value. Returns false if the value is not found. The
120 : // caller is required to use fallback value appropriately in this
121 : // case.
122 : //
123 : // service is a string denoting the type of Intl object; used when
124 : // printing the error message.
125 : V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Maybe<bool> GetBoolOption(
126 : Isolate* isolate, Handle<JSReceiver> options, const char* property,
127 : const char* service, bool* result);
128 :
129 : // Canonicalize the locale.
130 : // https://tc39.github.io/ecma402/#sec-canonicalizelanguagetag,
131 : // including type check and structural validity check.
132 : static Maybe<std::string> CanonicalizeLanguageTag(Isolate* isolate,
133 : Handle<Object> locale_in);
134 :
135 : static Maybe<std::string> CanonicalizeLanguageTag(Isolate* isolate,
136 : const std::string& locale);
137 :
138 : // https://tc39.github.io/ecma402/#sec-canonicalizelocalelist
139 : // {only_return_one_result} is an optimization for callers that only
140 : // care about the first result.
141 : static Maybe<std::vector<std::string>> CanonicalizeLocaleList(
142 : Isolate* isolate, Handle<Object> locales,
143 : bool only_return_one_result = false);
144 :
145 : // ecma-402 #sec-intl.getcanonicallocales
146 : V8_WARN_UNUSED_RESULT static MaybeHandle<JSArray> GetCanonicalLocales(
147 : Isolate* isolate, Handle<Object> locales);
148 :
149 : // For locale sensitive functions
150 : V8_WARN_UNUSED_RESULT static MaybeHandle<String> StringLocaleConvertCase(
151 : Isolate* isolate, Handle<String> s, bool is_upper,
152 : Handle<Object> locales);
153 :
154 : V8_WARN_UNUSED_RESULT static MaybeHandle<String> ConvertToUpper(
155 : Isolate* isolate, Handle<String> s);
156 :
157 : V8_WARN_UNUSED_RESULT static MaybeHandle<String> ConvertToLower(
158 : Isolate* isolate, Handle<String> s);
159 :
160 : V8_WARN_UNUSED_RESULT static MaybeHandle<Object> StringLocaleCompare(
161 : Isolate* isolate, Handle<String> s1, Handle<String> s2,
162 : Handle<Object> locales, Handle<Object> options);
163 :
164 : V8_WARN_UNUSED_RESULT static Handle<Object> CompareStrings(
165 : Isolate* isolate, const icu::Collator& collator, Handle<String> s1,
166 : Handle<String> s2);
167 :
168 : // ecma402/#sup-properties-of-the-number-prototype-object
169 : V8_WARN_UNUSED_RESULT static MaybeHandle<String> NumberToLocaleString(
170 : Isolate* isolate, Handle<Object> num, Handle<Object> locales,
171 : Handle<Object> options);
172 :
173 : // ecma402/#sec-setnfdigitoptions
174 : V8_WARN_UNUSED_RESULT static Maybe<bool> SetNumberFormatDigitOptions(
175 : Isolate* isolate, icu::DecimalFormat* number_format,
176 : Handle<JSReceiver> options, int mnfd_default, int mxfd_default);
177 :
178 : static icu::Locale CreateICULocale(const std::string& bcp47_locale);
179 :
180 : // Helper funciton to convert a UnicodeString to a Handle<String>
181 : V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToString(
182 : Isolate* isolate, const icu::UnicodeString& string);
183 :
184 : // Helper function to convert a substring of UnicodeString to a Handle<String>
185 : V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToString(
186 : Isolate* isolate, const icu::UnicodeString& string, int32_t begin,
187 : int32_t end);
188 :
189 : // Helper function to convert number field id to type string.
190 : static Handle<String> NumberFieldToType(Isolate* isolate,
191 : Handle<Object> numeric_obj,
192 : int32_t field_id);
193 :
194 : // A helper function to implement formatToParts which add element to array as
195 : // $array[$index] = { type: $field_type_string, value: $value }
196 : static void AddElement(Isolate* isolate, Handle<JSArray> array, int index,
197 : Handle<String> field_type_string,
198 : Handle<String> value);
199 :
200 : // A helper function to implement formatToParts which add element to array as
201 : // $array[$index] = {
202 : // type: $field_type_string, value: $value,
203 : // $additional_property_name: $additional_property_value
204 : // }
205 : static void AddElement(Isolate* isolate, Handle<JSArray> array, int index,
206 : Handle<String> field_type_string, Handle<String> value,
207 : Handle<String> additional_property_name,
208 : Handle<String> additional_property_value);
209 :
210 : // In ECMA 402 v1, Intl constructors supported a mode of operation
211 : // where calling them with an existing object as a receiver would
212 : // transform the receiver into the relevant Intl instance with all
213 : // internal slots. In ECMA 402 v2, this capability was removed, to
214 : // avoid adding internal slots on existing objects. In ECMA 402 v3,
215 : // the capability was re-added as "normative optional" in a mode
216 : // which chains the underlying Intl instance on any object, when the
217 : // constructor is called
218 : //
219 : // See ecma402/#legacy-constructor.
220 : V8_WARN_UNUSED_RESULT static MaybeHandle<Object> LegacyUnwrapReceiver(
221 : Isolate* isolate, Handle<JSReceiver> receiver,
222 : Handle<JSFunction> constructor, bool has_initialized_slot);
223 :
224 : // enum for "caseFirst" option: shared by Intl.Locale and Intl.Collator.
225 : enum class CaseFirst { kUpper, kLower, kFalse, kUndefined };
226 :
227 : // Shared function to read the "caseFirst" option.
228 : V8_WARN_UNUSED_RESULT static Maybe<CaseFirst> GetCaseFirst(
229 : Isolate* isolate, Handle<JSReceiver> options, const char* method);
230 :
231 : // enum for "hourCycle" option: shared by Intl.Locale and Intl.DateTimeFormat.
232 : enum class HourCycle { kH11, kH12, kH23, kH24, kUndefined };
233 :
234 : static HourCycle ToHourCycle(const std::string& str);
235 :
236 : // Shared function to read the "hourCycle" option.
237 : V8_WARN_UNUSED_RESULT static Maybe<HourCycle> GetHourCycle(
238 : Isolate* isolate, Handle<JSReceiver> options, const char* method);
239 :
240 : // enum for "localeMatcher" option: shared by many Intl objects.
241 : enum class MatcherOption { kBestFit, kLookup };
242 :
243 : // Shared function to read the "localeMatcher" option.
244 : V8_WARN_UNUSED_RESULT static Maybe<MatcherOption> GetLocaleMatcher(
245 : Isolate* isolate, Handle<JSReceiver> options, const char* method);
246 :
247 44652 : struct ResolvedLocale {
248 : std::string locale;
249 : icu::Locale icu_locale;
250 : std::map<std::string, std::string> extensions;
251 : };
252 :
253 : static ResolvedLocale ResolveLocale(
254 : Isolate* isolate, const std::set<std::string>& available_locales,
255 : const std::vector<std::string>& requested_locales, MatcherOption options,
256 : const std::set<std::string>& relevant_extension_keys);
257 :
258 : // A helper template to implement the GetAvailableLocales
259 : // Usage in src/objects/js-XXX.cc
260 : //
261 : // const std::set<std::string>& JSXxx::GetAvailableLocales() {
262 : // static base::LazyInstance<Intl::AvailableLocales<icu::YYY>>::type
263 : // available_locales = LAZY_INSTANCE_INITIALIZER;
264 : // return available_locales.Pointer()->Get();
265 : // }
266 : template <typename T>
267 : class AvailableLocales {
268 : public:
269 1039 : AvailableLocales() {
270 1039 : int32_t num_locales = 0;
271 : const icu::Locale* icu_available_locales =
272 1039 : T::getAvailableLocales(num_locales);
273 2078 : set = Intl::BuildLocaleSet(icu_available_locales, num_locales);
274 1039 : }
275 0 : virtual ~AvailableLocales() {}
276 : const std::set<std::string>& Get() const { return set; }
277 :
278 : private:
279 : std::set<std::string> set;
280 : };
281 :
282 : // Utility function to set text to BreakIterator.
283 : static Managed<icu::UnicodeString> SetTextToBreakIterator(
284 : Isolate* isolate, Handle<String> text,
285 : icu::BreakIterator* break_iterator);
286 :
287 : // ecma262 #sec-string.prototype.normalize
288 : V8_WARN_UNUSED_RESULT static MaybeHandle<String> Normalize(
289 : Isolate* isolate, Handle<String> string, Handle<Object> form_input);
290 : static base::TimezoneCache* CreateTimeZoneCache();
291 :
292 : // Convert a Handle<String> to icu::UnicodeString
293 : static icu::UnicodeString ToICUUnicodeString(Isolate* isolate,
294 : Handle<String> string);
295 :
296 : static const uint8_t* ToLatin1LowerTable();
297 :
298 : static String ConvertOneByteToLower(String src, String dst);
299 :
300 : static const std::set<std::string>& GetAvailableLocalesForLocale();
301 :
302 : static const std::set<std::string>& GetAvailableLocalesForDateFormat();
303 : };
304 :
305 : } // namespace internal
306 : } // namespace v8
307 :
308 : #endif // V8_OBJECTS_INTL_OBJECTS_H_
|