Line data Source code
1 : // Copyright 2018 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 : #include "src/objects/js-segmenter.h"
10 :
11 : #include <map>
12 : #include <memory>
13 : #include <string>
14 :
15 : #include "src/heap/factory.h"
16 : #include "src/isolate.h"
17 : #include "src/objects-inl.h"
18 : #include "src/objects/intl-objects.h"
19 : #include "src/objects/js-segmenter-inl.h"
20 : #include "src/objects/managed.h"
21 : #include "unicode/brkiter.h"
22 :
23 : namespace v8 {
24 : namespace internal {
25 :
26 0 : JSSegmenter::Granularity JSSegmenter::GetGranularity(const char* str) {
27 0 : if (strcmp(str, "grapheme") == 0) return JSSegmenter::Granularity::GRAPHEME;
28 0 : if (strcmp(str, "word") == 0) return JSSegmenter::Granularity::WORD;
29 0 : if (strcmp(str, "sentence") == 0) return JSSegmenter::Granularity::SENTENCE;
30 0 : UNREACHABLE();
31 : }
32 :
33 630 : MaybeHandle<JSSegmenter> JSSegmenter::Initialize(
34 : Isolate* isolate, Handle<JSSegmenter> segmenter_holder,
35 : Handle<Object> locales, Handle<Object> input_options) {
36 : segmenter_holder->set_flags(0);
37 :
38 : // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
39 : Maybe<std::vector<std::string>> maybe_requested_locales =
40 630 : Intl::CanonicalizeLocaleList(isolate, locales);
41 630 : MAYBE_RETURN(maybe_requested_locales, Handle<JSSegmenter>());
42 : std::vector<std::string> requested_locales =
43 621 : maybe_requested_locales.FromJust();
44 :
45 : // 11. If options is undefined, then
46 : Handle<JSReceiver> options;
47 1242 : if (input_options->IsUndefined(isolate)) {
48 : // 11. a. Let options be ObjectCreate(null).
49 171 : options = isolate->factory()->NewJSObjectWithNullProto();
50 : // 12. Else
51 : } else {
52 : // 23. a. Let options be ? ToObject(options).
53 900 : ASSIGN_RETURN_ON_EXCEPTION(isolate, options,
54 : Object::ToObject(isolate, input_options),
55 : JSSegmenter);
56 : }
57 :
58 : // 4. Let opt be a new Record.
59 : // 5. Let matcher be ? GetOption(options, "localeMatcher", "string",
60 : // « "lookup", "best fit" », "best fit").
61 : // 6. Set opt.[[localeMatcher]] to matcher.
62 : Maybe<Intl::MatcherOption> maybe_locale_matcher =
63 621 : Intl::GetLocaleMatcher(isolate, options, "Intl.Segmenter");
64 621 : MAYBE_RETURN(maybe_locale_matcher, MaybeHandle<JSSegmenter>());
65 : Intl::MatcherOption matcher = maybe_locale_matcher.FromJust();
66 :
67 : // 9. Let r be ResolveLocale(%Segmenter%.[[AvailableLocales]],
68 : // requestedLocales, opt, %Segmenter%.[[RelevantExtensionKeys]]).
69 : Intl::ResolvedLocale r =
70 : Intl::ResolveLocale(isolate, JSSegmenter::GetAvailableLocales(),
71 1836 : requested_locales, matcher, {});
72 :
73 : // 10. Set segmenter.[[Locale]] to the value of r.[[Locale]].
74 : Handle<String> locale_str =
75 612 : isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str());
76 612 : segmenter_holder->set_locale(*locale_str);
77 :
78 : // 13. Let granularity be ? GetOption(options, "granularity", "string", «
79 : // "grapheme", "word", "sentence" », "grapheme").
80 : Maybe<Granularity> maybe_granularity = Intl::GetStringOption<Granularity>(
81 : isolate, options, "granularity", "Intl.Segmenter",
82 : {"grapheme", "word", "sentence"},
83 : {Granularity::GRAPHEME, Granularity::WORD, Granularity::SENTENCE},
84 1836 : Granularity::GRAPHEME);
85 612 : MAYBE_RETURN(maybe_granularity, MaybeHandle<JSSegmenter>());
86 : Granularity granularity_enum = maybe_granularity.FromJust();
87 :
88 : // 14. Set segmenter.[[SegmenterGranularity]] to granularity.
89 558 : segmenter_holder->set_granularity(granularity_enum);
90 :
91 1116 : icu::Locale icu_locale = r.icu_locale;
92 : DCHECK(!icu_locale.isBogus());
93 :
94 558 : UErrorCode status = U_ZERO_ERROR;
95 : std::unique_ptr<icu::BreakIterator> icu_break_iterator;
96 :
97 558 : switch (granularity_enum) {
98 : case Granularity::GRAPHEME:
99 : icu_break_iterator.reset(
100 369 : icu::BreakIterator::createCharacterInstance(icu_locale, status));
101 : break;
102 : case Granularity::WORD:
103 : icu_break_iterator.reset(
104 99 : icu::BreakIterator::createWordInstance(icu_locale, status));
105 : break;
106 : case Granularity::SENTENCE:
107 : icu_break_iterator.reset(
108 90 : icu::BreakIterator::createSentenceInstance(icu_locale, status));
109 : break;
110 : case Granularity::COUNT:
111 0 : UNREACHABLE();
112 : }
113 :
114 1116 : CHECK(U_SUCCESS(status));
115 558 : CHECK_NOT_NULL(icu_break_iterator.get());
116 :
117 : Handle<Managed<icu::BreakIterator>> managed_break_iterator =
118 : Managed<icu::BreakIterator>::FromUniquePtr(isolate, 0,
119 1116 : std::move(icu_break_iterator));
120 :
121 558 : segmenter_holder->set_icu_break_iterator(*managed_break_iterator);
122 558 : return segmenter_holder;
123 : }
124 :
125 : // ecma402 #sec-Intl.Segmenter.prototype.resolvedOptions
126 81 : Handle<JSObject> JSSegmenter::ResolvedOptions(
127 : Isolate* isolate, Handle<JSSegmenter> segmenter_holder) {
128 : Factory* factory = isolate->factory();
129 : // 3. Let options be ! ObjectCreate(%ObjectPrototype%).
130 81 : Handle<JSObject> result = factory->NewJSObject(isolate->object_function());
131 : // 4. For each row of Table 1, except the header row, do
132 : // a. Let p be the Property value of the current row.
133 : // b. Let v be the value of pr's internal slot whose name is the Internal Slot
134 : // value of the current row.
135 : //
136 : // c. If v is not undefined, then
137 : // i. Perform ! CreateDataPropertyOrThrow(options, p, v).
138 : // Table 1: Resolved Options of Segmenter Instances
139 : // Internal Slot Property
140 : // [[Locale]] "locale"
141 : // [[SegmenterGranularity]] "granularity"
142 :
143 162 : Handle<String> locale(segmenter_holder->locale(), isolate);
144 : JSObject::AddProperty(isolate, result, factory->locale_string(), locale,
145 81 : NONE);
146 : JSObject::AddProperty(isolate, result, factory->granularity_string(),
147 162 : segmenter_holder->GranularityAsString(), NONE);
148 : // 5. Return options.
149 81 : return result;
150 : }
151 :
152 81 : Handle<String> JSSegmenter::GranularityAsString() const {
153 81 : switch (granularity()) {
154 : case Granularity::GRAPHEME:
155 162 : return GetReadOnlyRoots().grapheme_string_handle();
156 : case Granularity::WORD:
157 0 : return GetReadOnlyRoots().word_string_handle();
158 : case Granularity::SENTENCE:
159 0 : return GetReadOnlyRoots().sentence_string_handle();
160 : case Granularity::COUNT:
161 0 : UNREACHABLE();
162 : }
163 0 : }
164 :
165 41 : const std::set<std::string>& JSSegmenter::GetAvailableLocales() {
166 : static base::LazyInstance<Intl::AvailableLocales<icu::BreakIterator>>::type
167 : available_locales = LAZY_INSTANCE_INITIALIZER;
168 41 : return available_locales.Pointer()->Get();
169 : }
170 :
171 : } // namespace internal
172 178779 : } // namespace v8
|