1 /*
2 * Copyright (c) 2023 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 "shaper.h"
17
18 #include <queue>
19 #include <variant>
20
21 #include "bidi_processer.h"
22 #include "line_breaker.h"
23 #include "measurer.h"
24 #include "texgine/any_span.h"
25 #include "texgine_exception.h"
26 #include "texgine/utils/exlog.h"
27 #ifdef LOGGER_ENABLE_SCOPE
28 #include "texgine/utils/trace.h"
29 #endif
30 #include "text_breaker.h"
31 #include "text_merger.h"
32 #include "text_reverser.h"
33 #include "text_shaper.h"
34
35 namespace OHOS {
36 namespace Rosen {
37 namespace TextEngine {
38 #define MAXWIDTH 1e9
39 #define TEXTOVERFLOWER 1
40
41 namespace {
DumpLineMetrics(const std::vector<LineMetrics> & lineMetrics)42 void DumpLineMetrics(const std::vector<LineMetrics> &lineMetrics)
43 {
44 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), "DumpLineMetrics");
45 for (const auto &metric : lineMetrics) {
46 for (const auto &span : metric.lineSpans) {
47 span.Dump();
48 }
49 }
50 }
51 } // namespace
52
DidExceedMaxLines() const53 bool Shaper::DidExceedMaxLines() const
54 {
55 return didExceedMaxLines_;
56 }
57
GetMinIntrinsicWidth() const58 double Shaper::GetMinIntrinsicWidth() const
59 {
60 return minIntrinsicWidth_;
61 }
62
GetMaxIntrinsicWidth() const63 double Shaper::GetMaxIntrinsicWidth() const
64 {
65 return maxIntrinsicWidth_;
66 }
67
SetIndents(const std::vector<float> & indents)68 void Shaper::SetIndents(const std::vector<float> &indents)
69 {
70 indents_ = indents;
71 }
72
CreateEllipsisSpan(const TypographyStyle & ys,const TextStyle & textStyle,const std::shared_ptr<FontProviders> & fontProviders)73 std::vector<LineMetrics> Shaper::CreateEllipsisSpan(const TypographyStyle &ys, const TextStyle &textStyle,
74 const std::shared_ptr<FontProviders> &fontProviders)
75 {
76 if (ys.ellipsis.empty()) {
77 return {};
78 }
79
80 std::vector<VariantSpan> spans = {TextSpan::MakeFromText(ys.ellipsis)};
81 for (auto &span : spans) {
82 span.SetTextStyle(textStyle);
83 }
84 auto ys2 = ys;
85 ys2.wordBreakType = WordBreakType::BREAK_ALL;
86 ys2.breakStrategy = BreakStrategy::GREEDY;
87 return DoShapeBeforeEllipsis(spans, ys2, fontProviders, MAXWIDTH);
88 }
89
SetEllipsisProperty(std::vector<VariantSpan> & ellipsisSpans,std::vector<LineMetrics> & ellipsisMertics,double & ellipsisWidth)90 void Shaper::SetEllipsisProperty(std::vector<VariantSpan> &ellipsisSpans,
91 std::vector<LineMetrics> &ellipsisMertics, double &ellipsisWidth)
92 {
93 for (auto &metric : ellipsisMertics) {
94 for (auto &es : metric.lineSpans) {
95 ellipsisWidth += es.GetWidth();
96 ellipsisSpans.push_back(es);
97 }
98 }
99 }
100
ConsiderEllipsis(const TypographyStyle & tstyle,const std::shared_ptr<FontProviders> & fontProviders,const double widthLimit)101 void Shaper::ConsiderEllipsis(const TypographyStyle &tstyle,
102 const std::shared_ptr<FontProviders> &fontProviders, const double widthLimit)
103 {
104 didExceedMaxLines_ = false;
105 auto maxLines = tstyle.maxLines;
106 if (maxLines < 0) {
107 maxLines = 1;
108 }
109 if (maxLines == 0) {
110 lineMetrics_.erase(lineMetrics_.begin(), lineMetrics_.end());
111 return;
112 }
113
114 if (lineMetrics_.size() <= maxLines) {
115 if (tstyle.ellipsis.length() && tstyle.maxLines == std::numeric_limits<size_t>::max() &&
116 lineMetrics_.size() > 1) {
117 maxLines = TEXTOVERFLOWER;
118 } else {
119 return;
120 }
121 }
122
123 const auto &textStyle = lineMetrics_.back().lineSpans.back().GetTextStyle();
124 std::vector<LineMetrics> ellipsisMertics = CreateEllipsisSpan(tstyle, textStyle, fontProviders);
125 double ellipsisWidth = 0.0;
126 std::vector<VariantSpan> ellipsisSpans;
127 SetEllipsisProperty(ellipsisSpans, ellipsisMertics, ellipsisWidth);
128
129 EllipsisParams params{ellipsisSpans, ellipsisWidth, maxLines, widthLimit};
130 if (maxLines == 1) { // single line
131 switch (tstyle.ellipsisModal) {
132 case EllipsisModal::HEAD:
133 params.widthLimit -= lineMetrics_.front().indent;
134 ConsiderHeadEllipsis(tstyle, fontProviders, params);
135 break;
136 case EllipsisModal::MIDDLE:
137 params.widthLimit -= lineMetrics_.front().indent;
138 ConsiderMiddleEllipsis(tstyle, fontProviders, params);
139 break;
140 case EllipsisModal::TAIL:
141 default:
142 ConsiderTailEllipsis(tstyle, fontProviders, params);
143 break;
144 }
145 } else if (maxLines > 1) { // multi line
146 if (tstyle.ellipsisModal == EllipsisModal::TAIL) {
147 ConsiderTailEllipsis(tstyle, fontProviders, params);
148 } else if (maxLines < lineMetrics_.size()) {
149 lineMetrics_.erase(lineMetrics_.begin() + maxLines, lineMetrics_.end());
150 }
151 }
152 didExceedMaxLines_ = true;
153 }
154
ComputeIntrinsicWidth(const size_t maxLines)155 void Shaper::ComputeIntrinsicWidth(const size_t maxLines)
156 {
157 maxIntrinsicWidth_ = 0.0;
158 minIntrinsicWidth_ = 0.0;
159 double lastInvisibleWidth = 0;
160 for (const auto &line : lineMetrics_) {
161 for (const auto &span : line.lineSpans) {
162 if (span == nullptr) {
163 continue;
164 }
165
166 auto width = span.GetWidth();
167 auto visibleWidth = span.GetVisibleWidth();
168 maxIntrinsicWidth_ += width;
169 minIntrinsicWidth_ = std::max(visibleWidth, minIntrinsicWidth_);
170 lastInvisibleWidth = width - visibleWidth;
171 }
172 }
173
174 maxIntrinsicWidth_ -= lastInvisibleWidth;
175 if (maxLines > 1) {
176 minIntrinsicWidth_ = std::min(maxIntrinsicWidth_, minIntrinsicWidth_);
177 } else {
178 minIntrinsicWidth_ = maxIntrinsicWidth_;
179 }
180 }
181
DoShapeBeforeEllipsis(std::vector<VariantSpan> spans,const TypographyStyle & tstyle,const std::shared_ptr<FontProviders> & fontProviders,const double widthLimit)182 std::vector<LineMetrics> Shaper::DoShapeBeforeEllipsis(std::vector<VariantSpan> spans, const TypographyStyle &tstyle,
183 const std::shared_ptr<FontProviders> &fontProviders, const double widthLimit)
184 {
185 TextBreaker tb;
186 tb.SetWidthLimit(widthLimit);
187 tb.SetIndents(indents_);
188 auto ret = tb.WordBreak(spans, tstyle, fontProviders);
189 if (ret) {
190 LOGEX_FUNC_LINE(ERROR) << "word break failed";
191 return {};
192 }
193
194 BidiProcesser bp;
195 auto newSpans = bp.ProcessBidiText(spans, tstyle.direction);
196 if (newSpans.empty()) {
197 LOGEX_FUNC_LINE_DEBUG() << "Process BidiText failed";
198 return {};
199 }
200
201 LineBreaker lb;
202 return lb.BreakLines(newSpans, tstyle, widthLimit, indents_);
203 }
204
DoShape(const std::vector<VariantSpan> spans,const TypographyStyle & tstyle,const std::shared_ptr<FontProviders> & fontProviders,const double widthLimit)205 std::vector<LineMetrics> Shaper::DoShape(const std::vector<VariantSpan> spans, const TypographyStyle &tstyle,
206 const std::shared_ptr<FontProviders> &fontProviders, const double widthLimit)
207 {
208 #ifdef LOGGER_ENABLE_SCOPE
209 ScopedTrace scope("Shaper::DoShape");
210 #endif
211
212 lineMetrics_= DoShapeBeforeEllipsis(spans, tstyle, fontProviders, widthLimit);
213 ComputeIntrinsicWidth(tstyle.maxLines);
214 ConsiderEllipsis(tstyle, fontProviders, widthLimit);
215
216 TextMerger tm;
217 for (auto &metric : lineMetrics_) {
218 auto res = tm.MergeSpans(metric.lineSpans);
219 std::swap(res, metric.lineSpans);
220 }
221
222 TextReverser tr;
223 for (auto &metric : lineMetrics_) {
224 tr.ReverseRTLText(metric.lineSpans);
225 tr.ProcessTypoDirection(metric.lineSpans, tstyle.direction);
226 }
227
228 TextShaper textShaper;
229 for (const auto &metric : lineMetrics_) {
230 for (const auto &span : metric.lineSpans) {
231 textShaper.Shape(span, tstyle, fontProviders);
232 }
233 }
234 DumpLineMetrics(lineMetrics_);
235 return lineMetrics_;
236 }
237
ConsiderHeadEllipsis(const TypographyStyle & ys,const std::shared_ptr<FontProviders> & fontProviders,EllipsisParams params)238 void Shaper::ConsiderHeadEllipsis(const TypographyStyle &ys, const std::shared_ptr<FontProviders> &fontProviders,
239 EllipsisParams params)
240 {
241 bool isErase = false;
242 auto &lastLine = lineMetrics_.back();
243 double lastLineWidth = lastLine.GetAllSpanWidth();
244 if (params.maxLines < lineMetrics_.size()) {
245 if (params.ellipsisWidth > 0) {
246 // lineMetrics_.size() - 2 is the index of second to last
247 while (!lineMetrics_[lineMetrics_.size() - 2].lineSpans.empty() &&
248 lastLineWidth + params.ellipsisWidth < params.widthLimit) {
249 // lineMetrics_.size() - 2 is the index of second to last
250 auto lastSpan = lineMetrics_[lineMetrics_.size() - 2].lineSpans.back();
251 // lineMetrics_.size() - 2 is the index of second to last
252 lineMetrics_[lineMetrics_.size() - 2].lineSpans.pop_back();
253 lastLine.lineSpans.insert(lastLine.lineSpans.begin(), lastSpan);
254 lastLineWidth = lastLine.GetAllSpanWidth();
255 }
256 lineMetrics_.erase(lineMetrics_.begin(), lineMetrics_.end() - params.maxLines);
257 isErase = true;
258 } else {
259 lineMetrics_.erase(lineMetrics_.begin() + params.maxLines, lineMetrics_.end());
260 }
261 }
262
263 if (params.ellipsisSpans.empty() || (!isErase && lastLineWidth <= params.widthLimit)) {
264 return;
265 }
266
267 std::vector<VariantSpan> &lastLineSpans = lineMetrics_.back().lineSpans;
268 auto ts = lastLineSpans.front().TryToTextSpan();
269 if (ts == nullptr) {
270 if (lastLineWidth + params.ellipsisWidth > params.widthLimit) {
271 lastLineSpans.erase(lastLineSpans.begin());
272 lastLineSpans.insert(lastLineSpans.begin(), params.ellipsisSpans.begin(), params.ellipsisSpans.end());
273 } else if (isErase) {
274 lastLineSpans.insert(lastLineSpans.begin(), params.ellipsisSpans.begin(), params.ellipsisSpans.end());
275 }
276 } else {
277 if (lastLineWidth + params.ellipsisWidth > params.widthLimit) {
278 double exceedWidth = lastLineWidth + params.ellipsisWidth - params.widthLimit;
279 auto firstSpan = lastLineSpans.front();
280 lastLineSpans.erase(lastLineSpans.begin());
281 std::vector<LineMetrics> partlySpan = CreatePartlySpan(false, ys, fontProviders, firstSpan, exceedWidth);
282 if (!partlySpan.empty()) {
283 std::vector<VariantSpan> partlyLineSpans = partlySpan.front().lineSpans;
284 lastLineSpans.insert(lastLineSpans.begin(), partlyLineSpans.begin(), partlyLineSpans.end());
285 }
286 lastLineSpans.insert(lastLineSpans.begin(), params.ellipsisSpans.begin(), params.ellipsisSpans.end());
287 } else if (isErase) {
288 lastLineSpans.insert(lastLineSpans.begin(), params.ellipsisSpans.begin(), params.ellipsisSpans.end());
289 }
290 }
291 }
292
ConsiderLastLine(const TypographyStyle & style,const std::shared_ptr<FontProviders> & fontProviders,EllipsisParams params,const bool isErase)293 void Shaper::ConsiderLastLine(const TypographyStyle &style, const std::shared_ptr<FontProviders> &fontProviders,
294 EllipsisParams params, const bool isErase)
295 {
296 // maxLines - 1 is the index of last LineMetrics
297 auto &lastLine = params.maxLines < lineMetrics_.size() ? lineMetrics_[params.maxLines - 1] : lineMetrics_.back();
298 double lastLineWidth = lastLine.GetAllSpanWidth();
299 bool isExceed = (static_cast<int>(lastLineWidth + params.ellipsisWidth) > static_cast<int>(params.widthLimit));
300 if (isExceed) {
301 while ((!lastLine.lineSpans.empty()) && isExceed) {
302 auto lastSpan = lastLine.lineSpans.back();
303 lastLine.lineSpans.pop_back();
304 double exceedWidth = lastLineWidth + params.ellipsisWidth - params.widthLimit;
305 std::vector<LineMetrics> partlySpan = CreatePartlySpan(true, style, fontProviders, lastSpan, exceedWidth);
306 if (!partlySpan.empty()) {
307 std::vector<VariantSpan> partlyLineSpans = partlySpan.front().lineSpans;
308 lastLine.lineSpans.insert(lastLine.lineSpans.end(), partlyLineSpans.begin(),
309 partlyLineSpans.end());
310 }
311 lastLineWidth = lastLine.GetAllSpanWidth();
312 isExceed = (static_cast<int>(lastLineWidth + params.ellipsisWidth) > static_cast<int>(params.widthLimit));
313 }
314 lastLine.lineSpans.insert(lastLine.lineSpans.end(), params.ellipsisSpans.begin(),
315 params.ellipsisSpans.end());
316 } else if (isErase) {
317 lastLine.lineSpans.insert(lastLine.lineSpans.end(), params.ellipsisSpans.begin(),
318 params.ellipsisSpans.end());
319 }
320 }
321
ConsiderTailEllipsis(const TypographyStyle & style,const std::shared_ptr<FontProviders> & fontProviders,EllipsisParams params)322 void Shaper::ConsiderTailEllipsis(const TypographyStyle &style, const std::shared_ptr<FontProviders> &fontProviders,
323 EllipsisParams params)
324 {
325 bool isErase = false;
326 // maxLines - 1 is the index of last LineMetrics
327 auto &lastLine = params.maxLines < lineMetrics_.size() ? lineMetrics_[params.maxLines - 1] : lineMetrics_.back();
328 double lastLineWidth = lastLine.GetAllSpanWidth();
329 params.widthLimit -= lastLine.indent;
330 if (params.maxLines < lineMetrics_.size()) {
331 if (params.ellipsisWidth > 0 && lastLineWidth + params.ellipsisWidth < params.widthLimit &&
332 style.wordBreakType == WordBreakType::BREAK_ALL) {
333 lastLine.lineSpans.push_back(lineMetrics_[params.maxLines].lineSpans.front());
334 lastLineWidth = lastLine.GetAllSpanWidth();
335 }
336 lineMetrics_.erase(lineMetrics_.begin() + params.maxLines, lineMetrics_.end());
337 isErase = true;
338 }
339
340 if (params.ellipsisSpans.empty() || (!isErase && lastLineWidth <= params.widthLimit)) {
341 return;
342 }
343
344 auto ts = lastLine.lineSpans.back().TryToTextSpan();
345 if (ts == nullptr) {
346 if (lastLineWidth + params.ellipsisWidth > params.widthLimit) {
347 lastLine.lineSpans.pop_back();
348 lastLine.lineSpans.insert(lastLine.lineSpans.end(), params.ellipsisSpans.begin(),
349 params.ellipsisSpans.end());
350 } else if (isErase) {
351 lastLine.lineSpans.insert(lastLine.lineSpans.end(), params.ellipsisSpans.begin(),
352 params.ellipsisSpans.end());
353 }
354 } else {
355 ConsiderLastLine(style, fontProviders, params, isErase);
356 }
357 }
358
CreatePartlySpan(const bool cutRight,const TypographyStyle & ys,const std::shared_ptr<FontProviders> & fontProviders,const VariantSpan & span,const double exceedWidth)359 std::vector<LineMetrics> Shaper::CreatePartlySpan(const bool cutRight, const TypographyStyle &ys,
360 const std::shared_ptr<FontProviders> &fontProviders, const VariantSpan &span, const double exceedWidth)
361 {
362 auto textSpan = span.TryToTextSpan();
363 if (textSpan == nullptr) {
364 return {};
365 }
366
367 size_t startIndex = static_cast<size_t>(textSpan->cgs_.GetRange().start);
368 size_t endIndex = static_cast<size_t>(textSpan->cgs_.GetRange().end);
369 double deletedWidth = 0.0;
370 while (startIndex < endIndex) {
371 if (deletedWidth >= exceedWidth) {
372 break;
373 }
374 if (cutRight) {
375 endIndex--;
376 deletedWidth += textSpan->cgs_.GetCharWidth(endIndex);
377 } else {
378 deletedWidth += textSpan->cgs_.GetCharWidth(startIndex);
379 startIndex++;
380 }
381 }
382
383 if (startIndex < endIndex) {
384 // endIndex - 1 is the index of end
385 std::vector<uint16_t> chars = textSpan->cgs_.GetCharsToU16(startIndex, endIndex - 1, SpacesModel::NORMAL);
386 VariantSpan partlySpan(TextSpan::MakeFromText(chars));
387 partlySpan.SetTextStyle(span.GetTextStyle());
388 std::vector<VariantSpan> spans = {partlySpan};
389 return DoShapeBeforeEllipsis(spans, ys, fontProviders, MAXWIDTH);
390 } else {
391 return {};
392 }
393 }
394
CalcCharsIndex(const std::shared_ptr<TextSpan> textSpan,size_t & leftIndex,size_t & rightIndex,size_t & maxIndex,const int avalibleWidth) const395 bool Shaper::CalcCharsIndex(const std::shared_ptr<TextSpan> textSpan, size_t &leftIndex,
396 size_t &rightIndex, size_t &maxIndex, const int avalibleWidth) const
397 {
398 if (textSpan == nullptr) {
399 return false;
400 }
401 leftIndex = 0;
402 maxIndex = textSpan->cgs_.GetSize();
403 rightIndex = maxIndex;
404
405 double leftCharsWidth = 0.0;
406 double rightCharsWidth = 0.0;
407 bool isLeft = true;
408 bool isNormal = true;
409 int charsWidth = static_cast<int>(leftCharsWidth + rightCharsWidth);
410 while (charsWidth <= avalibleWidth) {
411 if (isLeft) {
412 leftCharsWidth += textSpan->cgs_.GetCharWidth(leftIndex);
413 charsWidth = static_cast<int>(leftCharsWidth + rightCharsWidth);
414 if (charsWidth > avalibleWidth) {
415 leftIndex--;
416 break;
417 }
418 isLeft = false;
419 } else {
420 rightIndex--;
421 rightCharsWidth += textSpan->cgs_.GetCharWidth(rightIndex);
422 charsWidth = static_cast<int>(leftCharsWidth + rightCharsWidth);
423 if (charsWidth > avalibleWidth) {
424 rightIndex++;
425 break;
426 }
427 leftIndex++;
428 isLeft = true;
429 }
430 if (leftIndex > rightIndex) {
431 isNormal = false;
432 break;
433 }
434 }
435 return isNormal;
436 }
437
SplitJointLeftSpans(const EllipsisParams & params,const size_t leftIndex,const TypographyStyle & style,const std::shared_ptr<FontProviders> & fontProviders,const VariantSpan & span)438 void Shaper::SplitJointLeftSpans(const EllipsisParams ¶ms, const size_t leftIndex,
439 const TypographyStyle &style, const std::shared_ptr<FontProviders> &fontProviders, const VariantSpan &span)
440 {
441 std::shared_ptr<TextSpan> textSpan = span.TryToTextSpan();
442 if (textSpan == nullptr) {
443 return;
444 }
445
446 // 0 means the first index of the array,true means handles spaces at the end of the left index of the array
447 std::vector<uint16_t> leftGroups = textSpan->cgs_.GetCharsToU16(0, leftIndex, SpacesModel::NORMAL);
448 VariantSpan leftSpan(TextSpan::MakeFromText(leftGroups));
449 leftSpan.SetTextStyle(span.GetTextStyle());
450 std::vector<VariantSpan> leftVariantSpans = {leftSpan};
451 lineMetrics_ = DoShapeBeforeEllipsis(leftVariantSpans, style, fontProviders, params.widthLimit);
452 lineMetrics_.back().lineSpans.insert(lineMetrics_.back().lineSpans.end(),
453 params.ellipsisSpans.begin(), params.ellipsisSpans.end());
454 }
455
SplitJointRightSpans(const EllipsisParams & params,const size_t rightIndex,const TypographyStyle & style,const std::shared_ptr<FontProviders> & fontProviders,const VariantSpan & span)456 void Shaper::SplitJointRightSpans(const EllipsisParams ¶ms, const size_t rightIndex,
457 const TypographyStyle &style, const std::shared_ptr<FontProviders> &fontProviders, const VariantSpan &span)
458 {
459 std::shared_ptr<TextSpan> textSpan = span.TryToTextSpan();
460 if (textSpan == nullptr) {
461 return;
462 }
463 size_t maxIndex = textSpan->cgs_.GetSize();
464 // maxIndex - 1 means last index of the array,false means handles spaces at the end of the right index of the array
465 std::vector<uint16_t> rightGroups = textSpan->cgs_.GetCharsToU16(rightIndex, maxIndex - 1, SpacesModel::NORMAL);
466 VariantSpan rightSpan(TextSpan::MakeFromText(rightGroups));
467 rightSpan.SetTextStyle(span.GetTextStyle());
468 std::vector<VariantSpan> rightVariantSpans = {rightSpan};
469 if (style.ellipsisModal == EllipsisModal::HEAD) {
470 lineMetrics_ = DoShapeBeforeEllipsis(rightVariantSpans, style, fontProviders, params.widthLimit);
471 lineMetrics_.front().lineSpans.insert(lineMetrics_.front().lineSpans.begin(),
472 params.ellipsisSpans.begin(), params.ellipsisSpans.end());
473 } else if (style.ellipsisModal == EllipsisModal::MIDDLE) {
474 std::vector<LineMetrics> rightLineMetrics = DoShapeBeforeEllipsis(rightVariantSpans,
475 style, fontProviders, params.widthLimit);
476 lineMetrics_.back().lineSpans.insert(lineMetrics_.back().lineSpans.end(),
477 rightLineMetrics.front().lineSpans.begin(), rightLineMetrics.front().lineSpans.end());
478 }
479 }
480
CalcMidSpanIndex(const std::vector<VariantSpan> & spans,size_t & leftIndex,size_t & rightIndex,struct SpansWidth & spansWidth,const int avalibleWidth)481 bool Shaper::CalcMidSpanIndex(const std::vector<VariantSpan> &spans, size_t &leftIndex, size_t &rightIndex,
482 struct SpansWidth &spansWidth, const int avalibleWidth)
483 {
484 double leftSpansWidth = 0.0;
485 double rightSpansWidth = 0.0;
486 bool isLeft = true;
487 bool isNormal = true;
488 int curSpansWidth = static_cast<int>(leftSpansWidth + rightSpansWidth);
489 while (curSpansWidth <= avalibleWidth) {
490 if (isLeft) {
491 leftSpansWidth += spans.at(leftIndex).GetWidth();
492 curSpansWidth = static_cast<int>(leftSpansWidth + rightSpansWidth);
493 if (curSpansWidth > avalibleWidth) {
494 break;
495 }
496 isLeft = false;
497 } else {
498 rightIndex--;
499 rightSpansWidth += spans.at(rightIndex).GetWidth();
500 curSpansWidth = static_cast<int>(leftSpansWidth + rightSpansWidth);
501 if (curSpansWidth > avalibleWidth) {
502 break;
503 }
504 leftIndex++;
505 isLeft = true;
506 }
507 if (leftIndex >= rightIndex) {
508 isNormal = false;
509 break;
510 }
511 }
512 spansWidth.leftWidth = leftSpansWidth;
513 spansWidth.rightWidth = rightSpansWidth;
514 return isNormal;
515 }
516
ConsideMidSpanEllipsis(const TypographyStyle & style,const std::shared_ptr<FontProviders> & fontProviders,const EllipsisParams & params,const std::vector<VariantSpan> & spans)517 void Shaper::ConsideMidSpanEllipsis(const TypographyStyle &style, const std::shared_ptr<FontProviders> &fontProviders,
518 const EllipsisParams ¶ms, const std::vector<VariantSpan> &spans)
519 {
520 struct SpansWidth spansWidth;
521 size_t leftIndex = 0;
522 size_t rightIndex = spans.size();
523 int avalibleWidth = static_cast<int>(params.widthLimit - params.ellipsisWidth);
524 auto &firstLineSpans = lineMetrics_.front().lineSpans;
525 if (!CalcMidSpanIndex(spans, leftIndex, rightIndex, spansWidth, avalibleWidth)) {
526 firstLineSpans = params.ellipsisSpans;
527 lineMetrics_.erase(lineMetrics_.begin() + params.maxLines, lineMetrics_.end());
528 return;
529 }
530 std::shared_ptr<TextSpan> textSpan = spans.front().TryToTextSpan();
531 double exceedWidth = spansWidth.leftWidth + spansWidth.rightWidth + params.ellipsisWidth - params.widthLimit;
532 std::vector<LineMetrics> partlySpan;
533 bool isLeft = static_cast<int>(spansWidth.leftWidth) > static_cast<int>(spansWidth.rightWidth);
534 if (isLeft) {
535 if (leftIndex >= spans.size()) {
536 firstLineSpans = params.ellipsisSpans;
537 lineMetrics_.erase(lineMetrics_.begin() + params.maxLines, lineMetrics_.end());
538 return;
539 }
540 partlySpan = CreatePartlySpan(true, style, fontProviders, spans.at(leftIndex), exceedWidth);
541 leftIndex--;
542 } else {
543 if (rightIndex < spans.size()) {
544 partlySpan = CreatePartlySpan(false, style, fontProviders, spans.at(rightIndex), exceedWidth);
545 rightIndex++;
546 }
547 }
548
549 firstLineSpans = params.ellipsisSpans;
550 lineMetrics_.erase(lineMetrics_.begin() + params.maxLines, lineMetrics_.end());
551
552 if (leftIndex < spans.size()) {
553 firstLineSpans.insert(firstLineSpans.begin(), spans.begin(), spans.begin() + leftIndex + 1);
554 }
555 if (isLeft) {
556 if (!partlySpan.empty()) {
557 std::vector<VariantSpan> partlyLineSpans = partlySpan.front().lineSpans;
558 firstLineSpans.insert(firstLineSpans.end() - params.ellipsisSpans.size(),
559 partlyLineSpans.begin(), partlyLineSpans.end());
560 }
561 } else {
562 if (!partlySpan.empty()) {
563 std::vector<VariantSpan> partlyLineSpans = partlySpan.front().lineSpans;
564 firstLineSpans.insert(firstLineSpans.end(), partlyLineSpans.begin(), partlyLineSpans.end());
565 }
566 }
567 if (rightIndex < spans.size()) {
568 firstLineSpans.insert(firstLineSpans.end(), spans.begin() + rightIndex, spans.end());
569 }
570 }
571
GetLoopNum(VariantSpan & span,std::vector<VariantSpan> & spans,int & loopNum,int & breakPos,bool & haveAnySpan)572 void Shaper::GetLoopNum(VariantSpan &span, std::vector<VariantSpan> &spans,
573 int &loopNum, int &breakPos, bool &haveAnySpan)
574 {
575 auto textSpan = span.TryToTextSpan();
576 if (textSpan && textSpan->cgs_.GetSize()) {
577 breakPos = textSpan->cgs_.FindHardBreakPos();
578 if (breakPos == -1) {
579 if (static_cast<int>(textSpan->cgs_.GetSize()) == textSpan->cgs_.GetRange().end) {
580 loopNum += textSpan->cgs_.GetRange().end;
581 }
582 spans.push_back(span);
583 } else {
584 loopNum += breakPos;
585 spans.push_back(span);
586 }
587 } else {
588 haveAnySpan = true;
589 }
590 }
591
GetAllTextSpan(std::vector<VariantSpan> & spans,int & loopNum,int & breakPos)592 void Shaper::GetAllTextSpan(std::vector<VariantSpan> &spans, int &loopNum, int &breakPos)
593 {
594 bool haveAnySpan = false;
595 for (auto metric : lineMetrics_) {
596 for (auto span : metric.lineSpans) {
597 GetLoopNum(span, spans, loopNum, breakPos, haveAnySpan);
598 if (haveAnySpan || (breakPos != -1)) {
599 break;
600 }
601 }
602 if (haveAnySpan || (breakPos != -1)) {
603 break;
604 }
605 }
606 }
607
HaveExceedWidth(const std::vector<VariantSpan> & spans,struct SpanPosition & spanPos,const int & charsWidth,struct SpansWidth & spanWidth)608 bool Shaper::HaveExceedWidth(const std::vector<VariantSpan> &spans, struct SpanPosition &spanPos,
609 const int &charsWidth, struct SpansWidth &spanWidth)
610 {
611 if (charsWidth > spanPos.avalibleWidth) {
612 spanPos.rightCharIndex++;
613 if (spanPos.rightCharIndex == spans.at(spanPos.rightSpanIndex).TryToTextSpan()->cgs_.GetRange().end) {
614 spanPos.rightSpanIndex++;
615 if (spanPos.rightSpanIndex <= spanPos.maxSpanIndex) {
616 spanPos.rightCharIndex = spans.at(spanPos.rightSpanIndex).TryToTextSpan()->cgs_.GetRange().start;
617 }
618 }
619 return true;
620 }
621 return false;
622 }
623
CalcAvalibleWidth(const std::vector<VariantSpan> & spans,struct SpanPosition & spanPos,bool & isLeft,int & charsWidth,struct SpansWidth & spanWidth)624 bool Shaper::CalcAvalibleWidth(const std::vector<VariantSpan> &spans, struct SpanPosition &spanPos,
625 bool &isLeft, int &charsWidth, struct SpansWidth &spanWidth)
626 {
627 if (isLeft) {
628 auto leftSpanCharGroups = spans.at(spanPos.leftSpanIndex).TryToTextSpan()->cgs_;
629 spanWidth.leftWidth += leftSpanCharGroups.GetCharWidth(spanPos.leftCharIndex);
630 charsWidth = static_cast<int>(spanWidth.leftWidth + spanWidth.rightWidth);
631 if (charsWidth > spanPos.avalibleWidth) {
632 if (spanPos.leftSpanIndex &&
633 spanPos.leftCharIndex == spans.at(spanPos.leftSpanIndex).TryToTextSpan()->cgs_.GetRange().start) {
634 spanPos.leftSpanIndex--;
635 spanPos.leftCharIndex = spans.at(spanPos.leftSpanIndex).TryToTextSpan()->cgs_.GetRange().end;
636 }
637 spanPos.leftCharIndex--;
638 return true;
639 }
640
641 if (spanPos.rightCharIndex == spans.at(spanPos.rightSpanIndex).TryToTextSpan()->cgs_.GetRange().start) {
642 spanPos.rightSpanIndex--;
643 spanPos.rightCharIndex = spans.at(spanPos.rightSpanIndex).TryToTextSpan()->cgs_.GetRange().end;
644 }
645 spanPos.rightCharIndex--;
646 isLeft = false;
647 } else {
648 auto rightSpanCharGroups = spans.at(spanPos.rightSpanIndex).TryToTextSpan()->cgs_;
649 spanWidth.rightWidth += rightSpanCharGroups.GetCharWidth(spanPos.rightCharIndex);
650 charsWidth = static_cast<int>(spanWidth.leftWidth + spanWidth.rightWidth);
651
652 if (HaveExceedWidth(spans, spanPos, charsWidth, spanWidth)) {
653 return true;
654 }
655
656 spanPos.leftCharIndex++;
657 if (spanPos.leftCharIndex == spans.at(spanPos.leftSpanIndex).TryToTextSpan()->cgs_.GetRange().end) {
658 spanPos.leftSpanIndex++;
659 if (spanPos.leftSpanIndex <= spanPos.rightSpanIndex) {
660 spanPos.leftCharIndex = spans.at(spanPos.leftSpanIndex).TryToTextSpan()->cgs_.GetRange().start;
661 }
662 }
663 isLeft = true;
664 }
665 return false;
666 }
667
CalcSpanPosition(const std::vector<VariantSpan> & spans,struct SpanPosition & spanPos,const int & breakPos,const int loopNum)668 bool Shaper::CalcSpanPosition(const std::vector<VariantSpan> &spans, struct SpanPosition &spanPos,
669 const int &breakPos, const int loopNum)
670 {
671 spanPos.leftSpanIndex = 0;
672 spanPos.rightSpanIndex = spans.size() - 1;
673 spanPos.maxSpanIndex = spanPos.rightSpanIndex;
674 spanPos.leftCharIndex = spans.at(spanPos.leftSpanIndex).TryToTextSpan()->cgs_.GetRange().start;
675 spanPos.rightCharIndex = spans.at(spanPos.rightSpanIndex).TryToTextSpan()->cgs_.GetRange().end;
676
677 if (breakPos != -1) {
678 spanPos.rightCharIndex = breakPos;
679 if (spanPos.maxSpanIndex &&
680 (spanPos.rightCharIndex == spans.at(spanPos.maxSpanIndex).TryToTextSpan()->cgs_.GetRange().start)) {
681 spanPos.maxSpanIndex--;
682 spanPos.rightSpanIndex = spanPos.maxSpanIndex;
683 spanPos.rightCharIndex = spans.at(spanPos.maxSpanIndex).TryToTextSpan()->cgs_.GetRange().end;
684 }
685 }
686
687 struct SpansWidth spanWidth;
688 spanWidth.leftWidth = 0.0;
689 spanWidth.rightWidth = 0.0;
690
691 bool isLeft = true;
692 bool isNormal = true;
693 int charsWidth = 0;
694 for (auto i = 0; i < loopNum; i++) {
695 if (charsWidth <= spanPos.avalibleWidth) {
696 if (CalcAvalibleWidth(spans, spanPos, isLeft, charsWidth, spanWidth)) {
697 break;
698 }
699 if (spanPos.leftSpanIndex == spanPos.rightSpanIndex && spanPos.leftCharIndex == spanPos.rightCharIndex) {
700 break;
701 }
702 if (spanPos.leftSpanIndex > spanPos.rightSpanIndex) {
703 isNormal = false;
704 break;
705 }
706 }
707 }
708 return isNormal;
709 }
710
JointCriticalLeftSpans(const std::vector<VariantSpan> & spans,std::vector<VariantSpan> & leftLineSpans,struct SpanPosition & spanPos,const TypographyStyle & style,const std::shared_ptr<FontProviders> & fontProviders)711 void Shaper::JointCriticalLeftSpans(const std::vector<VariantSpan> &spans, std::vector<VariantSpan> &leftLineSpans,
712 struct SpanPosition &spanPos, const TypographyStyle &style, const std::shared_ptr<FontProviders> &fontProviders)
713 {
714 auto leftCharGroupsRange = spans.at(spanPos.leftSpanIndex).TryToTextSpan()->cgs_.GetRange();
715 auto leftEnd = leftCharGroupsRange.end;
716 auto leftStart = leftCharGroupsRange.start;
717 leftEnd--;
718 if (spanPos.leftCharIndex == leftEnd) {
719 leftLineSpans.insert(leftLineSpans.end(), spans.at(spanPos.leftSpanIndex));
720 } else if ((spanPos.leftCharIndex >= leftStart) && (spanPos.leftCharIndex < leftEnd)) {
721 std::vector<uint16_t> subChars =
722 spans.at(spanPos.leftSpanIndex).TryToTextSpan()->cgs_.GetSubCharsToU16(leftStart, spanPos.leftCharIndex);
723 if (subChars.empty()) {
724 return;
725 }
726 VariantSpan leftSpan(TextSpan::MakeFromText(subChars));
727 leftSpan.SetTextStyle(spans.at(spanPos.leftSpanIndex).GetTextStyle());
728 std::vector<VariantSpan> newSpans = {leftSpan};
729 std::vector<LineMetrics> partlySpan = DoShapeBeforeEllipsis(newSpans, style, fontProviders, MAXWIDTH);
730 if (!partlySpan.empty()) {
731 std::vector<VariantSpan> partlyLineSpans = partlySpan.front().lineSpans;
732 leftLineSpans.insert(leftLineSpans.end(), partlyLineSpans.begin(), partlyLineSpans.end());
733 }
734 }
735 }
736
SplitJointLeftLineSpans(const std::vector<VariantSpan> & spans,std::vector<VariantSpan> & leftLineSpans,struct SpanPosition & spanPos,const TypographyStyle & style,const std::shared_ptr<FontProviders> & fontProviders)737 void Shaper::SplitJointLeftLineSpans(const std::vector<VariantSpan> &spans, std::vector<VariantSpan> &leftLineSpans,
738 struct SpanPosition &spanPos, const TypographyStyle &style, const std::shared_ptr<FontProviders> &fontProviders)
739 {
740 for (size_t index = 0; index <= spanPos.leftSpanIndex; index++) {
741 if (index == spanPos.leftSpanIndex) {
742 JointCriticalLeftSpans(spans, leftLineSpans, spanPos, style, fontProviders);
743 } else {
744 leftLineSpans.insert(leftLineSpans.end(), spans.at(index));
745 }
746 }
747 }
748
JointRightLineSpans(const std::vector<VariantSpan> & spans,std::vector<VariantSpan> & rightLineSpans,struct SpanPosition & spanPos,const TypographyStyle & style,const std::shared_ptr<FontProviders> & fontProviders)749 void Shaper::JointRightLineSpans(const std::vector<VariantSpan> &spans, std::vector<VariantSpan> &rightLineSpans,
750 struct SpanPosition &spanPos, const TypographyStyle &style, const std::shared_ptr<FontProviders> &fontProviders)
751 {
752 const auto &rightCharGroupsRange = spans.at(spanPos.curIndex).TryToTextSpan()->cgs_.GetRange();
753 auto rightEnd = rightCharGroupsRange.end;
754 rightEnd--;
755
756 if ((spanPos.curIndex > spanPos.rightSpanIndex && spanPos.curIndex <= spanPos.maxSpanIndex) ||
757 (spanPos.curIndex != spanPos.leftSpanIndex && spanPos.curIndex == spanPos.maxSpanIndex &&
758 spanPos.rightCharIndex == rightCharGroupsRange.start)) {
759 rightLineSpans.insert(rightLineSpans.end(), spans.at(spanPos.curIndex));
760 } else if ((spanPos.rightCharIndex > rightCharGroupsRange.start) && (spanPos.rightCharIndex <= rightEnd)) {
761 std::vector<uint16_t> subChars =
762 spans.at(spanPos.curIndex).TryToTextSpan()->cgs_.GetSubCharsToU16(spanPos.rightCharIndex, rightEnd);
763 if (subChars.empty()) {
764 return;
765 }
766 VariantSpan rightSpan(TextSpan::MakeFromText(subChars));
767 rightSpan.SetTextStyle(spans.at(spanPos.curIndex).GetTextStyle());
768 std::vector<VariantSpan> newSpans = {rightSpan};
769 std::vector<LineMetrics> partlySpan = DoShapeBeforeEllipsis(newSpans, style, fontProviders, MAXWIDTH);
770 if (!partlySpan.empty()) {
771 std::vector<VariantSpan> partlyLineSpans = partlySpan.front().lineSpans;
772 rightLineSpans.insert(rightLineSpans.end(), partlyLineSpans.begin(), partlyLineSpans.end());
773 }
774 }
775 }
776
SplitJointRightLineSpans(const std::vector<VariantSpan> & spans,std::vector<VariantSpan> & rightLineSpans,struct SpanPosition & spanPos,const TypographyStyle & style,const std::shared_ptr<FontProviders> & fontProviders)777 void Shaper::SplitJointRightLineSpans(const std::vector<VariantSpan> &spans, std::vector<VariantSpan> &rightLineSpans,
778 struct SpanPosition &spanPos, const TypographyStyle &style, const std::shared_ptr<FontProviders> &fontProviders)
779 {
780 for (size_t index = spanPos.rightSpanIndex; index <= spanPos.maxSpanIndex; index++) {
781 if (index == spanPos.leftSpanIndex || (index != spanPos.leftSpanIndex && index == spanPos.maxSpanIndex)) {
782 spanPos.curIndex = index;
783 JointRightLineSpans(spans, rightLineSpans, spanPos, style, fontProviders);
784 } else {
785 rightLineSpans.insert(rightLineSpans.end(), spans.at(index));
786 }
787 }
788 }
789
SplitJointSpans(const std::vector<VariantSpan> & spans,const EllipsisParams & params,struct SpanPosition & spanPos,const TypographyStyle & style,const std::shared_ptr<FontProviders> & fontProviders)790 void Shaper::SplitJointSpans(const std::vector<VariantSpan> &spans, const EllipsisParams ¶ms,
791 struct SpanPosition &spanPos, const TypographyStyle &style, const std::shared_ptr<FontProviders> &fontProviders)
792 {
793 if ((spanPos.leftSpanIndex == spanPos.rightSpanIndex) && (spanPos.leftCharIndex == spanPos.rightCharIndex)) {
794 std::vector<VariantSpan> lineSpans;
795 for (size_t i = 0; i < spans.size(); i++) {
796 lineSpans.insert(lineSpans.end(), spans.at(i));
797 }
798 auto &firstLineSpans = lineMetrics_.front().lineSpans;
799 firstLineSpans = lineSpans;
800 lineMetrics_.erase(lineMetrics_.begin() + params.maxLines, lineMetrics_.end());
801 firstLineSpans.insert(firstLineSpans.end(), params.ellipsisSpans.begin(), params.ellipsisSpans.end());
802 } else {
803 std::vector<VariantSpan> leftLineSpans;
804 SplitJointLeftLineSpans(spans, leftLineSpans, spanPos, style, fontProviders);
805
806 auto &firstLineSpans = lineMetrics_.front().lineSpans;
807 if (leftLineSpans.empty()) {
808 firstLineSpans= params.ellipsisSpans;
809 lineMetrics_.erase(lineMetrics_.begin() + params.maxLines, lineMetrics_.end());
810 return;
811 } else {
812 firstLineSpans = leftLineSpans;
813 lineMetrics_.erase(lineMetrics_.begin() + params.maxLines, lineMetrics_.end());
814 firstLineSpans.insert(firstLineSpans.end(), params.ellipsisSpans.begin(), params.ellipsisSpans.end());
815 }
816
817 std::vector<VariantSpan> rightLineSpans;
818 SplitJointRightLineSpans(spans, rightLineSpans, spanPos, style, fontProviders);
819 if (!rightLineSpans.empty()) {
820 firstLineSpans.insert(firstLineSpans.end(), rightLineSpans.begin(), rightLineSpans.end());
821 }
822 }
823 }
824
ConsiderMiddleEllipsis(const TypographyStyle & style,const std::shared_ptr<FontProviders> & fontProviders,EllipsisParams params)825 void Shaper::ConsiderMiddleEllipsis(const TypographyStyle &style, const std::shared_ptr<FontProviders> &fontProviders,
826 EllipsisParams params)
827 {
828 if (params.maxLines >= lineMetrics_.size() || params.ellipsisSpans.empty()) {
829 return;
830 }
831
832 int avalibleWidth = static_cast<int>(params.widthLimit - params.ellipsisWidth);
833 if (avalibleWidth < 0) {
834 lineMetrics_.front().lineSpans = params.ellipsisSpans;
835 lineMetrics_.erase(lineMetrics_.begin() + params.maxLines, lineMetrics_.end());
836 return;
837 }
838
839 std::vector<VariantSpan> spans;
840 int loopNum = 0;
841 int breakPos = -1;
842 GetAllTextSpan(spans, loopNum, breakPos);
843
844 if (spans.empty() || !loopNum) {
845 lineMetrics_.front().lineSpans = params.ellipsisSpans;
846 lineMetrics_.erase(lineMetrics_.begin() + params.maxLines, lineMetrics_.end());
847 return;
848 }
849
850 struct SpanPosition spanPos;
851 spanPos.avalibleWidth = avalibleWidth;
852 bool isNormal = CalcSpanPosition(spans, spanPos, breakPos, loopNum);
853 std::shared_ptr<TextSpan> textSpan = nullptr;
854 if (!spanPos.leftSpanIndex) {
855 textSpan = spans.at(spanPos.leftSpanIndex).TryToTextSpan();
856 }
857
858 if ((!isNormal) || (!spanPos.leftSpanIndex && textSpan != nullptr &&
859 spanPos.leftCharIndex < textSpan->cgs_.GetRange().start)) {
860 lineMetrics_.front().lineSpans = params.ellipsisSpans;
861 lineMetrics_.erase(lineMetrics_.begin() + params.maxLines, lineMetrics_.end());
862 return;
863 }
864
865 SplitJointSpans(spans, params, spanPos, style, fontProviders);
866 }
867 } // namespace TextEngine
868 } // namespace Rosen
869 } // namespace OHOS
870