• 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 
20 #include "base/utils/string_utils.h"
21 #include "base/utils/utf_helper.h"
22 #include "core/text/text_emoji_processor.h"
23 #include "core/common/ace_engine.h"
24 #include "core/components_ng/pattern/text/paragraph_util.h"
25 
26 namespace OHOS::Ace {
27 
28 const std::unordered_set<SpanType> specailTypes = { SpanType::Image, SpanType::CustomSpan };
29 
GetWideStringSubstr(const std::u16string & content,int32_t start,int32_t length)30 std::u16string SpanString::GetWideStringSubstr(const std::u16string& content, int32_t start, int32_t length)
31 {
32     if (start >= static_cast<int32_t>(content.length())) {
33         return u"";
34     }
35     return content.substr(start, length);
36 }
37 
GetWideStringSubstr(const std::u16string & content,int32_t start)38 std::u16string SpanString::GetWideStringSubstr(const std::u16string& content, int32_t start)
39 {
40     if (start >= static_cast<int32_t>(content.length())) {
41         return u"";
42     }
43     return content.substr(start);
44 }
45 
SpanString(const std::u16string & text)46 SpanString::SpanString(const std::u16string& text) : text_(text)
47 {
48     auto spanItem = MakeRefPtr<NG::SpanItem>();
49     UtfUtils::HandleInvalidUTF16(reinterpret_cast<uint16_t*>(text_.data()), text_.length(), 0);
50     spanItem->content = text_;
51     spanItem->interval = { 0, text_.length() };
52     spans_.emplace_back(spanItem);
53     auto it = spans_.begin();
54     SplitSpansAndForward(it);
55 }
56 
SpanString(const ImageSpanOptions & options)57 SpanString::SpanString(const ImageSpanOptions& options) : text_(u" ")
58 {
59     auto spanItem = MakeRefPtr<NG::ImageSpanItem>();
60     spanItem->options = options;
61     spanItem->content = u" ";
62     spanItem->interval = { 0, 1 };
63     spans_.emplace_back(spanItem);
64     spansMap_[SpanType::Image].emplace_back(MakeRefPtr<ImageSpan>(options));
65 }
66 
SpanString(RefPtr<CustomSpan> & span)67 SpanString::SpanString(RefPtr<CustomSpan>& span) : text_(u" ")
68 {
69     auto spanItem = MakeRefPtr<NG::CustomSpanItem>();
70     spanItem->content = u" ";
71     spanItem->interval = { 0, 1 };
72     spanItem->onMeasure = span->GetOnMeasure();
73     spanItem->onDraw = span->GetOnDraw();
74     spans_.emplace_back(spanItem);
75     spansMap_[SpanType::CustomSpan].emplace_back(span);
76 }
77 
AddCustomSpan()78 void SpanString::AddCustomSpan()
79 {
80     auto spanBases = GetSpans(0, GetLength(), SpanType::CustomSpan);
81     for (const auto& spanBase : spanBases) {
82         if (spanBase->GetSpanType() != SpanType::CustomSpan) {
83             continue;
84         }
85         auto customSpan = DynamicCast<CustomSpan>(spanBase);
86         if (!customSpan) {
87             continue;
88         }
89         customSpan->AddStyledString(Referenced::WeakClaim(this));
90     }
91 }
92 
RemoveCustomSpan()93 void SpanString::RemoveCustomSpan()
94 {
95     auto spanBases = GetSpans(0, GetLength(), SpanType::CustomSpan);
96     for (const auto& spanBase : spanBases) {
97         if (spanBase->GetSpanType() != SpanType::CustomSpan) {
98             continue;
99         }
100         auto customSpan = DynamicCast<CustomSpan>(spanBase);
101         if (!customSpan) {
102             continue;
103         }
104         customSpan->RemoveStyledString(Referenced::WeakClaim(this));
105     }
106 }
SetFramNode(const WeakPtr<NG::FrameNode> & frameNode)107 void SpanString::SetFramNode(const WeakPtr<NG::FrameNode>& frameNode)
108 {
109     framNode_ = frameNode;
110 }
111 
MarkDirtyFrameNode()112 void SpanString::MarkDirtyFrameNode()
113 {
114     auto frameNode = framNode_.Upgrade();
115     CHECK_NULL_VOID(frameNode);
116     frameNode->MarkDirtyNode(NG::PROPERTY_UPDATE_RENDER);
117 }
118 
~SpanString()119 SpanString::~SpanString()
120 {
121     spansMap_.clear();
122     spans_.clear();
123 }
124 
UpdateImageLayoutPropertyByImageSpanAttribute(std::optional<ImageSpanAttribute> & imageAttribute,RefPtr<NG::ImageSpanNode> & imageNode)125 void UpdateImageLayoutPropertyByImageSpanAttribute(std::optional<ImageSpanAttribute>& imageAttribute,
126     RefPtr<NG::ImageSpanNode>& imageNode)
127 {
128     CHECK_NULL_VOID(imageAttribute.has_value());
129     auto imgAttr = imageAttribute.value();
130     auto imagePattern = imageNode->GetPattern<NG::ImagePattern>();
131     CHECK_NULL_VOID(imagePattern);
132     auto imageLayoutProperty = imageNode->GetLayoutProperty<NG::ImageLayoutProperty>();
133     CHECK_NULL_VOID(imageLayoutProperty);
134     imagePattern->SetSyncLoad(imgAttr.syncLoad);
135     if (imgAttr.size.has_value()) {
136         imageLayoutProperty->UpdateUserDefinedIdealSize(imgAttr.size->GetSize());
137     }
138     if (imgAttr.verticalAlign.has_value()) {
139         imageLayoutProperty->UpdateVerticalAlign(imgAttr.verticalAlign.value());
140     }
141     if (imgAttr.objectFit.has_value()) {
142         imageLayoutProperty->UpdateImageFit(imgAttr.objectFit.value());
143     }
144     if (imgAttr.marginProp.has_value()) {
145         imageLayoutProperty->UpdateMargin(imgAttr.marginProp.value());
146     }
147     if (imgAttr.paddingProp.has_value()) {
148         imageLayoutProperty->UpdatePadding(imgAttr.paddingProp.value());
149     }
150     if (imgAttr.borderRadius.has_value()) {
151         auto imageRenderCtx = imageNode->GetRenderContext();
152         imageRenderCtx->UpdateBorderRadius(imgAttr.borderRadius.value());
153         imageRenderCtx->SetClipToBounds(true);
154     }
155 }
156 
GetImageSpanItemPlaceholderRun(const RefPtr<NG::SpanItem> & child,std::optional<double> & maxWidth)157 PlaceholderRun GetImageSpanItemPlaceholderRun(const RefPtr<NG::SpanItem>& child,
158     std::optional<double>& maxWidth)
159 {
160     PlaceholderRun run;
161     auto imageSpanItem = AceType::DynamicCast<NG::ImageSpanItem>(child);
162     CHECK_NULL_RETURN(imageSpanItem, run);
163     auto imageNode = NG::ImageSpanNode::GetOrCreateSpanNode(V2::IMAGE_ETS_TAG,
164         ElementRegister::GetInstance()->MakeUniqueId(),
165         []() { return AceType::MakeRefPtr<NG::ImagePattern>(); });
166     auto imageLayoutProperty = imageNode->GetLayoutProperty<NG::ImageLayoutProperty>();
167     auto options = imageSpanItem->options;
168     imageLayoutProperty->UpdateImageSourceInfo(NG::ParagraphUtil::CreateImageSourceInfo(options));
169     UpdateImageLayoutPropertyByImageSpanAttribute(options.imageAttribute, imageNode);
170 
171     std::optional<NG::LayoutConstraintF> constraint = std::make_optional<NG::LayoutConstraintF>();
172     constraint->maxSize.SetWidth(maxWidth.has_value() ? maxWidth.value() : std::numeric_limits<float>::infinity());
173     imageNode->Measure(constraint);
174     TextStyle spanTextStyle;
175     auto baselineOffset = imageLayoutProperty->GetBaselineOffset().value_or(Dimension(0.0f));
176     auto geometryNode = imageNode->GetGeometryNode();
177     run.width = geometryNode->GetMarginFrameSize().Width();
178     run.height = geometryNode->GetMarginFrameSize().Height();
179     auto base = baselineOffset.ConvertToPxDistribute(
180         spanTextStyle.GetMinFontScale(), spanTextStyle.GetMaxFontScale(), spanTextStyle.IsAllowScale());
181     if (!NearZero(base)) {
182         run.baseline_offset = base;
183         run.alignment = PlaceholderAlignment::BASELINE;
184     } else {
185         run.alignment = NG::GetPlaceHolderAlignmentFromVerticalAlign(
186             imageLayoutProperty->GetVerticalAlign().value_or(VerticalAlign::BOTTOM));
187     }
188     return run;
189 }
190 
AddSpanItemToParagraph(RefPtr<NG::Paragraph> & paragraph,const RefPtr<NG::SpanItem> & child,std::optional<double> & maxWidth)191 void AddSpanItemToParagraph(RefPtr<NG::Paragraph>& paragraph, const RefPtr<NG::SpanItem>& child,
192     std::optional<double>& maxWidth)
193 {
194     CHECK_NULL_VOID(child);
195     auto context = PipelineContext::GetCurrentContextSafelyWithCheck();
196     CHECK_NULL_VOID(context);
197     auto theme = context->GetTheme<TextTheme>();
198     CHECK_NULL_VOID(theme);
199     if (child->spanItemType == SpanItemType::NORMAL) {
200         TextStyle spanTextStyle = CreateTextStyleUsingTheme(child->fontStyle, child->textLineStyle, theme, false);
201         paragraph->PushStyle(spanTextStyle);
202         if (!child->content.empty()) {
203             auto displayText = child->content;
204             auto textCase = spanTextStyle.GetTextCase();
205             StringUtils::TransformStrCase(displayText, static_cast<int32_t>(textCase));
206             UtfUtils::HandleInvalidUTF16(reinterpret_cast<uint16_t*>(displayText.data()),
207                 displayText.length(), 0);
208             paragraph->AddText(displayText);
209         }
210         paragraph->PopStyle();
211         return;
212     }
213     PlaceholderRun run;
214     if (child->spanItemType == SpanItemType::IMAGE) {
215         run = GetImageSpanItemPlaceholderRun(child, maxWidth);
216     } else if (child->spanItemType == SpanItemType::CustomSpan) {
217         auto customSpanItem = AceType::DynamicCast<NG::CustomSpanItem>(child);
218         CHECK_NULL_VOID(customSpanItem);
219         auto fontSize = theme->GetTextStyle().GetFontSize().ConvertToVp() * context->GetFontScale();
220         if (customSpanItem->onMeasure.has_value()) {
221             auto onMeasure = customSpanItem->onMeasure.value();
222             CustomSpanMetrics customSpanMetrics = onMeasure({ fontSize });
223             run.width = static_cast<float>(customSpanMetrics.width * context->GetDipScale());
224             run.height = static_cast<float>(
225                 customSpanMetrics.height.value_or(fontSize / context->GetFontScale()) * context->GetDipScale());
226         }
227     }
228     TextStyle spanTextStyle;
229     paragraph->PushStyle(spanTextStyle);
230     paragraph->AddPlaceholder(run);
231     paragraph->PopStyle();
232 }
233 
GetParagraphStyleSpanItem(std::list<RefPtr<NG::SpanItem>> & group)234 RefPtr<NG::SpanItem> GetParagraphStyleSpanItem(std::list<RefPtr<NG::SpanItem>>& group)
235 {
236     RefPtr<NG::SpanItem> paraStyleSpanItem = *group.begin();
237     auto it = group.begin();
238     while (it != group.end()) {
239         if (!AceType::DynamicCast<NG::PlaceholderSpanItem>(*it)) {
240             paraStyleSpanItem = *it;
241             break;
242         }
243         ++it;
244     }
245     return paraStyleSpanItem;
246 }
247 
GetLayoutInfo(const RefPtr<SpanString> & spanStr,std::optional<double> & maxWidth)248 std::vector<RefPtr<NG::Paragraph>> SpanString::GetLayoutInfo(const RefPtr<SpanString>& spanStr,
249     std::optional<double>& maxWidth)
250 {
251     auto spans = spanStr->GetSpanItems();
252     std::vector<std::list<RefPtr<NG::SpanItem>>> spanGroupVec;
253     bool spanStringHasMaxLines = false;
254     NG::ParagraphUtil::ConstructParagraphSpanGroup(spans, spanGroupVec, spanStringHasMaxLines);
255     TextStyle textStyle;
256     std::vector<RefPtr<NG::Paragraph>> paraVec;
257     auto paraStyle = NG::ParagraphUtil::GetParagraphStyle(textStyle);
258     paraStyle.fontSize = textStyle.GetFontSize().ConvertToPxDistribute(
259         textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
260     paraStyle.leadingMarginAlign = Alignment::CENTER;
261 
262     auto maxLines = static_cast<int32_t>(paraStyle.maxLines);
263     for (auto groupIt = spanGroupVec.begin(); groupIt != spanGroupVec.end(); groupIt++) {
264         auto& group = *(groupIt);
265         NG::ParagraphStyle spanParagraphStyle = paraStyle;
266         if (paraStyle.maxLines != UINT32_MAX) {
267             if (!paraVec.empty()) {
268                 maxLines -= static_cast<int32_t>(paraVec.back()->GetLineCount());
269             }
270             spanParagraphStyle.maxLines = std::max(maxLines, 0);
271         }
272         RefPtr<NG::SpanItem> paraStyleSpanItem = GetParagraphStyleSpanItem(group);
273         if (paraStyleSpanItem) {
274             // unable to get text direction because no layoutwrapper
275             NG::ParagraphUtil::GetSpanParagraphStyle(nullptr, paraStyleSpanItem, spanParagraphStyle);
276             if (paraStyleSpanItem->fontStyle->HasFontSize()) {
277                 spanParagraphStyle.fontSize = paraStyleSpanItem->fontStyle->GetFontSizeValue().ConvertToPxDistribute(
278                     textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
279             }
280             spanParagraphStyle.isEndAddParagraphSpacing = paraStyleSpanItem->textLineStyle->HasParagraphSpacing() &&
281                 Positive(paraStyleSpanItem->textLineStyle->GetParagraphSpacingValue().ConvertToPx()) &&
282                 std::next(groupIt) != spanGroupVec.end();
283             spanParagraphStyle.isFirstParagraphLineSpacing = (groupIt == spanGroupVec.begin());
284         }
285         auto&& paragraph = NG::Paragraph::Create(spanParagraphStyle, NG::FontCollection::Current());
286         if (!paragraph) {
287             continue;
288         }
289         for (const auto& child : group) {
290             AddSpanItemToParagraph(paragraph, child, maxWidth);
291         }
292         NG::ParagraphUtil::HandleEmptyParagraph(paragraph, group);
293         paragraph->Build();
294         auto maxWidthVal = maxWidth.has_value()? maxWidth.value() : std::numeric_limits<float>::max();
295         NG::ParagraphUtil::ApplyIndent(spanParagraphStyle, paragraph, maxWidthVal, textStyle, maxWidthVal);
296         paragraph->Layout(maxWidthVal);
297         paraVec.emplace_back(paragraph);
298     }
299     return paraVec;
300 }
301 
SplitSpansAndForward(std::list<RefPtr<NG::SpanItem>>::iterator & it)302 std::list<RefPtr<NG::SpanItem>>::iterator SpanString::SplitSpansAndForward(
303     std::list<RefPtr<NG::SpanItem>>::iterator& it)
304 {
305     auto wString = (*it)->content;
306     auto newlineIndex = static_cast<int32_t>(wString.find(u'\n'));
307     int32_t offset = (*it)->interval.first;
308     while (newlineIndex != -1 && newlineIndex != static_cast<int32_t>(wString.size()) - 1) {
309         auto newSpan = (*it)->GetSameStyleSpanItem();
310         newSpan->interval = { offset + newlineIndex + 1, (*it)->interval.second };
311         (*it)->interval = { offset, offset + newlineIndex + 1 };
312         (*it)->UpdateContent(GetWideStringSubstr(wString, 0, newlineIndex + 1));
313         wString = GetWideStringSubstr(wString, newlineIndex + 1);
314         newSpan->UpdateContent(wString);
315         newlineIndex = static_cast<int32_t>(wString.find(u'\n'));
316 
317         offset = newSpan->interval.first;
318         ++it;
319         it = spans_.insert(it, newSpan);
320     }
321 
322     return std::next(it);
323 }
324 
ApplyToSpans(const RefPtr<SpanBase> & span,std::pair<int32_t,int32_t> interval,SpanOperation operation)325 void SpanString::ApplyToSpans(
326     const RefPtr<SpanBase>& span, std::pair<int32_t, int32_t> interval, SpanOperation operation)
327 {
328     SetGroupId(span);
329     for (auto it = spans_.begin(); it != spans_.end(); ++it) {
330         auto intersection = (*it)->GetIntersectionInterval(interval);
331         if (!intersection) {
332             continue;
333         }
334         auto oldStart = (*it)->interval.first;
335         auto oldEnd = (*it)->interval.second;
336         if (oldStart == intersection->first && intersection->second == oldEnd) {
337             span->ApplyToSpanItem(*it, operation);
338             continue;
339         }
340         auto wContent = (*it)->content;
341         auto newSpan = (*it)->GetSameStyleSpanItem();
342         auto firstStartIdx = std::clamp(intersection->first - oldStart, 0, static_cast<int32_t>(wContent.length()));
343         auto secondStartIdx = std::clamp(intersection->second - oldStart, 0, static_cast<int32_t>(wContent.length()));
344         if (oldStart < intersection->first && intersection->second < oldEnd) {
345             (*it)->interval = { oldStart, intersection->first };
346             (*it)->content = wContent.substr(0, firstStartIdx);
347 
348             newSpan->interval = { intersection->first, intersection->second };
349             newSpan->content = wContent.substr(firstStartIdx,
350                 intersection->second - intersection->first);
351             span->ApplyToSpanItem(newSpan, operation);
352 
353             auto newSpan2 = (*it)->GetSameStyleSpanItem();
354             newSpan2->interval = { intersection->second, oldEnd };
355             newSpan2->content = wContent.substr(secondStartIdx);
356             it = spans_.insert(std::next(it), newSpan);
357             it = spans_.insert(std::next(it), newSpan2);
358             continue;
359         }
360         if (oldEnd > intersection->second) {
361             (*it)->content = wContent.substr(0, secondStartIdx);
362             (*it)->interval = { oldStart, intersection->second };
363             span->ApplyToSpanItem(*it, operation);
364             newSpan->interval = { intersection->second, oldEnd };
365             newSpan->content = wContent.substr(secondStartIdx);
366             it = spans_.insert(std::next(it), newSpan);
367             continue;
368         }
369         if (intersection->first > oldStart) {
370             (*it)->content = wContent.substr(0, firstStartIdx);
371             (*it)->interval = { oldStart, intersection->first };
372             newSpan->interval = { intersection->first, oldEnd };
373             newSpan->content = wContent.substr(firstStartIdx);
374             span->ApplyToSpanItem(newSpan, operation);
375             it = spans_.insert(std::next(it), newSpan);
376         }
377     }
378 }
379 
SplitInterval(std::list<RefPtr<SpanBase>> & spans,std::pair<int32_t,int32_t> interval)380 void SpanString::SplitInterval(std::list<RefPtr<SpanBase>>& spans, std::pair<int32_t, int32_t> interval)
381 {
382     std::list<RefPtr<SpanBase>> newSpans;
383     for (auto it = spans.begin(); it != spans.end();) {
384         auto intersection = (*it)->GetIntersectionInterval(interval);
385         if (!intersection) {
386             ++it;
387             continue;
388         }
389         auto oldStart = (*it)->GetStartIndex();
390         auto oldEnd = (*it)->GetEndIndex();
391         if (intersection->first == oldStart && intersection->second == oldEnd) {
392             it = spans.erase(it);
393             continue;
394         }
395         if (oldStart < intersection->first && intersection->second < oldEnd) {
396             newSpans.emplace_back((*it)->GetSubSpan(oldStart, intersection->first));
397             newSpans.emplace_back((*it)->GetSubSpan(intersection->second, oldEnd));
398             it = spans.erase(it);
399             continue;
400         }
401         if (oldEnd > intersection->second) {
402             (*it)->UpdateStartIndex(intersection->second);
403             ++it;
404             continue;
405         }
406         if (intersection->first > oldStart) {
407             (*it)->UpdateEndIndex(intersection->first);
408             ++it;
409         }
410     }
411     spans.merge(newSpans);
412 }
413 
SortSpans(std::list<RefPtr<SpanBase>> & spans)414 void SpanString::SortSpans(std::list<RefPtr<SpanBase>>& spans)
415 {
416     spans.sort(
417         [](const RefPtr<SpanBase>& a, const RefPtr<SpanBase>& b) { return a->GetStartIndex() < b->GetStartIndex(); });
418 }
419 
CanMerge(const RefPtr<SpanBase> & a,const RefPtr<SpanBase> & b)420 bool SpanString::CanMerge(const RefPtr<SpanBase>& a, const RefPtr<SpanBase>& b)
421 {
422     return a->GetEndIndex() >= b->GetStartIndex() && a->IsAttributesEqual(b);
423 }
424 
MergeIntervals(std::list<RefPtr<SpanBase>> & spans)425 void SpanString::MergeIntervals(std::list<RefPtr<SpanBase>>& spans)
426 {
427     auto it = spans.begin();
428     while (it != spans.end()) {
429         auto spanType = (*it)->GetSpanType();
430         if (spanType == SpanType::Image || spanType == SpanType::CustomSpan) {
431             return;
432         }
433         auto current = it++;
434         if (it != spans.end() && CanMerge(*current, *it)) {
435             (*current)->UpdateStartIndex(std::min((*current)->GetStartIndex(), (*it)->GetStartIndex()));
436             (*current)->UpdateEndIndex(std::max((*current)->GetEndIndex(), (*it)->GetEndIndex()));
437             spans.erase(it++);
438             if (it == spans.end()) {
439                 break;
440             }
441             it = current;
442         }
443     }
444 }
445 
GetStepsByPosition(int32_t pos)446 int32_t SpanString::GetStepsByPosition(int32_t pos)
447 {
448     if (pos == 0) {
449         return 0;
450     }
451     int32_t step = 0;
452     for (auto iter = spans_.begin(); iter != spans_.end(); ++iter) {
453         if ((*iter)->interval.first == pos) {
454             return step;
455         }
456         if ((*iter)->interval.first < pos && pos < (*iter)->interval.second) {
457             auto spanItem = (*iter)->GetSameStyleSpanItem();
458             spanItem->interval.first = pos;
459             spanItem->interval.second = (*iter)->interval.second;
460             auto wStr = spanItem->content;
461             auto start = (*iter)->interval.first;
462             spanItem->content = wStr.substr(std::clamp(pos - start, 0, static_cast<int32_t>(wStr.length())));
463             spans_.insert(std::next(iter), spanItem);
464             (*iter)->interval.second = pos;
465             (*iter)->content = wStr.substr(0, pos - start);
466             return step;
467         }
468         step++;
469     }
470     return step;
471 }
472 
AddSpecialSpan(const RefPtr<SpanBase> & span,SpanType type,int32_t start)473 void SpanString::AddSpecialSpan(const RefPtr<SpanBase>& span, SpanType type, int32_t start)
474 {
475     start = std::clamp(start, 0, static_cast<int32_t>(GetU16string().length()));
476     text_ = GetU16string().substr(0, start) + u" " + GetU16string().substr(start);
477     auto iter = spans_.begin();
478     auto step = GetStepsByPosition(start);
479     std::advance(iter, step);
480     RefPtr<NG::SpanItem> spanItem;
481     if (type == SpanType::Image) {
482         auto imageSpan = DynamicCast<ImageSpan>(span);
483         CHECK_NULL_VOID(imageSpan);
484         spanItem = MakeImageSpanItem(imageSpan);
485     } else if (type == SpanType::CustomSpan) {
486         auto customSpan = AceType::DynamicCast<CustomSpan>(span);
487         CHECK_NULL_VOID(customSpan);
488         spanItem = MakeCustomSpanItem(customSpan);
489     }
490     iter = spans_.insert(iter, spanItem);
491     for (++iter; iter != spans_.end(); ++iter) {
492         ++(*iter)->interval.first;
493         ++(*iter)->interval.second;
494     }
495 
496     UpdateSpanMapWithOffset(start - 1, 1);
497     if (spansMap_.find(type) == spansMap_.end()) {
498         spansMap_[type].emplace_back(span);
499     } else {
500         auto specialList = spansMap_[type];
501         int32_t step = 0;
502         for (const auto& specialSpan : specialList) {
503             if (specialSpan->GetStartIndex() >= start) {
504                 break;
505             }
506             ++step;
507         }
508         auto iter = specialList.begin();
509         std::advance(iter, step);
510         specialList.insert(iter, span);
511         spansMap_[type] = specialList;
512     }
513 }
514 
MakeImageSpanItem(const RefPtr<ImageSpan> & imageSpan)515 RefPtr<NG::ImageSpanItem> SpanString::MakeImageSpanItem(const RefPtr<ImageSpan>& imageSpan)
516 {
517     auto spanItem = MakeRefPtr<NG::ImageSpanItem>();
518     spanItem->content = u" ";
519     spanItem->interval.first = imageSpan->GetStartIndex();
520     spanItem->interval.second = imageSpan->GetEndIndex();
521     spanItem->SetImageSpanOptions(imageSpan->GetImageSpanOptions());
522     return spanItem;
523 }
524 
MakeCustomSpanItem(const RefPtr<CustomSpan> & customSpan)525 RefPtr<NG::CustomSpanItem> SpanString::MakeCustomSpanItem(const RefPtr<CustomSpan>& customSpan)
526 {
527     auto spanItem = MakeRefPtr<NG::CustomSpanItem>();
528     spanItem->content = u" ";
529     spanItem->interval.first = customSpan->GetStartIndex();
530     spanItem->interval.second = customSpan->GetEndIndex();
531     spanItem->onDraw = customSpan->GetOnDraw();
532     spanItem->onMeasure = customSpan->GetOnMeasure();
533     return spanItem;
534 }
535 
CheckMultiTypeDecorationSpan(const RefPtr<SpanBase> & span)536 bool SpanString::CheckMultiTypeDecorationSpan(const RefPtr<SpanBase>& span)
537 {
538     if (span->GetSpanType() != SpanType::Decoration) {
539         return false;
540     }
541     auto decorationSpan = AceType::DynamicCast<DecorationSpan>(span);
542     if (!decorationSpan->GetTextDecorationOptions().has_value()) {
543         return false;
544     }
545     auto options = decorationSpan->GetTextDecorationOptions().value();
546     return options.enableMultiType.value_or(false);
547 }
548 
GetWholeSpans(int32_t start,int32_t end,SpanType spanType) const549 std::vector<RefPtr<SpanBase>> SpanString::GetWholeSpans(int32_t start, int32_t end, SpanType spanType) const
550 {
551     std::vector<RefPtr<SpanBase>> res;
552     if (!CheckRange(start, end - start)) {
553         return res;
554     }
555 
556     auto spans = spansMap_.find(spanType)->second;
557     for (const auto& span : spans) {
558         int32_t tempStart = span->GetStartIndex();
559         int32_t tempEnd = span->GetEndIndex();
560         if ((tempStart <= start && tempEnd > start) ||
561             (tempStart <= end && tempEnd > end) ||
562             (tempStart >= start && tempEnd <= end)) {
563             res.push_back(span);
564         }
565     }
566     return res;
567 }
568 
ProcessMultiDecorationSpanForIntersection(const RefPtr<SpanBase> & span,const RefPtr<SpanBase> & lastSpan,std::vector<int32_t> & spanNoIntersection,int32_t start,int32_t end)569 void SpanString::ProcessMultiDecorationSpanForIntersection(
570     const RefPtr<SpanBase>& span, const RefPtr<SpanBase>& lastSpan,
571     std::vector<int32_t>& spanNoIntersection, int32_t start, int32_t end)
572 {
573     auto lastDecorationSpan = AceType::DynamicCast<DecorationSpan>(lastSpan);
574     auto lastDecorations = lastDecorationSpan->GetTextDecorationTypes();
575 
576     int32_t lastSpanStart = lastSpan->GetStartIndex();
577     int32_t lastSpanEnd = lastSpan->GetEndIndex();
578     int32_t intersectionStart = std::max(start, lastSpanStart);
579     int32_t intersectionEnd = std::min(end, lastSpanEnd);
580 
581     bool spanInRight = lastSpanStart <= start && lastSpanEnd <= end;
582     bool isInclude = lastSpanStart <= start && lastSpanEnd >= end;
583 
584     int32_t newStart = 0;
585     int32_t newEnd = 0;
586     if (isInclude) {
587         newStart = intersectionStart;
588         newEnd = intersectionEnd;
589     } else if (spanInRight) {
590         newStart = intersectionStart;
591         newEnd = lastSpanEnd;
592     } else {
593         newStart = lastSpanStart;
594         newEnd = intersectionEnd;
595     }
596     auto intersectionSpan = span->GetSubSpan(newStart, newEnd);
597     auto intersectionDecorationSpan = AceType::DynamicCast<DecorationSpan>(intersectionSpan);
598     // apply new data to newSpan
599     if (CheckMultiTypeDecorationSpan(lastSpan) && CheckMultiTypeDecorationSpan(intersectionSpan)) {
600         for (TextDecoration value : lastDecorations) {
601             intersectionDecorationSpan->AddTextDecorationType(value);
602         }
603     } else {
604         TextDecorationOptions option { false };
605         intersectionDecorationSpan->SetTextDecorationOptions(option);
606     }
607     AddSpan(intersectionSpan, false);
608     for (int32_t index = newStart; index < newEnd; index++) {
609         spanNoIntersection[index] = 0; //unmark
610     }
611 }
612 
ProcessMultiDecorationSpanForNoIntersection(const RefPtr<SpanBase> & span,std::vector<int32_t> & spanNoIntersection,int32_t start,int32_t end)613 void SpanString::ProcessMultiDecorationSpanForNoIntersection(
614     const RefPtr<SpanBase>& span, std::vector<int32_t>& spanNoIntersection,
615     int32_t start, int32_t end)
616 {
617     int32_t tempStart = start;
618     int32_t tempEnd = start;
619     for (int32_t index = start; index < end;) {
620         index++;
621         if (spanNoIntersection[tempStart] != 0) {
622             while (tempEnd < end && spanNoIntersection[tempEnd] != 0) {
623                 tempEnd++;
624             }
625             if (tempEnd == tempStart) {
626                 continue;
627             }
628             auto tempSpan = span->GetSubSpan(tempStart, tempEnd);
629             AddSpan(tempSpan, false);
630         } else {
631             tempStart = index;
632             tempEnd = index;
633         }
634     }
635 }
636 
ProcessMultiDecorationSpan(const RefPtr<SpanBase> & span,int32_t start,int32_t end)637 bool SpanString::ProcessMultiDecorationSpan(const RefPtr<SpanBase>& span, int32_t start, int32_t end)
638 {
639     bool multiTypeDecoration = CheckMultiTypeDecorationSpan(span);
640     if (!multiTypeDecoration) {
641         return false;
642     }
643     auto lastSpans = GetWholeSpans(start, end, SpanType::Decoration);
644     if (lastSpans.size() <= 0) {
645         return false;
646     }
647     std::vector<int32_t> spanNoIntersection;
648     for (int32_t index = 0; index <= end; index++) {
649         if (index >= start) {
650             spanNoIntersection.push_back(1); // mark
651         } else {
652             spanNoIntersection.push_back(0);
653         }
654     }
655     for (const RefPtr<SpanBase>& lastSpan : lastSpans) {
656         ProcessMultiDecorationSpanForIntersection(span, lastSpan, spanNoIntersection, start, end);
657     }
658     ProcessMultiDecorationSpanForNoIntersection(span, spanNoIntersection, start, end);
659     return true;
660 }
661 
AddSpan(const RefPtr<SpanBase> & span,bool processMultiDecoration,bool isFromHtml,bool removeOriginStyle)662 void SpanString::AddSpan(const RefPtr<SpanBase>& span, bool processMultiDecoration, bool isFromHtml,
663     bool removeOriginStyle)
664 {
665     if (!span || !CheckRange(span)) {
666         return;
667     }
668     auto start = span->GetStartIndex();
669     auto end = span->GetEndIndex();
670     if (span->GetSpanType() == SpanType::Image || span->GetSpanType() == SpanType::CustomSpan) {
671         AddSpecialSpan(span, span->GetSpanType(), start);
672         return;
673     }
674     if (spansMap_.find(span->GetSpanType()) == spansMap_.end()) {
675         spansMap_[span->GetSpanType()].emplace_back(span);
676         ApplyToSpans(span, { start, end }, SpanOperation::ADD);
677         return;
678     } else if (span->GetSpanType() == SpanType::Font && isFromHtml) {
679         // If the span type is Font and the span is from HTML, directly add it to the spansMap_ and apply it.
680         spansMap_[span->GetSpanType()].emplace_back(span);
681         ApplyToSpans(span, { start, end }, SpanOperation::ADD);
682         return;
683     }
684     if (processMultiDecoration && ProcessMultiDecorationSpan(span, start, end)) {
685         return;
686     }
687     if (removeOriginStyle) {
688         RemoveSpan(start, end - start, span->GetSpanType());
689     }
690     auto spans = spansMap_[span->GetSpanType()];
691     ApplyToSpans(span, { start, end }, SpanOperation::ADD);
692     SplitInterval(spans, { start, end });
693     spans.emplace_back(span);
694     SortSpans(spans);
695     MergeIntervals(spans);
696     spansMap_[span->GetSpanType()] = spans;
697 }
698 
RemoveSpan(int32_t start,int32_t length,SpanType key)699 void SpanString::RemoveSpan(int32_t start, int32_t length, SpanType key)
700 {
701     if (!CheckRange(start, length)) {
702         return;
703     }
704     auto end = start + length;
705     length = end - start;
706     auto it = spansMap_.find(key);
707     if (it == spansMap_.end()) {
708         return;
709     }
710     auto spans = spansMap_[key];
711     if (key == SpanType::Image) {
712         RemoveSpecialSpan(start, end, key);
713         return;
714     }
715     if (key == SpanType::CustomSpan) {
716         RemoveSpecialSpan(start, end, key);
717         return;
718     }
719     auto defaultSpan = GetDefaultSpan(key);
720     CHECK_NULL_VOID(defaultSpan);
721     defaultSpan->UpdateStartIndex(start);
722     defaultSpan->UpdateEndIndex(end);
723     ApplyToSpans(defaultSpan, { start, end }, SpanOperation::REMOVE);
724     SplitInterval(spans, { start, end });
725     SortSpans(spans);
726     MergeIntervals(spans);
727     if (spans.empty()) {
728         spansMap_.erase(key);
729     } else {
730         spansMap_[key] = spans;
731     }
732 }
733 
GetDefaultSpan(SpanType type)734 RefPtr<SpanBase> SpanString::GetDefaultSpan(SpanType type)
735 {
736     switch (type) {
737         case SpanType::Font:
738             return MakeRefPtr<FontSpan>();
739         case SpanType::TextShadow:
740             return MakeRefPtr<TextShadowSpan>();
741         case SpanType::Gesture:
742             return MakeRefPtr<GestureSpan>();
743         case SpanType::Decoration:
744             return MakeRefPtr<DecorationSpan>();
745         case SpanType::BaselineOffset:
746             return MakeRefPtr<BaselineOffsetSpan>();
747         case SpanType::LetterSpacing:
748             return MakeRefPtr<LetterSpacingSpan>();
749         case SpanType::ParagraphStyle:
750             return MakeRefPtr<ParagraphStyleSpan>();
751         case SpanType::LineHeight:
752             return MakeRefPtr<LineHeightSpan>();
753         case SpanType::ExtSpan:
754             return MakeRefPtr<ExtSpan>();
755         case SpanType::BackgroundColor:
756             return MakeRefPtr<BackgroundColorSpan>();
757         case SpanType::Url:
758             return MakeRefPtr<UrlSpan>();
759         default:
760             return nullptr;
761     }
762 }
763 
CheckRange(const RefPtr<SpanBase> & spanBase) const764 bool SpanString::CheckRange(const RefPtr<SpanBase>& spanBase) const
765 {
766     auto start = spanBase->GetStartIndex();
767     auto length = spanBase->GetLength();
768     if (length <= 0) {
769         return false;
770     }
771     auto spanType = spanBase->GetSpanType();
772     auto len = spanType == SpanType::Image || spanType == SpanType::CustomSpan ? GetLength() + 1 : GetLength();
773     auto end = start + length;
774 
775     if (start > len || end > len) {
776         return false;
777     }
778 
779     if (start < 0) {
780         return false;
781     }
782 
783     return true;
784 }
785 
CheckRange(int32_t start,int32_t length,bool allowLengthZero) const786 bool SpanString::CheckRange(int32_t start, int32_t length, bool allowLengthZero) const
787 {
788     if (length < 0 || (length == 0 && !allowLengthZero)) {
789         return false;
790     }
791 
792     auto len = GetLength();
793     auto end = start + length;
794 
795     if (start > len || end > len) {
796         return false;
797     }
798 
799     if (start < 0) {
800         return false;
801     }
802 
803     return true;
804 }
805 
GetDefaultSpanItem(const std::u16string & text)806 RefPtr<NG::SpanItem> SpanString::GetDefaultSpanItem(const std::u16string& text)
807 {
808     auto spanItem = MakeRefPtr<NG::SpanItem>();
809     spanItem->content = text;
810     spanItem->interval = { 0, text.length() };
811     return spanItem;
812 }
813 
SetString(const std::u16string & text)814 void SpanString::SetString(const std::u16string& text)
815 {
816     text_ = text;
817 }
818 
SetGroupId(const RefPtr<SpanBase> & span)819 void SpanString::SetGroupId(const RefPtr<SpanBase>& span)
820 {
821     if (span->GetSpanType() == SpanType::BackgroundColor) {
822         auto backgroundColorSpan = DynamicCast<BackgroundColorSpan>(span);
823         CHECK_NULL_VOID(backgroundColorSpan);
824         backgroundColorSpan->SetBackgroundColorGroupId(groupId_++);
825     }
826 }
SetSpanItems(const std::list<RefPtr<NG::SpanItem>> && spanItems)827 void SpanString::SetSpanItems(const std::list<RefPtr<NG::SpanItem>>&& spanItems)
828 {
829     spans_ = spanItems;
830 }
831 
SetSpanMap(std::unordered_map<SpanType,std::list<RefPtr<SpanBase>>> && spansMap)832 void SpanString::SetSpanMap(std::unordered_map<SpanType, std::list<RefPtr<SpanBase>>>&& spansMap)
833 {
834     spansMap_ = spansMap;
835 }
836 
GetString() const837 const std::string SpanString::GetString() const
838 {
839     return UtfUtils::Str16DebugToStr8(text_);
840 }
841 
GetU16string() const842 const std::u16string& SpanString::GetU16string() const
843 {
844     return text_;
845 }
846 
GetLength() const847 int32_t SpanString::GetLength() const
848 {
849     return text_.length();
850 }
851 
IsEqualToSpanString(const RefPtr<SpanString> & other) const852 bool SpanString::IsEqualToSpanString(const RefPtr<SpanString>& other) const
853 {
854     return *this == *other;
855 }
856 
GetSubSpanString(int32_t start,int32_t length,bool includeStartHalf,bool includeEndHalf,bool rangeNeedNotChange) const857 RefPtr<SpanString> SpanString::GetSubSpanString(int32_t start, int32_t length, bool includeStartHalf,
858     bool includeEndHalf, bool rangeNeedNotChange) const
859 {
860     if (!CheckRange(start, length)) {
861         RefPtr<SpanString> span = AceType::MakeRefPtr<SpanString>(u"");
862         return span;
863     }
864     int32_t end = start + length;
865     if (!rangeNeedNotChange) {
866         TextEmojiSubStringRange range = TextEmojiProcessor::CalSubU16stringRange(
867             start, end - start, text_, includeStartHalf, includeEndHalf);
868         start = range.startIndex;
869         end = range.endIndex;
870         length = end - start;
871     }
872     start = std::clamp(start, 0, static_cast<int32_t>(text_.length()));
873     RefPtr<SpanString> span =
874         AceType::MakeRefPtr<SpanString>(text_.substr(start, length));
875     std::unordered_map<SpanType, std::list<RefPtr<SpanBase>>> subMap;
876     for (const auto& map : spansMap_) {
877         auto subList = GetSubSpanList(start, length, map.second);
878         if (!subList.empty()) {
879             subMap.insert({ map.first, subList });
880         }
881     }
882     span->spansMap_ = subMap;
883 
884     std::list<RefPtr<NG::SpanItem>> subSpans_;
885     for (const auto& spanItem : spans_) {
886         auto intersection = spanItem->GetIntersectionInterval({start, start+length});
887         if (intersection) {
888             int32_t oldStart = spanItem->interval.first;
889             int32_t oldEnd = spanItem->interval.second;
890             auto spanStart = oldStart <= start ? 0 : oldStart - start;
891             auto spanEnd = oldEnd < end ? oldEnd - start : end - start;
892             auto newSpanItem = spanItem->GetSameStyleSpanItem();
893             newSpanItem->interval = { spanStart, spanEnd };
894             newSpanItem->content = spanItem->content
895                     .substr(std::max(start - oldStart, 0), std::min(end, oldEnd) - std::max(start, oldStart));
896             subSpans_.emplace_back(newSpanItem);
897         }
898     }
899     span->spans_ = subSpans_;
900     return span;
901 }
902 
GetSubSpanList(int32_t start,int32_t length,const std::list<RefPtr<SpanBase>> & spans) const903 std::list<RefPtr<SpanBase>> SpanString::GetSubSpanList(
904     int32_t start, int32_t length, const std::list<RefPtr<SpanBase>>& spans) const
905 {
906     std::list<RefPtr<SpanBase>> res;
907     int32_t end = start + length;
908     for (auto& span : spans) {
909         auto intersection = span->GetIntersectionInterval({ start, end });
910         if (intersection) {
911             int32_t spanStart = span->GetStartIndex();
912             int32_t spanEnd = span->GetEndIndex();
913             spanStart = spanStart <= start ? 0 : spanStart - start;
914             spanEnd = spanEnd < end ? spanEnd - start : end - start;
915             if (spanStart == spanEnd) {
916                 continue;
917             }
918             res.emplace_back(span->GetSubSpan(spanStart, spanEnd));
919         }
920     }
921     return res;
922 }
923 
GetSpansMap() const924 const std::unordered_map<SpanType, std::list<RefPtr<SpanBase>>>& SpanString::GetSpansMap() const
925 {
926     return spansMap_;
927 }
928 
GetSpans(int32_t start,int32_t length) const929 std::vector<RefPtr<SpanBase>> SpanString::GetSpans(int32_t start, int32_t length) const
930 {
931     std::vector<RefPtr<SpanBase>> res;
932     if (!CheckRange(start, length)) {
933         return res;
934     }
935 
936     for (const auto& map : spansMap_) {
937         auto spans = GetSpans(start, length, map.first);
938         res.insert(res.begin(), spans.begin(), spans.end());
939     }
940     return res;
941 }
942 
GetSpans(int32_t start,int32_t length,SpanType spanType) const943 std::vector<RefPtr<SpanBase>> SpanString::GetSpans(int32_t start, int32_t length, SpanType spanType) const
944 {
945     std::vector<RefPtr<SpanBase>> res;
946     if (!CheckRange(start, length)) {
947         return res;
948     }
949     int32_t end = start + length;
950     RefPtr<SpanBase> span;
951     while ((span = GetSpan(start, length, spanType)) != nullptr) {
952         res.emplace_back(span);
953         start = span->GetEndIndex();
954         length = end - start;
955     }
956     return res;
957 }
958 
GetSpan(int32_t start,int32_t length,SpanType spanType) const959 RefPtr<SpanBase> SpanString::GetSpan(int32_t start, int32_t length, SpanType spanType) const
960 {
961     if (!CheckRange(start, length) || spansMap_.find(spanType) == spansMap_.end()) {
962         return nullptr;
963     }
964     int32_t end = start + length;
965     auto spanBaseList = spansMap_.find(spanType)->second;
966     for (auto& spanBase : spanBaseList) {
967         auto intersection = spanBase->GetIntersectionInterval({ start, end });
968         if (intersection) {
969             int32_t newStart = intersection->first;
970             int32_t newEnd = intersection->second;
971             if (newStart == newEnd) {
972                 continue;
973             }
974             return spanBase->GetSubSpan(newStart, newEnd);
975         }
976     }
977     return nullptr;
978 }
979 
operator ==(const SpanString & other) const980 bool SpanString::operator==(const SpanString& other) const
981 {
982     if (text_ != other.text_) {
983         return false;
984     }
985     auto size =
986         !spansMap_.empty()
987             ? (static_cast<int32_t>(spansMap_.size()) - (spansMap_.find(SpanType::Gesture) == spansMap_.end() ? 0 : 1))
988             : 0;
989     auto sizeOther = !other.spansMap_.empty()
990                          ? (static_cast<int32_t>(other.spansMap_.size()) -
991                                (other.spansMap_.find(SpanType::Gesture) == other.spansMap_.end() ? 0 : 1))
992                          : 0;
993     if (size != sizeOther) {
994         return false;
995     }
996 
997     for (const auto& map : spansMap_) {
998         if (map.first == SpanType::Gesture) {
999             continue;
1000         }
1001         auto spansOtherMap = other.spansMap_.find(map.first);
1002         if (spansOtherMap == other.spansMap_.end()) {
1003             return false;
1004         }
1005         auto spans = map.second;
1006         auto spansOther = spansOtherMap->second;
1007         if (spans.size() != spansOther.size()) {
1008             return false;
1009         }
1010         for (auto spansItr = spans.begin(), spansOtherItr = spansOther.begin();
1011              spansItr != spans.end() && spansOtherItr != spansOther.end(); ++spansItr, ++spansOtherItr) {
1012             if (!(*spansItr)->IsAttributesEqual(*spansOtherItr) ||
1013                 (*spansItr)->GetEndIndex() != (*spansOtherItr)->GetEndIndex() ||
1014                 (*spansItr)->GetStartIndex() != (*spansOtherItr)->GetStartIndex()) {
1015                 return false;
1016             }
1017         }
1018     }
1019     return true;
1020 }
1021 
GetSpanItems() const1022 std::list<RefPtr<NG::SpanItem>> SpanString::GetSpanItems() const
1023 {
1024     return spans_;
1025 }
1026 
BindWithSpans(const std::vector<RefPtr<SpanBase>> & spans)1027 void SpanString::BindWithSpans(const std::vector<RefPtr<SpanBase>>& spans)
1028 {
1029     for (auto& span : spans) {
1030         AddSpan(span);
1031     }
1032 }
1033 
UpdateSpansWithOffset(int32_t start,int32_t offset)1034 void SpanString::UpdateSpansWithOffset(int32_t start, int32_t offset)
1035 {
1036     for (auto& span : spans_) {
1037         if (span->interval.second > start && span->interval.first != start) {
1038             span->interval.second += offset;
1039         }
1040         if (span->interval.first > start) {
1041             span->interval.first += offset;
1042         }
1043     }
1044 }
1045 
UpdateSpanMapWithOffset(int32_t start,int32_t offset)1046 void SpanString::UpdateSpanMapWithOffset(int32_t start, int32_t offset)
1047 {
1048     for (auto& iter : spansMap_) {
1049         if (spansMap_.find(iter.first) == spansMap_.end()) {
1050             continue;
1051         }
1052         auto spans = spansMap_[iter.first];
1053         for (auto& it : spans) {
1054             UpdateSpanBaseWithOffset(it, start, offset);
1055         }
1056         spansMap_[iter.first] = spans;
1057     }
1058 }
1059 
UpdateSpanBaseWithOffset(RefPtr<SpanBase> & span,int32_t start,int32_t offset)1060 void SpanString::UpdateSpanBaseWithOffset(RefPtr<SpanBase>& span, int32_t start, int32_t offset)
1061 {
1062     if (span->GetEndIndex() > start && span->GetStartIndex() != start) {
1063         span->UpdateEndIndex(span->GetEndIndex() + offset);
1064     }
1065     if (span->GetStartIndex() > start) {
1066         span->UpdateStartIndex(span->GetStartIndex() + offset);
1067     }
1068 }
1069 
RemoveSpecialSpan(int32_t start,int32_t end,SpanType type)1070 void SpanString::RemoveSpecialSpan(int32_t start, int32_t end, SpanType type)
1071 {
1072     auto spans = spansMap_[type];
1073     int32_t count = 0;
1074     for (auto iter = spans.begin(); iter != spans.end();) {
1075         if ((*iter)->GetStartIndex() >= start && (*iter)->GetStartIndex() < end - count) {
1076             text_.erase((*iter)->GetStartIndex(), 1);
1077             UpdateSpanMapWithOffset((*iter)->GetStartIndex(), -1);
1078             iter = spans.erase(iter);
1079             ++count;
1080             continue;
1081         }
1082         ++iter;
1083     }
1084     if (spans.empty()) {
1085         spansMap_.erase(type);
1086     } else {
1087         spansMap_[type] = spans;
1088     }
1089     count = 0;
1090     for (auto iter = spans_.begin(); iter != spans_.end();) {
1091         if ((*iter)->interval.first >= start && (*iter)->interval.first < end - count
1092             && ((type == SpanType::Image && (*iter)->spanItemType == SpanItemType::IMAGE)
1093                 || (type == SpanType::CustomSpan && (*iter)->spanItemType == SpanItemType::CustomSpan))) {
1094             UpdateSpansWithOffset((*iter)->interval.first, -1);
1095             iter = spans_.erase(iter);
1096             ++count;
1097             continue;
1098         }
1099         ++iter;
1100     }
1101 }
1102 
GetSpecialTypesVector(std::list<int32_t> & indexList,int32_t start,int32_t length)1103 void SpanString::GetSpecialTypesVector(std::list<int32_t>& indexList, int32_t start, int32_t length)
1104 {
1105     int32_t end = start + length;
1106     auto iter = indexList.begin();
1107     for (const auto& type : specailTypes) {
1108         auto spans = spansMap_[type];
1109         for (const auto& span : spans) {
1110             auto intersection = span->GetIntersectionInterval({ start, end });
1111             if (!intersection) {
1112                 continue;
1113             }
1114             iter = indexList.insert(iter, span->GetStartIndex());
1115         }
1116     }
1117     indexList.sort([](const int32_t& a, const int32_t& b) { return a < b; });
1118 }
1119 
GetNormalTypesVector(std::list<std::pair<int32_t,int32_t>> & indexList,int32_t start,int32_t length)1120 void SpanString::GetNormalTypesVector(std::list<std::pair<int32_t, int32_t>>& indexList, int32_t start, int32_t length)
1121 {
1122     std::list<int32_t> specialList;
1123     GetSpecialTypesVector(specialList, start, length);
1124     auto next = start;
1125     auto iter = indexList.begin();
1126     for (const auto& index : specialList) {
1127         if (index > next) {
1128             iter = indexList.insert(iter, { next, index - next });
1129         }
1130         next = index + 1;
1131     }
1132     if (next < start + length) {
1133         indexList.insert(iter, { next, start + length - next });
1134     }
1135 }
1136 
ContainSpecialNode(int32_t start,int32_t length)1137 bool SpanString::ContainSpecialNode(int32_t start, int32_t length)
1138 {
1139     int32_t end = start + length;
1140     for (const auto& type : specailTypes) {
1141         auto spans = spansMap_[type];
1142         for (const auto& span : spans) {
1143             auto intersection = span->GetIntersectionInterval({ start, end });
1144             if (intersection) {
1145                 return true;
1146             }
1147             if (span->GetStartIndex() >= end) {
1148                 break;
1149             }
1150         }
1151     }
1152     return false;
1153 }
1154 
IsSpecialNode(RefPtr<SpanBase> span)1155 bool SpanString::IsSpecialNode(RefPtr<SpanBase> span)
1156 {
1157     auto type = span->GetSpanType();
1158     if (specailTypes.find(type) == specailTypes.end()) {
1159         return false;
1160     }
1161     return true;
1162 }
1163 
ClearSpans()1164 void SpanString::ClearSpans()
1165 {
1166     spans_.clear();
1167 }
1168 
AppendSpanItem(const RefPtr<NG::SpanItem> & spanItem)1169 void SpanString::AppendSpanItem(const RefPtr<NG::SpanItem>& spanItem)
1170 {
1171     spans_.emplace_back(spanItem);
1172 }
1173 
EncodeTlv(std::vector<uint8_t> & buff)1174 bool SpanString::EncodeTlv(std::vector<uint8_t>& buff)
1175 {
1176     TLVUtil::WriteUint8(buff, TLV_SPAN_STRING_SPANS);
1177     TLVUtil::WriteInt32(buff, spans_.size());
1178     for (auto it = spans_.begin(); it != spans_.end(); ++it) {
1179         auto spanItem = (*it);
1180         if (spanItem->spanItemType == SpanItemType::CustomSpan) {
1181             TLVUtil::WriteInt32(buff, static_cast<int32_t>(SpanItemType::NORMAL));
1182             auto placeHolderSpan = AceType::MakeRefPtr<NG::SpanItem>();
1183             placeHolderSpan->content = u" ";
1184             placeHolderSpan->interval = spanItem->interval;
1185             placeHolderSpan->EncodeTlv(buff);
1186             continue;
1187         }
1188         TLVUtil::WriteInt32(buff, static_cast<int32_t>(spanItem->spanItemType));
1189         spanItem->EncodeTlv(buff);
1190     }
1191     TLVUtil::WriteUint8(buff, TLV_SPAN_STRING_CONTENT);
1192     TLVUtil::WriteString(buff, UtfUtils::Str16DebugToStr8(text_));
1193     TLVUtil::WriteUint8(buff, TLV_END);
1194     std::vector<uint8_t> otherInfo;
1195     TLVUtil::WriteInt32(otherInfo, isFromStyledStringMode ? 1 : 0);
1196     TLVUtil::WriteUint8(buff, TLV_SPAN_STRING_MODE_FLAG);
1197     TLVUtil::WriteInt32(buff, static_cast<int32_t>(otherInfo.size()));
1198     buff.insert(buff.end(), otherInfo.begin(), otherInfo.end());
1199     return true;
1200 }
1201 
DecodeTlv(std::vector<uint8_t> & buff)1202 RefPtr<SpanString> SpanString::DecodeTlv(std::vector<uint8_t>& buff)
1203 {
1204     RefPtr<SpanString> spanStr = MakeRefPtr<SpanString>(u"");
1205     SpanString* spanString = AceType::RawPtr(spanStr);
1206     std::function<RefPtr<ExtSpan>(const std::vector<uint8_t>&, int32_t, int32_t)> unmarshallCallback;
1207     DecodeTlvExt(buff, spanString, std::move(unmarshallCallback));
1208     return spanStr;
1209 }
1210 
DecodeTlv(std::vector<uint8_t> & buff,const std::function<RefPtr<ExtSpan> (const std::vector<uint8_t> &,int32_t,int32_t)> && unmarshallCallback,int32_t instanceId)1211 RefPtr<SpanString> SpanString::DecodeTlv(std::vector<uint8_t>& buff,
1212     const std::function<RefPtr<ExtSpan>(const std::vector<uint8_t>&, int32_t, int32_t)>&& unmarshallCallback,
1213     int32_t instanceId)
1214 {
1215     RefPtr<SpanString> spanStr = MakeRefPtr<SpanString>(u"");
1216     SpanString* spanString = AceType::RawPtr(spanStr);
1217     DecodeTlvExt(buff, spanString, std::move(unmarshallCallback), instanceId);
1218     return spanStr;
1219 }
1220 
DecodeTlvExt(std::vector<uint8_t> & buff,SpanString * spanString,const std::function<RefPtr<ExtSpan> (const std::vector<uint8_t> &,int32_t,int32_t)> && unmarshallCallback,int32_t instanceId)1221 void SpanString::DecodeTlvExt(std::vector<uint8_t>& buff, SpanString* spanString,
1222     const std::function<RefPtr<ExtSpan>(const std::vector<uint8_t>&, int32_t, int32_t)>&& unmarshallCallback,
1223     int32_t instanceId)
1224 {
1225     CHECK_NULL_VOID(spanString);
1226     int32_t cursor = 0;
1227     DecodeTlvOldExt(buff, spanString, cursor);
1228 
1229     for (uint8_t tag = TLVUtil::ReadUint8(buff, cursor); tag != TLV_END; tag = TLVUtil::ReadUint8(buff, cursor)) {
1230         auto buffLength = TLVUtil::ReadInt32(buff, cursor);
1231         if (buffLength == 0) {
1232             continue;
1233         }
1234         auto lastCursor = cursor;
1235         switch (tag) {
1236             case TLV_CUSTOM_MARSHALL_BUFFER_START: {
1237                 CHECK_NULL_BREAK(unmarshallCallback);
1238                 auto start = TLVUtil::ReadInt32(buff, cursor);
1239                 auto length = TLVUtil::ReadInt32(buff, cursor);
1240                 auto endOfUserDataArrBuff = buffLength + cursor + cursor - lastCursor;
1241                 std::vector<uint8_t> bufferSubVec(buff.begin() + cursor, buff.begin() + endOfUserDataArrBuff);
1242                 ContainerScope scope(instanceId);
1243                 auto container = AceEngine::Get().GetContainer(instanceId);
1244                 CHECK_NULL_VOID(container);
1245                 auto taskExecutor = container->GetTaskExecutor();
1246                 CHECK_NULL_VOID(taskExecutor);
1247                 taskExecutor->PostSyncTask([spanString, start, length, bufferSubVec, unmarshallCallback]() mutable {
1248                         auto extSpan = unmarshallCallback(bufferSubVec, start, length);
1249                         spanString->AddSpan(extSpan);
1250                     }, TaskExecutor::TaskType::UI, "SpanstringDecodeTlvExt", PriorityType::IMMEDIATE);
1251                 cursor = lastCursor + buffLength;
1252                 break;
1253             }
1254             case TLV_SPAN_STRING_MODE_FLAG: {
1255                 auto isFromStyledStringMode = TLVUtil::ReadInt32(buff, cursor);
1256                 spanString->isFromStyledStringMode = isFromStyledStringMode == 1;
1257             }
1258             default:
1259                 break;
1260         }
1261         cursor = lastCursor + buffLength;
1262     }
1263 }
1264 
DecodeTlvOldExt(std::vector<uint8_t> & buff,SpanString * spanString,int32_t & cursor)1265 void SpanString::DecodeTlvOldExt(std::vector<uint8_t>& buff, SpanString* spanString, int32_t& cursor)
1266 {
1267     CHECK_NULL_VOID(spanString);
1268     spanString->ClearSpans();
1269     for (uint8_t tag = TLVUtil::ReadUint8(buff, cursor); tag != TLV_END; tag = TLVUtil::ReadUint8(buff, cursor)) {
1270         switch (tag) {
1271             case TLV_SPAN_STRING_CONTENT: {
1272                 auto str = UtfUtils::Str8DebugToStr16(TLVUtil::ReadString(buff, cursor));
1273                 spanString->SetString(str);
1274                 break;
1275             }
1276             case TLV_SPAN_STRING_SPANS: {
1277                 DecodeSpanItemListExt(buff, cursor, spanString);
1278                 break;
1279             }
1280             default:
1281                 break;
1282         }
1283     }
1284 }
1285 
DecodeSpanItemListExt(std::vector<uint8_t> & buff,int32_t & cursor,SpanString * spanStr)1286 void SpanString::DecodeSpanItemListExt(std::vector<uint8_t>& buff, int32_t& cursor, SpanString* spanStr)
1287 {
1288     CHECK_NULL_VOID(spanStr);
1289     int32_t spanLength = TLVUtil::ReadInt32(buff, cursor);
1290     for (auto i = 0; i < spanLength; i++) {
1291         auto spanItemType = TLVUtil::ReadInt32(buff, cursor);
1292         if (spanItemType == static_cast<int32_t>(SpanItemType::IMAGE)) {
1293             auto imageSpanItem = NG::ImageSpanItem::DecodeTlv(buff, cursor);
1294             spanStr->AppendSpanItem(imageSpanItem);
1295         } else {
1296             auto spanItem = NG::SpanItem::DecodeTlv(buff, cursor);
1297             spanStr->AppendSpanItem(spanItem);
1298         }
1299     }
1300     spanStr->UpdateSpansMap();
1301 }
1302 
DecodeSpanItemList(std::vector<uint8_t> & buff,int32_t & cursor,RefPtr<SpanString> & spanStr)1303 void SpanString::DecodeSpanItemList(std::vector<uint8_t>& buff, int32_t& cursor, RefPtr<SpanString>& spanStr)
1304 {
1305     CHECK_NULL_VOID(spanStr);
1306     DecodeSpanItemListExt(buff, cursor, Referenced::RawPtr(spanStr));
1307 }
1308 
UpdateSpansMap()1309 void SpanString::UpdateSpansMap()
1310 {
1311     spansMap_.clear();
1312     for (auto& spanItem : spans_) {
1313         if (!spanItem) {
1314             continue;
1315         }
1316         auto start = spanItem->interval.first;
1317         auto end = spanItem->interval.second;
1318         std::list<RefPtr<SpanBase>> spanBases;
1319         if (spanItem->spanItemType == SpanItemType::IMAGE) {
1320             spanBases = { ToImageSpan(spanItem, start, end) };
1321         } else if (spanItem->spanItemType == SpanItemType::NORMAL)
1322             spanBases = { ToFontSpan(spanItem, start, end),
1323                 ToDecorationSpan(spanItem, start, end),
1324                 ToBaselineOffsetSpan(spanItem, start, end),
1325                 ToLetterSpacingSpan(spanItem, start, end),
1326                 ToGestureSpan(spanItem, start, end),
1327                 ToParagraphStyleSpan(spanItem, start, end),
1328                 ToLineHeightSpan(spanItem, start, end),
1329                 ToBackgroundColorSpan(spanItem, start, end),
1330                 ToUrlSpan(spanItem, start, end) };
1331         for (auto& spanBase : spanBases) {
1332             if (!spanBase) {
1333                 continue;
1334             }
1335             auto it = spansMap_.find(spanBase->GetSpanType());
1336             if (it == spansMap_.end()) {
1337                 spansMap_.insert({ spanBase->GetSpanType(), { spanBase } });
1338             } else {
1339                 it->second.emplace_back(std::move(spanBase));
1340             }
1341         }
1342     }
1343 }
1344 
ToString()1345 std::string SpanString::ToString()
1346 {
1347     std::stringstream ss;
1348     for (auto span: spans_) {
1349         ss << "Get spanItem [" << span->interval.first << ":"
1350             << span->interval.second << "] " << UtfUtils::Str16DebugToStr8(span->content) << std::endl;
1351     }
1352     for (auto& iter : spansMap_) {
1353         auto spans = spansMap_[iter.first];
1354         for (auto it = spans.begin(); it != spans.end(); ++it) {
1355             ss << (*it)->ToString() << std::endl;
1356         }
1357     }
1358     std::string output = ss.str();
1359     return output;
1360 }
1361 
ToFontSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1362 RefPtr<FontSpan> SpanString::ToFontSpan(const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1363 {
1364     CHECK_NULL_RETURN(spanItem && spanItem->fontStyle, nullptr);
1365     Font font;
1366     font.fontColor = spanItem->fontStyle->GetTextColor();
1367     font.fontFamiliesNG = spanItem->fontStyle->GetFontFamily();
1368     font.fontSize = spanItem->fontStyle->GetFontSize();
1369     font.fontStyle = spanItem->fontStyle->GetItalicFontStyle();
1370     font.fontWeight = spanItem->fontStyle->GetFontWeight();
1371     font.strokeWidth = spanItem->fontStyle->GetStrokeWidth();
1372     font.strokeColor = spanItem->fontStyle->GetStrokeColor();
1373     font.superscript = spanItem->fontStyle->GetSuperscript();
1374     return AceType::MakeRefPtr<FontSpan>(font, start, end);
1375 }
1376 
ToDecorationSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1377 RefPtr<DecorationSpan> SpanString::ToDecorationSpan(
1378     const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1379 {
1380     CHECK_NULL_RETURN(spanItem && spanItem->fontStyle, nullptr);
1381     std::vector<TextDecoration> types = spanItem->fontStyle->GetTextDecoration().value_or(
1382         std::vector<TextDecoration>({TextDecoration::NONE}));
1383     std::optional<Color> color = spanItem->fontStyle->GetTextDecorationColor();
1384     std::optional<TextDecorationStyle> style = spanItem->fontStyle->GetTextDecorationStyle();
1385     std::optional<float> lineThicknessScale = spanItem->fontStyle->GetLineThicknessScale();
1386     std::optional<TextDecorationOptions> options;
1387     return AceType::MakeRefPtr<DecorationSpan>(
1388         types, color, style, lineThicknessScale, options, start, end);
1389 }
1390 
ToBaselineOffsetSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1391 RefPtr<BaselineOffsetSpan> SpanString::ToBaselineOffsetSpan(
1392     const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1393 {
1394     CHECK_NULL_RETURN(spanItem && spanItem->textLineStyle, nullptr);
1395     Dimension baselineOffset;
1396     if (spanItem->textLineStyle->GetBaselineOffset().has_value()) {
1397         baselineOffset.SetValue(spanItem->textLineStyle->GetBaselineOffsetValue().ConvertToVp());
1398     }
1399     return AceType::MakeRefPtr<BaselineOffsetSpan>(baselineOffset, start, end);
1400 }
1401 
ToLetterSpacingSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1402 RefPtr<LetterSpacingSpan> SpanString::ToLetterSpacingSpan(
1403     const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1404 {
1405     CHECK_NULL_RETURN(spanItem && spanItem->fontStyle, nullptr);
1406     Dimension letterSpacing;
1407     if (spanItem->fontStyle->GetLetterSpacing().has_value()) {
1408         letterSpacing.SetValue(spanItem->fontStyle->GetLetterSpacingValue().ConvertToVp());
1409     }
1410     return AceType::MakeRefPtr<LetterSpacingSpan>(letterSpacing, start, end);
1411 }
1412 
ToGestureSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1413 RefPtr<GestureSpan> SpanString::ToGestureSpan(const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1414 {
1415     GestureStyle gestureInfo;
1416     if (spanItem->onClick) {
1417         gestureInfo.onClick = spanItem->onClick;
1418     }
1419     if (spanItem->onLongPress) {
1420         gestureInfo.onLongPress = spanItem->onLongPress;
1421     }
1422     return AceType::MakeRefPtr<GestureSpan>(gestureInfo, start, end);
1423 }
1424 
ToTextShadowSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1425 RefPtr<TextShadowSpan> SpanString::ToTextShadowSpan(
1426     const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1427 {
1428     CHECK_NULL_RETURN(spanItem && spanItem->fontStyle, nullptr);
1429     std::vector<Shadow> textShadow = spanItem->fontStyle->GetTextShadow().value_or(std::vector<Shadow> { Shadow() });
1430     return AceType::MakeRefPtr<TextShadowSpan>(textShadow, start, end);
1431 }
1432 
ToImageSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1433 RefPtr<ImageSpan> SpanString::ToImageSpan(const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1434 {
1435     auto imageItem = DynamicCast<NG::ImageSpanItem>(spanItem);
1436     CHECK_NULL_RETURN(imageItem && start + 1 == end, nullptr);
1437     return AceType::MakeRefPtr<ImageSpan>(imageItem->options, start);
1438 }
1439 
ToParagraphStyleSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1440 RefPtr<ParagraphStyleSpan> SpanString::ToParagraphStyleSpan(
1441     const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1442 {
1443     CHECK_NULL_RETURN(spanItem && spanItem->textLineStyle, nullptr);
1444     SpanParagraphStyle paragraphStyle;
1445     paragraphStyle.align = spanItem->textLineStyle->GetTextAlign();
1446     paragraphStyle.textVerticalAlign = spanItem->textLineStyle->GetTextVerticalAlign();
1447     paragraphStyle.maxLines = spanItem->textLineStyle->GetMaxLines();
1448     paragraphStyle.textOverflow = spanItem->textLineStyle->GetTextOverflow();
1449     paragraphStyle.leadingMargin = spanItem->textLineStyle->GetLeadingMargin();
1450     paragraphStyle.wordBreak = spanItem->textLineStyle->GetWordBreak();
1451     paragraphStyle.textIndent = spanItem->textLineStyle->GetTextIndent();
1452     paragraphStyle.paragraphSpacing = spanItem->textLineStyle->GetParagraphSpacing();
1453     return AceType::MakeRefPtr<ParagraphStyleSpan>(paragraphStyle, start, end);
1454 }
1455 
ToLineHeightSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1456 RefPtr<LineHeightSpan> SpanString::ToLineHeightSpan(const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1457 {
1458     CHECK_NULL_RETURN(spanItem && spanItem->textLineStyle, nullptr);
1459     Dimension lineHeight;
1460     if (spanItem->textLineStyle->GetLineHeight().has_value()) {
1461         lineHeight.SetValue(spanItem->textLineStyle->GetLineHeightValue().ConvertToVp());
1462     }
1463     return AceType::MakeRefPtr<LineHeightSpan>(lineHeight, start, end);
1464 }
1465 
ToBackgroundColorSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1466 RefPtr<BackgroundColorSpan> SpanString::ToBackgroundColorSpan(
1467     const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1468 {
1469     CHECK_NULL_RETURN(spanItem, nullptr);
1470     std::optional<TextBackgroundStyle> backgroundStyle;
1471     if (spanItem->backgroundStyle.has_value()) {
1472         backgroundStyle = spanItem->backgroundStyle.value();
1473     }
1474     return AceType::MakeRefPtr<BackgroundColorSpan>(backgroundStyle, start, end);
1475 }
1476 
ToUrlSpan(const RefPtr<NG::SpanItem> & spanItem,int32_t start,int32_t end)1477 RefPtr<UrlSpan> SpanString::ToUrlSpan(const RefPtr<NG::SpanItem>& spanItem, int32_t start, int32_t end)
1478 {
1479     CHECK_NULL_RETURN(spanItem && spanItem->urlOnRelease && !spanItem->GetUrlAddress().empty(), nullptr);
1480     std::string urlAddress = UtfUtils::Str16DebugToStr8(spanItem->GetUrlAddress());
1481     return AceType::MakeRefPtr<UrlSpan>(urlAddress, start, end);
1482 }
1483 
1484 } // namespace OHOS::Ace
1485