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