• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/common/properties/text_style.h"
17 #include "core/components_ng/pattern/text/text_styles.h"
18 #include "ui/base/utils/utils.h"
19 
20 namespace OHOS::Ace {
21 const std::vector<WordBreak> WORD_BREAK_TYPES = { WordBreak::NORMAL, WordBreak::BREAK_ALL, WordBreak::BREAK_WORD,
22     WordBreak::HYPHENATION };
23 const std::vector<LineBreakStrategy> LINE_BREAK_STRATEGY_TYPES = { LineBreakStrategy::GREEDY,
24     LineBreakStrategy::HIGH_QUALITY, LineBreakStrategy::BALANCED };
TextStyle(const std::vector<std::string> & fontFamilies,double fontSize,FontWeight fontWeight,FontStyle fontStyle,const Color & textColor)25 TextStyle::TextStyle(const std::vector<std::string>& fontFamilies, double fontSize, FontWeight fontWeight,
26     FontStyle fontStyle, const Color& textColor)
27     : propFontFamilies_(fontFamilies), propFontStyle_(fontStyle), propTextColor_(textColor),
28       fontWeight_(fontWeight)
29 {
30     SetFontSize(Dimension(fontSize));
31 }
32 
operator ==(const TextStyle & rhs) const33 bool TextStyle::operator==(const TextStyle& rhs) const
34 {
35     return propFontFamilies_ == rhs.propFontFamilies_ && fontFeatures_ == rhs.fontFeatures_ &&
36            propTextDecorationStyle_ == rhs.propTextDecorationStyle_ && preferFontSizes_ == rhs.preferFontSizes_ &&
37            fontSize_.value == rhs.fontSize_.value && adaptMinFontSize_.value == rhs.adaptMinFontSize_.value &&
38            adaptMaxFontSize_.value == rhs.adaptMaxFontSize_.value &&
39            propAdaptFontSizeStep_.value == rhs.propAdaptFontSizeStep_.value &&
40            lineHeight_.value == rhs.lineHeight_.value && fontWeight_ == rhs.fontWeight_ &&
41            propFontStyle_ == rhs.propFontStyle_ && propTextBaseline_ == rhs.propTextBaseline_ &&
42            propTextOverflow_ == rhs.propTextOverflow_ && propTextAlign_ == rhs.propTextAlign_ &&
43            propTextColor_ == rhs.propTextColor_ && propTextDecoration_ == rhs.propTextDecoration_ &&
44            propTextShadows_ == rhs.propTextShadows_ && propLetterSpacing_.value == rhs.propLetterSpacing_.value &&
45            propMaxLines_ == rhs.propMaxLines_ && adaptTextSize_ == rhs.adaptTextSize_ &&
46            propAllowScale_ == rhs.propAllowScale_ && propWordBreak_ == rhs.propWordBreak_ &&
47            propTextDecorationColor_ == rhs.propTextDecorationColor_ && propTextCase_ == rhs.propTextCase_ &&
48            propBaselineOffset_.value == rhs.propBaselineOffset_.value && adaptHeight_ == rhs.adaptHeight_ &&
49            propTextIndent_.value == rhs.propTextIndent_.value && propTextVerticalAlign_ == rhs.propTextVerticalAlign_ &&
50            propWordSpacing_.value == rhs.propWordSpacing_.value && propEllipsisMode_ == rhs.propEllipsisMode_ &&
51            propLineBreakStrategy_ == rhs.propLineBreakStrategy_ &&
52            propTextBackgroundStyle_ == rhs.propTextBackgroundStyle_ &&
53            NearEqual(propLineThicknessScale_, rhs.propLineThicknessScale_);
54 }
55 
operator !=(const TextStyle & rhs) const56 bool TextStyle::operator!=(const TextStyle& rhs) const
57 {
58     return !(rhs == *this);
59 }
60 
SetAdaptTextSize(const Dimension & maxFontSize,const Dimension & minFontSize,const Dimension & fontSizeStep)61 void TextStyle::SetAdaptTextSize(
62     const Dimension& maxFontSize, const Dimension& minFontSize, const Dimension& fontSizeStep)
63 {
64     adaptMaxFontSize_.value = maxFontSize;
65     adaptMinFontSize_.value = minFontSize;
66     propAdaptFontSizeStep_.value = fontSizeStep;
67     adaptTextSize_ = true;
68 }
69 
ToJsonValue(std::unique_ptr<JsonValue> & json,const std::optional<TextBackgroundStyle> & style,const NG::InspectorFilter & filter)70 void TextBackgroundStyle::ToJsonValue(std::unique_ptr<JsonValue>& json, const std::optional<TextBackgroundStyle>& style,
71     const NG::InspectorFilter& filter)
72 {
73     NG::BorderRadiusProperty defaultRadius;
74     TextBackgroundStyle exportStyle = { .backgroundColor = Color::TRANSPARENT, .backgroundRadius = defaultRadius };
75     if (style.has_value()) {
76         exportStyle.backgroundColor = style.value().backgroundColor.value_or(Color::TRANSPARENT);
77         exportStyle.backgroundRadius = style.value().backgroundRadius.value_or(defaultRadius);
78     }
79 
80     auto styleJson = JsonUtil::Create(true);
81     styleJson->Put("color", exportStyle.backgroundColor->ColorToString().c_str());
82     auto radiusJson = JsonUtil::Create(true);
83     exportStyle.backgroundRadius->ToJsonValue(radiusJson, styleJson, filter);
84 
85     json->PutExtAttr("textBackgroundStyle", styleJson, filter);
86 }
87 
ToJsonValue(std::unique_ptr<JsonValue> & json,const std::optional<TextStyle> & style,const NG::InspectorFilter & filter)88 void TextStyle::ToJsonValue(std::unique_ptr<JsonValue>& json, const std::optional<TextStyle>& style,
89                             const NG::InspectorFilter& filter)
90 {
91     CHECK_NULL_VOID(json);
92     CHECK_NULL_VOID(style);
93     /* no fixed attr below, just return */
94     if (filter.IsFastFilter()) {
95         return;
96     }
97     json->PutExtAttr("decoration", GetDeclarationString(style->GetTextDecorationColor(), style->GetTextDecoration(),
98         style->GetTextDecorationStyle(), style->GetLineThicknessScale()).c_str(), filter);
99 }
100 
GetDeclarationString(const std::optional<Color> & color,const std::vector<TextDecoration> & textDecorations,const std::optional<TextDecorationStyle> & textDecorationStyle,const std::optional<float> & lineThicknessScale)101 std::string TextStyle::GetDeclarationString(
102     const std::optional<Color>& color, const std::vector<TextDecoration>& textDecorations,
103     const std::optional<TextDecorationStyle>& textDecorationStyle, const std::optional<float>& lineThicknessScale)
104 {
105     auto jsonSpanDeclaration = JsonUtil::Create(true);
106     jsonSpanDeclaration->Put(
107         "type", V2::ConvertWrapTextDecorationToStirng(textDecorations).c_str());
108     jsonSpanDeclaration->Put("color", (color.value_or(Color::BLACK).ColorToString()).c_str());
109     jsonSpanDeclaration->Put("style", V2::ConvertWrapTextDecorationStyleToString(
110         textDecorationStyle.value_or(TextDecorationStyle::SOLID)).c_str());
111     jsonSpanDeclaration->Put("thicknessScale",
112         StringUtils::DoubleToString(static_cast<double>(lineThicknessScale.value_or(1.0f))).c_str());
113     return jsonSpanDeclaration->ToString();
114 }
115 
UpdateColorByResourceId()116 void TextStyle::UpdateColorByResourceId()
117 {
118     propTextColor_.UpdateColorByResourceId();
119     propTextDecorationColor_.UpdateColorByResourceId();
120     if (propTextBackgroundStyle_.has_value()) {
121         propTextBackgroundStyle_->UpdateColorByResourceId();
122     }
123     std::for_each(propRenderColors_.begin(), propRenderColors_.end(), [](Color& cl) { cl.UpdateColorByResourceId(); });
124     std::for_each(propTextShadows_.begin(), propTextShadows_.end(), [](Shadow& sd) { sd.UpdateColorByResourceId(); });
125 }
126 
ToString() const127 std::string TextStyle::ToString() const
128 {
129     auto jsonValue = JsonUtil::Create(true);
130     JSON_STRING_PUT_STRINGABLE(jsonValue, fontSize_.value);
131     JSON_STRING_PUT_STRINGABLE(jsonValue, propTextColor_);
132     JSON_STRING_PUT_STRINGABLE(jsonValue, lineHeight_.value);
133     JSON_STRING_PUT_STRINGABLE(jsonValue, propBaselineOffset_.value);
134     JSON_STRING_PUT_STRINGABLE(jsonValue, propWordSpacing_.value);
135     JSON_STRING_PUT_STRINGABLE(jsonValue, propTextIndent_.value);
136     JSON_STRING_PUT_STRINGABLE(jsonValue, propLetterSpacing_.value);
137     JSON_STRING_PUT_STRINGABLE(jsonValue, lineSpacing_.value);
138 
139     JSON_STRING_PUT_INT(jsonValue, fontWeight_);
140     JSON_STRING_PUT_INT(jsonValue, propFontStyle_);
141     JSON_STRING_PUT_INT(jsonValue, propTextBaseline_);
142     JSON_STRING_PUT_INT(jsonValue, propTextOverflow_);
143     JSON_STRING_PUT_INT(jsonValue, propTextVerticalAlign_);
144     JSON_STRING_PUT_INT(jsonValue, propTextAlign_);
145     JSON_STRING_PUT_INT(jsonValue, propTextDecorationStyle_);
146     JSON_STRING_PUT_INT(
147         jsonValue, propTextDecoration_.size() > 0 ? propTextDecoration_[0] : TextDecoration::NONE);
148     JSON_STRING_PUT_INT(jsonValue, propLineThicknessScale_);
149     JSON_STRING_PUT_INT(jsonValue, propWhiteSpace_);
150     JSON_STRING_PUT_INT(jsonValue, propWordBreak_);
151     JSON_STRING_PUT_INT(jsonValue, propTextCase_);
152     JSON_STRING_PUT_INT(jsonValue, propEllipsisMode_);
153     JSON_STRING_PUT_INT(jsonValue, propLineBreakStrategy_);
154 
155     std::stringstream ss;
156     std::for_each(
157         propRenderColors_.begin(), propRenderColors_.end(), [&ss](const Color& c) { ss << c.ToString() << ","; });
158     jsonValue->Put("renderColors", ss.str().c_str());
159     JSON_STRING_PUT_INT(jsonValue, propRenderStrategy_);
160     JSON_STRING_PUT_INT(jsonValue, propEffectStrategy_);
161     JSON_STRING_PUT_OPTIONAL_STRINGABLE(jsonValue, GetInnerSymbolEffectOptions());
162 
163     return jsonValue->ToString();
164 }
165 
CompareCommonSubType(const std::optional<NG::SymbolEffectOptions> & options,const std::optional<NG::SymbolEffectOptions> & oldOptions)166 void TextStyle::CompareCommonSubType(const std::optional<NG::SymbolEffectOptions>& options,
167     const std::optional<NG::SymbolEffectOptions>& oldOptions)
168 {
169     auto newOpts = options.value();
170     auto oldOpts = oldOptions.value();
171     if (newOpts.GetCommonSubType().has_value()) {
172         auto commonType = static_cast<uint16_t>(newOpts.GetCommonSubType().value());
173         if (oldOpts.GetCommonSubType().has_value()) {
174             auto oldCommonType = static_cast<uint16_t>(oldOpts.GetCommonSubType().value());
175             if (commonType != oldCommonType) {
176                 reLayoutSymbolStyleBitmap_.set(static_cast<int32_t>(SymbolStyleAttribute::COMMONSUB_TYPE));
177             }
178         }
179     } else {
180         if (oldOpts.GetCommonSubType().has_value()) {
181             reLayoutSymbolStyleBitmap_.set(static_cast<int32_t>(SymbolStyleAttribute::COMMONSUB_TYPE));
182         }
183     }
184 }
185 
CompareAnimationMode(const std::optional<NG::SymbolEffectOptions> & options,const std::optional<NG::SymbolEffectOptions> & oldOptions)186 void TextStyle::CompareAnimationMode(const std::optional<NG::SymbolEffectOptions>& options,
187     const std::optional<NG::SymbolEffectOptions>& oldOptions)
188 {
189     auto newOpts = options.value();
190     auto oldOpts = oldOptions.value();
191     auto effectType = newOpts.GetEffectType();
192     if (effectType == SymbolEffectType::HIERARCHICAL && newOpts.GetFillStyle().has_value()) {
193         if (oldOpts.GetFillStyle().has_value()) {
194             if (newOpts.GetFillStyle().value() != oldOpts.GetFillStyle().value()) {
195                 reLayoutSymbolStyleBitmap_.set(static_cast<int32_t>(SymbolStyleAttribute::ANIMATION_MODE));
196             }
197         } else {
198             reLayoutSymbolStyleBitmap_.set(static_cast<int32_t>(SymbolStyleAttribute::ANIMATION_MODE));
199         }
200         return;
201     }
202     if (newOpts.GetScopeType().has_value()) {
203         if (oldOpts.GetScopeType().has_value()) {
204             if (newOpts.GetScopeType().value() != oldOpts.GetScopeType().value()) {
205                 reLayoutSymbolStyleBitmap_.set(static_cast<int32_t>(SymbolStyleAttribute::ANIMATION_MODE));
206             }
207         } else {
208             reLayoutSymbolStyleBitmap_.set(static_cast<int32_t>(SymbolStyleAttribute::ANIMATION_MODE));
209         }
210     }
211 }
212 
SetWhenOnlyOneOptionIsValid(const std::optional<NG::SymbolEffectOptions> & options)213 void TextStyle::SetWhenOnlyOneOptionIsValid(const std::optional<NG::SymbolEffectOptions>& options)
214 {
215     auto symbolOptions = options.value();
216     if (symbolOptions.GetEffectType() != SymbolEffectType::NONE) {
217         reLayoutSymbolStyleBitmap_.set(static_cast<int32_t>(SymbolStyleAttribute::EFFECT_STRATEGY));
218     }
219     if (symbolOptions.GetIsTxtActive()) {
220         reLayoutSymbolStyleBitmap_.set(static_cast<int32_t>(SymbolStyleAttribute::ANIMATION_START));
221     }
222     if (symbolOptions.GetCommonSubType().has_value()) {
223         reLayoutSymbolStyleBitmap_.set(static_cast<int32_t>(SymbolStyleAttribute::COMMONSUB_TYPE));
224     }
225     if (symbolOptions.GetFillStyle().has_value() || symbolOptions.GetScopeType().has_value()) {
226         reLayoutSymbolStyleBitmap_.set(static_cast<int32_t>(SymbolStyleAttribute::ANIMATION_MODE));
227     }
228 }
229 
SetSymbolEffectOptions(const std::optional<NG::SymbolEffectOptions> & symbolEffectOptions)230 void TextStyle::SetSymbolEffectOptions(const std::optional<NG::SymbolEffectOptions>& symbolEffectOptions)
231 {
232     auto innerSymbolEffectOptions = GetInnerSymbolEffectOptions();
233     if (symbolEffectOptions.has_value() && innerSymbolEffectOptions.has_value()) {
234         auto options = symbolEffectOptions.value();
235         auto oldOptions = innerSymbolEffectOptions.value();
236         if (oldOptions.GetEffectType() != options.GetEffectType()) {
237             reLayoutSymbolStyleBitmap_.set(static_cast<int32_t>(SymbolStyleAttribute::EFFECT_STRATEGY));
238         }
239         if (oldOptions.GetIsTxtActive() != options.GetIsTxtActive() ||
240             (options.GetTriggerNum().has_value() && options.GetIsTxtActive())) {
241             reLayoutSymbolStyleBitmap_.set(static_cast<int32_t>(SymbolStyleAttribute::ANIMATION_START));
242         }
243         CompareCommonSubType(options, oldOptions);
244         CompareAnimationMode(options, oldOptions);
245     } else {
246         if (innerSymbolEffectOptions.has_value()) {
247             auto oldOptions = innerSymbolEffectOptions.value();
248             SetWhenOnlyOneOptionIsValid(oldOptions);
249         }
250     }
251     SetInnerSymbolEffectOptionsWithoutMark(symbolEffectOptions);
252 }
253 }  // namespace OHOS::Ace
254