1 /*
2 * Copyright (c) 2022 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/utils/utils.h"
21 #include "core/components/common/layout/constants.h"
22 #include "core/components/common/properties/text_style.h"
23 #include "core/components_ng/base/frame_node.h"
24 #include "core/components_ng/pattern/text/text_pattern.h"
25 #include "core/components_ng/pattern/text/text_styles.h"
26 #include "core/components_ng/property/property.h"
27 #include "core/components_ng/render/drawing.h"
28 #include "core/components_ng/render/drawing_prop_convertor.h"
29 #include "core/components_ng/render/paragraph.h"
30 #include "core/pipeline/pipeline_context.h"
31
32 namespace OHOS::Ace::NG {
33 namespace {
GetDeclaration(const std::optional<Color> & color,const std::optional<TextDecoration> & textDecoration)34 std::string GetDeclaration(const std::optional<Color>& color, const std::optional<TextDecoration>& textDecoration)
35 {
36 auto jsonSpanDeclaration = JsonUtil::Create(true);
37 jsonSpanDeclaration->Put(
38 "type", V2::ConvertWrapTextDecorationToStirng(textDecoration.value_or(TextDecoration::NONE)).c_str());
39 jsonSpanDeclaration->Put("color", (color.value_or(Color::BLACK).ColorToString()).c_str());
40 return jsonSpanDeclaration->ToString();
41 }
42 } // namespace
43
ToJsonValue(std::unique_ptr<JsonValue> & json) const44 void SpanItem::ToJsonValue(std::unique_ptr<JsonValue>& json) const
45 {
46 json->Put("content", content.c_str());
47 if (fontStyle) {
48 json->Put("fontSize", fontStyle->GetFontSize().value_or(Dimension()).ToString().c_str());
49 json->Put(
50 "decoration", GetDeclaration(fontStyle->GetTextDecorationColor(), fontStyle->GetTextDecoration()).c_str());
51 json->Put("letterSpacing", fontStyle->GetLetterSpacing().value_or(Dimension()).ToString().c_str());
52 json->Put(
53 "textCase", V2::ConvertWrapTextCaseToStirng(fontStyle->GetTextCase().value_or(TextCase::NORMAL)).c_str());
54 json->Put("fontColor", fontStyle->GetForegroundColor()
55 .value_or(fontStyle->GetTextColor().value_or(Color::BLACK)).ColorToString().c_str());
56 json->Put("fontStyle",
57 fontStyle->GetItalicFontStyle().value_or(Ace::FontStyle::NORMAL) == Ace::FontStyle::NORMAL
58 ? "FontStyle.Normal" : "FontStyle.Italic");
59 json->Put("fontWeight",
60 V2::ConvertWrapFontWeightToStirng(fontStyle->GetFontWeight().value_or(FontWeight::NORMAL)).c_str());
61 std::vector<std::string> fontFamilyVector =
62 fontStyle->GetFontFamily().value_or<std::vector<std::string>>({ "HarmonyOS Sans" });
63 if (fontFamilyVector.empty()) {
64 fontFamilyVector = std::vector<std::string>({ "HarmonyOS Sans" });
65 }
66 std::string fontFamily = fontFamilyVector.at(0);
67 for (uint32_t i = 1; i < fontFamilyVector.size(); ++i) {
68 fontFamily += ',' + fontFamilyVector.at(i);
69 }
70 json->Put("fontFamily", fontFamily.c_str());
71 }
72 }
73
GetOrCreateSpanNode(int32_t nodeId)74 RefPtr<SpanNode> SpanNode::GetOrCreateSpanNode(int32_t nodeId)
75 {
76 auto spanNode = ElementRegister::GetInstance()->GetSpecificItemById<SpanNode>(nodeId);
77 if (spanNode) {
78 return spanNode;
79 }
80 spanNode = MakeRefPtr<SpanNode>(nodeId);
81 ElementRegister::GetInstance()->AddUINode(spanNode);
82 return spanNode;
83 }
84
MountToParagraph()85 void SpanNode::MountToParagraph()
86 {
87 auto parent = GetParent();
88 while (parent) {
89 auto spanNode = DynamicCast<SpanNode>(parent);
90 if (spanNode) {
91 spanNode->AddChildSpanItem(Claim(this));
92 return;
93 }
94 auto textNode = DynamicCast<FrameNode>(parent);
95 if (textNode) {
96 auto textPattern = textNode->GetPattern<TextPattern>();
97 if (textPattern) {
98 textPattern->AddChildSpanItem(Claim(this));
99 return;
100 }
101 }
102 parent = parent->GetParent();
103 }
104 LOGE("fail to find Text or Parent Span");
105 }
106
RequestTextFlushDirty()107 void SpanNode::RequestTextFlushDirty()
108 {
109 auto parent = GetParent();
110 while (parent) {
111 auto textNode = DynamicCast<FrameNode>(parent);
112 if (textNode) {
113 textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
114 auto textPattern = textNode->GetPattern<TextPattern>();
115 if (textPattern) {
116 textPattern->OnModifyDone();
117 return;
118 }
119 }
120 parent = parent->GetParent();
121 }
122 LOGE("fail to find Text or Parent Span");
123 }
124
UpdateParagraph(const RefPtr<Paragraph> & builder)125 void SpanItem::UpdateParagraph(const RefPtr<Paragraph>& builder)
126 {
127 CHECK_NULL_VOID(builder);
128 if (fontStyle) {
129 auto pipelineContext = PipelineContext::GetCurrentContext();
130 CHECK_NULL_VOID(pipelineContext);
131 TextStyle textStyle = CreateTextStyleUsingTheme(fontStyle, nullptr, pipelineContext->GetTheme<TextTheme>());
132 builder->PushStyle(textStyle);
133 }
134 auto displayText = content;
135 auto textCase = fontStyle ? fontStyle->GetTextCase().value_or(TextCase::NORMAL) : TextCase::NORMAL;
136 StringUtils::TransformStrCase(displayText, static_cast<int32_t>(textCase));
137 builder->AddText(StringUtils::Str8ToStr16(displayText));
138 for (const auto& child : children) {
139 if (child) {
140 child->UpdateParagraph(builder);
141 }
142 }
143 if (fontStyle) {
144 builder->PopStyle();
145 }
146 }
147 } // namespace OHOS::Ace::NG
148