From d79ce3388f3ce1c56ff7c536756dcdbf9d25aa44 Mon Sep 17 00:00:00 2001 From: jyj-0306 Date: Mon, 11 Mar 2024 16:41:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0addspan=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: jyj-0306 Change-Id: I9a704e537191391d726347573ba966ddd2caaad6 --- .../pattern/text/span/mutable_span_string.h | 6 - .../pattern/text/span/span_object.cpp | 56 ++++++- .../pattern/text/span/span_object.h | 2 - .../pattern/text/span/span_string.cpp | 143 +++++++++++++++++- .../pattern/text/span/span_string.h | 8 +- .../components_ng/pattern/text/span_node.cpp | 62 ++++++++ .../components_ng/pattern/text/span_node.h | 3 + .../components_ng/pattern/text/text_model.h | 4 + .../pattern/text_field/text_field_model.h | 24 +++ 9 files changed, 297 insertions(+), 11 deletions(-) diff --git a/frameworks/core/components_ng/pattern/text/span/mutable_span_string.h b/frameworks/core/components_ng/pattern/text/span/mutable_span_string.h index ade93fc1745..e28ea2c8ae0 100644 --- a/frameworks/core/components_ng/pattern/text/span/mutable_span_string.h +++ b/frameworks/core/components_ng/pattern/text/span/mutable_span_string.h @@ -40,7 +40,6 @@ public: void InsertString(int32_t start, const std::string& other); void RemoveString(int32_t start, int32_t length); void ReplaceSpan(int32_t start, int32_t length, const RefPtr& span); - void AddSpan(const RefPtr& span); void RemoveSpan(int32_t start, int32_t length, SpanType key); void RemoveSpans(int32_t start, int32_t length); void ClearAllSpans(); @@ -49,12 +48,7 @@ public: void AppendSpanString(const RefPtr& spanString); private: - void SortSpans(std::list>& spans); - bool CanMerge(const RefPtr& a, const RefPtr& b); - void MergeIntervals(std::list>& spans); void KeepSpansOrder(); - void SplitInterval(std::list>& spans, std::pair interval); - void ApplyToSpans(const RefPtr& spans, std::pair interval, SpanOperation operation); void ApplyReplaceStringToSpans(int32_t start, int32_t length, const std::string& other); void ApplyRemoveStringToSpans(int32_t start, int32_t length); void ApplyInsertStringToSpans(int32_t start, const std::string& other); diff --git a/frameworks/core/components_ng/pattern/text/span/span_object.cpp b/frameworks/core/components_ng/pattern/text/span/span_object.cpp index 290a62d8eee..b9dcdf75af4 100644 --- a/frameworks/core/components_ng/pattern/text/span/span_object.cpp +++ b/frameworks/core/components_ng/pattern/text/span/span_object.cpp @@ -21,4 +21,58 @@ #include "core/components/common/properties/color.h" #include "core/components_ng/pattern/text_field/text_field_model.h" -namespace OHOS::Ace {} // namespace OHOS::Ace \ No newline at end of file +namespace OHOS::Ace { +// SpanBase +int32_t SpanBase::GetStartIndex() const +{ + return start_; +} + +int32_t SpanBase::GetEndIndex() const +{ + return end_; +} +void SpanBase::UpdateStartIndex(int32_t startIndex) +{ + start_ = startIndex; +} + +void SpanBase::UpdateEndIndex(int32_t endIndex) +{ + end_ = endIndex; +} + +// FontSpan +void FontSpan::ApplyToSpanItem(const RefPtr& spanItem) const +{ + if (font_.fontColor.has_value()) { + spanItem->fontStyle->UpdateTextColor(font_.fontColor.value()); + } + + if (font_.fontFamiliesNG.has_value()) { + spanItem->fontStyle->UpdateFontFamily(font_.fontFamiliesNG.value()); + } + + if (font_.fontSize.has_value()) { + spanItem->fontStyle->UpdateFontSize(font_.fontSize.value()); + } + + if (font_.fontStyle.has_value()) { + spanItem->fontStyle->UpdateItalicFontStyle(font_.fontStyle.value()); + } + + if (font_.fontWeight.has_value()) { + spanItem->fontStyle->UpdateFontWeight(font_.fontWeight.value()); + } +} + +bool FontSpan::IsAttributesEqual(const RefPtr& other) const +{ + auto fontSpan = DynamicCast(other); + if (!fontSpan) { + return false; + } + auto font = fontSpan->GetFont(); + return font_.IsEqual(font); +} +} // namespace OHOS::Ace \ No newline at end of file diff --git a/frameworks/core/components_ng/pattern/text/span/span_object.h b/frameworks/core/components_ng/pattern/text/span/span_object.h index c1801d3a3ca..06ff19348e6 100644 --- a/frameworks/core/components_ng/pattern/text/span/span_object.h +++ b/frameworks/core/components_ng/pattern/text/span/span_object.h @@ -47,7 +47,6 @@ public: virtual RefPtr GetSubSpan(int32_t start, int32_t end) = 0; virtual SpanType GetSpanType() const = 0; virtual void ApplyToSpanItem(const RefPtr& spanItem) const = 0; - virtual void RemoveToSpanItem(const RefPtr& spanItem) const = 0; virtual RefPtr CreateNewSpanItem() const = 0; int32_t GetStartIndex() const; int32_t GetEndIndex() const; @@ -73,7 +72,6 @@ public: SpanType GetSpanType() const override; std::string ToString() const override; void ApplyToSpanItem(const RefPtr& spanItem) const override; - void RemoveToSpanItem(const RefPtr& spanItem) const override; RefPtr CreateNewSpanItem() const override; static RefPtr CreateDefaultSpan(); diff --git a/frameworks/core/components_ng/pattern/text/span/span_string.cpp b/frameworks/core/components_ng/pattern/text/span/span_string.cpp index 10917748d2e..a56d2ace830 100644 --- a/frameworks/core/components_ng/pattern/text/span/span_string.cpp +++ b/frameworks/core/components_ng/pattern/text/span/span_string.cpp @@ -20,4 +20,145 @@ #include "core/components/common/properties/color.h" #include "core/components_ng/pattern/text/span/span_objects.h" -namespace OHOS::Ace {} // namespace OHOS::Ace \ No newline at end of file +namespace OHOS::Ace { +void SpanString::ApplyToSpans(const RefPtr& span, std::pair interval) +{ + for (auto it = spans_.begin(); it != spans_.end(); ++it) { + auto intersection = (*it)->GetIntersectionInterval(interval); + if (!intersection) { + continue; + } + auto oldStart = (*it)->interval.first; + auto oldEnd = (*it)->interval.second; + if (oldStart == intersection->first && intersection->second == oldEnd) { + span->ApplyToSpanItem(*it); + continue; + } + + auto wContent = StringUtils::ToWstring((*it)->content); + auto newSpan = (*it)->GetSameStyleSpanItem(); + if (oldStart < intersection->first && intersection->second < oldEnd) { + (*it)->interval = { oldStart, intersection->first }; + (*it)->content = StringUtils::ToString(wContent.substr(0, intersection->first - oldStart)); + + newSpan->interval = { intersection->first, intersection->second }; + newSpan->content = StringUtils::ToString( + wContent.substr(intersection->first - oldStart, intersection->second - intersection->first)); + span->ApplyToSpanItem(newSpan); + + auto newSpan2 = (*it)->GetSameStyleSpanItem(); + newSpan2->interval = { intersection->second, oldEnd }; + newSpan2->content = StringUtils::ToString(wContent.substr(intersection->second - oldStart)); + it = spans_.insert(std::next(it), newSpan); + it = spans_.insert(std::next(it), newSpan2); + continue; + } + + if (oldEnd > intersection->second) { + (*it)->content = StringUtils::ToString(wContent.substr(0, intersection->second - oldStart)); + (*it)->interval = { oldStart, intersection->second }; + span->ApplyToSpanItem(*it); + newSpan->interval = { intersection->second, oldEnd }; + newSpan->content = StringUtils::ToString(wContent.substr(intersection->second - oldStart)); + it = spans_.insert(std::next(it), newSpan); + continue; + } + + if (intersection->first > oldStart) { + (*it)->content = StringUtils::ToString(wContent.substr(0, intersection->first - oldStart)); + (*it)->interval = { oldStart, intersection->first }; + newSpan->interval = { intersection->first, oldEnd }; + newSpan->content = StringUtils::ToString(wContent.substr(intersection->first - oldStart)); + span->ApplyToSpanItem(newSpan); + it = spans_.insert(std::next(it), newSpan); + } + } + NotifySpanWatcher(); +} + +void SpanString::SplitInterval(std::list>& spans, std::pair interval) +{ + std::list> newSpans; + for (auto it = spans.begin(); it != spans.end();) { + auto intersection = (*it)->GetIntersectionInterval(interval); + if (!intersection) { + ++it; + continue; + } + auto oldStart = (*it)->GetStartIndex(); + auto oldEnd = (*it)->GetEndIndex(); + if (intersection->first == oldStart && intersection->second == oldEnd) { + it = spans.erase(it); + continue; + } + if (oldStart < intersection->first && intersection->second < oldEnd) { + newSpans.emplace_back((*it)->GetSubSpan(oldStart, intersection->first)); + newSpans.emplace_back((*it)->GetSubSpan(intersection->second, oldEnd)); + it = spans.erase(it); + continue; + } + if (oldEnd > intersection->second) { + (*it)->UpdateStartIndex(intersection->second); + ++it; + continue; + } + if (intersection->first > oldStart) { + (*it)->UpdateEndIndex(intersection->first); + ++it; + } + } + spans.merge(newSpans); +} + +void SpanString::SortSpans(std::list>& spans) +{ + spans.sort( + [](const RefPtr& a, const RefPtr& b) { return a->GetStartIndex() < b->GetStartIndex(); }); +} + +bool SpanString::CanMerge(const RefPtr& a, const RefPtr& b) +{ + return a->GetEndIndex() >= b->GetStartIndex() && a->IsAttributesEqual(b); +} + +void SpanString::MergeIntervals(std::list>& spans) +{ + auto it = spans.begin(); + while (it != spans.end()) { + auto current = it++; + if (it != spans.end() && CanMerge(*current, *it)) { + (*current)->UpdateStartIndex(std::min((*current)->GetStartIndex(), (*it)->GetStartIndex())); + (*current)->UpdateEndIndex(std::max((*current)->GetEndIndex(), (*it)->GetEndIndex())); + spans.erase(it++); + if (it == spans.end()) { + break; + } + it = current; + } + } +} + +void SpanString::AddSpan(const RefPtr& span) +{ + if (!span) { + return; + } + if (!CheckRange(span->GetStartIndex(), span->GetLength())) { + return; + } + auto spans = spansMap_[span->GetSpanType()]; + auto start = span->GetStartIndex(); + auto end = span->GetEndIndex(); + if (spansMap_.find(span->GetSpanType()) == spansMap_.end()) { + spansMap_[span->GetSpanType()].emplace_back(span); + ApplyToSpans(span, { start, end }); + return; + } + ApplyToSpans(span, { start, end }); + SplitInterval(spans, { start, end }); + spans.emplace_back(span); + SortSpans(spans); + MergeIntervals(spans); + spansMap_[span->GetSpanType()] = spans; +} +} // namespace OHOS::Ace \ No newline at end of file diff --git a/frameworks/core/components_ng/pattern/text/span/span_string.h b/frameworks/core/components_ng/pattern/text/span/span_string.h index 59d0510403a..66ff63787e6 100644 --- a/frameworks/core/components_ng/pattern/text/span/span_string.h +++ b/frameworks/core/components_ng/pattern/text/span/span_string.h @@ -28,7 +28,7 @@ namespace OHOS::Ace { class ACE_EXPORT SpanString : public SpanStringBase { - DECLARE_ACE_TYPE(SpanString, AceType); + DECLARE_ACE_TYPE(SpanString, SpanStringBase); public: SpanString(const SpanString& other); @@ -50,11 +50,17 @@ public: void NotifySpanWatcher(); const std::list>& GetSpanItems() const; static RefPtr GetDefaultSpanItem(const std::string& text); + void AddSpan(const RefPtr& span); protected: RefPtr GetSpan(int32_t start, int32_t length, SpanType spanType) const; void BindWithSpans(std::vector> spans); bool CheckRange(int32_t start, int32_t length, bool allowLengthZero = false) const; + void MergeIntervals(std::list>& spans); + void SplitInterval(std::list>& spans, std::pair interval); + void ApplyToSpans(const RefPtr& spans, std::pair interval); + void SortSpans(std::list>& spans); + bool CanMerge(const RefPtr& a, const RefPtr& b); std::string text_; std::unordered_map>> spansMap_; diff --git a/frameworks/core/components_ng/pattern/text/span_node.cpp b/frameworks/core/components_ng/pattern/text/span_node.cpp index b8982028861..6517d3a447c 100644 --- a/frameworks/core/components_ng/pattern/text/span_node.cpp +++ b/frameworks/core/components_ng/pattern/text/span_node.cpp @@ -473,6 +473,68 @@ bool SpanItem::IsDragging() return selectedStart >= 0 && selectedEnd >= 0; } +#define COPY_TEXT_STYLE(group, name, func) \ + do { \ + if ((group)->Has##name()) { \ + sameSpan->group->func((group)->prop##name.value()); \ + } \ + } while (false) + +RefPtr SpanItem::GetSameStyleSpanItem() const +{ + auto sameSpan = MakeRefPtr(); + COPY_TEXT_STYLE(fontStyle, FontSize, UpdateFontSize); + COPY_TEXT_STYLE(fontStyle, TextColor, UpdateTextColor); + COPY_TEXT_STYLE(fontStyle, TextShadow, UpdateTextShadow); + COPY_TEXT_STYLE(fontStyle, ItalicFontStyle, UpdateItalicFontStyle); + COPY_TEXT_STYLE(fontStyle, FontWeight, UpdateFontWeight); + COPY_TEXT_STYLE(fontStyle, FontFamily, UpdateFontFamily); + COPY_TEXT_STYLE(fontStyle, FontFeature, UpdateFontFeature); + COPY_TEXT_STYLE(fontStyle, TextDecoration, UpdateTextDecoration); + COPY_TEXT_STYLE(fontStyle, TextDecorationColor, UpdateTextDecorationColor); + COPY_TEXT_STYLE(fontStyle, TextDecorationStyle, UpdateTextDecorationStyle); + COPY_TEXT_STYLE(fontStyle, TextCase, UpdateTextCase); + COPY_TEXT_STYLE(fontStyle, AdaptMinFontSize, UpdateAdaptMinFontSize); + COPY_TEXT_STYLE(fontStyle, AdaptMaxFontSize, UpdateAdaptMaxFontSize); + COPY_TEXT_STYLE(fontStyle, LetterSpacing, UpdateLetterSpacing); + + COPY_TEXT_STYLE(textLineStyle, LineHeight, UpdateLineHeight); + COPY_TEXT_STYLE(textLineStyle, TextBaseline, UpdateTextBaseline); + COPY_TEXT_STYLE(textLineStyle, BaselineOffset, UpdateBaselineOffset); + COPY_TEXT_STYLE(textLineStyle, TextOverflow, UpdateTextOverflow); + COPY_TEXT_STYLE(textLineStyle, TextAlign, UpdateTextAlign); + COPY_TEXT_STYLE(textLineStyle, MaxLength, UpdateMaxLength); + COPY_TEXT_STYLE(textLineStyle, MaxLines, UpdateMaxLines); + COPY_TEXT_STYLE(textLineStyle, HeightAdaptivePolicy, UpdateHeightAdaptivePolicy); + COPY_TEXT_STYLE(textLineStyle, TextIndent, UpdateTextIndent); + COPY_TEXT_STYLE(textLineStyle, LeadingMargin, UpdateLeadingMargin); + COPY_TEXT_STYLE(textLineStyle, WordBreak, UpdateWordBreak); + COPY_TEXT_STYLE(textLineStyle, EllipsisMode, UpdateEllipsisMode); + + if (backgroundStyle.has_value()) { + sameSpan->backgroundStyle->backgroundColor = backgroundStyle->backgroundColor; + sameSpan->backgroundStyle->backgroundRadius = backgroundStyle->backgroundRadius; + sameSpan->backgroundStyle->groupId = backgroundStyle->groupId; + } + + sameSpan->onClick = onClick; + sameSpan->onLongPress = onLongPress; + return sameSpan; +} + +std::optional> SpanItem::GetIntersectionInterval(std::pair interval) const +{ + // Check the intersection + if (this->interval.second <= interval.first || interval.second <= this->interval.first) { + return std::nullopt; + } + + // Calculate the intersection interval + int start = std::max(this->interval.first, interval.first); + int end = std::min(this->interval.second, interval.second); + return std::make_optional>(std::make_pair(start, end)); +} + int32_t ImageSpanItem::UpdateParagraph(const RefPtr& /* frameNode */, const RefPtr& builder, double width, double height, VerticalAlign verticalAlign) { diff --git a/frameworks/core/components_ng/pattern/text/span_node.h b/frameworks/core/components_ng/pattern/text/span_node.h index f16f0d9e871..8b789099007 100644 --- a/frameworks/core/components_ng/pattern/text/span_node.h +++ b/frameworks/core/components_ng/pattern/text/span_node.h @@ -156,6 +156,7 @@ public: std::string description; std::string content; uint32_t unicode = 0; + std::pair interval; std::unique_ptr fontStyle = std::make_unique(); std::unique_ptr textLineStyle = std::make_unique(); // for text background style @@ -189,6 +190,8 @@ public: virtual void StartDrag(int32_t start, int32_t end); virtual void EndDrag(); virtual bool IsDragging(); + RefPtr GetSameStyleSpanItem() const; + std::optional> GetIntersectionInterval(std::pair interval) const; std::optional GetTextStyle() const { return textStyle_; diff --git a/frameworks/core/components_ng/pattern/text/text_model.h b/frameworks/core/components_ng/pattern/text/text_model.h index d0851d3f9f3..261a90f168f 100644 --- a/frameworks/core/components_ng/pattern/text/text_model.h +++ b/frameworks/core/components_ng/pattern/text/text_model.h @@ -41,6 +41,10 @@ public: virtual void CloseSelectionMenu() = 0; }; +class ACE_EXPORT SpanStringBase : public AceType { + DECLARE_ACE_TYPE(SpanStringBase, AceType); +}; + class ACE_EXPORT TextModel { public: static TextModel* GetInstance(); diff --git a/frameworks/core/components_ng/pattern/text_field/text_field_model.h b/frameworks/core/components_ng/pattern/text_field/text_field_model.h index 0251aa39c00..4fc798bc42f 100644 --- a/frameworks/core/components_ng/pattern/text_field/text_field_model.h +++ b/frameworks/core/components_ng/pattern/text_field/text_field_model.h @@ -43,6 +43,30 @@ struct Font { std::optional fontSize; std::optional fontStyle; std::vector fontFamilies; + std::optional fontColor; + std::optional> fontFamiliesNG; + + bool IsEqual(const Font& other) const + { + bool flag = fontWeight == other.fontWeight && fontSize == other.fontSize && fontStyle == other.fontStyle && + fontColor == other.fontColor; + if (!flag) { + return false; + } + if (fontFamiliesNG.has_value() && other.fontFamiliesNG) { + auto curFontFamilies = fontFamiliesNG.value(); + auto otherFontFamilies = other.fontFamiliesNG.value(); + if (curFontFamilies.size() !=otherFontFamilies.size()) { + return false; + } + for (size_t i = 0; i < curFontFamilies.size(); ++i) { + if (curFontFamilies[i] != otherFontFamilies[i]) { + return false; + } + } + } + return flag; + } }; struct CaretStyle { -- Gitee