1 /*
2 * Copyright (c) 2025 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 <filesystem>
17 #include "gtest/gtest.h"
18 #include "drawing_bitmap.h"
19 #include "drawing_font_collection.h"
20 #include "drawing_rect.h"
21 #include "drawing_text_global.h"
22 #include "drawing_text_line.h"
23 #include "drawing_text_typography.h"
24
25 using namespace testing;
26 using namespace testing::ext;
27
28 namespace {
ExistNotdef()29 bool ExistNotdef()
30 {
31 return std::filesystem::exists("/system/fonts/HarmonyOS_Sans_Notdef.ttf");
32 }
33
ExistNotoSans()34 bool ExistNotoSans()
35 {
36 return std::filesystem::exists("/system/fonts/NotoSans[wdth,wght].ttf");
37 }
38 } // namespace
39
40 namespace OHOS {
41 namespace Rosen {
42 namespace {
43 const int NUM_1 = 1;
44 const int NUM_3 = 3;
45 const int NUM_100 = 100;
46 }
47
48 class NativeUndefinedGlyphDisplayTest : public testing::Test {
49 public:
50 OH_Drawing_Typography* PrepareCreateTypography(
51 const std::string& text, const char** fontFamilies = nullptr, int fontCount = 0);
52 void BoundsResult(OH_Drawing_Typography* typography, const float rectResult[][4], size_t size);
53
54 static constexpr const char* text_ = "Hello 测 World \uffff\n!@#$%^&*~(){\uffff\uffff}[]90 - = ,.\n\uffff"
55 "testlp\uffff试\uffff Drawing\uffff";
56 static constexpr const char* noGlyphText_ = "\uffff";
57 static constexpr float defaultResult_[][4] = { { 2.0, 2.0, 206.63979, 29.0 }, { 1.0, 5.0, 388.10962, 37.0 },
58 { 0, 8.0, 319.4397, 42.0 } };
59 static constexpr float tofuResult_[][4] = { { 2.0, 2.0, 228.63979, 29.0 }, { 1.0, 5.0, 388.10962, 37.0 },
60 { 8.0, 8.0, 341.4397, 42.0 } };
61 static constexpr float notoResult_[][4] = { { 2.0, 2.0, 232.20976, 29.0 }, { 2.0, 5.0, 388.43961, 33.0 },
62 { 8.0, 8.0, 347.76962, 42.0 } };
63 static constexpr float noGlyphTofuResult_[][4] = { { 8.0, 0, 22.0, 22.0 } };
64 static constexpr float noGlyphDefaultResult_[][4] = { { 0, 0, 0, 0 } };
65 static constexpr float noGlyphNotoResult_[][4] = { { 0, 0, 0, 0 } };
66 };
67
PrepareCreateTypography(const std::string & text,const char ** fontFamilies,int fontCount)68 OH_Drawing_Typography* NativeUndefinedGlyphDisplayTest::PrepareCreateTypography(
69 const std::string& text, const char** fontFamilies, int fontCount)
70 {
71 double maxWidth = 500.0;
72 OH_Drawing_TypographyStyle* typoStyle = OH_Drawing_CreateTypographyStyle();
73 EXPECT_NE(typoStyle, nullptr);
74 OH_Drawing_TextStyle* txtStyle = OH_Drawing_CreateTextStyle();
75 EXPECT_NE(txtStyle, nullptr);
76 OH_Drawing_SetTextStyleFontFamilies(txtStyle, fontCount, fontFamilies);
77 OH_Drawing_FontCollection* fontCollection = OH_Drawing_GetFontCollectionGlobalInstance();
78 EXPECT_NE(fontCollection, nullptr);
79 OH_Drawing_TypographyCreate* handler = OH_Drawing_CreateTypographyHandler(typoStyle, fontCollection);
80 EXPECT_NE(handler, nullptr);
81 OH_Drawing_SetTextStyleColor(txtStyle, OH_Drawing_ColorSetArgb(0xFF, 0x00, 0x00, 0x00));
82 double fontSize = 30;
83 OH_Drawing_SetTextStyleFontSize(txtStyle, fontSize);
84 OH_Drawing_SetTextStyleFontWeight(txtStyle, FONT_WEIGHT_400);
85 OH_Drawing_TypographyHandlerPushTextStyle(handler, txtStyle);
86 OH_Drawing_TypographyHandlerAddText(handler, text.c_str());
87 OH_Drawing_Typography* typography = OH_Drawing_CreateTypography(handler);
88 EXPECT_NE(typography, nullptr);
89 OH_Drawing_TypographyLayout(typography, maxWidth);
90 OH_Drawing_DestroyTypographyStyle(typoStyle);
91 OH_Drawing_DestroyTextStyle(txtStyle);
92 OH_Drawing_DestroyTypographyHandler(handler);
93 return typography;
94 }
95
BoundsResult(OH_Drawing_Typography * typography,const float rectResult[][4],size_t size)96 void NativeUndefinedGlyphDisplayTest::BoundsResult(
97 OH_Drawing_Typography* typography, const float rectResult[][4], size_t size)
98 {
99 OH_Drawing_Array* textLines = OH_Drawing_TypographyGetTextLines(typography);
100 size_t arraySize = OH_Drawing_GetDrawingArraySize(textLines);
101 EXPECT_EQ(size, arraySize);
102 for (size_t index = 0; index < arraySize; index++) {
103 OH_Drawing_TextLine* textLine = OH_Drawing_GetTextLineByIndex(textLines, index);
104 OH_Drawing_Rect* rect = OH_Drawing_TextLineGetImageBounds(textLine);
105 EXPECT_FLOAT_EQ(rectResult[index][0], OH_Drawing_RectGetLeft(rect));
106 EXPECT_FLOAT_EQ(rectResult[index][1], OH_Drawing_RectGetTop(rect));
107 // 2 is the index of right
108 EXPECT_FLOAT_EQ(rectResult[index][2], OH_Drawing_RectGetRight(rect));
109 // 3 is the index of bottom
110 EXPECT_FLOAT_EQ(rectResult[index][3], OH_Drawing_RectGetBottom(rect));
111 OH_Drawing_RectDestroy(rect);
112 OH_Drawing_DestroyTextLine(textLine);
113 }
114 OH_Drawing_DestroyTextLines(textLines);
115 }
116
117 /*
118 * @tc.number: SUB_GRAPHIC_GRAPHIC_2D_SetTextUndefinedGlyphDisplay_001
119 * @tc.name : OHDrawingSetTextUndefinedGlyphDisplay001
120 * @tc.desc : Test undefined glyph display use tofu
121 * @tc.size : MediumTest
122 * @tc.type : Function
123 * @tc.level : Level 0
124 */
125 HWTEST_F(NativeUndefinedGlyphDisplayTest, OHDrawingSetTextUndefinedGlyphDisplay001, Function | MediumTest | Level0)
126 {
127 OH_Drawing_SetTextUndefinedGlyphDisplay(TEXT_UNDEFINED_GLYPH_USE_TOFU);
128 OH_Drawing_Typography* typography = PrepareCreateTypography(text_);
129 EXPECT_NE(typography, nullptr);
130 if (ExistNotdef()) {
131 BoundsResult(typography, tofuResult_, NUM_3);
132 } else {
133 BoundsResult(typography, defaultResult_, NUM_3);
134 }
135 OH_Drawing_DestroyTypography(typography);
136 }
137
138 /*
139 * @tc.number: SUB_GRAPHIC_GRAPHIC_2D_SetTextUndefinedGlyphDisplay_002
140 * @tc.name : OHDrawingSetTextUndefinedGlyphDisplay002
141 * @tc.desc : Test undefined glyph display use default
142 * @tc.size : MediumTest
143 * @tc.type : Function
144 * @tc.level : Level 0
145 */
146 HWTEST_F(NativeUndefinedGlyphDisplayTest, OHDrawingSetTextUndefinedGlyphDisplay002, Function | MediumTest | Level0)
147 {
148 OH_Drawing_SetTextUndefinedGlyphDisplay(TEXT_UNDEFINED_GLYPH_USE_DEFAULT);
149 OH_Drawing_Typography* typography = PrepareCreateTypography(text_);
150 EXPECT_NE(typography, nullptr);
151 BoundsResult(typography, defaultResult_, NUM_3);
152 OH_Drawing_DestroyTypography(typography);
153 }
154
155 /*
156 * @tc.number: SUB_GRAPHIC_GRAPHIC_2D_SetTextUndefinedGlyphDisplay_003
157 * @tc.name : OHDrawingSetTextUndefinedGlyphDisplay003
158 * @tc.desc : Test undefined glyph display use invalid input
159 * @tc.size : MediumTest
160 * @tc.type : Function
161 * @tc.level : Level 0
162 */
163 HWTEST_F(NativeUndefinedGlyphDisplayTest, OHDrawingSetTextUndefinedGlyphDisplay003, Function | MediumTest | Level0)
164 {
165 OH_Drawing_SetTextUndefinedGlyphDisplay(TEXT_UNDEFINED_GLYPH_USE_DEFAULT);
166 OH_Drawing_SetTextUndefinedGlyphDisplay(static_cast<OH_Drawing_TextUndefinedGlyphDisplay>(NUM_100));
167 OH_Drawing_Typography* defaultTypography = PrepareCreateTypography(text_);
168 EXPECT_NE(defaultTypography, nullptr);
169 BoundsResult(defaultTypography, defaultResult_, NUM_3);
170 OH_Drawing_SetTextUndefinedGlyphDisplay(TEXT_UNDEFINED_GLYPH_USE_TOFU);
171 OH_Drawing_SetTextUndefinedGlyphDisplay(static_cast<OH_Drawing_TextUndefinedGlyphDisplay>(NUM_100));
172 OH_Drawing_Typography* tofuTypography = PrepareCreateTypography(text_);
173 EXPECT_NE(tofuTypography, nullptr);
174 if (ExistNotdef()) {
175 BoundsResult(tofuTypography, tofuResult_, NUM_3);
176 } else {
177 BoundsResult(tofuTypography, defaultResult_, NUM_3);
178 }
179 OH_Drawing_DestroyTypography(defaultTypography);
180 OH_Drawing_DestroyTypography(tofuTypography);
181 }
182
183 /*
184 * @tc.number: SUB_GRAPHIC_GRAPHIC_2D_SetTextUndefinedGlyphDisplay_004
185 * @tc.name : OHDrawingSetTextUndefinedGlyphDisplay004
186 * @tc.desc : Test undefined glyph display use only no glyph
187 * @tc.size : MediumTest
188 * @tc.type : Function
189 * @tc.level : Level 0
190 */
191 HWTEST_F(NativeUndefinedGlyphDisplayTest, OHDrawingSetTextUndefinedGlyphDisplay004, Function | MediumTest | Level0)
192 {
193 OH_Drawing_SetTextUndefinedGlyphDisplay(TEXT_UNDEFINED_GLYPH_USE_DEFAULT);
194 OH_Drawing_SetTextUndefinedGlyphDisplay(static_cast<OH_Drawing_TextUndefinedGlyphDisplay>(NUM_100));
195 OH_Drawing_Typography* defaultTypography = PrepareCreateTypography(noGlyphText_);
196 EXPECT_NE(defaultTypography, nullptr);
197 BoundsResult(defaultTypography, noGlyphDefaultResult_, NUM_1);
198 OH_Drawing_SetTextUndefinedGlyphDisplay(TEXT_UNDEFINED_GLYPH_USE_TOFU);
199 OH_Drawing_SetTextUndefinedGlyphDisplay(static_cast<OH_Drawing_TextUndefinedGlyphDisplay>(NUM_100));
200 OH_Drawing_Typography* tofuTypography = PrepareCreateTypography(noGlyphText_);
201 EXPECT_NE(tofuTypography, nullptr);
202 if (ExistNotdef()) {
203 BoundsResult(tofuTypography, noGlyphTofuResult_, NUM_1);
204 } else {
205 BoundsResult(defaultTypography, noGlyphDefaultResult_, NUM_1);
206 }
207 OH_Drawing_DestroyTypography(defaultTypography);
208 OH_Drawing_DestroyTypography(tofuTypography);
209 }
210
211 /*
212 * @tc.number: SUB_GRAPHIC_GRAPHIC_2D_SetTextUndefinedGlyphDisplay_005
213 * @tc.name : OHDrawingSetTextUndefinedGlyphDisplay005
214 * @tc.desc : Test set family name, but still force tofu
215 * @tc.size : MediumTest
216 * @tc.type : Function
217 * @tc.level : Level 0
218 */
219 HWTEST_F(NativeUndefinedGlyphDisplayTest, OHDrawingSetTextUndefinedGlyphDisplay005, Function | MediumTest | Level0)
220 {
221 OH_Drawing_SetTextUndefinedGlyphDisplay(TEXT_UNDEFINED_GLYPH_USE_TOFU);
222 const char* fontFamilies[] = { "Noto Sans" };
223 OH_Drawing_Typography* typography = PrepareCreateTypography(text_, fontFamilies, NUM_1);
224 EXPECT_NE(typography, nullptr);
225 if (ExistNotoSans()) {
226 BoundsResult(typography, notoResult_, NUM_3);
227 } else {
228 BoundsResult(typography, defaultResult_, NUM_3);
229 }
230 OH_Drawing_Typography* onlyTypography = PrepareCreateTypography(noGlyphText_, fontFamilies, NUM_1);
231 EXPECT_NE(onlyTypography, nullptr);
232 if (ExistNotdef()) {
233 BoundsResult(onlyTypography, noGlyphTofuResult_, NUM_1);
234 } else {
235 BoundsResult(onlyTypography, noGlyphDefaultResult_, NUM_1);
236 }
237 OH_Drawing_SetTextUndefinedGlyphDisplay(TEXT_UNDEFINED_GLYPH_USE_DEFAULT);
238 OH_Drawing_DestroyTypography(typography);
239 OH_Drawing_DestroyTypography(onlyTypography);
240 }
241 }
242 } // namespace OHOS