• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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/span_string.h"
17 
18 #include <cstdint>
19 #include <iterator>
20 #include <utility>
21 
22 #include "base/utils/string_utils.h"
23 #include "base/utils/utils.h"
24 #include "core/components/common/properties/color.h"
25 #include "core/components_ng/pattern/text/span/span_object.h"
26 #include "core/components_ng/pattern/text/span_node.h"
27 #include "core/text/text_emoji_processor.h"
28 
29 namespace OHOS::Ace {
30 
31 const std::unordered_set<SpanType> specailTypes = { SpanType::Image, SpanType::CustomSpan };
32 
GetWideStringSubstr(const std::wstring & content,int32_t start,int32_t length)33 std::wstring SpanString::GetWideStringSubstr(const std::wstring& content, int32_t start, int32_t length)
34 {
35     if (start >= static_cast<int32_t>(content.length())) {
36         return StringUtils::ToWstring("");
37     }
38     return content.substr(start, length);
39 }
40 
GetWideStringSubstr(const std::wstring & content,int32_t start)41 std::wstring SpanString::GetWideStringSubstr(const std::wstring& content, int32_t start)
42 {
43     if (start >= static_cast<int32_t>(content.length())) {
44         return StringUtils::ToWstring("");
45     }
46     return content.substr(start);
47 }
48 
SpanString(const std::string & text)49 SpanString::SpanString(const std::string& text)
50 {
51     auto spanItem = MakeRefPtr<NG::SpanItem>();
52     std::wstring wideText = StringUtils::ToWstring(text);
53     if (wideText.length() == 0 && text.length() != 0) {
54         text_ = TextEmojiProcessor::ConvertU8stringUnpairedSurrogates(text);
55         wideText = StringUtils::ToWstring(text_);
56     } else {
57         text_ = text;
58     }
59     spanItem->content = text_;
60     spanItem->interval = { 0, wideText.length() };
61     spans_.emplace_back(spanItem);
62     auto it = spans_.begin();
63     SplitSpansAndForward(it);
64 }
65 
SpanString(const ImageSpanOptions & options)66 SpanString::SpanString(const ImageSpanOptions& options) : text_(" ")
67 {
68     auto spanItem = MakeRefPtr<NG::ImageSpanItem>();
69     spanItem->options = options;
70     spanItem->content = " ";
71     spanItem->interval = { 0, 1 };
72     spans_.emplace_back(spanItem);
73     spansMap_[SpanType::Image].emplace_back(MakeRefPtr<ImageSpan>(options));
74 }
75 
SpanString(RefPtr<CustomSpan> & span)76 SpanString::SpanString(RefPtr<CustomSpan>& span) : text_(" ")
77 {
78     auto spanItem = MakeRefPtr<NG::CustomSpanItem>();
79     spanItem->content = " ";
80     spanItem->interval = { 0, 1 };
81     spanItem->onMeasure = span->GetOnMeasure();
82     spanItem->onDraw = span->GetOnDraw();
83     spans_.emplace_back(spanItem);
84     spansMap_[SpanType::CustomSpan].emplace_back(span);
85 }
86 
AddCustomSpan()87 void SpanString::AddCustomSpan()
88 {
89     auto spanBases = GetSpans(0, GetLength(), SpanType::CustomSpan);
90     for (const auto& spanBase : spanBases) {
91         if (spanBase->GetSpanType() != SpanType::CustomSpan) {
92             continue;
93         }
94         auto customSpan = DynamicCast<CustomSpan>(spanBase);
95         if (!customSpan) {
96             continue;
97         }
98         customSpan->AddStyledString(Referenced::WeakClaim(this));
99     }
100 }
101 
RemoveCustomSpan()102 void SpanString::RemoveCustomSpan()
103 {
104     auto spanBases = GetSpans(0, GetLength(), SpanType::CustomSpan);
105     for (const auto& spanBase : spanBases) {
106         if (spanBase->GetSpanType() != SpanType::CustomSpan) {
107             continue;
108         }
109         auto customSpan = DynamicCast<CustomSpan>(spanBase);
110         if (!customSpan) {
111             continue;
112         }
113         customSpan->RemoveStyledString(Referenced::WeakClaim(this));
114     }
115 }
SetFramNode(const WeakPtr<NG::FrameNode> & frameNode)116 void SpanString::SetFramNode(const WeakPtr<NG::FrameNode>& frameNode)
117 {
118     framNode_ = frameNode;
119 }
120 
MarkDirtyFrameNode()121 void SpanString::MarkDirtyFrameNode()
122 {
123     auto frameNode = framNode_.Upgrade();
124     CHECK_NULL_VOID(frameNode);
125     frameNode->MarkDirtyNode(NG::PROPERTY_UPDATE_RENDER);
126 }
127 
~SpanString()128 SpanString::~SpanString()
129 {
130     spansMap_.clear();
131     spans_.clear();
132 }
133 
SplitSpansAndForward(std::list<RefPtr<NG::SpanItem>>::iterator & it)134 std::list<RefPtr<NG::SpanItem>>::iterator SpanString::SplitSpansAndForward(
135     std::list<RefPtr<NG::SpanItem>>::iterator& it)
136 {
137     auto wString = StringUtils::ToWstring((*it)->content);
138     auto newlineIndex = static_cast<int32_t>(wString.find(L'\n'));
139     int32_t offset = (*it)->interval.first;
140     while (newlineIndex != -1 && newlineIndex != static_cast<int32_t>(wString.size()) - 1) {
141         auto newSpan = (*it)->GetSameStyleSpanItem();
142         newSpan->interval = { offset + newlineIndex + 1, (*it)->interval.second };
143         (*it)->interval = { offset, offset + newlineIndex + 1 };
144         (*it)->content = StringUtils::ToString(GetWideStringSubstr(wString, 0, newlineIndex + 1));
145         wString = GetWideStringSubstr(wString, newlineIndex + 1);
146         newSpan->content = StringUtils::ToString(wString);
147         newlineIndex = static_cast<int32_t>(wString.find(L'\n'));
148 
149         offset = newSpan->interval.first;
150         ++it;
151         it = spans_.insert(it, newSpan);
152     }
153 
154     return std::next(it);
155 }
156 
ApplyToSpans(const RefPtr<SpanBase> & span,std::pair<int32_t,int32_t> interval,SpanOperation operation)157 void SpanString::ApplyToSpans(
158     const RefPtr<SpanBase>& span, std::pair<int32_t, int32_t> interval, SpanOperation operation)
159 {
160     for (auto it = spans_.begin(); it != spans_.end(); ++it) {
161         auto intersection = (*it)->GetIntersectionInterval(interval);
162         if (!intersection) {
163             continue;
164         }
165         auto oldStart = (*it)->interval.first;
166         auto oldEnd = (*it)->interval.second;
167         if (oldStart == intersection->first && intersection->second == oldEnd) {
168             span->ApplyToSpanItem(*it, operation);
169             continue;
170         }
171 
172         auto wContent = StringUtils::ToWstring((*it)->content);
173         auto newSpan = (*it)->GetSameStyleSpanItem();
174         if (oldStart < intersection->first && intersection->second < oldEnd) {
175             (*it)->interval = { oldStart, intersection->first };
176             (*it)->content = StringUtils::ToString(wContent.substr(0, intersection->first - oldStart));
177 
178             newSpan->interval = { intersection->first, intersection->second };
179             newSpan->content = StringUtils::ToString(
180                 wContent.substr(intersection->first - oldStart, intersection->second - intersection->first));
181             span->ApplyToSpanItem(newSpan, operation);
182 
183             auto newSpan2 = (*it)->GetSameStyleSpanItem();
184             newSpan2->interval = { intersection->second, oldEnd };
185             newSpan2->content = StringUtils::ToString(wContent.substr(intersection->second - oldStart));
186             it = spans_.insert(std::next(it), newSpan);
187             it = spans_.insert(std::next(it), newSpan2);
188             continue;
189         }
190 
191         if (oldEnd > intersection->second) {
192             (*it)->content = StringUtils::ToString(wContent.substr(0, intersection->second - oldStart));
193             (*it)->interval = { oldStart, intersection->second };
194             span->ApplyToSpanItem(*it, operation);
195             newSpan->interval = { intersection->second, oldEnd };
196             newSpan->content = StringUtils::ToString(wContent.substr(intersection->second - oldStart));
197             it = spans_.insert(std::next(it), newSpan);
198             continue;
199         }
200 
201         if (intersection->first > oldStart) {
202             (*it)->content = StringUtils::ToString(wContent.substr(0, intersection->first - oldStart));
203             (*it)->interval = { oldStart, intersection->first };
204             newSpan->interval = { intersection->first, oldEnd };
205             newSpan->content = StringUtils::ToString(wContent.substr(intersection->first - oldStart));
206             span->ApplyToSpanItem(newSpan, operation);
207             it = spans_.insert(std::next(it), newSpan);
208         }
209     }
210 }
211 
SplitInterval(std::list<RefPtr<SpanBase>> & spans,std::pair<int32_t,int32_t> interval)212 void SpanString::SplitInterval(std::list<RefPtr<SpanBase>>& spans, std::pair<int32_t, int32_t> interval)
213 {
214     std::list<RefPtr<SpanBase>> newSpans;
215     for (auto it = spans.begin(); it != spans.end();) {
216         auto intersection = (*it)->GetIntersectionInterval(interval);
217         if (!intersection) {
218             ++it;
219             continue;
220         }
221         auto oldStart = (*it)->GetStartIndex();
222         auto oldEnd = (*it)->GetEndIndex();
223         if (intersection->first == oldStart && intersection->second == oldEnd) {
224             it = spans.erase(it);
225             continue;
226         }
227         if (oldStart < intersection->first && intersection->second < oldEnd) {
228             newSpans.emplace_back((*it)->GetSubSpan(oldStart, intersection->first));
229             newSpans.emplace_back((*it)->GetSubSpan(intersection->second, oldEnd));
230             it = spans.erase(it);
231             continue;
232         }
233         if (oldEnd > intersection->second) {
234             (*it)->UpdateStartIndex(intersection->second);
235             ++it;
236             continue;
237         }
238         if (intersection->first > oldStart) {
239             (*it)->UpdateEndIndex(intersection->first);
240             ++it;
241         }
242     }
243     spans.merge(newSpans);
244 }
245 
SortSpans(std::list<RefPtr<SpanBase>> & spans)246 void SpanString::SortSpans(std::list<RefPtr<SpanBase>>& spans)
247 {
248     spans.sort(
249         [](const RefPtr<SpanBase>& a, const RefPtr<SpanBase>& b) { return a->GetStartIndex() < b->GetStartIndex(); });
250 }
251 
CanMerge(const RefPtr<SpanBase> & a,const RefPtr<SpanBase> & b)252 bool SpanString::CanMerge(const RefPtr<SpanBase>& a, const RefPtr<SpanBase>& b)
253 {
254     return a->GetEndIndex() >= b->GetStartIndex() && a->IsAttributesEqual(b);
255 }
256 
MergeIntervals(std::list<RefPtr<SpanBase>> & spans)257 void SpanString::MergeIntervals(std::list<RefPtr<SpanBase>>& spans)
258 {
259     auto it = spans.begin();
260     while (it != spans.end()) {
261         auto spanType = (*it)->GetSpanType();
262         if (spanType == SpanType::Image || spanType == SpanType::CustomSpan) {
263             return;
264         }
265         auto current = it++;
266         if (it != spans.end() && CanMerge(*current, *it)) {
267             (*current)->UpdateStartIndex(std::min((*current)->GetStartIndex(), (*it)->GetStartIndex()));
268             (*current)->UpdateEndIndex(std::max((*current)->GetEndIndex(), (*it)->GetEndIndex()));
269             spans.erase(it++);
270             if (it == spans.end()) {
271                 break;
272             }
273             it = current;
274         }
275     }
276 }
277 
GetStepsByPosition(int32_t pos)278 int32_t SpanString::GetStepsByPosition(int32_t pos)
279 {
280     if (pos == 0) {
281         return 0;
282     }
283     int32_t step = 0;
284     for (auto iter = spans_.begin(); iter != spans_.end(); ++iter) {
285         if ((*iter)->interval.first == pos) {
286             return step;
287         }
288         if ((*iter)->interval.first < pos && pos < (*iter)->interval.second) {
289             auto spanItem = (*iter)->GetSameStyleSpanItem();
290             spanItem->interval.first = pos;
291             spanItem->interval.second = (*iter)->interval.second;
292             auto wStr = StringUtils::ToWstring(spanItem->content);
293             auto start = (*iter)->interval.first;
294             spanItem->content = StringUtils::ToString(wStr.substr(pos - start));
295             spans_.insert(std::next(iter), spanItem);
296             (*iter)->interval.second = pos;
297             (*iter)->content = StringUtils::ToString(wStr.substr(0, pos - start));
298             return step;
299         }
300         step++;
301     }
302     return step;
303 }
304 
AddSpecialSpan(const RefPtr<SpanBase> & span,SpanType type,int32_t start)305 void SpanString::AddSpecialSpan(const RefPtr<SpanBase>& span, SpanType type, int32_t start)
306 {
307     auto wStr = GetWideString();
308     text_ = StringUtils::ToString(
309         wStr.substr(0, start) + StringUtils::ToWstring(" ") + wStr.substr(start));
310     auto iter = spans_.begin();
311     auto step = GetStepsByPosition(start);
312     std::advance(iter, step);
313     RefPtr<NG::SpanItem> spanItem;
314     if (type == SpanType::Image) {
315         auto imageSpan = DynamicCast<ImageSpan>(span);
316         CHECK_NULL_VOID(imageSpan);
317         spanItem = MakeImageSpanItem(imageSpan);
318     } else if (type == SpanType::CustomSpan) {
319         auto customSpan = AceType::DynamicCast<CustomSpan>(span);
320         CHECK_NULL_VOID(customSpan);
321         spanItem = MakeCustomSpanItem(customSpan);
322     }
323     iter = spans_.insert(iter, spanItem);
324     for (++iter; iter != spans_.end(); ++iter) {
325         ++(*iter)->interval.first;
326         ++(*iter)->interval.second;
327     }
328 
329     UpdateSpanMapWithOffset(start - 1, 1);
330     if (spansMap_.find(type) == spansMap_.end()) {
331         spansMap_[type].emplace_back(span);
332     } else {
333         auto specialList = spansMap_[type];
334         int32_t step = 0;
335         for (const auto& specialSpan : specialList) {
336             if (specialSpan->GetStartIndex() >= start) {
337                 break;
338             }
339             ++step;
340         }
341         auto iter = specialList.begin();
342         std::advance(iter, step);
343         specialList.insert(iter, span);
344         spansMap_[type] = specialList;
345     }
346 }
347 
MakeImageSpanItem(const RefPtr<ImageSpan> & imageSpan)348 RefPtr<NG::ImageSpanItem> SpanString::MakeImageSpanItem(const RefPtr<ImageSpan>& imageSpan)
349 {
350     auto spanItem = MakeRefPtr<NG::ImageSpanItem>();
351     spanItem->content = " ";
352     spanItem->interval.first = imageSpan->GetStartIndex();
353     spanItem->interval.second = imageSpan->GetEndIndex();
354     spanItem->SetImageSpanOptions(imageSpan->GetImageSpanOptions());
355     return spanItem;
356 }
357 
MakeCustomSpanItem(const RefPtr<CustomSpan> & customSpan)358 RefPtr<NG::CustomSpanItem> SpanString::MakeCustomSpanItem(const RefPtr<CustomSpan>& customSpan)
359 {
360     auto spanItem = MakeRefPtr<NG::CustomSpanItem>();
361     spanItem->content = " ";
362     spanItem->interval.first = customSpan->GetStartIndex();
363     spanItem->interval.second = customSpan->GetEndIndex();
364     spanItem->onDraw = customSpan->GetOnDraw();
365     spanItem->onMeasure = customSpan->GetOnMeasure();
366     return spanItem;
367 }
368 
ChangeStartAndEndToCorrectNum(int32_t & start,int32_t & end)369 void SpanString::ChangeStartAndEndToCorrectNum(int32_t& start, int32_t& end)
370 {
371     auto text = GetWideString();
372     TextEmojiSubStringRange range = TextEmojiProcessor::CalSubWstringRange(
373         start, end-start, text, true);
374     int startIndex = range.startIndex;
375     int endIndex = range.endIndex;
376 
377     if (start == startIndex) {
378         ChangeStartToCorrectNum(start);
379     } else {
380         LOGI("SpanString: Get Emoji, Change Start %{public}d to %{public}d",
381             start, startIndex);
382         start = startIndex;
383     }
384 
385     if (end == endIndex) {
386         ChangeEndToCorrectNum(end);
387     } else {
388         LOGI("SpanString: Get Emoji, Change End %{public}d to %{public}d",
389             end, endIndex);
390         end = endIndex;
391     }
392 
393     if (end < start) {
394         std::swap(start, end);
395     }
396 }
397 
ChangeStartToCorrectNum(int32_t & start)398 void SpanString::ChangeStartToCorrectNum(int32_t& start)
399 {
400     if (start == 0) {
401         return;
402     }
403     auto text = GetWideString();
404     auto textLen = static_cast<int32_t>(text.length());
405     if (textLen == 0) {
406         return;
407     }
408     auto tmpStart = start;
409     auto substr = StringUtils::ToString(GetWideStringSubstr(text, 0, tmpStart));
410     while (substr.length() == 0) {
411         if (tmpStart == textLen) {
412             break;
413         }
414         tmpStart --;
415         if (tmpStart <= 0) {
416             break;
417         }
418         substr = StringUtils::ToString(GetWideStringSubstr(text, 0, tmpStart));
419     }
420     if (tmpStart != start) {
421         LOGI("SpanString: Get Complex Char, Change Start %{public}d to %{public}d", start, tmpStart);
422         start = tmpStart;
423     }
424 }
425 
ChangeEndToCorrectNum(int32_t & end)426 void SpanString::ChangeEndToCorrectNum(int32_t& end)
427 {
428     auto text = GetWideString();
429     auto textLen = static_cast<int32_t>(text.length());
430     if (textLen == 0) {
431         return;
432     }
433     auto tmpEnd = end;
434     auto substr = StringUtils::ToString(GetWideStringSubstr(text, end));
435     while (substr.length() == 0) {
436         if (tmpEnd == textLen) {
437             break;
438         }
439         tmpEnd ++;
440         if (tmpEnd >= textLen) {
441             break;
442         }
443         substr = StringUtils::ToString(GetWideStringSubstr(text, tmpEnd));
444     }
445     if (tmpEnd != end) {
446         LOGI("SpanString: Get Complex Char, Change End %{public}d to %{public}d", end, tmpEnd);
447         end = tmpEnd;
448     }
449 }
450 
AddSpan(const RefPtr<SpanBase> & span)451 void SpanString::AddSpan(const RefPtr<SpanBase>& span)
452 {
453     if (!span || !CheckRange(span)) {
454         return;
455     }
456     auto start = span->GetStartIndex();
457     auto end = span->GetEndIndex();
458     ChangeStartAndEndToCorrectNum(start, end);
459     if (span->GetSpanType() == SpanType::Image || span->GetSpanType() == SpanType::CustomSpan) {
460         AddSpecialSpan(span, span->GetSpanType(), start);
461         return;
462     }
463     if (spansMap_.find(span->GetSpanType()) == spansMap_.end()) {
464         spansMap_[span->GetSpanType()].emplace_back(span);
465         ApplyToSpans(span, { start, end }, SpanOperation::ADD);
466         return;
467     }
468     RemoveSpan(start, end - start, span->GetSpanType());
469     auto spans = spansMap_[span->GetSpanType()];
470     ApplyToSpans(span, { start, end }, SpanOperation::ADD);
471     SplitInterval(spans, { start, end });
472     spans.emplace_back(span);
473     SortSpans(spans);
474     MergeIntervals(spans);
475     spansMap_[span->GetSpanType()] = spans;
476 }
477 
RemoveSpan(int32_t start,int32_t length,SpanType key)478 void SpanString::RemoveSpan(int32_t start, int32_t length, SpanType key)
479 {
480     if (!CheckRange(start, length)) {
481         return;
482     }
483     auto end = start + length;
484     ChangeStartAndEndToCorrectNum(start, end);
485     length = end - start;
486     auto it = spansMap_.find(key);
487     if (it == spansMap_.end()) {
488         return;
489     }
490     auto spans = spansMap_[key];
491     if (key == SpanType::Image) {
492         RemoveSpecialSpan(start, end, key);
493         return;
494     }
495     if (key == SpanType::CustomSpan) {
496         RemoveSpecialSpan(start, end, key);
497         return;
498     }
499     auto defaultSpan = GetDefaultSpan(key);
500     CHECK_NULL_VOID(defaultSpan);
501     defaultSpan->UpdateStartIndex(start);
502     defaultSpan->UpdateEndIndex(end);
503     ApplyToSpans(defaultSpan, { start, end }, SpanOperation::REMOVE);
504     SplitInterval(spans, { start, end });
505     SortSpans(spans);
506     MergeIntervals(spans);
507     if (spans.empty()) {
508         spansMap_.erase(key);
509     } else {
510         spansMap_[key] = spans;
511     }
512 }
513 
GetDefaultSpan(SpanType type)514 RefPtr<SpanBase> SpanString::GetDefaultSpan(SpanType type)
515 {
516     switch (type) {
517         case SpanType::Font:
518             return MakeRefPtr<FontSpan>();
519         case SpanType::TextShadow:
520             return MakeRefPtr<TextShadowSpan>();
521         case SpanType::Gesture:
522             return MakeRefPtr<GestureSpan>();
523         case SpanType::Decoration:
524             return MakeRefPtr<DecorationSpan>();
525         case SpanType::BaselineOffset:
526             return MakeRefPtr<BaselineOffsetSpan>();
527         case SpanType::LetterSpacing:
528             return MakeRefPtr<LetterSpacingSpan>();
529         case SpanType::ParagraphStyle:
530             return MakeRefPtr<ParagraphStyleSpan>();
531         case SpanType::LineHeight:
532             return MakeRefPtr<LineHeightSpan>();
533         case SpanType::ExtSpan:
534             return MakeRefPtr<ExtSpan>();
535         default:
536             return nullptr;
537     }
538 }
539 
CheckRange(const RefPtr<SpanBase> & spanBase) const540 bool SpanString::CheckRange(const RefPtr<SpanBase>& spanBase) const
541 {
542     auto start = spanBase->GetStartIndex();
543     auto length = spanBase->GetLength();
544     if (length <= 0) {
545         return false;
546     }
547     auto spanType = spanBase->GetSpanType();
548     auto len = spanType == SpanType::Image || spanType == SpanType::CustomSpan ? GetLength() + 1 : GetLength();
549     auto end = start + length;
550 
551     if (start > len || end > len) {
552         return false;
553     }
554 
555     if (start < 0) {
556         return false;
557     }
558 
559     return true;
560 }
561 
CheckRange(int32_t start,int32_t length,bool allowLengthZero) const562 bool SpanString::CheckRange(int32_t start, int32_t length, bool allowLengthZero) const
563 {
564     if (length < 0 || (length == 0 && !allowLengthZero)) {
565         return false;
566     }
567 
568     auto len = GetLength();
569     auto end = start + length;
570 
571     if (start > len || end > len) {
572         return false;
573     }
574 
575     if (start < 0) {
576         return false;
577     }
578 
579     return true;
580 }
581 
GetDefaultSpanItem(const std::string & text)582 RefPtr<NG::SpanItem> SpanString::GetDefaultSpanItem(const std::string& text)
583 {
584     auto spanItem = MakeRefPtr<NG::SpanItem>();
585     spanItem->content = text;
586     spanItem->interval = { 0, StringUtils::ToWstring(text).length() };
587     return spanItem;
588 }
589 
SetString(const std::string & text)590 void SpanString::SetString(const std::string& text)
591 {
592     text_ = text;
593 }
594 
SetSpanItems(const std::list<RefPtr<NG::SpanItem>> && spanItems)595 void SpanString::SetSpanItems(const std::list<RefPtr<NG::SpanItem>>&& spanItems)
596 {
597     spans_ = spanItems;
598 }
599 
SetSpanMap(std::unordered_map<SpanType,std::list<RefPtr<SpanBase>>> && spansMap)600 void SpanString::SetSpanMap(std::unordered_map<SpanType, std::list<RefPtr<SpanBase>>>&& spansMap)
601 {
602     spansMap_ = spansMap;
603 }
604 
GetString() const605 const std::string& SpanString::GetString() const
606 {
607     return text_;
608 }
609 
GetWideString()610 std::wstring SpanString::GetWideString()
611 {
612     return StringUtils::ToWstring(text_);
613 }
614 
GetLength() const615 int32_t SpanString::GetLength() const
616 {
617     return StringUtils::ToWstring(text_).length();
618 }
619 
IsEqualToSpanString(const RefPtr<SpanString> & other) const620 bool SpanString::IsEqualToSpanString(const RefPtr<SpanString>& other) const
621 {
622     return *this == *other;
623 }
624 
GetSubSpanString(int32_t start,int32_t length) const625 RefPtr<SpanString> SpanString::GetSubSpanString(int32_t start, int32_t length) const
626 {
627     if (!CheckRange(start, length)) {
628         RefPtr<SpanString> span = AceType::MakeRefPtr<SpanString>("");
629         return span;
630     }
631     int32_t end = start + length;
632     RefPtr<SpanString> span =
633         AceType::MakeRefPtr<SpanString>(StringUtils::ToString(StringUtils::ToWstring(text_).substr(start, length)));
634     std::unordered_map<SpanType, std::list<RefPtr<SpanBase>>> subMap;
635     for (const auto& map : spansMap_) {
636         auto subList = GetSubSpanList(start, length, map.second);
637         if (!subList.empty()) {
638             subMap.insert({ map.first, subList });
639         }
640     }
641     span->spansMap_ = subMap;
642 
643     std::list<RefPtr<NG::SpanItem>> subSpans_;
644     for (const auto& spanItem : spans_) {
645         auto intersection = spanItem->GetIntersectionInterval({start, start+length});
646         if (intersection) {
647             int32_t oldStart = spanItem->interval.first;
648             int32_t oldEnd = spanItem->interval.second;
649             auto spanStart = oldStart <= start ? 0 : oldStart - start;
650             auto spanEnd = oldEnd < end ? oldEnd - start : end - start;
651             auto newSpanItem = spanItem->GetSameStyleSpanItem();
652             newSpanItem->interval = { spanStart, spanEnd };
653             newSpanItem->content = StringUtils::ToString(
654                 StringUtils::ToWstring(spanItem->content)
655                     .substr(std::max(start - oldStart, 0), std::min(end, oldEnd) - std::max(start, oldStart)));
656             subSpans_.emplace_back(newSpanItem);
657         }
658     }
659     span->spans_ = subSpans_;
660     return span;
661 }
662 
GetSubSpanList(int32_t start,int32_t length,const std::list<RefPtr<SpanBase>> & spans) const663 std::list<RefPtr<SpanBase>> SpanString::GetSubSpanList(
664     int32_t start, int32_t length, const std::list<RefPtr<SpanBase>>& spans) const
665 {
666     std::list<RefPtr<SpanBase>> res;
667     int32_t end = start + length;
668     for (auto& span : spans) {
669         auto intersection = span->GetIntersectionInterval({ start, end });
670         if (intersection) {
671             int32_t spanStart = span->GetStartIndex();
672             int32_t spanEnd = span->GetEndIndex();
673             spanStart = spanStart <= start ? 0 : spanStart - start;
674             spanEnd = spanEnd < end ? spanEnd - start : end - start;
675             if (spanStart == spanEnd) {
676                 continue;
677             }
678             res.emplace_back(span->GetSubSpan(spanStart, spanEnd));
679         }
680     }
681     return res;
682 }
683 
GetSpansMap() const684 const std::unordered_map<SpanType, std::list<RefPtr<SpanBase>>>& SpanString::GetSpansMap() const
685 {
686     return spansMap_;
687 }
688 
GetSpans(int32_t start,int32_t length) const689 std::vector<RefPtr<SpanBase>> SpanString::GetSpans(int32_t start, int32_t length) const
690 {
691     std::vector<RefPtr<SpanBase>> res;
692     if (!CheckRange(start, length)) {
693         return res;
694     }
695 
696     for (const auto& map : spansMap_) {
697         auto spans = GetSpans(start, length, map.first);
698         res.insert(res.begin(), spans.begin(), spans.end());
699     }
700     return res;
701 }
702 
GetSpans(int32_t start,int32_t length,SpanType spanType) const703 std::vector<RefPtr<SpanBase>> SpanString::GetSpans(int32_t start, int32_t length, SpanType spanType) const
704 {
705     std::vector<RefPtr<SpanBase>> res;
706     if (!CheckRange(start, length)) {
707         return res;
708     }
709     int32_t end = start + length;
710     RefPtr<SpanBase> span;
711     while ((span = GetSpan(start, length, spanType)) != nullptr) {
712         res.emplace_back(span);
713         start = span->GetEndIndex();
714         length = end - start;
715     }
716     return res;
717 }
718 
GetSpan(int32_t start,int32_t length,SpanType spanType) const719 RefPtr<SpanBase> SpanString::GetSpan(int32_t start, int32_t length, SpanType spanType) const
720 {
721     if (!CheckRange(start, length) || spansMap_.find(spanType) == spansMap_.end()) {
722         return nullptr;
723     }
724     int32_t end = start + length;
725     auto spanBaseList = spansMap_.find(spanType)->second;
726     for (auto& spanBase : spanBaseList) {
727         auto intersection = spanBase->GetIntersectionInterval({ start, end });
728         if (intersection) {
729             int32_t newStart = intersection->first;
730             int32_t newEnd = intersection->second;
731             if (newStart == newEnd) {
732                 continue;
733             }
734             return spanBase->GetSubSpan(newStart, newEnd);
735         }
736     }
737     return nullptr;
738 }
739 
operator ==(const SpanString & other) const740 bool SpanString::operator==(const SpanString& other) const
741 {
742     if (text_ != other.text_) {
743         return false;
744     }
745     auto size =
746         !spansMap_.empty()
747             ? (static_cast<int32_t>(spansMap_.size()) - (spansMap_.find(SpanType::Gesture) == spansMap_.end() ? 0 : 1))
748             : 0;
749     auto sizeOther = !other.spansMap_.empty()
750                          ? (static_cast<int32_t>(other.spansMap_.size()) -
751                                (other.spansMap_.find(SpanType::Gesture) == other.spansMap_.end() ? 0 : 1))
752                          : 0;
753     if (size != sizeOther) {
754         return false;
755     }
756 
757     for (const auto& map : spansMap_) {
758         if (map.first == SpanType::Gesture) {
759             continue;
760         }
761         auto spansOtherMap = other.spansMap_.find(map.first);
762         if (spansOtherMap == other.spansMap_.end()) {
763             return false;
764         }
765         auto spans = map.second;
766         auto spansOther = spansOtherMap->second;
767         if (spans.size() != spansOther.size()) {
768             return false;
769         }
770         for (auto spansItr = spans.begin(), spansOtherItr = spansOther.begin();
771              spansItr != spans.end() && spansOtherItr != spansOther.end(); ++spansItr, ++spansOtherItr) {
772             if (!(*spansItr)->IsAttributesEqual(*spansOtherItr) ||
773                 (*spansItr)->GetEndIndex() != (*spansOtherItr)->GetEndIndex() ||
774                 (*spansItr)->GetStartIndex() != (*spansOtherItr)->GetStartIndex()) {
775                 return false;
776             }
777         }
778     }
779     return true;
780 }
781 
GetSpanItems() const782 std::list<RefPtr<NG::SpanItem>> SpanString::GetSpanItems() const
783 {
784     return spans_;
785 }
786 
BindWithSpans(const std::vector<RefPtr<SpanBase>> & spans)787 void SpanString::BindWithSpans(const std::vector<RefPtr<SpanBase>>& spans)
788 {
789     for (auto& span : spans) {
790         AddSpan(span);
791     }
792 }
793 
UpdateSpansWithOffset(int32_t start,int32_t offset)794 void SpanString::UpdateSpansWithOffset(int32_t start, int32_t offset)
795 {
796     for (auto& span : spans_) {
797         if (span->interval.second > start && span->interval.first != start) {
798             span->interval.second += offset;
799         }
800         if (span->interval.first > start) {
801             span->interval.first += offset;
802         }
803     }
804 }
805 
UpdateSpanMapWithOffset(int32_t start,int32_t offset)806 void SpanString::UpdateSpanMapWithOffset(int32_t start, int32_t offset)
807 {
808     for (auto& iter : spansMap_) {
809         if (spansMap_.find(iter.first) == spansMap_.end()) {
810             continue;
811         }
812         auto spans = spansMap_[iter.first];
813         for (auto& it : spans) {
814             UpdateSpanBaseWithOffset(it, start, offset);
815         }
816         spansMap_[iter.first] = spans;
817     }
818 }
819 
UpdateSpanBaseWithOffset(RefPtr<SpanBase> & span,int32_t start,int32_t offset)820 void SpanString::UpdateSpanBaseWithOffset(RefPtr<SpanBase>& span, int32_t start, int32_t offset)
821 {
822     if (span->GetEndIndex() > start && span->GetStartIndex() != start) {
823         span->UpdateEndIndex(span->GetEndIndex() + offset);
824     }
825     if (span->GetStartIndex() > start) {
826         span->UpdateStartIndex(span->GetStartIndex() + offset);
827     }
828 }
829 
RemoveSpecialSpan(int32_t start,int32_t end,SpanType type)830 void SpanString::RemoveSpecialSpan(int32_t start, int32_t end, SpanType type)
831 {
832     auto spans = spansMap_[type];
833     int32_t count = 0;
834     for (auto iter = spans.begin(); iter != spans.end();) {
835         if ((*iter)->GetStartIndex() >= start && (*iter)->GetStartIndex() < end - count) {
836             auto wStr = GetWideString();
837             wStr.erase((*iter)->GetStartIndex(), 1);
838             text_ = StringUtils::ToString(wStr);
839             UpdateSpanMapWithOffset((*iter)->GetStartIndex(), -1);
840             iter = spans.erase(iter);
841             ++count;
842             continue;
843         }
844         ++iter;
845     }
846     if (spans.empty()) {
847         spansMap_.erase(type);
848     } else {
849         spansMap_[type] = spans;
850     }
851     count = 0;
852     for (auto iter = spans_.begin(); iter != spans_.end();) {
853         if ((*iter)->interval.first >= start && (*iter)->interval.first < end - count
854             && ((type == SpanType::Image && (*iter)->spanItemType == NG::SpanItemType::IMAGE)
855                 || (type == SpanType::CustomSpan && (*iter)->spanItemType == NG::SpanItemType::CustomSpan))) {
856             UpdateSpansWithOffset((*iter)->interval.first, -1);
857             iter = spans_.erase(iter);
858             ++count;
859             continue;
860         }
861         ++iter;
862     }
863 }
864 
GetSpecialTypesVector(std::list<int32_t> & indexList,int32_t start,int32_t length)865 void SpanString::GetSpecialTypesVector(std::list<int32_t>& indexList, int32_t start, int32_t length)
866 {
867     int32_t end = start + length;
868     auto iter = indexList.begin();
869     for (const auto& type : specailTypes) {
870         auto spans = spansMap_[type];
871         for (const auto& span : spans) {
872             auto intersection = span->GetIntersectionInterval({ start, end });
873             if (!intersection) {
874                 continue;
875             }
876             iter = indexList.insert(iter, span->GetStartIndex());
877         }
878     }
879     indexList.sort([](const int32_t& a, const int32_t& b) { return a < b; });
880 }
881 
GetNormalTypesVector(std::list<std::pair<int32_t,int32_t>> & indexList,int32_t start,int32_t length)882 void SpanString::GetNormalTypesVector(std::list<std::pair<int32_t, int32_t>>& indexList, int32_t start, int32_t length)
883 {
884     std::list<int32_t> specialList;
885     GetSpecialTypesVector(specialList, start, length);
886     auto next = start;
887     auto iter = indexList.begin();
888     for (const auto& index : specialList) {
889         if (index > next) {
890             iter = indexList.insert(iter, { next, index - next });
891         }
892         next = index + 1;
893     }
894     if (next < start + length) {
895         indexList.insert(iter, { next, start + length - next });
896     }
897 }
898 
ContainSpecialNode(int32_t start,int32_t length)899 bool SpanString::ContainSpecialNode(int32_t start, int32_t length)
900 {
901     int32_t end = start + length;
902     for (const auto& type : specailTypes) {
903         auto spans = spansMap_[type];
904         for (const auto& span : spans) {
905             auto intersection = span->GetIntersectionInterval({ start, end });
906             if (intersection) {
907                 return true;
908             }
909             if (span->GetStartIndex() >= end) {
910                 break;
911             }
912         }
913     }
914     return false;
915 }
916 
IsSpecialNode(RefPtr<SpanBase> span)917 bool SpanString::IsSpecialNode(RefPtr<SpanBase> span)
918 {
919     auto type = span->GetSpanType();
920     if (specailTypes.find(type) == specailTypes.end()) {
921         return false;
922     }
923     return true;
924 }
925 
ClearSpans()926 void SpanString::ClearSpans()
927 {
928     spans_.clear();
929 }
930 
AppendSpanItem(const RefPtr<NG::SpanItem> & spanItem)931 void SpanString::AppendSpanItem(const RefPtr<NG::SpanItem>& spanItem)
932 {
933     spans_.emplace_back(spanItem);
934 }
935 
EncodeTlv(std::vector<uint8_t> & buff)936 bool SpanString::EncodeTlv(std::vector<uint8_t>& buff)
937 {
938     TLVUtil::WriteUint8(buff, TLV_SPAN_STRING_SPANS);
939     TLVUtil::WriteInt32(buff, spans_.size());
940     for (auto it = spans_.begin(); it != spans_.end(); ++it) {
941         auto spanItem = (*it);
942         if (spanItem->spanItemType == NG::SpanItemType::CustomSpan) {
943             TLVUtil::WriteInt32(buff, static_cast<int32_t>(NG::SpanItemType::NORMAL));
944             auto placeHolderSpan = AceType::MakeRefPtr<NG::SpanItem>();
945             placeHolderSpan->content = " ";
946             placeHolderSpan->interval = spanItem->interval;
947             placeHolderSpan->EncodeTlv(buff);
948             continue;
949         }
950         TLVUtil::WriteInt32(buff, static_cast<int32_t>(spanItem->spanItemType));
951         spanItem->EncodeTlv(buff);
952     }
953     TLVUtil::WriteUint8(buff, TLV_SPAN_STRING_CONTENT);
954     TLVUtil::WriteString(buff, text_);
955     TLVUtil::WriteUint8(buff, TLV_END);
956     return true;
957 }
958 
DecodeTlv(std::vector<uint8_t> & buff)959 RefPtr<SpanString> SpanString::DecodeTlv(std::vector<uint8_t>& buff)
960 {
961     int32_t cursor = 0;
962     RefPtr<SpanString> spanStr = MakeRefPtr<SpanString>("");
963     spanStr->ClearSpans();
964     for (uint8_t tag = TLVUtil::ReadUint8(buff, cursor); tag != TLV_END; tag = TLVUtil::ReadUint8(buff, cursor)) {
965         switch (tag) {
966             case TLV_SPAN_STRING_CONTENT: {
967                 auto str = TLVUtil::ReadString(buff, cursor);
968                 spanStr->SetString(str);
969                 break;
970             }
971             case TLV_SPAN_STRING_SPANS: {
972                 DecodeSpanItemList(buff, cursor, spanStr);
973                 break;
974             }
975             default:
976                 break;
977         }
978     }
979     return spanStr;
980 }
981 
DecodeSpanItemList(std::vector<uint8_t> & buff,int32_t & cursor,RefPtr<SpanString> & spanStr)982 void SpanString::DecodeSpanItemList(std::vector<uint8_t>& buff, int32_t& cursor, RefPtr<SpanString>& spanStr)
983 {
984     int32_t spanLength = TLVUtil::ReadInt32(buff, cursor);
985     for (auto i = 0; i < spanLength; i++) {
986         auto spanItemType = TLVUtil::ReadInt32(buff, cursor);
987         if (spanItemType == static_cast<int32_t>(NG::SpanItemType::IMAGE)) {
988             auto imageSpanItem = NG::ImageSpanItem::DecodeTlv(buff, cursor);
989             spanStr->AppendSpanItem(imageSpanItem);
990         } else {
991             auto spanItem = NG::SpanItem::DecodeTlv(buff, cursor);
992             spanStr->AppendSpanItem(spanItem);
993         }
994     }
995     spanStr->UpdateSpansMap();
996 }
997 
UpdateSpansMap()998 void SpanString::UpdateSpansMap()
999 {
1000     spansMap_.clear();
1001     for (auto& spanItem : spans_) {
1002         if (!spanItem) {
1003             continue;
1004         }
1005         auto start = spanItem->interval.first;
1006         auto end = spanItem->interval.second;
1007         std::list<RefPtr<SpanBase>> spanBases = {
1008             ToFontSpan(spanItem, start, end),
1009             ToDecorationSpan(spanItem, start, end),
1010             ToBaselineOffsetSpan(spanItem, start, end),
1011             ToLetterSpacingSpan(spanItem, start, end),
1012             ToGestureSpan(spanItem, start, end),
1013             ToImageSpan(spanItem),
1014             ToParagraphStyleSpan(spanItem, start, end),
1015             ToLineHeightSpan(spanItem, start, end) };
1016         for (auto& spanBase : spanBases) {
1017             if (!spanBase) {
1018                 continue;
1019             }
1020             auto it = spansMap_.find(spanBase->GetSpanType());
1021             if (it == spansMap_.end()) {
1022                 spansMap_.insert({ spanBase->GetSpanType(), { spanBase } });
1023             } else {
1024                 it->second.emplace_back(std::move(spanBase));
1025             }
1026         }
1027     }
1028 }
1029 
ToFontSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1030 RefPtr<FontSpan> SpanString::ToFontSpan(const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1031 {
1032     CHECK_NULL_RETURN(spanItem && spanItem->fontStyle, nullptr);
1033     Font font;
1034     font.fontColor = spanItem->fontStyle->GetTextColor();
1035     font.fontFamiliesNG = spanItem->fontStyle->GetFontFamily();
1036     font.fontSize = spanItem->fontStyle->GetFontSize();
1037     font.fontStyle = spanItem->fontStyle->GetItalicFontStyle();
1038     font.fontWeight = spanItem->fontStyle->GetFontWeight();
1039     return AceType::MakeRefPtr<FontSpan>(font, start, end);
1040 }
1041 
ToDecorationSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1042 RefPtr<DecorationSpan> SpanString::ToDecorationSpan(
1043     const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1044 {
1045     CHECK_NULL_RETURN(spanItem && spanItem->fontStyle, nullptr);
1046     TextDecoration type = spanItem->fontStyle->GetTextDecoration().value_or(TextDecoration::NONE);
1047     std::optional<Color> color = spanItem->fontStyle->GetTextDecorationColor();
1048     std::optional<TextDecorationStyle> style = spanItem->fontStyle->GetTextDecorationStyle();
1049     return AceType::MakeRefPtr<DecorationSpan>(type, color, style, start, end);
1050 }
1051 
ToBaselineOffsetSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1052 RefPtr<BaselineOffsetSpan> SpanString::ToBaselineOffsetSpan(
1053     const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1054 {
1055     CHECK_NULL_RETURN(spanItem && spanItem->textLineStyle, nullptr);
1056     Dimension baselineOffset;
1057     if (spanItem->textLineStyle->GetBaselineOffset().has_value()) {
1058         baselineOffset.SetValue(spanItem->textLineStyle->GetBaselineOffsetValue().ConvertToVp());
1059     }
1060     return AceType::MakeRefPtr<BaselineOffsetSpan>(baselineOffset, start, end);
1061 }
1062 
ToLetterSpacingSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1063 RefPtr<LetterSpacingSpan> SpanString::ToLetterSpacingSpan(
1064     const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1065 {
1066     CHECK_NULL_RETURN(spanItem && spanItem->fontStyle, nullptr);
1067     Dimension letterSpacing;
1068     if (spanItem->fontStyle->GetLetterSpacing().has_value()) {
1069         letterSpacing.SetValue(spanItem->fontStyle->GetLetterSpacingValue().ConvertToVp());
1070     }
1071     return AceType::MakeRefPtr<LetterSpacingSpan>(letterSpacing, start, end);
1072 }
1073 
ToGestureSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1074 RefPtr<GestureSpan> SpanString::ToGestureSpan(const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1075 {
1076     GestureStyle gestureInfo;
1077     if (spanItem->onClick) {
1078         gestureInfo.onClick = spanItem->onClick;
1079     }
1080     if (spanItem->onLongPress) {
1081         gestureInfo.onLongPress = spanItem->onLongPress;
1082     }
1083     return AceType::MakeRefPtr<GestureSpan>(gestureInfo, start, end);
1084 }
1085 
ToTextShadowSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1086 RefPtr<TextShadowSpan> SpanString::ToTextShadowSpan(
1087     const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1088 {
1089     CHECK_NULL_RETURN(spanItem && spanItem->fontStyle, nullptr);
1090     std::vector<Shadow> textShadow = spanItem->fontStyle->GetTextShadow().value_or(std::vector<Shadow> { Shadow() });
1091     return AceType::MakeRefPtr<TextShadowSpan>(textShadow, start, end);
1092 }
1093 
ToImageSpan(const RefPtr<NG::SpanItem> & spanItem)1094 RefPtr<ImageSpan> SpanString::ToImageSpan(const RefPtr<NG::SpanItem>& spanItem)
1095 {
1096     auto imageItem = DynamicCast<NG::ImageSpanItem>(spanItem);
1097     CHECK_NULL_RETURN(imageItem, nullptr);
1098     return AceType::MakeRefPtr<ImageSpan>(imageItem->options);
1099 }
1100 
ToParagraphStyleSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1101 RefPtr<ParagraphStyleSpan> SpanString::ToParagraphStyleSpan(
1102     const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1103 {
1104     CHECK_NULL_RETURN(spanItem && spanItem->textLineStyle, nullptr);
1105     SpanParagraphStyle paragraphStyle;
1106     paragraphStyle.align = spanItem->textLineStyle->GetTextAlign();
1107     paragraphStyle.maxLines = spanItem->textLineStyle->GetMaxLines();
1108     paragraphStyle.textOverflow = spanItem->textLineStyle->GetTextOverflow();
1109     paragraphStyle.leadingMargin = spanItem->textLineStyle->GetLeadingMargin();
1110     paragraphStyle.wordBreak = spanItem->textLineStyle->GetWordBreak();
1111     paragraphStyle.textIndent = spanItem->textLineStyle->GetTextIndent();
1112     return AceType::MakeRefPtr<ParagraphStyleSpan>(paragraphStyle, start, end);
1113 }
1114 
ToLineHeightSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1115 RefPtr<LineHeightSpan> SpanString::ToLineHeightSpan(const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1116 {
1117     CHECK_NULL_RETURN(spanItem && spanItem->textLineStyle, nullptr);
1118     Dimension lineHeight;
1119     if (spanItem->textLineStyle->GetLineHeight().has_value()) {
1120         lineHeight.SetValue(spanItem->textLineStyle->GetLineHeightValue().ConvertToVp());
1121     }
1122     return AceType::MakeRefPtr<LineHeightSpan>(lineHeight, start, end);
1123 }
1124 } // namespace OHOS::Ace
1125