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
16 #include "html_to_span.h"
17
18 #include <iterator>
19 #include <ostream>
20 #include <string>
21 #include <utility>
22
23 #include "base/geometry/dimension.h"
24 #include "base/image/file_uri_helper.h"
25 #include "base/image/image_source.h"
26 #include "base/memory/ace_type.h"
27 #include "base/memory/referenced.h"
28 #include "base/utils/string_utils.h"
29 #include "base/utils/utils.h"
30 #include "core/components/common/properties/color.h"
31 #include "core/components/common/properties/text_style.h"
32 #include "core/components/common/properties/text_style_parser.h"
33 #include "core/components/text/text_theme.h"
34 #include "core/components_ng/image_provider/image_loading_context.h"
35 #include "core/components_ng/image_provider/image_provider.h"
36 #include "core/components_ng/pattern/text/span/mutable_span_string.h"
37 #include "core/components_ng/pattern/text/span/span_object.h"
38 #include "core/components_ng/pattern/text/span/span_string.h"
39 #include "core/components_ng/pattern/text/span_node.h"
40 #include "core/components_ng/pattern/text/text_pattern.h"
41 #include "core/components_ng/pattern/text/text_styles.h"
42 #include "core/components_ng/property/calc_length.h"
43 #include "core/components_v2/inspector/utils.h"
44 #include "core/text/html_utils.h"
45
46 namespace OHOS::Ace {
47 constexpr int ONE_PARAM = 1;
48 constexpr int TWO_PARAM = 2;
49 constexpr int THREE_PARAM = 3;
50 constexpr int FOUR_PARAM = 4;
51
52 constexpr int TOP_PARAM = 0;
53 constexpr int RIGHT_PARAM = 1;
54 constexpr int BOTTOM_PARAM = 2;
55 constexpr int LEFT_PARAM = 3;
56 constexpr int FIRST_PARAM = 0;
57 constexpr int SECOND_PARAM = 1;
58 constexpr int THIRD_PARAM = 2;
59 constexpr int FOUTH_PARAM = 3;
60
61 constexpr int MAX_STYLE_FORMAT_NUMBER = 3;
62
ToLowerCase(std::string & str)63 void ToLowerCase(std::string& str)
64 {
65 for (auto& c : str) {
66 c = tolower(c);
67 }
68 }
69
ParseFontFamily(const std::string & fontFamily)70 std::vector<std::string> ParseFontFamily(const std::string& fontFamily)
71 {
72 std::vector<std::string> fonts;
73 std::stringstream ss(fontFamily);
74 std::string token;
75 while (std::getline(ss, token, ',')) {
76 std::string font = std::string(token.begin(), token.end());
77 font.erase(std::remove_if(font.begin(), font.end(), isspace), font.end());
78
79 if (!font.empty()) {
80 fonts.push_back(font);
81 }
82 }
83
84 return fonts;
85 }
86
StringToTextVerticalAlign(const std::string & align)87 VerticalAlign StringToTextVerticalAlign(const std::string& align)
88 {
89 if (align == "bottom") {
90 return VerticalAlign::BOTTOM;
91 }
92 if (align == "middle") {
93 return VerticalAlign::CENTER;
94 }
95 if (align == "top") {
96 return VerticalAlign::TOP;
97 }
98 return VerticalAlign::NONE;
99 }
100
StringToFontStyle(const std::string & fontStyle)101 FontStyle StringToFontStyle(const std::string& fontStyle)
102 {
103 return fontStyle == "italic" ? FontStyle::ITALIC : FontStyle::NORMAL;
104 }
105
StringToTextDecorationStyle(const std::string & textDecorationStyle)106 TextDecorationStyle StringToTextDecorationStyle(const std::string& textDecorationStyle)
107 {
108 if (textDecorationStyle == "dashed") {
109 return TextDecorationStyle::DASHED;
110 }
111 if (textDecorationStyle == "dotted") {
112 return TextDecorationStyle::DOTTED;
113 }
114 if (textDecorationStyle == "double") {
115 return TextDecorationStyle::DOUBLE;
116 }
117 if (textDecorationStyle == "solid") {
118 return TextDecorationStyle::SOLID;
119 }
120 if (textDecorationStyle == "wavy") {
121 return TextDecorationStyle::WAVY;
122 }
123
124 return TextDecorationStyle::SOLID;
125 }
126
StringToTextDecoration(const std::string & textDecoration)127 TextDecoration StringToTextDecoration(const std::string& textDecoration)
128 {
129 if (textDecoration == "inherit") {
130 return TextDecoration::INHERIT;
131 }
132 if (textDecoration == "line-through") {
133 return TextDecoration::LINE_THROUGH;
134 }
135 if (textDecoration == "none") {
136 return TextDecoration::NONE;
137 }
138 if (textDecoration == "overline") {
139 return TextDecoration::OVERLINE;
140 }
141 if (textDecoration == "underline") {
142 return TextDecoration::UNDERLINE;
143 }
144 return TextDecoration::NONE;
145 }
146
ConvertStrToFit(const std::string & fit)147 ImageFit ConvertStrToFit(const std::string& fit)
148 {
149 if (fit == "fill") {
150 return ImageFit::FILL;
151 }
152 if (fit == "contain") {
153 return ImageFit::CONTAIN;
154 }
155 if (fit == "cover") {
156 return ImageFit::COVER;
157 }
158 if (fit == "scaledown") {
159 return ImageFit::SCALE_DOWN;
160 }
161 if (fit == "none") {
162 return ImageFit::NONE;
163 }
164
165 return ImageFit::CONTAIN;
166 }
167
ParseStyleAttr(const std::string & style)168 HtmlToSpan::Styles HtmlToSpan::ParseStyleAttr(const std::string& style)
169 {
170 Styles styles;
171 std::regex pattern(R"(\s*([^:]+):([^;]+);?)");
172 std::smatch match;
173 std::string::const_iterator searchStart(style.begin());
174
175 while (std::regex_search(searchStart, style.end(), match, pattern)) {
176 if (match.size() < MAX_STYLE_FORMAT_NUMBER) {
177 continue;
178 }
179 std::string key = std::regex_replace(match[1].str(), std::regex(R"(\s+)"), "");
180 std::string value = std::regex_replace(match[2].str(), std::regex(R"(\s+)"), " ");
181 ToLowerCase(key);
182 styles.emplace_back(key, value);
183 searchStart = match[0].second;
184 }
185
186 return styles;
187 }
188
189 template<class T>
Get(StyleValue * styleValue) const190 T* HtmlToSpan::Get(StyleValue* styleValue) const
191 {
192 auto v = std::get_if<T>(styleValue);
193 if (v == nullptr) {
194 return nullptr;
195 }
196 return static_cast<T*>(v);
197 }
198
199 // for example str = 0.00px
FromString(const std::string & str)200 Dimension HtmlToSpan::FromString(const std::string& str)
201 {
202 static const int32_t PERCENT_UNIT = 100;
203 static const std::unordered_map<std::string, DimensionUnit> uMap {
204 { "px", DimensionUnit::PX },
205 { "vp", DimensionUnit::VP },
206 { "fp", DimensionUnit::FP },
207 { "%", DimensionUnit::PERCENT },
208 { "lpx", DimensionUnit::LPX },
209 { "auto", DimensionUnit::AUTO },
210 { "rem", DimensionUnit::INVALID },
211 { "em", DimensionUnit::INVALID },
212 };
213
214 double value = 0.0;
215 DimensionUnit unit = DimensionUnit::VP;
216 if (str.empty()) {
217 LOGE("UITree |ERROR| empty string");
218 return Dimension(NG::TEXT_DEFAULT_FONT_SIZE);
219 }
220
221 for (int32_t i = static_cast<int32_t>(str.length()) - 1; i >= 0; --i) {
222 if (str[i] >= '0' && str[i] <= '9') {
223 value = StringUtils::StringToDouble(str.substr(0, i + 1));
224 auto subStr = str.substr(i + 1);
225 if (subStr == "pt") {
226 value = static_cast<int>(value * PT_TO_PX + ROUND_TO_INT);
227 break;
228 }
229 auto iter = uMap.find(subStr);
230 if (iter != uMap.end()) {
231 unit = iter->second;
232 }
233 value = unit == DimensionUnit::PERCENT ? value / PERCENT_UNIT : value;
234 break;
235 }
236 }
237 if (unit == DimensionUnit::PX) {
238 return Dimension(value, DimensionUnit::VP);
239 } else if (unit == DimensionUnit::INVALID) {
240 return Dimension(NG::TEXT_DEFAULT_FONT_SIZE);
241 }
242
243 return Dimension(value, unit);
244 }
245
InitFont(const std::string & key,const std::string & value,const std::string & index,StyleValues & values)246 void HtmlToSpan::InitFont(
247 const std::string& key, const std::string& value, const std::string& index, StyleValues& values)
248 {
249 auto [ret, styleValue] = GetStyleValue<Font>(index, values);
250 if (!ret) {
251 return;
252 }
253
254 Font* font = Get<Font>(styleValue);
255 if (font == nullptr) {
256 return;
257 }
258
259 if (key == "color") {
260 font->fontColor = ToSpanColor(value);
261 } else if (key == "font-size") {
262 font->fontSize = FromString(value);
263 } else if (key == "font-weight") {
264 font->fontWeight = StringUtils::StringToFontWeight(value);
265 } else if (key == "font-style") {
266 font->fontStyle = StringToFontStyle(value);
267 } else if (key == "font-family") {
268 font->fontFamilies = ParseFontFamily(value);
269 } else if (key == "font-variant") { // not support
270 }
271 }
272
IsFontAttr(const std::string & key)273 bool HtmlToSpan::IsFontAttr(const std::string& key)
274 {
275 if (key == "font-size" || key == "font-weight" || key == "font-style" || key == "font-family" || key == "color") {
276 return true;
277 }
278 return false;
279 }
280
InitParagrap(const std::string & key,const std::string & value,const std::string & index,StyleValues & values)281 void HtmlToSpan::InitParagrap(
282 const std::string& key, const std::string& value, const std::string& index, StyleValues& values)
283 {
284 auto [ret, styleValue] = GetStyleValue<SpanParagraphStyle>(index, values);
285 if (!ret) {
286 return;
287 }
288
289 SpanParagraphStyle* style = Get<SpanParagraphStyle>(styleValue);
290 if (style == nullptr) {
291 return;
292 }
293
294 if (key == "text-align") {
295 style->align = StringToTextAlign(value);
296 } else if (key == "word-break") {
297 style->wordBreak = StringToWordBreak(value);
298 } else if (key == "text-overflow") {
299 style->textOverflow = StringToTextOverflow(value);
300 } else if (IsTextIndentAttr(key)) {
301 style->textIndent = FromString(value);
302 } else {
303 }
304 }
305
IsParagraphAttr(const std::string & key)306 bool HtmlToSpan::IsParagraphAttr(const std::string& key)
307 {
308 if (key == "text-align" || key == "word-break" || key == "text-overflow" || key == "text-indent") {
309 return true;
310 }
311 return false;
312 }
313
IsDecorationLine(const std::string & key)314 bool HtmlToSpan::IsDecorationLine(const std::string& key)
315 {
316 if (key == "none" || key == "underline" || key == "overline" || key == "line-through" || key == "blink" ||
317 key == "inherit") {
318 return true;
319 }
320 return false;
321 }
322
IsDecorationStyle(const std::string & key)323 bool HtmlToSpan::IsDecorationStyle(const std::string& key)
324 {
325 if (key == "solid" || key == "double" || key == "dotted" || key == "dashed" || key == "wavy" || key == "inherit") {
326 return true;
327 }
328 return false;
329 }
330
InitDecoration(const std::string & key,const std::string & value,const std::string & index,StyleValues & values)331 void HtmlToSpan::InitDecoration(
332 const std::string& key, const std::string& value, const std::string& index, StyleValues& values)
333 {
334 auto [ret, styleValue] = GetStyleValue<DecorationSpanParam>(index, values);
335 if (!ret) {
336 return;
337 }
338 DecorationSpanParam* decoration = Get<DecorationSpanParam>(styleValue);
339 if (decoration == nullptr) {
340 return;
341 }
342
343 if (key == "text-decoration-line") {
344 decoration->decorationType = StringToTextDecoration(value);
345 } else if (key == "text-decoration-style") {
346 decoration->decorationSytle = StringToTextDecorationStyle(value);
347 } else if (key == "text-decoration-color") {
348 decoration->color = ToSpanColor(value);
349 } else if (key == "text-decoration-thickness") { // not support
350 } else if (key == "text-decoration") {
351 std::istringstream ss1(value);
352 std::string word;
353 std::vector<std::string> words;
354 while (ss1 >> word) {
355 words.push_back(word);
356 if (IsDecorationLine(word)) {
357 decoration->decorationType = StringToTextDecoration(word);
358 } else if (IsDecorationStyle(word)) {
359 decoration->decorationSytle = StringToTextDecorationStyle(word);
360 } else {
361 decoration->color = ToSpanColor(word);
362 }
363 }
364 }
365 }
366
IsDecorationAttr(const std::string & key)367 bool HtmlToSpan::IsDecorationAttr(const std::string& key)
368 {
369 return key.compare(0, strlen("text-decoration"), "text-decoration") == 0;
370 }
371
372 template<class T>
InitDimension(const std::string & key,const std::string & value,const std::string & index,StyleValues & values)373 void HtmlToSpan::InitDimension(
374 const std::string& key, const std::string& value, const std::string& index, StyleValues& values)
375 {
376 if (value.compare(0, strlen("normal"), "normal") == 0) {
377 return;
378 }
379 auto [ret, styleValue] = GetStyleValue<T>(index, values);
380 if (!ret) {
381 return;
382 }
383 T* obj = Get<T>(styleValue);
384 if (obj == nullptr) {
385 return;
386 }
387 obj->dimension = FromString(value);
388 }
389
InitLineHeight(const std::string & key,const std::string & value,StyleValues & values)390 void HtmlToSpan::InitLineHeight(const std::string& key, const std::string& value, StyleValues& values)
391 {
392 auto [unit, size] = GetUnitAndSize(value);
393 if (!unit.empty()) {
394 InitDimension<LineHeightSpanSparam>(key, value, "line-height", values);
395 return;
396 }
397
398 auto it = values.find("font");
399 if (it == values.end()) {
400 return;
401 }
402 Font* font = Get<Font>(&it->second);
403 if (font != nullptr) {
404 size = size * font->fontSize->Value();
405 InitDimension<LineHeightSpanSparam>(key, std::to_string(size) + unit, "line-height", values);
406 }
407 }
408
IsLetterSpacingAttr(const std::string & key)409 bool HtmlToSpan::IsLetterSpacingAttr(const std::string& key)
410 {
411 return key.compare(0, strlen("letter-spacing"), "letter-spacing") == 0;
412 }
413
ToSpanColor(const std::string & value)414 Color HtmlToSpan::ToSpanColor(const std::string& value)
415 {
416 std::smatch matches;
417 std::string color = value;
418 std::string tmp = value;
419 tmp.erase(std::remove(tmp.begin(), tmp.end(), ' '), tmp.end());
420 if (std::regex_match(tmp, matches, std::regex("#[0-9A-Fa-f]{6,8}"))) {
421 auto rgb = tmp.substr(1);
422 // remove last 2 character rgba -> argb
423 rgb.erase(rgb.length() - 2, 2);
424 auto alpha = tmp.substr(tmp.length() - 2);
425 color = "#" + alpha + rgb;
426 }
427
428 return Color::FromString(color);
429 }
430
InitTextShadow(const std::string & key,const std::string & value,const std::string & index,StyleValues & values)431 void HtmlToSpan::InitTextShadow(
432 const std::string& key, const std::string& value, const std::string& index, StyleValues& values)
433 {
434 auto [ret, styleValue] = GetStyleValue<std::vector<Shadow>>(index, values);
435 if (!ret) {
436 return;
437 }
438 std::vector<Shadow>* shadow = Get<std::vector<Shadow>>(styleValue);
439 if (shadow == nullptr) {
440 return;
441 }
442 std::istringstream ss(value);
443 std::string tmp;
444 std::vector<std::vector<std::string>> shadows;
445 while (std::getline(ss, tmp, ',')) {
446 std::istringstream iss(tmp);
447 std::string word;
448 std::vector<std::string> words;
449 while (iss >> word) {
450 words.emplace_back(word);
451 }
452 if (words.size() > FOUR_PARAM || words.size() < TWO_PARAM) {
453 return;
454 }
455 shadows.emplace_back(words);
456 }
457 for (const auto &its : shadows) {
458 std::vector<std::string> attribute(FOUR_PARAM);
459 uint8_t num = 0;
460 for (const auto &it : its) {
461 if (IsLength(it)) {
462 attribute[num] = it;
463 num++;
464 continue;
465 }
466 attribute[FOUTH_PARAM] = it;
467 }
468 Shadow textShadow;
469 InitShadow(textShadow, attribute);
470 shadow->emplace_back(std::move(textShadow));
471 }
472 }
473
InitShadow(Shadow & textShadow,std::vector<std::string> & attribute)474 void HtmlToSpan::InitShadow(Shadow &textShadow, std::vector<std::string> &attribute)
475 {
476 if (!attribute[FIRST_PARAM].empty()) {
477 textShadow.SetOffsetX(FromString(attribute[FIRST_PARAM]).Value());
478 }
479 if (!attribute[SECOND_PARAM].empty()) {
480 textShadow.SetOffsetY(FromString(attribute[SECOND_PARAM]).Value());
481 }
482 if (!attribute[THIRD_PARAM].empty()) {
483 textShadow.SetBlurRadius(FromString(attribute[THIRD_PARAM]).Value());
484 }
485 if (!attribute[FOUTH_PARAM].empty()) {
486 textShadow.SetColor(ToSpanColor(attribute[FOUTH_PARAM]));
487 }
488 }
489
IsLength(const std::string & str)490 bool HtmlToSpan::IsLength(const std::string& str)
491 {
492 return !str.empty() &&
493 (std::all_of(str.begin(), str.end(), ::isdigit) || str.find("px") != std::string::npos);
494 }
495
IsTextShadowAttr(const std::string & key)496 bool HtmlToSpan::IsTextShadowAttr(const std::string& key)
497 {
498 return key.compare(0, strlen("text-shadow"), "text-shadow") == 0;
499 }
500
IsTextIndentAttr(const std::string & key)501 bool HtmlToSpan::IsTextIndentAttr(const std::string& key)
502 {
503 return key.compare(0, strlen("text-indent"), "text-indent") == 0;
504 }
505
IsLineHeightAttr(const std::string & key)506 bool HtmlToSpan::IsLineHeightAttr(const std::string& key)
507 {
508 return key.compare(0, strlen("line-height"), "line-height") == 0;
509 }
510
IsPaddingAttr(const std::string & key)511 bool HtmlToSpan::IsPaddingAttr(const std::string& key)
512 {
513 if (key == "padding" || key == "padding-top" || key == "padding-right" || key == "padding-bottom" ||
514 key == "padding-left") {
515 return true;
516 }
517 return false;
518 }
519
IsMarginAttr(const std::string & key)520 bool HtmlToSpan::IsMarginAttr(const std::string& key)
521 {
522 if (key == "margin" || key == "margin-top" || key == "margin-right" || key == "margin-bottom" ||
523 key == "margin-left") {
524 return true;
525 }
526 return false;
527 }
528
IsBorderAttr(const std::string & key)529 bool HtmlToSpan::IsBorderAttr(const std::string& key)
530 {
531 if (key == "border-radius" || key == "border-top-left-radius" || key == "border-top-right-radius" ||
532 key == "border-bottom-right-radius" || key == "border-bottom-left-radius") {
533 return true;
534 }
535 return false;
536 }
537
SetPaddingOption(const std::string & key,const std::string & value,ImageSpanOptions & options)538 void HtmlToSpan::SetPaddingOption(const std::string& key, const std::string& value, ImageSpanOptions& options)
539 {
540 if (!options.imageAttribute->paddingProp) {
541 options.imageAttribute->paddingProp = std::make_optional<NG::PaddingProperty>();
542 }
543 auto& paddings = options.imageAttribute->paddingProp;
544 if (key == "padding") {
545 std::istringstream ss(value);
546 std::string word;
547 std::vector<std::string> words;
548 while (ss >> word) {
549 words.push_back(word);
550 }
551
552 size_t size = words.size();
553 if (size == ONE_PARAM) {
554 paddings->top = NG::CalcLength::FromString(words[TOP_PARAM]);
555 paddings->right = NG::CalcLength::FromString(words[TOP_PARAM]);
556 paddings->bottom = NG::CalcLength::FromString(words[TOP_PARAM]);
557 paddings->left = NG::CalcLength::FromString(words[TOP_PARAM]);
558 } else if (size == TWO_PARAM) {
559 paddings->top = NG::CalcLength::FromString(words[TOP_PARAM]);
560 paddings->right = NG::CalcLength::FromString(words[RIGHT_PARAM]);
561 paddings->bottom = NG::CalcLength::FromString(words[TOP_PARAM]);
562 paddings->left = NG::CalcLength::FromString(words[RIGHT_PARAM]);
563 } else if (size == THREE_PARAM) {
564 paddings->top = NG::CalcLength::FromString(words[TOP_PARAM]);
565 paddings->right = NG::CalcLength::FromString(words[RIGHT_PARAM]);
566 paddings->bottom = NG::CalcLength::FromString(words[BOTTOM_PARAM]);
567 paddings->left = NG::CalcLength::FromString(words[RIGHT_PARAM]);
568 } else if (size == FOUR_PARAM) {
569 paddings->top = NG::CalcLength::FromString(words[TOP_PARAM]);
570 paddings->right = NG::CalcLength::FromString(words[RIGHT_PARAM]);
571 paddings->bottom = NG::CalcLength::FromString(words[BOTTOM_PARAM]);
572 paddings->left = NG::CalcLength::FromString(words[LEFT_PARAM]);
573 }
574 } else if (key == "padding-top") {
575 paddings->top = NG::CalcLength::FromString(value);
576 } else if (key == "padding-right") {
577 paddings->right = NG::CalcLength::FromString(value);
578 } else if (key == "padding-bottom") {
579 paddings->bottom = NG::CalcLength::FromString(value);
580 } else if (key == "padding-left") {
581 paddings->left = NG::CalcLength::FromString(value);
582 }
583 }
SetMarginOption(const std::string & key,const std::string & value,ImageSpanOptions & options)584 void HtmlToSpan::SetMarginOption(const std::string& key, const std::string& value, ImageSpanOptions& options)
585 {
586 if (!options.imageAttribute->marginProp) {
587 options.imageAttribute->marginProp = std::make_optional<NG::MarginProperty>();
588 }
589 auto& marginProp = options.imageAttribute->marginProp;
590 if (key == "margin") {
591 std::istringstream ss(value);
592 std::string word;
593 std::vector<std::string> words;
594 while (ss >> word) {
595 words.push_back(word);
596 }
597
598 size_t size = words.size();
599 if (size == ONE_PARAM) {
600 marginProp->top = NG::CalcLength::FromString(words[TOP_PARAM]);
601 marginProp->right = NG::CalcLength::FromString(words[TOP_PARAM]);
602 marginProp->bottom = NG::CalcLength::FromString(words[TOP_PARAM]);
603 marginProp->left = NG::CalcLength::FromString(words[TOP_PARAM]);
604 } else if (size == TWO_PARAM) {
605 marginProp->top = NG::CalcLength::FromString(words[TOP_PARAM]);
606 marginProp->right = NG::CalcLength::FromString(words[RIGHT_PARAM]);
607 marginProp->bottom = NG::CalcLength::FromString(words[TOP_PARAM]);
608 marginProp->left = NG::CalcLength::FromString(words[RIGHT_PARAM]);
609 } else if (size == THREE_PARAM) {
610 marginProp->top = NG::CalcLength::FromString(words[TOP_PARAM]);
611 marginProp->right = NG::CalcLength::FromString(words[RIGHT_PARAM]);
612 marginProp->bottom = NG::CalcLength::FromString(words[BOTTOM_PARAM]);
613 marginProp->left = NG::CalcLength::FromString(words[RIGHT_PARAM]);
614 } else if (size == FOUR_PARAM) {
615 marginProp->top = NG::CalcLength::FromString(words[TOP_PARAM]);
616 marginProp->right = NG::CalcLength::FromString(words[RIGHT_PARAM]);
617 marginProp->bottom = NG::CalcLength::FromString(words[BOTTOM_PARAM]);
618 marginProp->left = NG::CalcLength::FromString(words[LEFT_PARAM]);
619 }
620 } else if (key == "margin-top") {
621 marginProp->top = NG::CalcLength::FromString(value);
622 } else if (key == "margin-right") {
623 marginProp->right = NG::CalcLength::FromString(value);
624 } else if (key == "margin-bottom") {
625 marginProp->bottom = NG::CalcLength::FromString(value);
626 } else if (key == "margin-left") {
627 marginProp->left = NG::CalcLength::FromString(value);
628 }
629 }
SetBorderOption(const std::string & key,const std::string & value,ImageSpanOptions & options)630 void HtmlToSpan::SetBorderOption(const std::string& key, const std::string& value, ImageSpanOptions& options)
631 {
632 if (!options.imageAttribute->borderRadius) {
633 options.imageAttribute->borderRadius = std::make_optional<NG::BorderRadiusProperty>();
634 }
635 auto& borderRadius = options.imageAttribute->borderRadius;
636 if (key == "border-radius") {
637 std::istringstream ss(value);
638 std::string word;
639 std::vector<std::string> words;
640 while (ss >> word) {
641 words.push_back(word);
642 }
643 size_t size = words.size();
644 if (size == ONE_PARAM) {
645 borderRadius->radiusTopLeft = NG::CalcLength::FromString(words[TOP_PARAM]).GetDimension();
646 borderRadius->radiusTopRight = NG::CalcLength::FromString(words[TOP_PARAM]).GetDimension();
647 borderRadius->radiusBottomRight = NG::CalcLength::FromString(words[TOP_PARAM]).GetDimension();
648 borderRadius->radiusBottomLeft = NG::CalcLength::FromString(words[TOP_PARAM]).GetDimension();
649 } else if (size == TWO_PARAM) {
650 borderRadius->radiusTopLeft = NG::CalcLength::FromString(words[TOP_PARAM]).GetDimension();
651 borderRadius->radiusTopRight = NG::CalcLength::FromString(words[RIGHT_PARAM]).GetDimension();
652 borderRadius->radiusBottomRight = NG::CalcLength::FromString(words[TOP_PARAM]).GetDimension();
653 borderRadius->radiusBottomLeft = NG::CalcLength::FromString(words[RIGHT_PARAM]).GetDimension();
654 } else if (size == THREE_PARAM) {
655 borderRadius->radiusTopLeft = NG::CalcLength::FromString(words[TOP_PARAM]).GetDimension();
656 borderRadius->radiusTopRight = NG::CalcLength::FromString(words[RIGHT_PARAM]).GetDimension();
657 borderRadius->radiusBottomRight = NG::CalcLength::FromString(words[BOTTOM_PARAM]).GetDimension();
658 borderRadius->radiusBottomLeft = NG::CalcLength::FromString(words[RIGHT_PARAM]).GetDimension();
659 } else if (size == FOUR_PARAM) {
660 borderRadius->radiusTopLeft = NG::CalcLength::FromString(words[TOP_PARAM]).GetDimension();
661 borderRadius->radiusTopRight = NG::CalcLength::FromString(words[RIGHT_PARAM]).GetDimension();
662 borderRadius->radiusBottomRight = NG::CalcLength::FromString(words[BOTTOM_PARAM]).GetDimension();
663 borderRadius->radiusBottomLeft = NG::CalcLength::FromString(words[LEFT_PARAM]).GetDimension();
664 }
665 } else if (key == "border-top-left-radius") {
666 borderRadius->radiusTopLeft = NG::CalcLength::FromString(value).GetDimension();
667 } else if (key == "border-top-right-radius") {
668 borderRadius->radiusTopRight = NG::CalcLength::FromString(value).GetDimension();
669 } else if (key == "border-bottom-right-radius") {
670 borderRadius->radiusBottomRight = NG::CalcLength::FromString(value).GetDimension();
671 } else if (key == "border-bottom-left-radius") {
672 borderRadius->radiusBottomLeft = NG::CalcLength::FromString(value).GetDimension();
673 }
674 }
HandleImgSpanOption(const Styles & styleMap,ImageSpanOptions & options)675 void HtmlToSpan::HandleImgSpanOption(const Styles& styleMap, ImageSpanOptions& options)
676 {
677 for (const auto& [key, value] : styleMap) {
678 if (IsPaddingAttr(key)) {
679 SetPaddingOption(key, value, options);
680 } else if (IsMarginAttr(key)) {
681 SetMarginOption(key, value, options);
682 } else if (IsBorderAttr(key)) {
683 SetBorderOption(key, value, options);
684 } else if (key == "object-fit") {
685 options.imageAttribute->objectFit = ConvertStrToFit(value);
686 } else if (key == "vertical-align") {
687 options.imageAttribute->verticalAlign = StringToTextVerticalAlign(value);
688 } else if (key == "width" || key == "height") {
689 HandleImageSize(key, value, options);
690 } else if (key == "sync-load") {
691 options.imageAttribute->syncLoad = V2::ConvertStringToBool(value);
692 }
693 }
694 }
HandleImagePixelMap(const std::string & src,ImageSpanOptions & option)695 void HtmlToSpan::HandleImagePixelMap(const std::string& src, ImageSpanOptions& option)
696 {
697 if (src.empty()) {
698 return;
699 }
700 NG::LoadNotifier loadNotifier(nullptr, nullptr, nullptr);
701 RefPtr<NG::ImageLoadingContext> ctx =
702 AceType::MakeRefPtr<NG::ImageLoadingContext>(ImageSourceInfo(src), std::move(loadNotifier), true);
703 CHECK_NULL_VOID(ctx);
704 ctx->LoadImageData();
705 ctx->MakeCanvasImageIfNeed(ctx->GetImageSize(), true, ImageFit::NONE);
706 auto image = ctx->MoveCanvasImage();
707 if (image != nullptr) {
708 auto pixelMap = image->GetPixelMap();
709 if (pixelMap) {
710 option.imagePixelMap = pixelMap;
711 }
712 }
713 if (option.imagePixelMap.has_value() && option.imagePixelMap.value() != nullptr) {
714 auto pixel = option.imagePixelMap.value();
715 LOGI("img height: %{public}d, width: %{public}d, size:%{public}d", pixel->GetHeight(),
716 pixel->GetWidth(), pixel->GetByteCount());
717 } else {
718 option.image = src;
719 }
720 }
721
HandleImageSize(const std::string & key,const std::string & value,ImageSpanOptions & options)722 void HtmlToSpan::HandleImageSize(const std::string& key, const std::string& value, ImageSpanOptions& options)
723 {
724 if (!options.imageAttribute->size) {
725 options.imageAttribute->size = std::make_optional<ImageSpanSize>();
726 }
727 if (key == "width") {
728 options.imageAttribute->size->width = FromString(value);
729 } else {
730 options.imageAttribute->size->height = FromString(value);
731 }
732 }
733
MakeImageSpanOptions(const std::string & key,const std::string & value,ImageSpanOptions & options)734 void HtmlToSpan::MakeImageSpanOptions(const std::string& key, const std::string& value, ImageSpanOptions& options)
735 {
736 if (key == "src") {
737 options.image = value;
738 HandleImagePixelMap(value, options);
739 } else if (key == "style") {
740 Styles styleMap = ParseStyleAttr(value);
741 HandleImgSpanOption(styleMap, options);
742 } else if (key == "width" || key == "height") {
743 HandleImageSize(key, value, options);
744 }
745 }
746
StringToTextAlign(const std::string & value)747 TextAlign HtmlToSpan::StringToTextAlign(const std::string& value)
748 {
749 if (value == "left") {
750 return TextAlign::LEFT;
751 }
752 if (value == "right") {
753 return TextAlign::RIGHT;
754 }
755 if (value == "center") {
756 return TextAlign::CENTER;
757 }
758 if (value == "justify") {
759 return TextAlign::JUSTIFY;
760 }
761 return TextAlign::LEFT;
762 }
763
StringToWordBreak(const std::string & value)764 WordBreak HtmlToSpan::StringToWordBreak(const std::string& value)
765 {
766 if (value == "normal") {
767 return WordBreak::NORMAL;
768 }
769 if (value == "break-all") {
770 return WordBreak::BREAK_ALL;
771 }
772 if (value == "keep-all") {
773 return WordBreak::BREAK_WORD;
774 }
775 return WordBreak::NORMAL;
776 }
777
StringToTextOverflow(const std::string & value)778 TextOverflow HtmlToSpan::StringToTextOverflow(const std::string& value)
779 {
780 if (value == "clip") {
781 return TextOverflow::CLIP;
782 }
783 if (value == "ellipsis") {
784 return TextOverflow::ELLIPSIS;
785 }
786 return TextOverflow::NONE;
787 }
788
ToDefalutSpan(xmlNodePtr node,size_t len,size_t & pos,std::vector<SpanInfo> & spanInfos)789 void HtmlToSpan::ToDefalutSpan(xmlNodePtr node, size_t len, size_t& pos, std::vector<SpanInfo>& spanInfos)
790 {
791 if (len == 0) {
792 return;
793 }
794
795 SpanInfo info;
796 info.type = HtmlType::DEFAULT;
797 info.start = pos;
798 info.end = pos + len;
799 spanInfos.emplace_back(std::move(info));
800 }
801
802 template<class T>
GetStyleValue(const std::string & key,std::map<std::string,StyleValue> & values)803 std::pair<bool, HtmlToSpan::StyleValue*> HtmlToSpan::GetStyleValue(
804 const std::string& key, std::map<std::string, StyleValue>& values)
805 {
806 auto it = values.find(key);
807 if (it == values.end()) {
808 StyleValue value = T();
809 it = values.emplace(key, value).first;
810 }
811
812 if (it == values.end()) {
813 return std::make_pair(false, nullptr);
814 }
815
816 return std::make_pair(true, &it->second);
817 }
818
ToParagraphSpan(xmlNodePtr node,size_t len,size_t & pos,std::vector<SpanInfo> & spanInfos)819 void HtmlToSpan::ToParagraphSpan(xmlNodePtr node, size_t len, size_t& pos, std::vector<SpanInfo>& spanInfos)
820 {
821 SpanInfo info;
822 info.type = HtmlType::PARAGRAPH;
823 info.start = pos;
824 info.end = pos + len;
825 xmlAttrPtr curNode = node->properties;
826 if (curNode == nullptr) {
827 SpanParagraphStyle style;
828 info.values.emplace_back(style);
829 } else {
830 for (; curNode; curNode = curNode->next) {
831 auto styles = ToTextSpanStyle(curNode);
832 for (auto [key, value] : styles) {
833 info.values.emplace_back(value);
834 }
835 }
836 }
837
838 spanInfos.emplace_back(std::move(info));
839 }
840
GetUnitAndSize(const std::string & str)841 std::pair<std::string, double> HtmlToSpan::GetUnitAndSize(const std::string& str)
842 {
843 double value = 0.0;
844 for (int32_t i = static_cast<int32_t>(str.length() - 1); i >= 0; --i) {
845 if (str[i] >= '0' && str[i] <= '9') {
846 value = StringUtils::StringToDouble(str.substr(0, i + 1));
847 auto subStr = str.substr(i + 1);
848 return { subStr, value };
849 }
850 }
851 return { "", value };
852 }
853
ToTextSpanStyle(xmlAttrPtr curNode)854 std::map<std::string, HtmlToSpan::StyleValue> HtmlToSpan::ToTextSpanStyle(xmlAttrPtr curNode)
855 {
856 auto attrContent = xmlGetProp(curNode->parent, curNode->name);
857 if (attrContent == nullptr) {
858 return {};
859 }
860 std::string strStyle(reinterpret_cast<const char*>(attrContent));
861 xmlFree(attrContent);
862 Styles styleMap = ParseStyleAttr(strStyle);
863 std::map<std::string, StyleValue> styleValues;
864 for (auto& [key, value] : styleMap) {
865 if (IsFontAttr(key)) {
866 InitFont(key, value, "font", styleValues);
867 } else if (IsDecorationAttr(key)) {
868 InitDecoration(key, value, "decoration", styleValues);
869 } else if (IsLetterSpacingAttr(key)) {
870 InitDimension<LetterSpacingSpanParam>(key, value, "letterSpacing", styleValues);
871 } else if (IsTextShadowAttr(key)) {
872 InitTextShadow(key, value, "shadow", styleValues);
873 } else if (IsLineHeightAttr(key)) {
874 InitLineHeight(key, value, styleValues);
875 } else if (IsParagraphAttr(key)) {
876 InitParagrap(key, value, "paragrap", styleValues);
877 }
878 }
879
880 return styleValues;
881 }
882
AddStyleSpan(const std::string & element,SpanInfo & info)883 void HtmlToSpan::AddStyleSpan(const std::string& element, SpanInfo& info)
884 {
885 std::map<std::string, StyleValue> styles;
886 if (element == "strong") {
887 InitFont("font-weight", "bold", "font", styles);
888 }
889
890 for (auto [key, value] : styles) {
891 info.values.emplace_back(value);
892 }
893 }
894
ToTextSpan(const std::string & element,xmlNodePtr node,size_t len,size_t & pos,std::vector<SpanInfo> & spanInfos)895 void HtmlToSpan::ToTextSpan(
896 const std::string& element, xmlNodePtr node, size_t len, size_t& pos, std::vector<SpanInfo>& spanInfos)
897 {
898 SpanInfo info;
899 info.type = HtmlType::TEXT;
900 info.start = pos;
901 info.end = pos + len;
902 xmlAttrPtr curNode = node->properties;
903 for (; curNode; curNode = curNode->next) {
904 auto styles = ToTextSpanStyle(curNode);
905 for (auto [key, value] : styles) {
906 info.values.emplace_back(value);
907 }
908 }
909 if (!element.empty()) {
910 AddStyleSpan(element, info);
911 }
912 if (info.values.empty()) {
913 return;
914 }
915 spanInfos.emplace_back(std::move(info));
916 }
917
ToImageOptions(const std::map<std::string,std::string> & styles,ImageSpanOptions & option)918 void HtmlToSpan::ToImageOptions(const std::map<std::string, std::string>& styles, ImageSpanOptions& option)
919 {
920 option.imageAttribute = std::make_optional<ImageSpanAttribute>();
921 for (auto& [key, value] : styles) {
922 MakeImageSpanOptions(key, value, option);
923 }
924 }
925
ToImage(xmlNodePtr node,size_t len,size_t & pos,std::vector<SpanInfo> & spanInfos,bool isProcessImageOptions)926 void HtmlToSpan::ToImage(xmlNodePtr node, size_t len, size_t& pos, std::vector<SpanInfo>& spanInfos,
927 bool isProcessImageOptions)
928 {
929 std::map<std::string, std::string> styleMap;
930 xmlAttrPtr curNode = node->properties;
931 for (; curNode; curNode = curNode->next) {
932 auto attrContent = xmlGetProp(curNode->parent, curNode->name);
933 if (attrContent != nullptr) {
934 styleMap[reinterpret_cast<const char*>(curNode->name)] = reinterpret_cast<const char*>(attrContent);
935 xmlFree(attrContent);
936 }
937 }
938
939 ImageSpanOptions option;
940 if (isProcessImageOptions) {
941 ToImageOptions(styleMap, option);
942 }
943
944 SpanInfo info;
945 info.type = HtmlType::IMAGE;
946 info.start = pos;
947 info.end = pos + len;
948 info.values.emplace_back(std::move(option));
949 spanInfos.emplace_back(std::move(info));
950 }
951
ToSpan(xmlNodePtr curNode,size_t & pos,std::string & allContent,std::vector<SpanInfo> & spanInfos,bool isNeedLoadPixelMap)952 void HtmlToSpan::ToSpan(
953 xmlNodePtr curNode, size_t& pos, std::string& allContent, std::vector<SpanInfo>& spanInfos,
954 bool isNeedLoadPixelMap)
955 {
956 size_t curNodeLen = 0;
957 if (curNode->content) {
958 std::string curNodeContent = reinterpret_cast<const char*>(curNode->content);
959 allContent += curNodeContent;
960 curNodeLen = StringUtils::ToWstring(curNodeContent).length();
961 }
962
963 std::string htmlTag = reinterpret_cast<const char*>(curNode->name);
964 size_t childPos = pos + curNodeLen;
965 ParaseHtmlToSpanInfo(curNode->children, childPos, allContent, spanInfos);
966 if (curNode->type == XML_ELEMENT_NODE) {
967 if (htmlTag == "p") {
968 if (curNode->parent == nullptr || curNode->parent->type != XML_ELEMENT_NODE ||
969 xmlStrcmp(curNode->parent->name, (const xmlChar*)"span") != 0) {
970 // The <p> contained in <span> is discarded. It is not considered as a standard writing method.
971 allContent += "\n";
972 childPos++;
973 ToParagraphSpan(curNode, childPos - pos, pos, spanInfos);
974 }
975 } else if (htmlTag == "img") {
976 childPos++;
977 ToImage(curNode, childPos - pos, pos, spanInfos, isNeedLoadPixelMap);
978 } else {
979 ToTextSpan(htmlTag, curNode, childPos - pos, pos, spanInfos);
980 }
981 }
982 pos = childPos;
983 }
984
ParaseHtmlToSpanInfo(xmlNodePtr node,size_t & pos,std::string & allContent,std::vector<SpanInfo> & spanInfos,bool isNeedLoadPixelMap)985 void HtmlToSpan::ParaseHtmlToSpanInfo(
986 xmlNodePtr node, size_t& pos, std::string& allContent, std::vector<SpanInfo>& spanInfos, bool isNeedLoadPixelMap)
987 {
988 xmlNodePtr curNode = nullptr;
989 for (curNode = node; curNode; curNode = curNode->next) {
990 if (curNode->type == XML_ELEMENT_NODE || curNode->type == XML_TEXT_NODE) {
991 ToSpan(curNode, pos, allContent, spanInfos, isNeedLoadPixelMap);
992 }
993 }
994 }
995
PrintSpanInfos(const std::vector<SpanInfo> & spanInfos)996 void HtmlToSpan::PrintSpanInfos(const std::vector<SpanInfo>& spanInfos)
997 {
998 for (auto& info : spanInfos) {
999 LOGI("span type %{public}d start:%{public}zu end:%{public}zu, style size:%{public}zu",
1000 static_cast<int>(info.type), info.start, info.end, info.values.size());
1001 }
1002 }
1003
AfterProcSpanInfos(std::vector<SpanInfo> & spanInfos)1004 void HtmlToSpan::AfterProcSpanInfos(std::vector<SpanInfo>& spanInfos)
1005 {
1006 std::vector<std::pair<size_t, size_t>> paragraphPos;
1007 for (auto& info : spanInfos) {
1008 if (info.type == HtmlType::PARAGRAPH) {
1009 paragraphPos.push_back({ info.start, info.end });
1010 }
1011 }
1012
1013 for (auto& pos : paragraphPos) {
1014 for (auto& info : spanInfos) {
1015 if (info.type != HtmlType::PARAGRAPH && info.type != HtmlType::IMAGE && pos.second == info.end + 1) {
1016 info.end += 1;
1017 break;
1018 }
1019 }
1020 }
1021 }
1022
CreateSpan(size_t index,const SpanInfo & info,StyleValue & value)1023 RefPtr<SpanBase> HtmlToSpan::CreateSpan(size_t index, const SpanInfo& info, StyleValue& value)
1024 {
1025 if (index == static_cast<uint32_t>(StyleIndex::STYLE_FONT)) {
1026 return MakeSpan<Font, FontSpan>(info, value);
1027 }
1028
1029 if (index == static_cast<uint32_t>(StyleIndex::STYLE_DECORATION)) {
1030 return MakeDecorationSpan(info, value);
1031 }
1032
1033 if (index == static_cast<uint32_t>(StyleIndex::STYLE_BASELINE)) {
1034 return MakeDimensionSpan<BaseLineSpanParam, BaselineOffsetSpan>(info, value);
1035 }
1036
1037 if (index == static_cast<uint32_t>(StyleIndex::STYLE_LETTERSPACE)) {
1038 return MakeDimensionSpan<LetterSpacingSpanParam, LetterSpacingSpan>(info, value);
1039 }
1040
1041 if (index == static_cast<uint32_t>(StyleIndex::STYLE_LINEHEIGHT)) {
1042 return MakeDimensionSpan<LineHeightSpanSparam, LineHeightSpan>(info, value);
1043 }
1044
1045 if (index == static_cast<uint32_t>(StyleIndex::STYLE_SHADOWS)) {
1046 return MakeSpan<std::vector<Shadow>, TextShadowSpan>(info, value);
1047 }
1048
1049 if (index == static_cast<uint32_t>(StyleIndex::STYLE_PARAGRAPH)) {
1050 return MakeSpan<SpanParagraphStyle, ParagraphStyleSpan>(info, value);
1051 }
1052
1053 return nullptr;
1054 }
1055
1056 template<class T, class P>
MakeSpan(const SpanInfo & info,StyleValue & value)1057 RefPtr<SpanBase> HtmlToSpan::MakeSpan(const SpanInfo& info, StyleValue& value)
1058 {
1059 auto style = Get<T>(&value);
1060 if (style != nullptr) {
1061 return AceType::MakeRefPtr<P>(*style, info.start, info.end);
1062 }
1063
1064 return nullptr;
1065 }
1066
1067 template<class T, class P>
MakeDimensionSpan(const SpanInfo & info,StyleValue & value)1068 RefPtr<SpanBase> HtmlToSpan::MakeDimensionSpan(const SpanInfo& info, StyleValue& value)
1069 {
1070 auto style = Get<T>(&value);
1071 if (style != nullptr) {
1072 return AceType::MakeRefPtr<P>(style->dimension, info.start, info.end);
1073 }
1074
1075 return nullptr;
1076 }
1077
MakeDecorationSpan(const SpanInfo & info,StyleValue & value)1078 RefPtr<SpanBase> HtmlToSpan::MakeDecorationSpan(const SpanInfo& info, StyleValue& value)
1079 {
1080 auto style = Get<DecorationSpanParam>(&value);
1081 if (style != nullptr) {
1082 return AceType::MakeRefPtr<DecorationSpan>(
1083 style->decorationType, style->color, style->decorationSytle, info.start, info.end);
1084 }
1085
1086 return nullptr;
1087 }
1088
AddSpans(const SpanInfo & info,RefPtr<MutableSpanString> mutableSpan)1089 void HtmlToSpan::AddSpans(const SpanInfo& info, RefPtr<MutableSpanString> mutableSpan)
1090 {
1091 for (auto value : info.values) {
1092 size_t index = value.index();
1093 RefPtr<SpanBase> span;
1094 if (index >= 0 && index < static_cast<size_t>(StyleIndex::STYLE_MAX)) {
1095 span = CreateSpan(index, info, value);
1096 }
1097 if (span != nullptr) {
1098 mutableSpan->AddSpan(span);
1099 }
1100 }
1101 }
1102
AddImageSpans(const SpanInfo & info,RefPtr<MutableSpanString> mutableSpan)1103 void HtmlToSpan::AddImageSpans(const SpanInfo& info, RefPtr<MutableSpanString> mutableSpan)
1104 {
1105 for (auto value : info.values) {
1106 auto style = Get<ImageSpanOptions>(&value);
1107 if (style == nullptr) {
1108 continue;
1109 }
1110 auto span = AceType::MakeRefPtr<MutableSpanString>(*style);
1111 mutableSpan->InsertSpanString(info.start, span);
1112 }
1113 }
1114
GenerateSpans(const std::string & allContent,const std::vector<SpanInfo> & spanInfos)1115 RefPtr<MutableSpanString> HtmlToSpan::GenerateSpans(
1116 const std::string& allContent, const std::vector<SpanInfo>& spanInfos)
1117 {
1118 auto mutableSpan = AceType::MakeRefPtr<MutableSpanString>(allContent);
1119 RefPtr<MutableSpanString> span;
1120 for (auto& info : spanInfos) {
1121 if (info.type == HtmlType::PARAGRAPH) {
1122 AddSpans(info, mutableSpan);
1123 } else if (info.type == HtmlType::IMAGE) {
1124 AddImageSpans(info, mutableSpan);
1125 } else {
1126 AddSpans(info, mutableSpan);
1127 }
1128 }
1129
1130 return mutableSpan;
1131 }
1132
ToSpanString(const std::string & html,const bool isNeedLoadPixelMap)1133 RefPtr<MutableSpanString> HtmlToSpan::ToSpanString(const std::string& html, const bool isNeedLoadPixelMap)
1134 {
1135 htmlDocPtr doc = htmlReadMemory(html.c_str(), html.length(), nullptr, "UTF-8", 0);
1136 if (doc == nullptr) {
1137 return nullptr;
1138 }
1139
1140 auto docSharedPtr = std::shared_ptr<xmlDoc>(doc, [](htmlDocPtr doc) { xmlFreeDoc(doc); });
1141 if (docSharedPtr == nullptr) {
1142 return nullptr;
1143 }
1144
1145 xmlNode* root = xmlDocGetRootElement(docSharedPtr.get());
1146 if (root == nullptr) {
1147 return nullptr;
1148 }
1149
1150 size_t pos = 0;
1151 std::string content;
1152 std::vector<SpanInfo> spanInfos;
1153 ParaseHtmlToSpanInfo(root, pos, content, spanInfos, isNeedLoadPixelMap);
1154 AfterProcSpanInfos(spanInfos);
1155 PrintSpanInfos(spanInfos);
1156 return GenerateSpans(content, spanInfos);
1157 }
1158
FromHtml(const std::string & html)1159 RefPtr<MutableSpanString> HtmlUtils::FromHtml(const std::string& html)
1160 {
1161 HtmlToSpan hts;
1162 auto styledString = hts.ToSpanString(html);
1163 return styledString;
1164 }
1165 } // namespace OHOS::Ace
1166