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