• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/text/span_node.h"
17 
18 #include <optional>
19 
20 #include "base/geometry/dimension.h"
21 #include "base/utils/utils.h"
22 #include "core/common/font_manager.h"
23 #include "core/components/common/layout/constants.h"
24 #include "core/components/common/properties/text_style.h"
25 #include "core/components_ng/base/frame_node.h"
26 #include "core/components_ng/pattern/text/text_pattern.h"
27 #include "core/components_ng/pattern/text/text_styles.h"
28 #include "core/components_ng/property/property.h"
29 #include "core/components_ng/render/drawing_prop_convertor.h"
30 #include "core/components_ng/render/paragraph.h"
31 #include "core/pipeline/pipeline_context.h"
32 
33 namespace OHOS::Ace::NG {
34 namespace {
GetDeclaration(const std::optional<Color> & color,const std::optional<TextDecoration> & textDecoration,const std::optional<TextDecorationStyle> & textDecorationStyle)35 std::string GetDeclaration(const std::optional<Color>& color, const std::optional<TextDecoration>& textDecoration,
36     const std::optional<TextDecorationStyle>& textDecorationStyle)
37 {
38     auto jsonSpanDeclaration = JsonUtil::Create(true);
39     jsonSpanDeclaration->Put(
40         "type", V2::ConvertWrapTextDecorationToStirng(textDecoration.value_or(TextDecoration::NONE)).c_str());
41     jsonSpanDeclaration->Put("color", (color.value_or(Color::BLACK).ColorToString()).c_str());
42     jsonSpanDeclaration->Put("style",
43         V2::ConvertWrapTextDecorationStyleToString(textDecorationStyle.value_or(TextDecorationStyle::SOLID)).c_str());
44     return jsonSpanDeclaration->ToString();
45 }
ConvertShadowToJson(const Shadow & shadow)46 inline std::unique_ptr<JsonValue> ConvertShadowToJson(const Shadow& shadow)
47 {
48     auto jsonShadow = JsonUtil::Create(true);
49     jsonShadow->Put("radius", std::to_string(shadow.GetBlurRadius()).c_str());
50     jsonShadow->Put("color", shadow.GetColor().ColorToString().c_str());
51     jsonShadow->Put("offsetX", std::to_string(shadow.GetOffset().GetX()).c_str());
52     jsonShadow->Put("offsetY", std::to_string(shadow.GetOffset().GetY()).c_str());
53     jsonShadow->Put("type", std::to_string(static_cast<int32_t>(shadow.GetShadowType())).c_str());
54     return jsonShadow;
55 }
ConvertShadowsToJson(const std::vector<Shadow> & shadows)56 std::unique_ptr<JsonValue> ConvertShadowsToJson(const std::vector<Shadow>& shadows)
57 {
58     auto jsonShadows = JsonUtil::CreateArray(true);
59     for (const auto& shadow : shadows) {
60         jsonShadows->Put(ConvertShadowToJson(shadow));
61     }
62     return jsonShadows;
63 }
64 } // namespace
65 
GetFont() const66 std::string SpanItem::GetFont() const
67 {
68     auto jsonValue = JsonUtil::Create(true);
69     jsonValue->Put("style", GetFontStyleInJson(fontStyle->GetItalicFontStyle()).c_str());
70     jsonValue->Put("size", GetFontSizeInJson(fontStyle->GetFontSize()).c_str());
71     jsonValue->Put("weight", GetFontWeightInJson(fontStyle->GetFontWeight()).c_str());
72     jsonValue->Put("family", GetFontFamilyInJson(fontStyle->GetFontFamily()).c_str());
73     return jsonValue->ToString();
74 }
75 
ToJsonValue(std::unique_ptr<JsonValue> & json) const76 void SpanItem::ToJsonValue(std::unique_ptr<JsonValue>& json) const
77 {
78     json->Put("content", content.c_str());
79     if (fontStyle) {
80         json->Put("font", GetFont().c_str());
81         json->Put("fontSize", GetFontSizeInJson(fontStyle->GetFontSize()).c_str());
82         json->Put("decoration", GetDeclaration(fontStyle->GetTextDecorationColor(), fontStyle->GetTextDecoration(),
83             fontStyle->GetTextDecorationStyle()).c_str());
84         json->Put("letterSpacing", fontStyle->GetLetterSpacing().value_or(Dimension()).ToString().c_str());
85         json->Put(
86             "textCase", V2::ConvertWrapTextCaseToStirng(fontStyle->GetTextCase().value_or(TextCase::NORMAL)).c_str());
87         json->Put("fontColor", fontStyle->GetForegroundColor()
88                                    .value_or(fontStyle->GetTextColor().value_or(Color::BLACK)).ColorToString().c_str());
89         json->Put("fontStyle", GetFontStyleInJson(fontStyle->GetItalicFontStyle()).c_str());
90         json->Put("fontWeight", GetFontWeightInJson(fontStyle->GetFontWeight()).c_str());
91         json->Put("fontFamily", GetFontFamilyInJson(fontStyle->GetFontFamily()).c_str());
92         json->Put("renderingStrategy",
93             GetSymbolRenderingStrategyInJson(fontStyle->GetSymbolRenderingStrategy()).c_str());
94         json->Put("effectStrategy", GetSymbolEffectStrategyInJson(fontStyle->GetSymbolEffectStrategy()).c_str());
95 
96         auto shadow = fontStyle->GetTextShadow().value_or(std::vector<Shadow> { Shadow() });
97         // Determines if there are multiple textShadows
98         auto jsonShadow = (shadow.size() == 1) ? ConvertShadowToJson(shadow.front()) : ConvertShadowsToJson(shadow);
99         json->Put("textShadow", jsonShadow);
100     }
101     if (textLineStyle) {
102         json->Put("lineHeight", textLineStyle->GetLineHeight().value_or(Dimension()).ToString().c_str());
103     }
104     TextBackgroundStyle::ToJsonValue(json, backgroundStyle);
105 }
106 
GetOrCreateSpanNode(int32_t nodeId)107 RefPtr<SpanNode> SpanNode::GetOrCreateSpanNode(int32_t nodeId)
108 {
109     auto spanNode = ElementRegister::GetInstance()->GetSpecificItemById<SpanNode>(nodeId);
110     if (spanNode) {
111         return spanNode;
112     }
113     spanNode = MakeRefPtr<SpanNode>(nodeId);
114     ElementRegister::GetInstance()->AddUINode(spanNode);
115     return spanNode;
116 }
117 
CreateSpanNode(int32_t nodeId)118 RefPtr<SpanNode> SpanNode::CreateSpanNode(int32_t nodeId)
119 {
120     auto spanNode = MakeRefPtr<SpanNode>(nodeId);
121     ElementRegister::GetInstance()->AddUINode(spanNode);
122     return spanNode;
123 }
124 
GetOrCreateSpanNode(const std::string & tag,int32_t nodeId)125 RefPtr<SpanNode> SpanNode::GetOrCreateSpanNode(const std::string& tag, int32_t nodeId)
126 {
127     auto spanNode = ElementRegister::GetInstance()->GetSpecificItemById<SpanNode>(nodeId);
128     if (spanNode) {
129         return spanNode;
130     }
131     spanNode = MakeRefPtr<SpanNode>(tag, nodeId);
132     ElementRegister::GetInstance()->AddUINode(spanNode);
133     return spanNode;
134 }
135 
MountToParagraph()136 void SpanNode::MountToParagraph()
137 {
138     auto parent = GetParent();
139     while (parent) {
140         auto spanNode = DynamicCast<SpanNode>(parent);
141         if (spanNode) {
142             spanNode->AddChildSpanItem(Claim(this));
143             return;
144         }
145         auto textNode = DynamicCast<FrameNode>(parent);
146         if (textNode) {
147             auto textPattern = textNode->GetPattern<TextPattern>();
148             if (textPattern) {
149                 textPattern->AddChildSpanItem(Claim(this));
150                 return;
151             }
152         }
153         parent = parent->GetParent();
154     }
155 }
156 
RequestTextFlushDirty()157 void SpanNode::RequestTextFlushDirty()
158 {
159     RequestTextFlushDirty(Claim<UINode>(this));
160 }
161 
RequestTextFlushDirty(const RefPtr<UINode> & node)162 void SpanNode::RequestTextFlushDirty(const RefPtr<UINode>& node)
163 {
164     CHECK_NULL_VOID(node);
165     auto parent = node->GetParent();
166     while (parent) {
167         auto textNode = DynamicCast<FrameNode>(parent);
168         if (textNode) {
169             textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
170             auto textPattern = textNode->GetPattern<TextPattern>();
171             if (textPattern) {
172                 textPattern->OnModifyDone();
173                 return;
174             }
175         }
176         parent = parent->GetParent();
177     }
178 }
179 
SetTextBackgroundStyle(const TextBackgroundStyle & style)180 void SpanNode::SetTextBackgroundStyle(const TextBackgroundStyle& style)
181 {
182     BaseSpan::SetTextBackgroundStyle(style);
183     spanItem_->backgroundStyle = GetTextBackgroundStyle();
184 }
185 
UpdateTextBackgroundFromParent(const std::optional<TextBackgroundStyle> & style)186 void SpanNode::UpdateTextBackgroundFromParent(const std::optional<TextBackgroundStyle>& style)
187 {
188     BaseSpan::UpdateTextBackgroundFromParent(style);
189     spanItem_->backgroundStyle = GetTextBackgroundStyle();
190 }
191 
UpdateParagraph(const RefPtr<FrameNode> & frameNode,const RefPtr<Paragraph> & builder,double,double,VerticalAlign)192 int32_t SpanItem::UpdateParagraph(const RefPtr<FrameNode>& frameNode,
193     const RefPtr<Paragraph>& builder, double /* width */, double /* height */, VerticalAlign /* verticalAlign */)
194 {
195     CHECK_NULL_RETURN(builder, -1);
196     std::optional<TextStyle> textStyle;
197     if (fontStyle || textLineStyle) {
198         auto pipelineContext = PipelineContext::GetCurrentContext();
199         CHECK_NULL_RETURN(pipelineContext, -1);
200         TextStyle themeTextStyle =
201             CreateTextStyleUsingTheme(fontStyle, textLineStyle, pipelineContext->GetTheme<TextTheme>());
202         if (frameNode) {
203             FontRegisterCallback(frameNode, themeTextStyle);
204         }
205         if (NearZero(themeTextStyle.GetFontSize().Value())) {
206             return -1;
207         }
208         textStyle = themeTextStyle;
209         textStyle->SetHalfLeading(pipelineContext->GetHalfLeading());
210         builder->PushStyle(themeTextStyle);
211     }
212 
213     auto spanContent = GetSpanContent(content);
214     auto pattern = frameNode->GetPattern<TextPattern>();
215     CHECK_NULL_RETURN(pattern, -1);
216     if (textStyle.has_value()) {
217         textStyle->SetTextBackgroundStyle(backgroundStyle);
218     }
219     if (pattern->NeedShowAIDetect() && !aiSpanMap.empty()) {
220         UpdateTextStyleForAISpan(spanContent, builder, textStyle);
221     } else {
222         UpdateTextStyle(spanContent, builder, textStyle);
223     }
224     textStyle_ = textStyle;
225 
226     for (const auto& child : children) {
227         if (child) {
228             if (!aiSpanMap.empty()) {
229                 child->aiSpanMap = aiSpanMap;
230             }
231             child->UpdateParagraph(frameNode, builder);
232         }
233     }
234     if (fontStyle || textLineStyle) {
235         builder->PopStyle();
236     }
237     return -1;
238 }
239 
UpdateSymbolSpanParagraph(const RefPtr<FrameNode> & frameNode,const RefPtr<Paragraph> & builder)240 void SpanItem::UpdateSymbolSpanParagraph(const RefPtr<FrameNode>& frameNode, const RefPtr<Paragraph>& builder)
241 {
242     CHECK_NULL_VOID(builder);
243     std::optional<TextStyle> textStyle;
244     auto symbolUnicode = GetSymbolUnicode();
245     if (fontStyle || textLineStyle) {
246         auto pipelineContext = PipelineContext::GetCurrentContext();
247         CHECK_NULL_VOID(pipelineContext);
248         TextStyle themeTextStyle =
249             CreateTextStyleUsingTheme(fontStyle, textLineStyle, pipelineContext->GetTheme<TextTheme>());
250         if (frameNode) {
251             FontRegisterCallback(frameNode, themeTextStyle);
252         }
253         if (NearZero(themeTextStyle.GetFontSize().Value())) {
254             return;
255         }
256         textStyle = themeTextStyle;
257         textStyle->SetHalfLeading(pipelineContext->GetHalfLeading());
258         if (symbolUnicode != 0) {
259             UpdateSymbolSpanColor(frameNode, themeTextStyle);
260         }
261         builder->PushStyle(themeTextStyle);
262     }
263     textStyle_ = textStyle;
264 
265     if (symbolUnicode != 0) {
266         textStyle_->isSymbolGlyph_ = true;
267         builder->AddSymbol(symbolUnicode);
268     }
269 
270     if (fontStyle || textLineStyle) {
271         builder->PopStyle();
272     }
273 }
274 
UpdateSymbolSpanColor(const RefPtr<FrameNode> & frameNode,TextStyle & symbolSpanStyle)275 void SpanItem::UpdateSymbolSpanColor(const RefPtr<FrameNode>& frameNode, TextStyle& symbolSpanStyle)
276 {
277     symbolSpanStyle.isSymbolGlyph_ = true;
278     CHECK_NULL_VOID(frameNode);
279     if (GetIsParentText() && symbolSpanStyle.GetSymbolColorList().empty()) {
280         RefPtr<LayoutProperty> layoutProperty = frameNode->GetLayoutProperty();
281         CHECK_NULL_VOID(layoutProperty);
282         RefPtr<TextLayoutProperty> textLayoutProperty = DynamicCast<TextLayoutProperty>(layoutProperty);
283         CHECK_NULL_VOID(textLayoutProperty);
284         if (textLayoutProperty->GetTextColor().has_value()) {
285             std::vector<Color> symbolColor;
286             symbolColor.emplace_back(textLayoutProperty->GetTextColor().value());
287             symbolSpanStyle.SetSymbolColorList(symbolColor);
288         }
289     }
290 }
291 
UpdateTextStyleForAISpan(const std::string & spanContent,const RefPtr<Paragraph> & builder,const std::optional<TextStyle> & textStyle)292 void SpanItem::UpdateTextStyleForAISpan(
293     const std::string& spanContent, const RefPtr<Paragraph>& builder, const std::optional<TextStyle>& textStyle)
294 {
295     auto wSpanContent = StringUtils::ToWstring(spanContent);
296     int32_t wSpanContentLength = static_cast<int32_t>(wSpanContent.length());
297     int32_t spanStart = position - wSpanContentLength;
298     if (needRemoveNewLine) {
299         spanStart -= 1;
300     }
301     int32_t preEnd = spanStart;
302     std::optional<TextStyle> aiSpanTextStyle = textStyle;
303     SetAiSpanTextStyle(aiSpanTextStyle);
304     while (!aiSpanMap.empty()) {
305         auto aiSpan = aiSpanMap.begin()->second;
306         if (aiSpan.start >= position || preEnd >= position) {
307             break;
308         }
309         int32_t aiSpanStartInSpan = std::max(spanStart, aiSpan.start);
310         int32_t aiSpanEndInSpan = std::min(position, aiSpan.end);
311         if (aiSpan.end <= spanStart || aiSpanStartInSpan < preEnd) {
312             TAG_LOGI(AceLogTag::ACE_TEXT, "Error prediction");
313             aiSpanMap.erase(aiSpanMap.begin());
314             continue;
315         }
316         if (preEnd < aiSpanStartInSpan) {
317             auto beforeContent =
318                 StringUtils::ToString(wSpanContent.substr(preEnd - spanStart, aiSpanStartInSpan - preEnd));
319             UpdateTextStyle(beforeContent, builder, textStyle);
320         }
321         auto displayContent = StringUtils::ToWstring(
322             aiSpan.content).substr(aiSpanStartInSpan - aiSpan.start, aiSpanEndInSpan - aiSpanStartInSpan);
323         UpdateTextStyle(StringUtils::ToString(displayContent), builder, aiSpanTextStyle);
324         preEnd = aiSpanEndInSpan;
325         if (aiSpan.end > position) {
326             return;
327         } else {
328             aiSpanMap.erase(aiSpanMap.begin());
329         }
330     }
331     if (preEnd < position) {
332         auto afterContent = StringUtils::ToString(wSpanContent.substr(preEnd - spanStart, position - preEnd));
333         UpdateTextStyle(afterContent, builder, textStyle);
334     }
335 }
336 
SetAiSpanTextStyle(std::optional<TextStyle> & aiSpanTextStyle)337 void SpanItem::SetAiSpanTextStyle(std::optional<TextStyle>& aiSpanTextStyle)
338 {
339     if (!aiSpanTextStyle.has_value()) {
340         auto pipelineContext = PipelineContext::GetCurrentContext();
341         CHECK_NULL_VOID(pipelineContext);
342         TextStyle themeTextStyle =
343             CreateTextStyleUsingTheme(fontStyle, textLineStyle, pipelineContext->GetTheme<TextTheme>());
344         if (NearZero(themeTextStyle.GetFontSize().Value())) {
345             return;
346         }
347         aiSpanTextStyle = themeTextStyle;
348     } else {
349         aiSpanTextStyle.value().SetTextColor(Color::BLUE);
350         aiSpanTextStyle.value().SetTextDecoration(TextDecoration::UNDERLINE);
351         aiSpanTextStyle.value().SetTextDecorationColor(Color::BLUE);
352     }
353 }
354 
FontRegisterCallback(const RefPtr<FrameNode> & frameNode,const TextStyle & textStyle)355 void SpanItem::FontRegisterCallback(const RefPtr<FrameNode>& frameNode, const TextStyle& textStyle)
356 {
357     auto callback = [weakNode = WeakPtr<FrameNode>(frameNode)] {
358         auto frameNode = weakNode.Upgrade();
359         CHECK_NULL_VOID(frameNode);
360         frameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
361         auto pattern = frameNode->GetPattern<TextPattern>();
362         CHECK_NULL_VOID(pattern);
363         auto modifier = DynamicCast<TextContentModifier>(pattern->GetContentModifier());
364         CHECK_NULL_VOID(modifier);
365         modifier->SetFontReady(true);
366     };
367     auto pipeline = frameNode->GetContext();
368     CHECK_NULL_VOID(pipeline);
369     auto fontManager = pipeline->GetFontManager();
370     if (fontManager) {
371         bool isCustomFont = false;
372         for (const auto& familyName : textStyle.GetFontFamilies()) {
373             bool customFont = fontManager->RegisterCallbackNG(frameNode, familyName, callback);
374             if (customFont) {
375                 isCustomFont = true;
376             }
377         }
378         if (isCustomFont) {
379             auto pattern = frameNode->GetPattern<TextPattern>();
380             CHECK_NULL_VOID(pattern);
381             pattern->SetIsCustomFont(true);
382             auto modifier = DynamicCast<TextContentModifier>(pattern->GetContentModifier());
383             CHECK_NULL_VOID(modifier);
384             modifier->SetIsCustomFont(true);
385         }
386     }
387 }
388 
UpdateTextStyle(const std::string & content,const RefPtr<Paragraph> & builder,const std::optional<TextStyle> & textStyle)389 void SpanItem::UpdateTextStyle(
390     const std::string& content, const RefPtr<Paragraph>& builder, const std::optional<TextStyle>& textStyle)
391 {
392     auto textCase = fontStyle ? fontStyle->GetTextCase().value_or(TextCase::NORMAL) : TextCase::NORMAL;
393     auto updateTextAction = [builder, textCase](const std::string& content, const std::optional<TextStyle>& textStyle) {
394         if (content.empty()) {
395             return;
396         }
397         auto displayText = content;
398         StringUtils::TransformStrCase(displayText, static_cast<int32_t>(textCase));
399         if (textStyle.has_value()) {
400             builder->PushStyle(textStyle.value());
401         }
402         builder->AddText(StringUtils::Str8ToStr16(displayText));
403         if (textStyle.has_value()) {
404             builder->PopStyle();
405         }
406     };
407     if (!IsDragging()) {
408         updateTextAction(content, textStyle);
409     } else {
410         if (content.empty()) {
411             return;
412         }
413         auto displayContent = StringUtils::Str8ToStr16(content);
414         auto contentLength = static_cast<int32_t>(displayContent.length());
415         auto beforeSelectedText = displayContent.substr(0, selectedStart);
416         updateTextAction(StringUtils::Str16ToStr8(beforeSelectedText), textStyle);
417 
418         if (selectedStart < contentLength) {
419             auto pipelineContext = PipelineContext::GetCurrentContext();
420             TextStyle normalStyle =
421                 !pipelineContext ? TextStyle()
422                                  : CreateTextStyleUsingTheme(nullptr, nullptr, pipelineContext->GetTheme<TextTheme>());
423             TextStyle selectedTextStyle = textStyle.value_or(normalStyle);
424             Color color = selectedTextStyle.GetTextColor().ChangeAlpha(DRAGGED_TEXT_OPACITY);
425             selectedTextStyle.SetTextColor(color);
426             auto selectedText = displayContent.substr(selectedStart, selectedEnd - selectedStart);
427             updateTextAction(StringUtils::Str16ToStr8(selectedText), selectedTextStyle);
428         }
429 
430         if (selectedEnd < contentLength) {
431             auto afterSelectedText = displayContent.substr(selectedEnd);
432             updateTextAction(StringUtils::Str16ToStr8(afterSelectedText), textStyle);
433         }
434     }
435 }
436 
GetSpanContent(const std::string & rawContent)437 std::string SpanItem::GetSpanContent(const std::string& rawContent)
438 {
439     std::string data;
440     if (needRemoveNewLine) {
441         data = rawContent.substr(0, rawContent.length() - 1);
442     } else {
443         data = rawContent;
444     }
445     return data;
446 }
447 
GetSpanContent()448 std::string SpanItem::GetSpanContent()
449 {
450     return content;
451 }
452 
GetSymbolUnicode()453 uint32_t SpanItem::GetSymbolUnicode()
454 {
455     return unicode;
456 }
457 
StartDrag(int32_t start,int32_t end)458 void SpanItem::StartDrag(int32_t start, int32_t end)
459 {
460     selectedStart = std::max(0, start);
461     int contentLen = content.size();
462     selectedEnd = std::min(contentLen, end);
463 }
464 
EndDrag()465 void SpanItem::EndDrag()
466 {
467     selectedStart = -1;
468     selectedEnd = -1;
469 }
470 
IsDragging()471 bool SpanItem::IsDragging()
472 {
473     return selectedStart >= 0 && selectedEnd >= 0;
474 }
475 
UpdateParagraph(const RefPtr<FrameNode> &,const RefPtr<Paragraph> & builder,double width,double height,VerticalAlign verticalAlign)476 int32_t ImageSpanItem::UpdateParagraph(const RefPtr<FrameNode>& /* frameNode */, const RefPtr<Paragraph>& builder,
477     double width, double height, VerticalAlign verticalAlign)
478 {
479     CHECK_NULL_RETURN(builder, -1);
480     PlaceholderRun run;
481     textStyle = TextStyle();
482     run.width = width;
483     run.height = height;
484     switch (verticalAlign) {
485         case VerticalAlign::TOP:
486             run.alignment = PlaceholderAlignment::TOP;
487             break;
488         case VerticalAlign::CENTER:
489             run.alignment = PlaceholderAlignment::MIDDLE;
490             break;
491         case VerticalAlign::BOTTOM:
492         case VerticalAlign::NONE:
493             run.alignment = PlaceholderAlignment::BOTTOM;
494             break;
495         case VerticalAlign::BASELINE:
496             run.alignment = PlaceholderAlignment::ABOVEBASELINE;
497             break;
498         default:
499             run.alignment = PlaceholderAlignment::BOTTOM;
500     }
501     // ImageSpan should ignore decoration styles
502     textStyle.SetTextDecoration(TextDecoration::NONE);
503     textStyle.SetTextBackgroundStyle(backgroundStyle);
504     builder->PushStyle(textStyle);
505     int32_t index = builder->AddPlaceholder(run);
506     builder->PopStyle();
507     return index;
508 }
509 
UpdatePlaceholderBackgroundStyle(const RefPtr<FrameNode> & imageNode)510 void ImageSpanItem::UpdatePlaceholderBackgroundStyle(const RefPtr<FrameNode>& imageNode)
511 {
512     CHECK_NULL_VOID(imageNode);
513     auto property = imageNode->GetLayoutProperty<ImageLayoutProperty>();
514     CHECK_NULL_VOID(property);
515     backgroundStyle = property->GetPlaceHolderStyle();
516 }
517 
GetIndex(int32_t & start,int32_t & end) const518 void SpanItem::GetIndex(int32_t& start, int32_t& end) const
519 {
520     auto contentLen = StringUtils::ToWstring(content).length();
521     start = position - contentLen;
522     end = position;
523 }
524 
UpdateParagraph(const RefPtr<FrameNode> &,const RefPtr<Paragraph> & builder,double width,double height,VerticalAlign)525 int32_t PlaceholderSpanItem::UpdateParagraph(const RefPtr<FrameNode>& /* frameNode */, const RefPtr<Paragraph>& builder,
526     double width, double height, VerticalAlign /* verticalAlign */)
527 {
528     CHECK_NULL_RETURN(builder, -1);
529     textStyle = TextStyle();
530     PlaceholderRun run;
531     run.width = width;
532     run.height = height;
533     textStyle.SetTextDecoration(TextDecoration::NONE);
534     builder->PushStyle(textStyle);
535     int32_t index = builder->AddPlaceholder(run);
536     builder->PopStyle();
537     return index;
538 }
539 
SetTextBackgroundStyle(const TextBackgroundStyle & style)540 void BaseSpan::SetTextBackgroundStyle(const TextBackgroundStyle& style)
541 {
542     textBackgroundStyle_ = style;
543     textBackgroundStyle_->groupId = groupId_;
544     SetHasTextBackgroundStyle(style.backgroundColor.has_value() || style.backgroundRadius.has_value());
545     MarkTextDirty();
546 }
547 
ToJsonValue(std::unique_ptr<JsonValue> & json) const548 void ContainerSpanNode::ToJsonValue(std::unique_ptr<JsonValue>& json) const
549 {
550     TextBackgroundStyle::ToJsonValue(json, GetTextBackgroundStyle());
551 }
552 } // namespace OHOS::Ace::NG
553