• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_RICH_EDITOR_TYPING_STYLE_MANAGER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_RICH_EDITOR_TYPING_STYLE_MANAGER_H
18 
19 #include "core/components_ng/pattern/rich_editor/rich_editor_pattern.h"
20 #include "core/components_ng/pattern/rich_editor/rich_editor_theme.h"
21 
22 namespace OHOS::Ace::NG {
23 
24 class StyleManager {
25 public:
StyleManager()26     StyleManager() {}
StyleManager(const WeakPtr<RichEditorPattern> & pattern)27     StyleManager(const WeakPtr<RichEditorPattern>& pattern) : weakPattern_(pattern) {}
28 
SetTypingStyle(const std::optional<struct UpdateSpanStyle> & typingStyle,const std::optional<TextStyle> & textStyle)29     void SetTypingStyle(const std::optional<struct UpdateSpanStyle>& typingStyle,
30         const std::optional<TextStyle>& textStyle)
31     {
32         typingFontStyle_ = typingStyle;
33         typingTextStyle_ = textStyle;
34     }
35 
SetTypingParagraphStyle(std::optional<struct UpdateParagraphStyle> & typingParagraphStyle)36     void SetTypingParagraphStyle(std::optional<struct UpdateParagraphStyle>& typingParagraphStyle)
37     {
38         typingParagraphStyle_ = typingParagraphStyle;
39     }
40 
UpdateParagraphStyle(const RefPtr<SpanNode> & spanNode,const struct UpdateParagraphStyle & style)41     static void UpdateParagraphStyle(const RefPtr<SpanNode>& spanNode, const struct UpdateParagraphStyle& style)
42     {
43         CHECK_NULL_VOID(spanNode);
44         spanNode->UpdateTextAlign(style.textAlign.value_or(TextAlign::START));
45         spanNode->UpdateWordBreak(style.wordBreak.value_or(WordBreak::BREAK_WORD));
46         spanNode->UpdateLineBreakStrategy(style.lineBreakStrategy.value_or(LineBreakStrategy::GREEDY));
47         spanNode->UpdateTextVerticalAlign(style.textVerticalAlign.value_or(TextVerticalAlign::BASELINE));
48         if (style.paragraphSpacing.has_value()) {
49             spanNode->UpdateParagraphSpacing(style.paragraphSpacing.value());
50         } else {
51             spanNode->ResetParagraphSpacing();
52         }
53         auto leadingMarginValue = spanNode->GetLeadingMarginValue({});
54         if (style.leadingMargin.has_value() && !leadingMarginValue.CheckLeadingMargin(style.leadingMargin.value())) {
55             spanNode->GetSpanItem()->leadingMargin = *style.leadingMargin;
56             spanNode->UpdateLeadingMargin(*style.leadingMargin);
57         }
58     }
59 
UpdateTextStyle(RefPtr<SpanNode> & spanNode,const struct UpdateSpanStyle & updateSpanStyle)60     static void UpdateTextStyle(RefPtr<SpanNode>& spanNode, const struct UpdateSpanStyle& updateSpanStyle)
61     {
62         CHECK_NULL_VOID(spanNode);
63         auto spanItem = spanNode->GetSpanItem();
64         CHECK_NULL_VOID(spanItem);
65         spanNode->UpdateTextColor(updateSpanStyle.updateTextColor);
66         IF_TRUE(updateSpanStyle.updateTextColor.has_value(), spanItem->useThemeFontColor = false);
67         spanNode->UpdateFontSize(updateSpanStyle.updateFontSize);
68         spanNode->UpdateItalicFontStyle(updateSpanStyle.updateItalicFontStyle);
69         spanNode->UpdateFontWeight(updateSpanStyle.updateFontWeight);
70         spanNode->UpdateFontFamily(updateSpanStyle.updateFontFamily);
71 
72         if (updateSpanStyle.updateTextDecoration.has_value()) {
73             spanNode->UpdateTextDecoration({ updateSpanStyle.updateTextDecoration.value() });
74         }
75         spanNode->UpdateTextDecorationColor(updateSpanStyle.updateTextDecorationColor);
76         IF_TRUE(updateSpanStyle.updateTextDecorationColor.has_value(), spanItem->useThemeDecorationColor = false);
77         spanNode->UpdateTextDecorationStyle(updateSpanStyle.updateTextDecorationStyle);
78         spanNode->UpdateTextShadow(updateSpanStyle.updateTextShadows);
79 
80         spanNode->UpdateLetterSpacing(updateSpanStyle.updateLetterSpacing);
81         spanNode->UpdateLineHeight(updateSpanStyle.updateLineHeight);
82         spanNode->UpdateHalfLeading(updateSpanStyle.updateHalfLeading);
83         spanNode->UpdateFontFeature(updateSpanStyle.updateFontFeature);
84 
85         UpdateTextBackgroundStyle(spanNode, updateSpanStyle.updateTextBackgroundStyle);
86     }
87 
UpdateTextBackgroundStyle(RefPtr<SpanNode> & spanNode,const std::optional<TextBackgroundStyle> & style)88     static void UpdateTextBackgroundStyle(RefPtr<SpanNode>& spanNode, const std::optional<TextBackgroundStyle>& style)
89     {
90         CHECK_NULL_VOID(style.has_value());
91         TextBackgroundStyle backgroundStyle = style.value();
92         backgroundStyle.needCompareGroupId = false;
93         if (backgroundStyle == spanNode->GetTextBackgroundStyle()) {
94             TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "text background style is same");
95             return;
96         }
97         backgroundStyle.needCompareGroupId = true;
98         spanNode->SetTextBackgroundStyle(backgroundStyle);
99     }
100 
UpdateStyleByTypingParagraphStyle(RefPtr<SpanNode> & spanNode)101     bool UpdateStyleByTypingParagraphStyle(RefPtr<SpanNode>& spanNode)
102     {
103         CHECK_NULL_RETURN(spanNode && typingParagraphStyle_.has_value(), false);
104         UpdateParagraphStyle(spanNode, typingParagraphStyle_.value());
105         return true;
106     }
107 
UpdateStyleByTypingParagraphStyle(RefPtr<SpanItem> & spanItem)108     bool UpdateStyleByTypingParagraphStyle(RefPtr<SpanItem>& spanItem)
109     {
110         CHECK_NULL_RETURN(spanItem && typingParagraphStyle_.has_value(), false);
111         auto spanNode = AceType::MakeRefPtr<SpanNode>(ElementRegister::GetInstance()->MakeUniqueId());
112         spanNode->SetSpanItem(spanItem);
113         return UpdateStyleByTypingParagraphStyle(spanNode);
114     }
115 
UpdateTextStyleByTypingStyle(RefPtr<SpanNode> & spanNode)116     void UpdateTextStyleByTypingStyle(RefPtr<SpanNode>& spanNode)
117     {
118         CHECK_NULL_VOID(spanNode && typingFontStyle_.has_value());
119         UpdateTextStyle(spanNode, typingFontStyle_.value());
120     }
121 
UpdateTextStyleByTypingStyle(RefPtr<SpanItem> & spanItem)122     void UpdateTextStyleByTypingStyle(RefPtr<SpanItem>& spanItem)
123     {
124         CHECK_NULL_VOID(spanItem && typingFontStyle_.has_value());
125         auto spanNode = AceType::MakeRefPtr<SpanNode>(ElementRegister::GetInstance()->MakeUniqueId());
126         spanNode->SetSpanItem(spanItem);
127         UpdateTextStyleByTypingStyle(spanNode);
128     }
129 
CreateFontSpanByTextStyle(const struct UpdateSpanStyle & updateSpanStyle,const TextStyle & textStyle,int32_t length)130     static RefPtr<FontSpan> CreateFontSpanByTextStyle(
131         const struct UpdateSpanStyle& updateSpanStyle, const TextStyle& textStyle, int32_t length)
132     {
133         Font font;
134         if (updateSpanStyle.updateFontWeight.has_value()) {
135             font.fontWeight = textStyle.GetFontWeight();
136         }
137         if (updateSpanStyle.updateFontSize.has_value()) {
138             font.fontSize = textStyle.GetFontSize();
139         }
140         if (updateSpanStyle.updateItalicFontStyle.has_value()) {
141             font.fontStyle = textStyle.GetFontStyle();
142         }
143         if (updateSpanStyle.updateFontFamily.has_value()) {
144             font.fontFamilies = textStyle.GetFontFamilies();
145         }
146         if (updateSpanStyle.updateTextColor.has_value()) {
147             font.fontColor = textStyle.GetTextColor();
148         }
149         return AceType::MakeRefPtr<FontSpan>(font, 0, length);
150     }
151 
CreateDecorationSpanByTextStyle(const struct UpdateSpanStyle & updateSpanStyle,const TextStyle & textStyle,int32_t length)152     static RefPtr<DecorationSpan> CreateDecorationSpanByTextStyle(
153         const struct UpdateSpanStyle& updateSpanStyle, const TextStyle& textStyle, int32_t length)
154     {
155         TextDecoration type = TextDecoration::NONE;
156         std::optional<Color> colorOption;
157         std::optional<TextDecorationStyle> styleOption;
158         std::optional<TextDecorationOptions> options;
159         if (updateSpanStyle.updateTextDecoration.has_value()) {
160             type = textStyle.GetTextDecorationFirst();
161         }
162         if (updateSpanStyle.updateTextDecorationColor.has_value()) {
163             colorOption = textStyle.GetTextDecorationColor();
164         }
165         if (updateSpanStyle.updateTextDecorationStyle.has_value()) {
166             styleOption = textStyle.GetTextDecorationStyle();
167         }
168         return AceType::MakeRefPtr<DecorationSpan>(
169             std::vector<TextDecoration>({type}), colorOption, styleOption, options, 0, length);
170     }
171 
NeedTypingParagraphStyle(const RefPtr<MutableSpanString> & styledString,int32_t changeStart,int32_t changeLength)172     bool NeedTypingParagraphStyle(const RefPtr<MutableSpanString>& styledString, int32_t changeStart, int32_t changeLength)
173     {
174         CHECK_NULL_RETURN(styledString && typingParagraphStyle_.has_value(), false);
175         auto length = styledString->GetLength();
176         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "length=%{public}d, changeStart=%{public}d, changeLength=%{public}d",
177             length, changeStart, changeLength);
178         CHECK_NULL_RETURN(length > 0 && changeLength != length, true);
179         CHECK_NULL_RETURN(changeStart + changeLength == length || changeStart == length, false);
180         auto& string = styledString->GetU16string();
181         if (changeStart > length || changeStart <= 0) {
182             TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "NeedTypingParagraphStyle, error, changeStart=%{public}d, length=%{public}d",
183                 changeStart, length);
184             return false;
185         }
186         bool lastNewLine = string[changeStart - 1] == u'\n';
187         CHECK_NULL_RETURN(!lastNewLine, true);
188         return false;
189     }
190 
NeedTypingParagraphStyle(const std::list<RefPtr<SpanItem>> & spans,const RichEditorChangeValue & changeValue)191     bool NeedTypingParagraphStyle(const std::list<RefPtr<SpanItem>>& spans, const RichEditorChangeValue& changeValue)
192     {
193         // empty
194         CHECK_NULL_RETURN(!spans.empty(), true);
195 
196         auto contentLength = spans.back()->position;
197         const auto& rangeBefore = changeValue.GetRangeBefore();
198         TAG_LOGD(AceLogTag::ACE_RICH_TEXT, "rangeBefore=[%{public}d, %{public}d], contentLength=%{public}d",
199             rangeBefore.start, rangeBefore.end, contentLength);
200 
201         // delete to empty
202         if (rangeBefore.start == 0 && rangeBefore.end == contentLength) {
203             return true;
204         }
205 
206         // insert in last new line
207         if (rangeBefore.start == rangeBefore.end) {
208             return spans.back()->content.back() == u'\n';
209         }
210 
211         // delete to last new line
212         if (rangeBefore.end == contentLength) {
213             for (auto& span : spans) {
214                 if (rangeBefore.start > span->position) {
215                     continue;
216                 }
217                 if ((rangeBefore.start) == span->position && span->content.back() == u'\n') {
218                     return true;
219                 }
220             }
221         }
222         return false;
223     }
224 
NeedTypingParagraphStyle(const std::list<RefPtr<SpanItem>> & spans,int32_t caretPosition)225     bool NeedTypingParagraphStyle(const std::list<RefPtr<SpanItem>>& spans, int32_t caretPosition)
226     {
227         // empty
228         CHECK_NULL_RETURN(!spans.empty(), true);
229 
230         // insert in last new Line
231         auto contentLength = spans.back()->position;
232         if (caretPosition == contentLength && spans.back()->content.back() == u'\n') {
233             return true;
234         }
235         return false;
236 
237     }
238 
UseTypingParaStyle(const std::list<RefPtr<SpanItem>> & spans,const RichEditorChangeValue & changeValue)239     bool UseTypingParaStyle(const std::list<RefPtr<SpanItem>>& spans, const RichEditorChangeValue& changeValue)
240     {
241         return typingParagraphStyle_.has_value() && NeedTypingParagraphStyle(spans, changeValue);
242     }
243 
UseTypingParaStyle(const std::list<RefPtr<SpanItem>> & spans,int32_t caretPosition)244     bool UseTypingParaStyle(const std::list<RefPtr<SpanItem>>& spans, int32_t caretPosition)
245     {
246         return typingParagraphStyle_.has_value() && NeedTypingParagraphStyle(spans, caretPosition);
247 
248     }
249 
CreateStyledStringByTypingStyle(const std::u16string & insertValue,const RefPtr<MutableSpanString> & styledString,int32_t changeStart,int32_t changeLength)250     RefPtr<SpanString> CreateStyledStringByTypingStyle(const std::u16string& insertValue, const RefPtr<MutableSpanString>& styledString, int32_t changeStart, int32_t changeLength)
251     {
252         bool hasTypingStyle = typingFontStyle_.has_value();
253         bool needTypingParagraphStyle = NeedTypingParagraphStyle(styledString, changeStart, changeLength);
254         CHECK_NULL_RETURN(hasTypingStyle || needTypingParagraphStyle, {});
255 
256         auto insertStyledString = AceType::MakeRefPtr<SpanString>(insertValue);
257         std::vector<RefPtr<SpanBase>> spans;
258         int length = insertStyledString->GetLength();
259         IF_TRUE(hasTypingStyle, HandleStyledStringByTypingTextStyle(length, spans));
260         IF_TRUE(needTypingParagraphStyle, HandleStyledStringByTypingParagraphStyle(length, spans));
261         insertStyledString->BindWithSpans(spans);
262         return insertStyledString;
263     }
264 
HandleStyledStringByTypingTextStyle(int length,std::vector<RefPtr<SpanBase>> & spans)265     void HandleStyledStringByTypingTextStyle(int length, std::vector<RefPtr<SpanBase>>& spans)
266     {
267         CHECK_NULL_VOID(typingTextStyle_.has_value() && typingFontStyle_.has_value());
268         auto& textStyle = typingTextStyle_.value();
269         auto& updateSpanStyle = typingFontStyle_.value();
270         spans.push_back(CreateFontSpanByTextStyle(updateSpanStyle, textStyle, length));
271         spans.push_back(CreateDecorationSpanByTextStyle(updateSpanStyle, textStyle, length));
272         if (updateSpanStyle.updateTextShadows.has_value()) {
273             spans.push_back(AceType::MakeRefPtr<TextShadowSpan>(textStyle.GetTextShadows(), 0, length));
274         }
275         if (updateSpanStyle.updateLineHeight.has_value()) {
276             spans.push_back(AceType::MakeRefPtr<LineHeightSpan>(textStyle.GetLineHeight(), 0, length));
277         }
278         if (updateSpanStyle.updateHalfLeading.has_value()) {
279             spans.push_back(AceType::MakeRefPtr<HalfLeadingSpan>(textStyle.GetHalfLeading(), 0, length));
280         }
281         if (updateSpanStyle.updateLetterSpacing.has_value()) {
282             spans.push_back(AceType::MakeRefPtr<LetterSpacingSpan>(textStyle.GetLetterSpacing(), 0, length));
283         }
284         if (updateSpanStyle.updateTextBackgroundStyle.has_value()) {
285             spans.push_back(AceType::MakeRefPtr<BackgroundColorSpan>(textStyle.GetTextBackgroundStyle(), 0, length));
286         }
287     }
288 
HandleStyledStringByTypingParagraphStyle(int length,std::vector<RefPtr<SpanBase>> & spans)289     void HandleStyledStringByTypingParagraphStyle(int length, std::vector<RefPtr<SpanBase>>& spans)
290     {
291         CHECK_NULL_VOID(typingParagraphStyle_.has_value());
292         auto& typingParagraphStyle = typingParagraphStyle_.value();
293         SpanParagraphStyle spanParagraphStyle;
294         spanParagraphStyle.align = typingParagraphStyle.textAlign;
295         spanParagraphStyle.wordBreak = typingParagraphStyle.wordBreak;
296         spanParagraphStyle.leadingMargin = typingParagraphStyle.leadingMargin;
297         spanParagraphStyle.paragraphSpacing = typingParagraphStyle.paragraphSpacing;
298         spanParagraphStyle.textVerticalAlign = typingParagraphStyle.textVerticalAlign;
299         spans.push_back(AceType::MakeRefPtr<ParagraphStyleSpan>(spanParagraphStyle, 0, length));
300     }
301 
GetTypingParagraphStyle()302     std::optional<struct UpdateParagraphStyle> GetTypingParagraphStyle()
303     {
304         return typingParagraphStyle_;
305     }
306 
HasTypingParagraphStyle()307     bool HasTypingParagraphStyle()
308     {
309         return typingParagraphStyle_.has_value();
310     }
311 
312 private:
313     std::optional<struct UpdateSpanStyle> typingFontStyle_;
314     std::optional<TextStyle> typingTextStyle_;
315     std::optional<struct UpdateParagraphStyle> typingParagraphStyle_;
316     WeakPtr<RichEditorPattern> weakPattern_;
317 };
318 
319 } // namespace OHOS::Ace::NG
320 
321 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_RICH_EDITOR_TYPING_STYLE_MANAGER_H