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
18using namespace skia_private;
19
20#ifdef SK_UNICODE_CLIENT_IMPLEMENTATION
21UNIX_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
35UNIX_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
46UNIX_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
59UNIX_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}
73UNIX_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
88UNIX_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
121UNIX_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
144UNIX_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
154UNIX_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
187UNIX_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