1 
2 /*
3  * Copyright 2023 Google LLC
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 #include "include/core/SkEncodedImageFormat.h"
9 #include "include/core/SkSpan.h"
10 #include "include/core/SkStream.h"
11 #include "include/core/SkString.h"
12 #include "include/core/SkTypeface.h"
13 #include "modules/skunicode/include/SkUnicode.h"
14 #include "tests/Test.h"
15 
16 #include <vector>
17 
18 using namespace skia_private;
19 
20 #ifdef SK_UNICODE_CLIENT_IMPLEMENTATION
UNIX_ONLY_TEST(SkUnicode_Client, reporter)21 UNIX_ONLY_TEST(SkUnicode_Client, reporter) {
22     std::u16string text = u"\U000f2008";
23     auto utf8 = SkUnicode::convertUtf16ToUtf8(text.data(), text.size());
24     auto client = SkUnicode::MakeClientBasedUnicode
25                   (SkSpan<char>(&utf8[0], utf8.size()), {}, {}, {});
26     skia_private::TArray<SkUnicode::CodeUnitFlags, true> results;
27     client->computeCodeUnitFlags(utf8.data(), utf8.size(), false, &results);
28 
29     for (auto flag : results) {
30         REPORTER_ASSERT(reporter, !SkUnicode::isPartOfWhiteSpaceBreak(flag));
31     }
32 }
33 #endif
34 #ifdef SK_UNICODE_ICU_IMPLEMENTATION
UNIX_ONLY_TEST(SkUnicode_Native, reporter)35 UNIX_ONLY_TEST(SkUnicode_Native, reporter) {
36     std::u16string text = u"\U000f2008";
37     auto utf8 = SkUnicode::convertUtf16ToUtf8(text.data(), text.size());
38     auto icu = SkUnicode::Make();
39     skia_private::TArray<SkUnicode::CodeUnitFlags, true> results;
40     icu->computeCodeUnitFlags(utf8.data(), utf8.size(), false, &results);
41     for (auto flag : results) {
42         REPORTER_ASSERT(reporter, !SkUnicode::isPartOfWhiteSpaceBreak(flag));
43     }
44 }
45 #endif
UNIX_ONLY_TEST(SkUnicode_GetWords, reporter)46 UNIX_ONLY_TEST(SkUnicode_GetWords, reporter) {
47     SkString text("1 22 333 4444 55555 666666 7777777");
48     std::vector<SkUnicode::Position> expected = { 0, 1, 2, 4, 5, 8, 9, 13, 14, 19, 20, 26, 27, 34 };
49     auto icu = SkUnicode::Make();
50     std::vector<SkUnicode::Position> results;
51     auto result = icu->getWords(text.data(), text.size(), "en", &results);
52     REPORTER_ASSERT(reporter, result);
53     REPORTER_ASSERT(reporter, results.size() == expected.size());
54     for (auto i = 0ul; i < results.size(); ++i) {
55         REPORTER_ASSERT(reporter, results[i] == expected[i]);
56     }
57 }
58 
UNIX_ONLY_TEST(SkUnicode_GetBidiRegionsLTR, reporter)59 UNIX_ONLY_TEST(SkUnicode_GetBidiRegionsLTR, reporter) {
60     SkString text("1 22 333 4444 55555 666666 7777777");
61     auto icu = SkUnicode::Make();
62     std::vector<SkUnicode::BidiRegion> results;
63     auto result = icu->getBidiRegions(text.data(),
64                                       text.size(),
65                                       SkUnicode::TextDirection::kLTR,
66                                       &results);
67     REPORTER_ASSERT(reporter, result);
68     REPORTER_ASSERT(reporter, results.size() == 1);
69     REPORTER_ASSERT(reporter, results[0].start == 0 &&
70                               results[0].end == text.size() &&
71                               results[0].level == 0);
72 }
UNIX_ONLY_TEST(SkUnicode_GetBidiRegionsRTL, reporter)73 UNIX_ONLY_TEST(SkUnicode_GetBidiRegionsRTL, reporter) {
74     SkString text("الهيمنة على العالم عبارة قبيحة ، أفضل أن أسميها تحسين العالم.");
75     auto icu = SkUnicode::Make();
76     std::vector<SkUnicode::BidiRegion> results;
77     auto result = icu->getBidiRegions(text.data(),
78                                       text.size(),
79                                       SkUnicode::TextDirection::kRTL,
80                                       &results);
81     REPORTER_ASSERT(reporter, result);
82     REPORTER_ASSERT(reporter, results.size() == 1);
83     REPORTER_ASSERT(reporter, results[0].start == 0 &&
84                               results[0].end == text.size() &&
85                               results[0].level == 1);
86 }
87 
UNIX_ONLY_TEST(SkUnicode_GetBidiRegionsMix1, reporter)88 UNIX_ONLY_TEST(SkUnicode_GetBidiRegionsMix1, reporter) {
89     // Spaces become Arabic (RTL) but numbers remain English (LTR)
90     SkString text("1 22 333 4444 55555 666666 7777777");
91     std::vector<SkUnicode::BidiRegion> expected = {
92         {0, 1, 2},
93         {1, 2, 1},
94         {2, 4, 2},
95         {4, 5, 1},
96         {5, 8, 2},
97         {8, 9, 1},
98         {9, 13, 2},
99         {13, 14, 1},
100         {14, 19, 2},
101         {19, 20, 1},
102         {20, 26, 2},
103         {26, 27, 1},
104         {27, 34, 2},
105     };
106     auto icu = SkUnicode::Make();
107     std::vector<SkUnicode::BidiRegion> results;
108     auto result = icu->getBidiRegions(text.data(),
109                                       text.size(),
110                                       SkUnicode::TextDirection::kRTL,
111                                       &results);
112     REPORTER_ASSERT(reporter, result);
113     REPORTER_ASSERT(reporter, results.size() == expected.size());
114     for (auto i = 0ul; i < results.size(); ++i) {
115       REPORTER_ASSERT(reporter, results[i].start == expected[i].start &&
116                                 results[i].end == expected[i].end &&
117                                 results[i].level == expected[i].level);
118     }
119 }
120 
UNIX_ONLY_TEST(SkUnicode_GetBidiRegionsMix2, reporter)121 UNIX_ONLY_TEST(SkUnicode_GetBidiRegionsMix2, reporter) {
122     // Few Russian/English words (ЛТР) in the mix
123     SkString text("World ЛТР Domination هي عبارة قبيحة ، أفضل أن أسميها World ЛТР Optimization.");
124     std::vector<SkUnicode::BidiRegion> expected = {
125         { 0, 24, 0},
126         { 24, 80, 1},
127         { 80, 107, 0},
128     };
129     auto icu = SkUnicode::Make();
130     std::vector<SkUnicode::BidiRegion> results;
131     auto result = icu->getBidiRegions(text.data(),
132                                       text.size(),
133                                       SkUnicode::TextDirection::kLTR,
134                                       &results);
135     REPORTER_ASSERT(reporter, result);
136     REPORTER_ASSERT(reporter, results.size() == expected.size());
137     for (auto i = 0ul; i < results.size(); ++i) {
138         REPORTER_ASSERT(reporter, results[i].start == expected[i].start &&
139                                   results[i].end == expected[i].end &&
140                                   results[i].level == expected[i].level);
141     }
142 }
143 
UNIX_ONLY_TEST(SkUnicode_ToUpper, reporter)144 UNIX_ONLY_TEST(SkUnicode_ToUpper, reporter) {
145     SkString lower("abcdefghijklmnopqrstuvwxyz");
146     SkString upper("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
147     auto icu = SkUnicode::Make();
148     auto icu_result1 = icu->toUpper(lower);
149     REPORTER_ASSERT(reporter, icu_result1.equals(upper));
150     auto icu_result2 = icu->toUpper(upper);
151     REPORTER_ASSERT(reporter, icu_result2.equals(upper));
152 }
153 
UNIX_ONLY_TEST(SkUnicode_ComputeCodeUnitFlags, reporter)154 UNIX_ONLY_TEST(SkUnicode_ComputeCodeUnitFlags, reporter) {
155     //SkString text("World domination is such an ugly phrase - I prefer to call it world optimisation");
156     SkString text("1\n22 333 4444 55555 666666 7777777");
157     // 4 8 13 19 24
158     auto icu = SkUnicode::Make();
159     TArray<SkUnicode::CodeUnitFlags> results;
160     auto result = icu->computeCodeUnitFlags(text.data(),
161                                             text.size(),
162                                             /*replaceTabs=*/true,
163                                             &results);
164     REPORTER_ASSERT(reporter, result);
165     REPORTER_ASSERT(reporter, results.size() == SkToS16(text.size() + 1));
166     for (auto i = 0; i < results.size(); ++i) {
167         auto flags = results[i];
168         auto expected = SkUnicode::CodeUnitFlags::kGraphemeStart;
169         if (i == 1) {
170             expected |= SkUnicode::CodeUnitFlags::kControl;
171         }
172         if (i == 2) {
173             expected |= SkUnicode::CodeUnitFlags::kHardLineBreakBefore;
174         }
175         if (i == 1 || i == 4 || i == 8 || i == 13 || i == 19 || i == 26) {
176             expected |= SkUnicode::CodeUnitFlags::kPartOfWhiteSpaceBreak;
177             expected |= SkUnicode::CodeUnitFlags::kPartOfIntraWordBreak;
178         }
179         if (i == 0 || i == 2 || i == 5 || i == 9 || i == 14 || i == 20
180                                                  || i == 27 || i == 34) {
181             expected |= SkUnicode::CodeUnitFlags::kSoftLineBreakBefore;
182         }
183         REPORTER_ASSERT(reporter, flags == expected);
184     }
185 }
186 
UNIX_ONLY_TEST(SkUnicode_ReorderVisual, reporter)187 UNIX_ONLY_TEST(SkUnicode_ReorderVisual, reporter) {
188     auto icu = SkUnicode::Make();
189     auto reorder = [&](std::vector<SkUnicode::BidiLevel> levels,
190                        std::vector<int32_t> expected) {
191             std::vector<int32_t> logicalOrder(levels.size());
192             icu->reorderVisual(levels.data(), levels.size(), logicalOrder.data());
193             for (auto i = 0ul; i < levels.size(); ++i) {
194                 REPORTER_ASSERT(reporter, expected[i] == logicalOrder[i]);
195             }
196         };
197     reorder({}, {});
198     reorder({0}, {0});
199     reorder({1}, {0});
200     reorder({0, 1, 0, 1}, {0, 1, 2, 3});
201 }
202