Line data Source code
1 : // Copyright 2017 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/builtins/builtins-utils.h"
10 : #include "src/builtins/builtins.h"
11 : #include "src/intl.h"
12 : #include "src/objects-inl.h"
13 :
14 : #include "unicode/normalizer2.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 :
19 596430 : BUILTIN(StringPrototypeToLowerCaseIntl) {
20 : HandleScope scope(isolate);
21 398160 : TO_THIS_STRING(string, "String.prototype.toLowerCase");
22 198540 : string = String::Flatten(string);
23 198540 : return ConvertCase(string, false, isolate);
24 : }
25 :
26 22446 : BUILTIN(StringPrototypeToUpperCaseIntl) {
27 : HandleScope scope(isolate);
28 15504 : TO_THIS_STRING(string, "String.prototype.toUpperCase");
29 7212 : string = String::Flatten(string);
30 7212 : return ConvertCase(string, true, isolate);
31 : }
32 :
33 7220 : BUILTIN(StringPrototypeNormalizeIntl) {
34 : HandleScope handle_scope(isolate);
35 7220 : TO_THIS_STRING(string, "String.prototype.normalize");
36 :
37 : Handle<Object> form_input = args.atOrUndefined(isolate, 1);
38 : const char* form_name;
39 : UNormalization2Mode form_mode;
40 3610 : if (form_input->IsUndefined(isolate)) {
41 : // default is FNC
42 : form_name = "nfc";
43 : form_mode = UNORM2_COMPOSE;
44 : } else {
45 : Handle<String> form;
46 6063 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, form,
47 : Object::ToString(isolate, form_input));
48 :
49 2950 : if (String::Equals(form, isolate->factory()->NFC_string())) {
50 : form_name = "nfc";
51 : form_mode = UNORM2_COMPOSE;
52 2305 : } else if (String::Equals(form, isolate->factory()->NFD_string())) {
53 : form_name = "nfc";
54 : form_mode = UNORM2_DECOMPOSE;
55 1675 : } else if (String::Equals(form, isolate->factory()->NFKC_string())) {
56 : form_name = "nfkc";
57 : form_mode = UNORM2_COMPOSE;
58 1031 : } else if (String::Equals(form, isolate->factory()->NFKD_string())) {
59 : form_name = "nfkc";
60 : form_mode = UNORM2_DECOMPOSE;
61 : } else {
62 : Handle<String> valid_forms =
63 163 : isolate->factory()->NewStringFromStaticChars("NFC, NFD, NFKC, NFKD");
64 326 : THROW_NEW_ERROR_RETURN_FAILURE(
65 : isolate,
66 : NewRangeError(MessageTemplate::kNormalizationForm, valid_forms));
67 : }
68 : }
69 :
70 : int length = string->length();
71 3447 : string = String::Flatten(string);
72 3447 : icu::UnicodeString result;
73 3447 : std::unique_ptr<uc16[]> sap;
74 3447 : UErrorCode status = U_ZERO_ERROR;
75 : {
76 : DisallowHeapAllocation no_gc;
77 3447 : String::FlatContent flat = string->GetFlatContent();
78 3447 : const UChar* src = GetUCharBufferFromFlat(flat, &sap, length);
79 3447 : icu::UnicodeString input(false, src, length);
80 : // Getting a singleton. Should not free it.
81 : const icu::Normalizer2* normalizer =
82 3447 : icu::Normalizer2::getInstance(nullptr, form_name, form_mode, status);
83 : DCHECK(U_SUCCESS(status));
84 3447 : CHECK(normalizer != nullptr);
85 : int32_t normalized_prefix_length =
86 3447 : normalizer->spanQuickCheckYes(input, status);
87 : // Quick return if the input is already normalized.
88 5396 : if (length == normalized_prefix_length) return *string;
89 : icu::UnicodeString unnormalized =
90 2996 : input.tempSubString(normalized_prefix_length);
91 : // Read-only alias of the normalized prefix.
92 1498 : result.setTo(false, input.getBuffer(), normalized_prefix_length);
93 : // copy-on-write; normalize the suffix and append to |result|.
94 2996 : normalizer->normalizeSecondAndAppend(result, unnormalized, status);
95 : }
96 :
97 1498 : if (U_FAILURE(status)) {
98 0 : return isolate->heap()->undefined_value();
99 : }
100 :
101 4494 : RETURN_RESULT_OR_FAILURE(
102 : isolate, isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>(
103 : reinterpret_cast<const uint16_t*>(result.getBuffer()),
104 : result.length())));
105 : }
106 :
107 : } // namespace internal
108 : } // namespace v8
|