1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <gtest/gtest.h>
17
18 #include "font_collection.h"
19 #include "measurer.h"
20 #include "mock/mock_any_span.h"
21 #include "mock/mock_measurer.h"
22 #include "param_test_macros.h"
23 #include "texgine_exception.h"
24 #include "texgine/font_providers.h"
25 #include "texgine_text_blob.h"
26 #include "texgine_text_blob_builder.h"
27 #include "texgine/typography_types.h"
28 #include "text_shaper.h"
29 #include "typeface.h"
30
31 using namespace testing;
32 using namespace testing::ext;
33
34 namespace OHOS {
35 namespace Rosen {
36 namespace TextEngine {
37 struct MockVars {
38 std::vector<uint16_t> catchedBufferGlyphs;
39 std::vector<float> catchedBufferPos;
40 std::vector<std::string> catchedGenerateFontCollectionFamilies;
41
42 std::shared_ptr<TexgineTextBlob> retvalTextBlobBuilderMake = nullptr;
43 std::shared_ptr<FontCollection> retvalGenerateFontCollection =
44 std::make_shared<FontCollection>(std::vector<std::shared_ptr<VariantFontStyleSet>>{});
45 std::unique_ptr<MockMeasurer> retvalMeasurerCreate = std::make_unique<MockMeasurer>();
46 } g_tsMockvars;
47
InitTsMockVars(struct MockVars && vars)48 void InitTsMockVars(struct MockVars &&vars)
49 {
50 g_tsMockvars = std::move(vars);
51 }
52
AllocRunPos(const TexgineFont & font,int count)53 std::shared_ptr<TexgineTextBlobBuilder::RunBuffer> TexgineTextBlobBuilder::AllocRunPos(const TexgineFont& font,
54 int count)
55 {
56 static std::shared_ptr<TexgineTextBlobBuilder::RunBuffer> buffer =
57 std::make_shared<TexgineTextBlobBuilder::RunBuffer>();
58 g_tsMockvars.catchedBufferGlyphs.resize(count);
59 g_tsMockvars.catchedBufferPos.resize(count * 2);
60 buffer->glyphs = g_tsMockvars.catchedBufferGlyphs.data();
61 buffer->pos = g_tsMockvars.catchedBufferPos.data();
62 return buffer;
63 }
64
Make()65 std::shared_ptr<TexgineTextBlob> TexgineTextBlobBuilder::Make()
66 {
67 return g_tsMockvars.retvalTextBlobBuilderMake;
68 }
69
GenerateFontCollection(const std::vector<std::string> & families) const70 std::shared_ptr<FontCollection> FontProviders::GenerateFontCollection(
71 const std::vector<std::string> &families) const noexcept(true)
72 {
73 g_tsMockvars.catchedGenerateFontCollectionFamilies = families;
74 return g_tsMockvars.retvalGenerateFontCollection;
75 }
76
Create(const std::vector<uint16_t> & text,const FontCollection & fontCollection)77 std::unique_ptr<Measurer> Measurer::Create(const std::vector<uint16_t> &text,
78 const FontCollection &fontCollection)
79 {
80 return std::move(g_tsMockvars.retvalMeasurerCreate);
81 }
82
83 struct TextSpanInfo {
84 CharGroups cgs_ = CharGroups::CreateEmpty();
85 };
86
87 class ControllerForTest {
88 public:
GenerateTextSpan(TextSpanInfo info)89 static std::shared_ptr<TextSpan> GenerateTextSpan(TextSpanInfo info)
90 {
91 auto ts = std::make_shared<TextSpan>();
92 ts->cgs_ = info.cgs_;
93 return ts;
94 }
95 };
96
GenerateTextSpan(TextSpanInfo info)97 auto GenerateTextSpan(TextSpanInfo info)
98 {
99 return ControllerForTest::GenerateTextSpan(info);
100 }
101
102 class TextShaperTest : public testing::TestWithParam<std::shared_ptr<TextSpan>> {
103 public:
SetUpTestCase()104 static void SetUpTestCase()
105 {
106 // {1, 1, 0, 0.1, 0.1} is {code point, advanceX, advanceY, offsetX, offsetY}
107 cgs1_.PushBack({ .glyphs = { {1, 1, 0, 0.1, 0.1}, {2, 1, 0, 0.2, 0.2} }, .visibleWidth = 2 });
108 cgs2_.PushBack({ .glyphs = { {1, 1, 0, 0.1, 0.1} }, .visibleWidth = 1 });
109 cgs2_.PushBack({ .glyphs = { {2, 1, 0, 0.2, 0.2} }, .visibleWidth = 1 });
110 }
111
112 static inline CharGroups cgs1_ = CharGroups::CreateEmpty();
113 static inline CharGroups cgs2_ = CharGroups::CreateEmpty();
114 static inline std::shared_ptr<TypographyStyle> ysNormal_ = std::make_shared<TypographyStyle>();
115 static inline std::shared_ptr<TypographyStyle> ysNoProvider_ = std::make_shared<TypographyStyle>();
116 };
117
118 /**
119 * @tc.name: DoShape1
120 * @tc.desc: Verify the DoShape
121 * @tc.type:FUNC
122 */
123 HWTEST_F(TextShaperTest, DoShape1, TestSize.Level1)
124 {
125 TextShaper shaper;
126 auto fp = FontProviders::Create();
127 std::shared_ptr<TextSpan> tsNullptr;
128 auto tsNormal = TextSpan::MakeFromText("normal");
129 ASSERT_EXCEPTION(ExceptionType::INVALID_ARGUMENT, shaper.DoShape(tsNullptr, {}, {}, fp));
130 ASSERT_EXCEPTION(ExceptionType::INVALID_ARGUMENT, shaper.DoShape(tsNormal, {}, {}, nullptr));
131 }
132
133 /**
134 * @tc.name: DoShape2
135 * @tc.desc: Verify the DoShape
136 * @tc.type:FUNC
137 */
138 HWTEST_F(TextShaperTest, DoShape2, TestSize.Level1)
139 {
140 InitTsMockVars({});
141 EXPECT_CALL(*g_tsMockvars.retvalMeasurerCreate, Measure).Times(1).WillOnce(testing::Return(0));
142 TypographyStyle ys;
143 ys.fontFamilies = {"Roboto"};
144 auto span = GenerateTextSpan({.cgs_ = cgs1_});
145
146 EXPECT_NO_THROW({
147 TextShaper shaper;
148 shaper.DoShape(span, {}, ys, FontProviders::Create());
149 ASSERT_EQ(ys.fontFamilies, g_tsMockvars.catchedGenerateFontCollectionFamilies);
150 });
151 }
152
153 /**
154 * @tc.name: DoShape3
155 * @tc.desc: Verify the DoShape
156 * @tc.type:FUNC
157 */
158 HWTEST_F(TextShaperTest, DoShape3, TestSize.Level1)
159 {
160 InitTsMockVars({});
161 EXPECT_CALL(*g_tsMockvars.retvalMeasurerCreate, Measure).Times(1).WillOnce(testing::Return(0));
162 TextStyle style = {.fontFamilies = {"Sans"}};
163 auto span = GenerateTextSpan({.cgs_ = cgs1_});
164
165 EXPECT_NO_THROW({
166 TextShaper shaper;
167 shaper.DoShape(span, style, {}, FontProviders::Create());
168 ASSERT_EQ(style.fontFamilies , g_tsMockvars.catchedGenerateFontCollectionFamilies);
169 });
170 }
171
172 /**
173 * @tc.name: DoShape4
174 * @tc.desc: Verify the DoShape
175 * @tc.type:FUNC
176 */
177 HWTEST_F(TextShaperTest, DoShape4, TestSize.Level1)
178 {
179 InitTsMockVars({.retvalGenerateFontCollection = nullptr});
180 auto span = GenerateTextSpan({});
181
182 EXPECT_NO_THROW({
183 TextShaper shaper;
184 auto ret = shaper.DoShape(span, {}, {}, FontProviders::Create());
185 ASSERT_EQ(ret, 1);
186 });
187 }
188
189 /**
190 * @tc.name: DoShape5
191 * @tc.desc: Verify the DoShape
192 * @tc.type:FUNC
193 */
194 HWTEST_F(TextShaperTest, DoShape5, TestSize.Level1)
195 {
196 InitTsMockVars({});
197 EXPECT_CALL(*g_tsMockvars.retvalMeasurerCreate, Measure).Times(1).WillOnce(testing::Return(1));
198 auto span = GenerateTextSpan({.cgs_ = cgs1_});
199
200 EXPECT_NO_THROW({
201 TextShaper shaper;
202 auto ret = shaper.DoShape(span, {}, {}, FontProviders::Create());
203 ASSERT_EQ(ret, 1);
204 });
205 }
206
207 /**
208 * @tc.name: DoShape6
209 * @tc.desc: Verify the DoShape
210 * @tc.type:FUNC
211 */
212 HWTEST_F(TextShaperTest, DoShape6, TestSize.Level1)
213 {
214 InitTsMockVars({});
215 EXPECT_CALL(*g_tsMockvars.retvalMeasurerCreate, Measure).Times(1).WillOnce(testing::Return(0));
216 auto span = GenerateTextSpan({.cgs_ = cgs1_});
217
218 EXPECT_NO_THROW({
219 TextShaper shaper;
220 auto ret = shaper.DoShape(span, {}, {}, FontProviders::Create());
221 ASSERT_EQ(ret, 0);
222 });
223 }
224
225 /**
226 * @tc.name: GenerateTextBlob1
227 * @tc.desc: Verify the GenerateTextBlob
228 * @tc.type:FUNC
229 */
230 HWTEST_F(TextShaperTest, GenerateTextBlob1, TestSize.Level1)
231 {
232 double spanWidth = 0.0;
233 std::vector<double> glyphWidths;
234 TextShaper shaper;
235 ASSERT_EXCEPTION(ExceptionType::API_FAILED, shaper.GenerateTextBlob({},
236 CharGroups::CreateEmpty(), spanWidth, glyphWidths));
237 }
238
239 /**
240 * @tc.name: GenerateTextBlob2
241 * @tc.desc: Verify the GenerateTextBlob
242 * @tc.type:FUNC
243 */
244 HWTEST_F(TextShaperTest, GenerateTextBlob2, TestSize.Level1)
245 {
246 EXPECT_NO_THROW({
247 double spanWidth = 0.0;
248 std::vector<double> glyphWidths;
249 TextShaper shaper;
250 shaper.GenerateTextBlob({}, cgs1_, spanWidth, glyphWidths);
251 ASSERT_EQ(spanWidth, 2);
252 // 2.0 is glyph width
253 ASSERT_EQ(glyphWidths, (std::vector<double>{2.0}));
254 // {0.1, -0.1, 1.2, -0.2} is the position of code point in text blob
255 ASSERT_EQ(g_tsMockvars.catchedBufferPos, (std::vector<float>{0.1, -0.1, 1.2, -0.2}));
256 // {1, 2} is the glyph in text blob
257 ASSERT_EQ(g_tsMockvars.catchedBufferGlyphs, (std::vector<uint16_t>{1, 2}));
258 });
259 }
260
261 /**
262 * @tc.name: GenerateTextBlob3
263 * @tc.desc: Verify the GenerateTextBlob
264 * @tc.type:FUNC
265 */
266 HWTEST_F(TextShaperTest, GenerateTextBlob3, TestSize.Level1)
267 {
268 EXPECT_NO_THROW({
269 double spanWidth = 0.0;
270 std::vector<double> glyphWidths;
271 TextShaper shaper;
272 shaper.GenerateTextBlob({}, cgs2_, spanWidth, glyphWidths);
273 ASSERT_EQ(spanWidth, 2);
274 ASSERT_EQ(glyphWidths, (std::vector<double>{1.0, 1.0}));
275 ASSERT_EQ(g_tsMockvars.catchedBufferPos, (std::vector<float>{0.1, -0.1, 1.2, -0.2}));
276 ASSERT_EQ(g_tsMockvars.catchedBufferGlyphs, (std::vector<uint16_t>{1, 2}));
277 });
278 }
279
280 /**
281 * @tc.name: Shape1
282 * @tc.desc: Verify the Shape
283 * @tc.type:FUNC
284 */
285 HWTEST_F(TextShaperTest, Shape1, TestSize.Level1)
286 {
287 std::shared_ptr<TextSpan> tsNullptr = nullptr;
288 std::shared_ptr<AnySpan> asNullptr = nullptr;
289 TextShaper shaper;
290 ASSERT_EXCEPTION(ExceptionType::INVALID_ARGUMENT, shaper.Shape(tsNullptr, {}, FontProviders::Create()));
291 ASSERT_EXCEPTION(ExceptionType::INVALID_ARGUMENT, shaper.Shape(asNullptr, {}, FontProviders::Create()));
292 }
293
294 /**
295 * @tc.name: Shape2
296 * @tc.desc: Verify the Shape
297 * @tc.type:FUNC
298 */
299 HWTEST_F(TextShaperTest, Shape2, TestSize.Level1)
300 {
301 InitTsMockVars({.retvalGenerateFontCollection = nullptr});
302
303 EXPECT_NO_THROW({
304 std::shared_ptr<MockAnySpan> mas = std::make_shared<MockAnySpan>();
305 TextShaper shaper;
306 auto ret = shaper.Shape(mas, {}, FontProviders::Create());
307 ASSERT_EQ(ret, 0);
308 });
309 }
310
311 /**
312 * @tc.name: Shape3
313 * @tc.desc: Verify the Shape
314 * @tc.type:FUNC
315 */
316 HWTEST_F(TextShaperTest, Shape3, TestSize.Level1)
317 {
318 InitTsMockVars({.retvalGenerateFontCollection = nullptr});
319
320 EXPECT_NO_THROW({
321 TextShaper shaper;
322 auto ret = shaper.Shape(GenerateTextSpan({}), {}, FontProviders::Create());
323 ASSERT_EQ(ret, 1);
324 });
325 }
326
327 /**
328 * @tc.name: Shape4
329 * @tc.desc: Verify the Shape
330 * @tc.type:FUNC
331 */
332 HWTEST_F(TextShaperTest, Shape4, TestSize.Level1)
333 {
334 InitTsMockVars({});
335 TextShaper shaper;
336 ASSERT_EXCEPTION(ExceptionType::INVALID_CHAR_GROUPS,
337 shaper.Shape(GenerateTextSpan({.cgs_ = {}}), {}, FontProviders::Create()));
338
339 InitTsMockVars({});
340 EXPECT_CALL(*g_tsMockvars.retvalMeasurerCreate, Measure).Times(1).WillOnce(testing::Return(0));
341 cgs1_.Get(0).typeface = nullptr;
342
343 ASSERT_EXCEPTION(ExceptionType::INVALID_ARGUMENT,
344 shaper.Shape(GenerateTextSpan({.cgs_ = cgs1_}), {}, FontProviders::Create()));
345 }
346
347 /**
348 * @tc.name: Shape5
349 * @tc.desc: Verify the Shape
350 * @tc.type:FUNC
351 */
352 HWTEST_F(TextShaperTest, Shape5, TestSize.Level1)
353 {
354 InitTsMockVars({});
355 EXPECT_CALL(*g_tsMockvars.retvalMeasurerCreate, Measure).Times(1).WillOnce(testing::Return(0));
356 cgs1_.Get(0).typeface = std::make_unique<Typeface>(nullptr);
357
358 EXPECT_NO_THROW({
359 TextShaper shaper;
360 auto ret = shaper.Shape(GenerateTextSpan({.cgs_ = cgs1_}), {}, FontProviders::Create());
361 ASSERT_EQ(ret, 1);
362 });
363 }
364
365 /**
366 * @tc.name: Shape6
367 * @tc.desc: Verify the Shape
368 * @tc.type:FUNC
369 */
370 HWTEST_F(TextShaperTest, Shape6, TestSize.Level1)
371 {
372 InitTsMockVars({});
373 EXPECT_CALL(*g_tsMockvars.retvalMeasurerCreate, Measure).Times(1).WillOnce(testing::Return(0));
374 g_tsMockvars.retvalTextBlobBuilderMake = std::make_shared<TexgineTextBlob>();
375
376 EXPECT_NO_THROW({
377 TextShaper shaper;
378 auto ret = shaper.Shape(GenerateTextSpan({.cgs_ = cgs1_}), {}, FontProviders::Create());
379 ASSERT_EQ(ret, 0);
380 });
381 }
382 } // namespace TextEngine
383 } // namespace Rosen
384 } // namespace OHOS
385