1 /*
2 * Copyright (c) 2024 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 #include <cstddef>
16 #include <cstdint>
17 #include <iostream>
18 #include <ostream>
19 #include <vector>
20
21 #include "test/mock/core/common/mock_theme_manager.h"
22 #include "test/mock/core/pipeline/mock_pipeline_context.h"
23 #include "test/mock/core/render/mock_paragraph.h"
24
25 #include "base/geometry/dimension.h"
26 #include "base/geometry/size.h"
27 #include "base/memory/ace_type.h"
28 #include "base/memory/referenced.h"
29 #include "core/components/common/properties/color.h"
30 #include "core/components/common/properties/text_style.h"
31 #include "core/components/text/text_theme.h"
32 #include "html_to_span.h"
33 #include "span_to_html.h"
34 #include "core/components_ng/pattern/text/span/mutable_span_string.h"
35 #include "core/components_ng/pattern/text/span/span_object.h"
36 #include "core/components_ng/pattern/text/span/span_string.h"
37 #include "core/components_ng/pattern/text/span_node.h"
38 #include "core/components_ng/pattern/text/text_pattern.h"
39 #include "core/components_ng/pattern/text/text_styles.h"
40 #include "core/components_ng/property/measure_property.h"
41
42 #undef private
43 #undef protected
44
45 using namespace testing;
46 using namespace testing::ext;
47 namespace OHOS::Ace::NG {
48 class HtmlConvertTestNg : public testing::Test {
49 public:
50 static void SetUpTestSuite();
51 static void TearDownTestSuite();
52 void SetUp() override;
53 void TearDown() override;
54 bool IsSpanItemSame(std::list<RefPtr<NG::SpanItem>> src, std::list<RefPtr<NG::SpanItem>> other);
55 SpanParagraphStyle GetDefaultParagraphStyle();
56 ImageSpanOptions GetImageOption(const std::string& src);
57 };
58
SetUpTestSuite()59 void HtmlConvertTestNg::SetUpTestSuite()
60 {
61 MockPipelineContext::SetUp();
62 }
63
TearDownTestSuite()64 void HtmlConvertTestNg::TearDownTestSuite()
65 {
66 MockPipelineContext::TearDown();
67 }
68
SetUp()69 void HtmlConvertTestNg::SetUp() {}
70
TearDown()71 void HtmlConvertTestNg::TearDown() {}
72
73 std::string test_str[] = { "hello", "world", "this", "find", "gank", "pink", "that", "when", "how", "cpp" };
74 Font testFont1 { OHOS::Ace::FontWeight::BOLD, Dimension(29.0, DimensionUnit::PX), OHOS::Ace::FontStyle::ITALIC,
75 std::vector<std::string>(test_str, test_str + 10), OHOS::Ace::Color::BLUE };
76 Font testFont2 { OHOS::Ace::FontWeight::LIGHTER, Dimension(19.0, DimensionUnit::PX), OHOS::Ace::FontStyle::ITALIC,
77 std::vector<std::string>(test_str, test_str + 10), OHOS::Ace::Color::GRAY };
78 Font testEmptyFont {};
GetImageOption(const std::string & src)79 ImageSpanOptions HtmlConvertTestNg::GetImageOption(const std::string& src)
80 {
81 ImageSpanSize size { .width = 50.0_vp, .height = 50.0_vp };
82 BorderRadiusProperty borderRadius;
83 borderRadius.SetRadius(2.0_vp);
84 MarginProperty margins;
85 // margins len 10.0
86 margins.SetEdges(CalcLength(10.0));
87 PaddingProperty paddings;
88 // paddings len 5.0
89 paddings.SetEdges(CalcLength(5.0));
90 ImageSpanAttribute attr { .size = size,
91 .paddingProp = paddings,
92 .marginProp = margins,
93 .borderRadius = borderRadius,
94 .objectFit = ImageFit::COVER,
95 .verticalAlign = VerticalAlign::BOTTOM };
96 ImageSpanOptions option { .image = src, .imageAttribute = attr };
97 return option;
98 }
99
GetDefaultParagraphStyle()100 SpanParagraphStyle HtmlConvertTestNg::GetDefaultParagraphStyle()
101 {
102 SpanParagraphStyle spanParagraphStyle;
103 spanParagraphStyle.align = TextAlign::END;
104 // default max lines 4
105 spanParagraphStyle.maxLines = 4;
106 spanParagraphStyle.wordBreak = WordBreak::BREAK_ALL;
107 spanParagraphStyle.textOverflow = TextOverflow::ELLIPSIS;
108 // defalut textIndent 23
109 spanParagraphStyle.textIndent = Dimension(23.0_vp);
110 spanParagraphStyle.leadingMargin = LeadingMargin();
111 // default width 25.0 height 26.0
112 spanParagraphStyle.leadingMargin->size = LeadingMarginSize(Dimension(25.0_vp), Dimension(26.0));
113 return spanParagraphStyle;
114 }
115
IsSpanItemSame(std::list<RefPtr<NG::SpanItem>> src,std::list<RefPtr<NG::SpanItem>> other)116 bool HtmlConvertTestNg::IsSpanItemSame(std::list<RefPtr<NG::SpanItem>> src, std::list<RefPtr<NG::SpanItem>> other)
117 {
118 if (src.size() != other.size()) {
119 return false;
120 }
121
122 while (src.size() != 0) {
123 auto it = src.front();
124 auto otherIt = other.front();
125 if (it->interval.first != otherIt->interval.first || it->interval.second != otherIt->interval.second ||
126 it->content != otherIt->content) {
127 return false;
128 }
129 src.pop_front();
130 other.pop_front();
131 }
132 return true;
133 }
134
135 HWTEST_F(HtmlConvertTestNg, HtmlConvert000, TestSize.Level1)
136 {
137 auto imageOption = GetImageOption("src/icon-1.png");
138 auto mutableStr = AceType::MakeRefPtr<MutableSpanString>(imageOption);
139 auto spanString3 = AceType::MakeRefPtr<SpanString>("012345678\n9");
140 spanString3->AddSpan(AceType::MakeRefPtr<FontSpan>(testFont1, 0, 3));
141 spanString3->AddSpan(AceType::MakeRefPtr<FontSpan>(testFont2, 3, 5));
142 spanString3->AddSpan(AceType::MakeRefPtr<FontSpan>(testEmptyFont, 5, 8));
143
144 spanString3->AddSpan(AceType::MakeRefPtr<BaselineOffsetSpan>(Dimension(4), 0, 2));
145 spanString3->AddSpan(AceType::MakeRefPtr<LetterSpacingSpan>(Dimension(5), 5, 8));
146 spanString3->AddSpan(AceType::MakeRefPtr<DecorationSpan>(
147 TextDecoration::LINE_THROUGH, Color::BLUE, TextDecorationStyle::WAVY, 0, 1));
148
149 auto spanParagraphStyle = GetDefaultParagraphStyle();
150 auto paraSpan = AceType::MakeRefPtr<ParagraphStyleSpan>(spanParagraphStyle, 2, 5);
151
152 spanString3->AddSpan(paraSpan);
153 Shadow textShadow;
154 textShadow.SetBlurRadius(0.0);
155 textShadow.SetColor(Color::BLUE);
156 textShadow.SetOffsetX(5.0);
157 textShadow.SetOffsetY(5.0);
158
159 Shadow textShadow1;
160 textShadow1.SetBlurRadius(1.0);
161 textShadow1.SetColor(Color::BLUE);
162 textShadow1.SetOffsetX(10.0);
163 textShadow1.SetOffsetY(10.0);
164
165 vector<Shadow> textShadows { textShadow, textShadow1 };
166 spanString3->AddSpan(AceType::MakeRefPtr<TextShadowSpan>(textShadows, 3, 6));
167 mutableStr->InsertSpanString(1, spanString3);
168
169 auto spanString2 = AceType::MakeRefPtr<SpanString>("测试一下中文,\n看看是什么情况");
170 spanString2->AddSpan(AceType::MakeRefPtr<FontSpan>(testFont1, 0, 5));
171 spanString2->AddSpan(AceType::MakeRefPtr<FontSpan>(testFont2, 6, 10));
172 spanString2->AddSpan(AceType::MakeRefPtr<LetterSpacingSpan>(Dimension(10), 12, 14));
173
174 mutableStr->InsertSpanString(5, spanString2);
175 SpanToHtml convert;
176 auto out = convert.ToHtml(*mutableStr);
177 HtmlToSpan toSpan;
178 auto dstSpan = toSpan.ToSpanString(out);
179 EXPECT_NE(dstSpan, nullptr);
180 auto items = dstSpan->GetSpanItems();
181 EXPECT_EQ(items.size(), 16);
182 }
183
184 HWTEST_F(HtmlConvertTestNg, HtmlConvert001, TestSize.Level1)
185 {
186 auto spanString = AceType::MakeRefPtr<SpanString>("0123456789");
187 spanString->AddSpan(AceType::MakeRefPtr<FontSpan>(testFont1, 0, 3));
188 spanString->AddSpan(AceType::MakeRefPtr<FontSpan>(testFont2, 3, 5));
189 spanString->AddSpan(AceType::MakeRefPtr<FontSpan>(testEmptyFont, 5, 8));
190
191 std::vector<uint8_t> buffer;
192 spanString->EncodeTlv(buffer);
193 SpanToHtml convert;
194 auto u8ToHtml = convert.ToHtml(buffer);
195 EXPECT_NE(u8ToHtml.empty(), true);
196
197 auto out = convert.ToHtml(*spanString);
198 EXPECT_NE(out.empty(), true);
199 EXPECT_EQ(out, u8ToHtml);
200
201 HtmlToSpan toSpan;
202 auto dstSpan = toSpan.ToSpanString(out);
203 EXPECT_NE(dstSpan, nullptr);
204 auto items = dstSpan->GetSpanItems();
205 EXPECT_EQ(items.size(), 4);
206
207 EXPECT_EQ(items.size(), spanString->GetSpanItems().size());
208 }
209
210 HWTEST_F(HtmlConvertTestNg, HtmlConvert002, TestSize.Level1)
211 {
212 auto imageOption = GetImageOption("src/icon-1.png");
213 auto imageSpan = AceType::MakeRefPtr<MutableSpanString>(imageOption);
214 auto mutableStr2 = AceType::MakeRefPtr<MutableSpanString>("123456");
215 imageSpan->AppendSpanString(mutableStr2);
216
217 std::vector<uint8_t> buffer;
218 imageSpan->EncodeTlv(buffer);
219
220 SpanToHtml convert;
221 auto u8ToHtml = convert.ToHtml(buffer);
222 EXPECT_NE(u8ToHtml.empty(), true);
223
224 auto out = convert.ToHtml(*imageSpan);
225 EXPECT_NE(out.empty(), true);
226 EXPECT_EQ(out, u8ToHtml);
227
228 HtmlToSpan toSpan;
229 auto dstSpan = toSpan.ToSpanString(out);
230 EXPECT_NE(dstSpan, nullptr);
231
232 auto dstHtml = convert.ToHtml(*dstSpan);
233 EXPECT_EQ(out, dstHtml);
234
235 // image is invalid,to html discart image the first char is not black space
236 EXPECT_EQ(dstSpan->GetString(), "123456");
237 auto spans = dstSpan->GetSpans(0, 6);
238 EXPECT_EQ(spans.size(), 1);
239 }
240
241 HWTEST_F(HtmlConvertTestNg, HtmlConvert003, TestSize.Level1)
242 {
243 const std::string fontHtml = "<!DOCTYPE html>"
244 "<html>"
245 "<body>"
246 "<p>我是正常的</p>"
247 "<p style=\"COLOR:red;\">我是红色的</p>"
248 "<p style=\"font-family: 'Times New Roman', serif; font-size: 14px; font-weight: "
249 "normal; color: red; color: blue;\">我是蓝色的<strong style=\"color:blue; "
250 "font-size:100px;\">这段文字很重要!</strong><del>蓝色</del></p>"
251 "<p style=\"font-size:50px;\">我是50的</p>"
252 "</body>"
253 "</html>";
254 HtmlToSpan toSpan;
255 auto dstSpan = toSpan.ToSpanString(fontHtml);
256 EXPECT_NE(dstSpan, nullptr);
257
258 SpanToHtml convert;
259 auto dstHtml = convert.ToHtml(*dstSpan);
260 HtmlToSpan toSpan1;
261 auto dstSpan1 = toSpan1.ToSpanString(dstHtml);
262 EXPECT_EQ(IsSpanItemSame(dstSpan->GetSpanItems(), dstSpan1->GetSpanItems()), true);
263 auto secondHtml = convert.ToHtml(*dstSpan1);
264 EXPECT_EQ(secondHtml, dstHtml);
265 }
266
267 HWTEST_F(HtmlConvertTestNg, SpanString004, TestSize.Level1)
268 {
269 auto spanString = AceType::MakeRefPtr<SpanString>("01234中文56789");
270 std::vector<uint8_t> buff;
271 spanString->EncodeTlv(buff);
272 EXPECT_EQ(buff.size() > 0, true);
273 SpanToHtml toHtml;
274 auto htmlFromU8 = toHtml.ToHtml(buff);
275 auto htmlFromSpan = toHtml.ToHtml(*spanString);
276 EXPECT_EQ(htmlFromU8, htmlFromSpan);
277
278 HtmlToSpan toSpan;
279 auto spanFromHtml = toSpan.ToSpanString(htmlFromU8);
280 EXPECT_EQ(IsSpanItemSame(spanFromHtml->GetSpanItems(), spanString->GetSpanItems()), true);
281
282 SpanToHtml toHtml1;
283 auto hmtlString = toHtml1.ToHtml(*spanFromHtml);
284 EXPECT_EQ(hmtlString, htmlFromSpan);
285 }
286
287 HWTEST_F(HtmlConvertTestNg, HtmlConvert005, TestSize.Level1)
288 {
289 auto spanString = AceType::MakeRefPtr<SpanString>("0123456789");
290 spanString->AddSpan(AceType::MakeRefPtr<FontSpan>(testFont1, 0, 3));
291 spanString->AddSpan(AceType::MakeRefPtr<FontSpan>(testFont2, 3, 5));
292 spanString->AddSpan(AceType::MakeRefPtr<FontSpan>(testEmptyFont, 5, 8));
293 spanString->AddSpan(AceType::MakeRefPtr<LetterSpacingSpan>(Dimension(5), 5, 8));
294 spanString->AddSpan(AceType::MakeRefPtr<DecorationSpan>(
295 TextDecoration::LINE_THROUGH, Color::BLUE, TextDecorationStyle::WAVY, 0, 1));
296
297 SpanToHtml convert;
298 auto out = convert.ToHtml(*spanString);
299 HtmlToSpan toSpan;
300 auto dstSpan = toSpan.ToSpanString(out);
301 EXPECT_EQ(IsSpanItemSame(dstSpan->GetSpanItems(), spanString->GetSpanItems()), true);
302 }
303 HWTEST_F(HtmlConvertTestNg, HtmlConvert006, TestSize.Level1)
304 {
305 const std::string multiHtml = "<html>"
306 "<body>"
307 "<p style=\"color:red;\">dddd当地经的123456</p>"
308 "</body>"
309 "</html>";
310 HtmlToSpan toSpan;
311 auto dstSpan = toSpan.ToSpanString(multiHtml);
312 std::list<RefPtr<NG::SpanItem>> spans = dstSpan->GetSpanItems();
313 EXPECT_EQ(spans.size(), 1);
314 auto it = spans.begin();
315 EXPECT_EQ((*it)->fontStyle->GetTextColor().value(), OHOS::Ace::Color::RED);
316 }
317
318 HWTEST_F(HtmlConvertTestNg, HtmlConvert007, TestSize.Level1)
319 {
320 const std::string multiHtml = "<html>"
321 "<body>"
322 "<p style=\"font-size:50px\">dddd当地经的123456</p>"
323 "</body>"
324 "</html>";
325 HtmlToSpan toSpan;
326 auto dstSpan = toSpan.ToSpanString(multiHtml);
327 std::list<RefPtr<NG::SpanItem>> spans = dstSpan->GetSpanItems();
328 EXPECT_EQ(spans.size(), 1);
329 auto it = spans.begin();
330 EXPECT_EQ((*it)->fontStyle->GetFontSize().value(), Dimension(50, DimensionUnit::VP));
331 }
332
333 HWTEST_F(HtmlConvertTestNg, HtmlConvert008, TestSize.Level1)
334 {
335 auto spanString = AceType::MakeRefPtr<SpanString>("段落标题\n正文第一段开始");
336 SpanParagraphStyle spanParagraphStyle;
337 spanParagraphStyle.align = TextAlign::CENTER;
338 // default max lines 4
339 spanParagraphStyle.maxLines = 4;
340 spanParagraphStyle.wordBreak = WordBreak::BREAK_ALL;
341 spanParagraphStyle.textOverflow = TextOverflow::ELLIPSIS;
342 // defalut textIndent 23
343 spanParagraphStyle.textIndent = Dimension(23.0_vp);
344 spanParagraphStyle.leadingMargin = LeadingMargin();
345 // default width 25.0 height 26.0
346 spanParagraphStyle.leadingMargin->size = LeadingMarginSize(Dimension(25.0_vp), Dimension(26.0));
347 auto paragraphStyle = AceType::MakeRefPtr<ParagraphStyleSpan>(spanParagraphStyle, 0, 5);
348 spanString->AddSpan(paragraphStyle);
349
350 SpanToHtml convert;
351 auto out = convert.ToHtml(*spanString);
352 std::string result =
353 "<div ><p style=\"text-align: center;text-indent: 23.00px;word-break: break_all;text-overflow: ellipsis;\">"
354 "<span style=\"font-size: 16.00px;font-style: normal;font-weight: normal;color: #000000FF;font-family: "
355 "HarmonyOS Sans;\">段落标题</span></p><span style=\"font-size: 16.00px;font-style: normal;font-weight: "
356 "normal;color: #000000FF;font-family: HarmonyOS Sans;\">正文第一段开始</span></div>";
357 EXPECT_EQ(out, result);
358 }
359
360 HWTEST_F(HtmlConvertTestNg, HtmlConvert009, TestSize.Level1)
361 {
362 auto spanString = AceType::MakeRefPtr<SpanString>("向上到顶适中向下到底");
363 spanString->AddSpan(AceType::MakeRefPtr<BaselineOffsetSpan>(Dimension(20.0_vp), 0, 4));
364 spanString->AddSpan(AceType::MakeRefPtr<BaselineOffsetSpan>(Dimension(10.0_vp), 4, 6));
365
366 SpanToHtml convert;
367 auto out = convert.ToHtml(*spanString);
368 std::string result =
369 "<div ><span style=\"font-size: 16.00px;font-style: normal;font-weight: normal;color: #000000FF;font-family: "
370 "HarmonyOS Sans;vertical-align: 20.00px;\">向上到顶</span><span style=\"font-size: 16.00px;font-style: "
371 "normal;font-weight: normal;color: #000000FF;font-family: HarmonyOS Sans;vertical-align: "
372 "10.00px;\">适中</span><span style=\"font-size: 16.00px;font-style: normal;font-weight: normal;color: "
373 "#000000FF;font-family: HarmonyOS Sans;\">向下到底</span></div>";
374 EXPECT_EQ(out, result);
375 }
376
377 HWTEST_F(HtmlConvertTestNg, HtmlConvert010, TestSize.Level1)
378 {
379 const std::string multiHtml =
380 "<html>"
381 "<body>"
382 "<p style=\"font-size:50px\"><span style=\"font-size:100px\">100fontsize</span>dddd当地经的123456<span "
383 "style=\"font-size:30px\">30fontsize</span>1232132</p>"
384 "</body>"
385 "</html>";
386 HtmlToSpan toSpan;
387 auto dstSpan = toSpan.ToSpanString(multiHtml);
388 std::list<RefPtr<NG::SpanItem>> spans = dstSpan->GetSpanItems();
389 EXPECT_EQ(spans.size(), 4);
390
391 SpanToHtml convert;
392 auto dstHtml = convert.ToHtml(*dstSpan);
393 HtmlToSpan toSpan1;
394 auto dstSpan1 = toSpan1.ToSpanString(dstHtml);
395 EXPECT_EQ(IsSpanItemSame(dstSpan->GetSpanItems(), dstSpan1->GetSpanItems()), true);
396 auto secondHtml = convert.ToHtml(*dstSpan1);
397 EXPECT_EQ(secondHtml, dstHtml);
398 }
399
400 HWTEST_F(HtmlConvertTestNg, HtmlConvert011, TestSize.Level1)
401 {
402 const std::string multiHtml =
403 "<html>"
404 "<head>"
405 "</head>"
406 "<body>"
407 "<p style=\"font-size:50px;text-shadow: 0 0 3px red, green 0 0;\">"
408 "<span style=\"font-size:100px\">100fontsize</span>dddd当地经的123456<span "
409 "style=\"font-size:30px\">30fontsize</span>1232132</p>"
410 "</body>"
411 "</html>";
412 HtmlToSpan toSpan;
413 auto dstSpan = toSpan.ToSpanString(multiHtml);
414 std::list<RefPtr<NG::SpanItem>> spans = dstSpan->GetSpanItems();
415 EXPECT_EQ(spans.size(), 4);
416 auto it = spans.begin();
417 EXPECT_EQ((*it)->fontStyle->GetTextShadow().value()[0].GetColor(), OHOS::Ace::Color::RED);
418 EXPECT_EQ((*it)->fontStyle->GetTextShadow().value()[1].GetColor(), OHOS::Ace::Color::GREEN);
419 }
420 } // namespace OHOS::Ace::NG