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