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