1cb93a386Sopenharmony_ci// Copyright 2019 Google LLC.
2cb93a386Sopenharmony_ci
3cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
4cb93a386Sopenharmony_ci#include "include/core/SkFontMetrics.h"
5cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h"
6cb93a386Sopenharmony_ci#include "include/core/SkPictureRecorder.h"
7cb93a386Sopenharmony_ci#include "include/core/SkSpan.h"
8cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h"
9cb93a386Sopenharmony_ci#include "include/private/SkTFitsIn.h"
10cb93a386Sopenharmony_ci#include "include/private/SkTo.h"
11cb93a386Sopenharmony_ci#include "modules/skparagraph/include/Metrics.h"
12cb93a386Sopenharmony_ci#include "modules/skparagraph/include/Paragraph.h"
13cb93a386Sopenharmony_ci#include "modules/skparagraph/include/ParagraphPainter.h"
14cb93a386Sopenharmony_ci#include "modules/skparagraph/include/ParagraphStyle.h"
15cb93a386Sopenharmony_ci#include "modules/skparagraph/include/TextStyle.h"
16cb93a386Sopenharmony_ci#include "modules/skparagraph/src/OneLineShaper.h"
17cb93a386Sopenharmony_ci#include "modules/skparagraph/src/ParagraphImpl.h"
18cb93a386Sopenharmony_ci#include "modules/skparagraph/src/ParagraphPainterImpl.h"
19cb93a386Sopenharmony_ci#include "modules/skparagraph/src/Run.h"
20cb93a386Sopenharmony_ci#include "modules/skparagraph/src/TextLine.h"
21cb93a386Sopenharmony_ci#include "modules/skparagraph/src/TextWrapper.h"
22cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
23cb93a386Sopenharmony_ci#include "utils/text_trace.h"
24cb93a386Sopenharmony_ci#endif
25cb93a386Sopenharmony_ci#include "src/utils/SkUTF.h"
26cb93a386Sopenharmony_ci#include <math.h>
27cb93a386Sopenharmony_ci#include <algorithm>
28cb93a386Sopenharmony_ci#include <utility>
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
31cb93a386Sopenharmony_ci#include "log.h"
32cb93a386Sopenharmony_ci#include "modules/skparagraph/src/TextLineBaseImpl.h"
33cb93a386Sopenharmony_ci#include "TextParameter.h"
34cb93a386Sopenharmony_ci#endif
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_cinamespace skia {
37cb93a386Sopenharmony_cinamespace textlayout {
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_cinamespace {
40cb93a386Sopenharmony_ciconstexpr int PARAM_DOUBLE = 2;
41cb93a386Sopenharmony_ciconstexpr ParagraphPainter::PaintID INVALID_PAINT_ID = -1;
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ciSkScalar littleRound(SkScalar a) {
44cb93a386Sopenharmony_ci    // This rounding is done to match Flutter tests. Must be removed..
45cb93a386Sopenharmony_ci    auto val = std::fabs(a);
46cb93a386Sopenharmony_ci    if (val < 10000) {
47cb93a386Sopenharmony_ci        return SkScalarRoundToScalar(a * 100.0)/100.0;
48cb93a386Sopenharmony_ci    } else if (val < 100000) {
49cb93a386Sopenharmony_ci        return SkScalarRoundToScalar(a * 10.0)/10.0;
50cb93a386Sopenharmony_ci    } else {
51cb93a386Sopenharmony_ci        return SkScalarFloorToScalar(a);
52cb93a386Sopenharmony_ci    }
53cb93a386Sopenharmony_ci}
54cb93a386Sopenharmony_ci}  // namespace
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ciTextRange operator*(const TextRange& a, const TextRange& b) {
57cb93a386Sopenharmony_ci    if (a.start == b.start && a.end == b.end) return a;
58cb93a386Sopenharmony_ci    auto begin = std::max(a.start, b.start);
59cb93a386Sopenharmony_ci    auto end = std::min(a.end, b.end);
60cb93a386Sopenharmony_ci    return end > begin ? TextRange(begin, end) : EMPTY_TEXT;
61cb93a386Sopenharmony_ci}
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ciTextRange textRangeMergeBtoA(const TextRange& a, const TextRange& b) {
64cb93a386Sopenharmony_ci    if (a.width() <= 0 || b.width() <= 0 || a.end < b.start || a.start > b.end) {
65cb93a386Sopenharmony_ci        return a;
66cb93a386Sopenharmony_ci    }
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci    return TextRange(std::min(a.start, b.start), std::max(a.end, b.end));
69cb93a386Sopenharmony_ci}
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_cistd::vector<SkUnichar> ParagraphImpl::convertUtf8ToUnicode(const SkString& utf8)
72cb93a386Sopenharmony_ci{
73cb93a386Sopenharmony_ci    fUnicodeIndexForUTF8Index.reset();
74cb93a386Sopenharmony_ci    std::vector<SkUnichar> result;
75cb93a386Sopenharmony_ci    auto p = utf8.c_str();
76cb93a386Sopenharmony_ci    auto end = p + utf8.size();
77cb93a386Sopenharmony_ci    while (p < end) {
78cb93a386Sopenharmony_ci        auto tmp = p;
79cb93a386Sopenharmony_ci        auto unichar = SkUTF::NextUTF8(&p, end);
80cb93a386Sopenharmony_ci        for (auto i = 0; i < p - tmp; ++i) {
81cb93a386Sopenharmony_ci            fUnicodeIndexForUTF8Index.emplace_back(result.size());
82cb93a386Sopenharmony_ci        }
83cb93a386Sopenharmony_ci        result.emplace_back(unichar);
84cb93a386Sopenharmony_ci    }
85cb93a386Sopenharmony_ci    fUnicodeIndexForUTF8Index.emplace_back(result.size());
86cb93a386Sopenharmony_ci    return result;
87cb93a386Sopenharmony_ci}
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_ciParagraph::Paragraph()
90cb93a386Sopenharmony_ci{ }
91cb93a386Sopenharmony_ci
92cb93a386Sopenharmony_ciParagraph::Paragraph(ParagraphStyle style, sk_sp<FontCollection> fonts)
93cb93a386Sopenharmony_ci            : fFontCollection(std::move(fonts))
94cb93a386Sopenharmony_ci            , fParagraphStyle(std::move(style))
95cb93a386Sopenharmony_ci            , fAlphabeticBaseline(0)
96cb93a386Sopenharmony_ci            , fIdeographicBaseline(0)
97cb93a386Sopenharmony_ci            , fHeight(0)
98cb93a386Sopenharmony_ci            , fWidth(0)
99cb93a386Sopenharmony_ci            , fMaxIntrinsicWidth(0)
100cb93a386Sopenharmony_ci            , fMinIntrinsicWidth(0)
101cb93a386Sopenharmony_ci            , fLongestLine(0)
102cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
103cb93a386Sopenharmony_ci            , fLongestLineWithIndent(0)
104cb93a386Sopenharmony_ci#endif
105cb93a386Sopenharmony_ci            , fExceededMaxLines(0)
106cb93a386Sopenharmony_ci{ }
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_ciParagraphImpl::ParagraphImpl()
109cb93a386Sopenharmony_ci{ }
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_ciParagraphImpl::ParagraphImpl(const SkString& text,
112cb93a386Sopenharmony_ci                             ParagraphStyle style,
113cb93a386Sopenharmony_ci                             SkTArray<Block, true> blocks,
114cb93a386Sopenharmony_ci                             SkTArray<Placeholder, true> placeholders,
115cb93a386Sopenharmony_ci                             sk_sp<FontCollection> fonts,
116cb93a386Sopenharmony_ci                             std::shared_ptr<SkUnicode> unicode)
117cb93a386Sopenharmony_ci        : Paragraph(std::move(style), std::move(fonts))
118cb93a386Sopenharmony_ci        , fTextStyles(std::move(blocks))
119cb93a386Sopenharmony_ci        , fPlaceholders(std::move(placeholders))
120cb93a386Sopenharmony_ci        , fText(text)
121cb93a386Sopenharmony_ci        , fState(kUnknown)
122cb93a386Sopenharmony_ci        , fUnresolvedGlyphs(0)
123cb93a386Sopenharmony_ci        , fPicture(nullptr)
124cb93a386Sopenharmony_ci        , fStrutMetrics(false)
125cb93a386Sopenharmony_ci        , fOldWidth(0)
126cb93a386Sopenharmony_ci        , fOldHeight(0)
127cb93a386Sopenharmony_ci        , fUnicode(std::move(unicode))
128cb93a386Sopenharmony_ci        , fHasLineBreaks(false)
129cb93a386Sopenharmony_ci        , fHasWhitespacesInside(false)
130cb93a386Sopenharmony_ci        , fTrailingSpaces(0)
131cb93a386Sopenharmony_ci{
132cb93a386Sopenharmony_ci    SkASSERT(fUnicode);
133cb93a386Sopenharmony_ci}
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ciParagraphImpl::ParagraphImpl(const std::u16string& utf16text,
136cb93a386Sopenharmony_ci                             ParagraphStyle style,
137cb93a386Sopenharmony_ci                             SkTArray<Block, true> blocks,
138cb93a386Sopenharmony_ci                             SkTArray<Placeholder, true> placeholders,
139cb93a386Sopenharmony_ci                             sk_sp<FontCollection> fonts,
140cb93a386Sopenharmony_ci                             std::shared_ptr<SkUnicode> unicode)
141cb93a386Sopenharmony_ci        : ParagraphImpl(SkString(),
142cb93a386Sopenharmony_ci                        std::move(style),
143cb93a386Sopenharmony_ci                        std::move(blocks),
144cb93a386Sopenharmony_ci                        std::move(placeholders),
145cb93a386Sopenharmony_ci                        std::move(fonts),
146cb93a386Sopenharmony_ci                        std::move(unicode))
147cb93a386Sopenharmony_ci{
148cb93a386Sopenharmony_ci    SkASSERT(fUnicode);
149cb93a386Sopenharmony_ci    fText =  SkUnicode::convertUtf16ToUtf8(utf16text);
150cb93a386Sopenharmony_ci}
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ciParagraphImpl::~ParagraphImpl() = default;
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ciint32_t ParagraphImpl::unresolvedGlyphs() {
155cb93a386Sopenharmony_ci    if (fState < kShaped) {
156cb93a386Sopenharmony_ci        return -1;
157cb93a386Sopenharmony_ci    }
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci    return fUnresolvedGlyphs;
160cb93a386Sopenharmony_ci}
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
163cb93a386Sopenharmony_cibool ParagraphImpl::GetLineFontMetrics(const size_t lineNumber, size_t& charNumber,
164cb93a386Sopenharmony_ci    std::vector<SkFontMetrics>& fontMetrics) {
165cb93a386Sopenharmony_ci#else
166cb93a386Sopenharmony_cibool ParagraphImpl::GetLineFontMetrics(const size_t lineNumber, size_t& charNumber,
167cb93a386Sopenharmony_ci    std::vector<RSFontMetrics>& fontMetrics) {
168cb93a386Sopenharmony_ci#endif
169cb93a386Sopenharmony_ci    if (lineNumber > fLines.size() || !lineNumber ||
170cb93a386Sopenharmony_ci        !fLines[lineNumber - 1].getLineAllRuns().size()) {
171cb93a386Sopenharmony_ci        return false;
172cb93a386Sopenharmony_ci    }
173cb93a386Sopenharmony_ci
174cb93a386Sopenharmony_ci    size_t textRange = 0;
175cb93a386Sopenharmony_ci    size_t lineCharCount = fLines[lineNumber - 1].clusters().end -
176cb93a386Sopenharmony_ci        fLines[lineNumber - 1].clusters().start;
177cb93a386Sopenharmony_ci
178cb93a386Sopenharmony_ci    for (auto& runIndex : fLines[lineNumber - 1].getLineAllRuns()) {
179cb93a386Sopenharmony_ci        Run& targetRun = this->run(runIndex);
180cb93a386Sopenharmony_ci        size_t runClock = 0;
181cb93a386Sopenharmony_ci        size_t currentRunCharNumber = targetRun.clusterRange().end -
182cb93a386Sopenharmony_ci            targetRun.clusterRange().start;
183cb93a386Sopenharmony_ci        for (;textRange < lineCharCount; textRange++) {
184cb93a386Sopenharmony_ci            if (++runClock > currentRunCharNumber) {
185cb93a386Sopenharmony_ci                break;
186cb93a386Sopenharmony_ci            }
187cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
188cb93a386Sopenharmony_ci            SkFontMetrics newFontMetrics;
189cb93a386Sopenharmony_ci            targetRun.fFont.getMetrics(&newFontMetrics);
190cb93a386Sopenharmony_ci#else
191cb93a386Sopenharmony_ci            RSFontMetrics newFontMetrics;
192cb93a386Sopenharmony_ci            targetRun.fFont.GetMetrics(&newFontMetrics);
193cb93a386Sopenharmony_ci#endif
194cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
195cb93a386Sopenharmony_ci            auto decompressFont = targetRun.fFont;
196cb93a386Sopenharmony_ci            scaleFontWithCompressionConfig(decompressFont, ScaleOP::DECOMPRESS);
197cb93a386Sopenharmony_ci            metricsIncludeFontPadding(&newFontMetrics, decompressFont);
198cb93a386Sopenharmony_ci#endif
199cb93a386Sopenharmony_ci            fontMetrics.emplace_back(newFontMetrics);
200cb93a386Sopenharmony_ci        }
201cb93a386Sopenharmony_ci    }
202cb93a386Sopenharmony_ci
203cb93a386Sopenharmony_ci    charNumber = lineCharCount;
204cb93a386Sopenharmony_ci    return true;
205cb93a386Sopenharmony_ci}
206cb93a386Sopenharmony_ci
207cb93a386Sopenharmony_cistd::unordered_set<SkUnichar> ParagraphImpl::unresolvedCodepoints() {
208cb93a386Sopenharmony_ci    return fUnresolvedCodepoints;
209cb93a386Sopenharmony_ci}
210cb93a386Sopenharmony_ci
211cb93a386Sopenharmony_civoid ParagraphImpl::addUnresolvedCodepoints(TextRange textRange) {
212cb93a386Sopenharmony_ci    fUnicode->forEachCodepoint(
213cb93a386Sopenharmony_ci        &fText[textRange.start], textRange.width(),
214cb93a386Sopenharmony_ci        [&](SkUnichar unichar, int32_t start, int32_t end, int32_t count) {
215cb93a386Sopenharmony_ci            fUnresolvedCodepoints.emplace(unichar);
216cb93a386Sopenharmony_ci        }
217cb93a386Sopenharmony_ci    );
218cb93a386Sopenharmony_ci}
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ciTextRange ParagraphImpl::resetRangeWithDeletedRange(const TextRange& sourceRange,
221cb93a386Sopenharmony_ci    const TextRange& deletedRange, const size_t& ellSize)
222cb93a386Sopenharmony_ci{
223cb93a386Sopenharmony_ci    if (sourceRange.end <= deletedRange.start) {
224cb93a386Sopenharmony_ci        return sourceRange;
225cb93a386Sopenharmony_ci    }
226cb93a386Sopenharmony_ci    auto changeSize = ellSize - deletedRange.width();
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_ci    if (sourceRange.start >= deletedRange.end) {
229cb93a386Sopenharmony_ci        return TextRange(sourceRange.start + changeSize, sourceRange.end + changeSize);
230cb93a386Sopenharmony_ci    }
231cb93a386Sopenharmony_ci
232cb93a386Sopenharmony_ci    TextRange target;
233cb93a386Sopenharmony_ci    target.start = sourceRange.start <= deletedRange.start ? sourceRange.start : deletedRange.start + ellSize;
234cb93a386Sopenharmony_ci    target.end = sourceRange.end <= deletedRange.end ? deletedRange.start + ellSize : sourceRange.end + changeSize;
235cb93a386Sopenharmony_ci    return target.start <= target.end ? target : EMPTY_RANGE;
236cb93a386Sopenharmony_ci}
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_civoid ParagraphImpl::resetTextStyleRange(const TextRange& deletedRange)
239cb93a386Sopenharmony_ci{
240cb93a386Sopenharmony_ci    auto tmpTextStyle = fTextStyles;
241cb93a386Sopenharmony_ci    fTextStyles.reset();
242cb93a386Sopenharmony_ci    for (auto fs : tmpTextStyle) {
243cb93a386Sopenharmony_ci        auto newTextRange = resetRangeWithDeletedRange(fs.fRange, deletedRange, this->getEllipsis().size());
244cb93a386Sopenharmony_ci        LOGD("ParagraphImpl::resetTextStyleRange old = [%{public}lu,%{public}lu), new = [%{public}lu,%{public}lu)",
245cb93a386Sopenharmony_ci            static_cast<unsigned long>(fs.fRange.start), static_cast<unsigned long>(fs.fRange.end),
246cb93a386Sopenharmony_ci            static_cast<unsigned long>(newTextRange.start), static_cast<unsigned long>(newTextRange.end));
247cb93a386Sopenharmony_ci        if (newTextRange.width() == 0) {
248cb93a386Sopenharmony_ci            continue;
249cb93a386Sopenharmony_ci        }
250cb93a386Sopenharmony_ci        fs.fRange = newTextRange;
251cb93a386Sopenharmony_ci        fTextStyles.emplace_back(fs);
252cb93a386Sopenharmony_ci    }
253cb93a386Sopenharmony_ci}
254cb93a386Sopenharmony_ci
255cb93a386Sopenharmony_civoid ParagraphImpl::resetPlaceholderRange(const TextRange& deletedRange)
256cb93a386Sopenharmony_ci{
257cb93a386Sopenharmony_ci    // reset fRange && fTextBefore && fBlockBefore
258cb93a386Sopenharmony_ci    auto ellSize = this->getEllipsis().size();
259cb93a386Sopenharmony_ci    auto tmpPlaceholders = fPlaceholders;
260cb93a386Sopenharmony_ci    fPlaceholders.reset();
261cb93a386Sopenharmony_ci    for (auto ph : tmpPlaceholders) {
262cb93a386Sopenharmony_ci        auto newTextRange = resetRangeWithDeletedRange(ph.fRange, deletedRange, ellSize);
263cb93a386Sopenharmony_ci        LOGD("ParagraphImpl::resetPlaceholderRange old = [%{public}lu,%{public}lu), new = [%{public}lu,%{public}lu)",
264cb93a386Sopenharmony_ci            static_cast<unsigned long>(ph.fRange.start), static_cast<unsigned long>(ph.fRange.end),
265cb93a386Sopenharmony_ci            static_cast<unsigned long>(newTextRange.start), static_cast<unsigned long>(newTextRange.end));
266cb93a386Sopenharmony_ci        if (newTextRange.empty()) {
267cb93a386Sopenharmony_ci            continue;
268cb93a386Sopenharmony_ci        }
269cb93a386Sopenharmony_ci        ph.fRange = newTextRange;
270cb93a386Sopenharmony_ci        newTextRange = ph.fTextBefore;
271cb93a386Sopenharmony_ci        newTextRange.start = fPlaceholders.empty() ? 0 : fPlaceholders.back().fRange.end;
272cb93a386Sopenharmony_ci        if (newTextRange.end > deletedRange.start) {
273cb93a386Sopenharmony_ci            newTextRange.end = newTextRange.end <= deletedRange.end ?
274cb93a386Sopenharmony_ci                deletedRange.start + ellSize : newTextRange.end + ellSize - deletedRange.width();
275cb93a386Sopenharmony_ci        }
276cb93a386Sopenharmony_ci        ph.fTextBefore = newTextRange;
277cb93a386Sopenharmony_ci        fPlaceholders.emplace_back(ph);
278cb93a386Sopenharmony_ci    }
279cb93a386Sopenharmony_ci}
280cb93a386Sopenharmony_ci
281cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
282cb93a386Sopenharmony_cibool ParagraphImpl::middleEllipsisDeal()
283cb93a386Sopenharmony_ci{
284cb93a386Sopenharmony_ci    if (fRuns.empty()) {
285cb93a386Sopenharmony_ci        return false;
286cb93a386Sopenharmony_ci    }
287cb93a386Sopenharmony_ci    isMiddleEllipsis = false;
288cb93a386Sopenharmony_ci
289cb93a386Sopenharmony_ci    size_t end = 0;
290cb93a386Sopenharmony_ci    size_t charbegin = 0;
291cb93a386Sopenharmony_ci    size_t charend = 0;
292cb93a386Sopenharmony_ci    if (fRuns.begin()->leftToRight()) {
293cb93a386Sopenharmony_ci        middleEllipsisLtrDeal(end, charbegin, charend);
294cb93a386Sopenharmony_ci    } else {
295cb93a386Sopenharmony_ci        middleEllipsisRtlDeal(end, charbegin, charend);
296cb93a386Sopenharmony_ci    }
297cb93a386Sopenharmony_ci    if (end != 0) {
298cb93a386Sopenharmony_ci        TextRange deletedRange(charbegin, charend);
299cb93a386Sopenharmony_ci        resetTextStyleRange(deletedRange);
300cb93a386Sopenharmony_ci        resetPlaceholderRange(deletedRange);
301cb93a386Sopenharmony_ci        fEllipsisRange = deletedRange;
302cb93a386Sopenharmony_ci    }
303cb93a386Sopenharmony_ci    // end = 0 means the text does not exceed the width limit
304cb93a386Sopenharmony_ci    return end != 0;
305cb93a386Sopenharmony_ci}
306cb93a386Sopenharmony_ci
307cb93a386Sopenharmony_civoid ParagraphImpl::middleEllipsisLtrDeal(size_t& end,
308cb93a386Sopenharmony_ci                                          size_t& charbegin,
309cb93a386Sopenharmony_ci                                          size_t& charend)
310cb93a386Sopenharmony_ci{
311cb93a386Sopenharmony_ci    const SkString& ell = this->getEllipsis();
312cb93a386Sopenharmony_ci    const char *ellStr = ell.c_str();
313cb93a386Sopenharmony_ci    size_t start = 0;
314cb93a386Sopenharmony_ci    if (ltrTextSize[0].phraseWidth >= fOldMaxWidth) {
315cb93a386Sopenharmony_ci        fText.reset();
316cb93a386Sopenharmony_ci        fText.set(ellStr);
317cb93a386Sopenharmony_ci        end = 1;
318cb93a386Sopenharmony_ci        charend = ell.size();
319cb93a386Sopenharmony_ci    } else {
320cb93a386Sopenharmony_ci        scanTextCutPoint(ltrTextSize, start, end);
321cb93a386Sopenharmony_ci        if (end) {
322cb93a386Sopenharmony_ci            charbegin = ltrTextSize[start].charbegin;
323cb93a386Sopenharmony_ci            charend = ltrTextSize[end].charOver;
324cb93a386Sopenharmony_ci            fText.remove(ltrTextSize[start].charbegin, ltrTextSize[end].charOver - ltrTextSize[start].charbegin);
325cb93a386Sopenharmony_ci            fText.insert(ltrTextSize[start].charbegin, ellStr);
326cb93a386Sopenharmony_ci        }
327cb93a386Sopenharmony_ci    }
328cb93a386Sopenharmony_ci    ltrTextSize.clear();
329cb93a386Sopenharmony_ci}
330cb93a386Sopenharmony_ci
331cb93a386Sopenharmony_civoid ParagraphImpl::middleEllipsisRtlDeal(size_t& end,
332cb93a386Sopenharmony_ci                                          size_t& charbegin,
333cb93a386Sopenharmony_ci                                          size_t& charend)
334cb93a386Sopenharmony_ci{
335cb93a386Sopenharmony_ci    const SkString& ell = this->getEllipsis();
336cb93a386Sopenharmony_ci    const char *ellStr = ell.c_str();
337cb93a386Sopenharmony_ci    size_t start = 0;
338cb93a386Sopenharmony_ci    scanTextCutPoint(rtlTextSize, start, end);
339cb93a386Sopenharmony_ci    if (start < 1 || end + PARAM_DOUBLE >= rtlTextSize.size()) {
340cb93a386Sopenharmony_ci        start = 0;
341cb93a386Sopenharmony_ci        end = 0;
342cb93a386Sopenharmony_ci    }
343cb93a386Sopenharmony_ci    if (end) {
344cb93a386Sopenharmony_ci        charbegin = rtlTextSize[start - 1].charbegin;
345cb93a386Sopenharmony_ci        charend = rtlTextSize[end + PARAM_DOUBLE].charbegin;
346cb93a386Sopenharmony_ci        fText.remove(rtlTextSize[start - 1].charbegin,
347cb93a386Sopenharmony_ci            rtlTextSize[end + PARAM_DOUBLE].charbegin - rtlTextSize[start - 1].charbegin);
348cb93a386Sopenharmony_ci        fText.insert(rtlTextSize[start - 1].charbegin, ellStr);
349cb93a386Sopenharmony_ci    }
350cb93a386Sopenharmony_ci    rtlTextSize.clear();
351cb93a386Sopenharmony_ci}
352cb93a386Sopenharmony_ci#endif
353cb93a386Sopenharmony_ci
354cb93a386Sopenharmony_ciSkScalar ParagraphImpl::resetEllipsisWidth(SkScalar ellipsisWidth, size_t& lastRunIndex, const size_t textIndex)
355cb93a386Sopenharmony_ci{
356cb93a386Sopenharmony_ci    auto targetCluster = cluster(clusterIndex(textIndex));
357cb93a386Sopenharmony_ci    if (lastRunIndex != targetCluster.runIndex()) {
358cb93a386Sopenharmony_ci        TextLine textLine;
359cb93a386Sopenharmony_ci        textLine.setParagraphImpl(this);
360cb93a386Sopenharmony_ci        auto blockRange = findAllBlocks(TextRange(textIndex, textIndex + 1));
361cb93a386Sopenharmony_ci        textLine.setBlockRange(blockRange);
362cb93a386Sopenharmony_ci        const SkString& ellipsis = this->getEllipsis();
363cb93a386Sopenharmony_ci        std::unique_ptr<Run> ellipsisRun;
364cb93a386Sopenharmony_ci        ellipsisRun = textLine.shapeEllipsis(ellipsis, &targetCluster);
365cb93a386Sopenharmony_ci        lastRunIndex = targetCluster.runIndex();
366cb93a386Sopenharmony_ci        ellipsisWidth = ellipsisRun->fAdvanceX();
367cb93a386Sopenharmony_ci        ellipsisRun.reset();
368cb93a386Sopenharmony_ci    }
369cb93a386Sopenharmony_ci    return ellipsisWidth;
370cb93a386Sopenharmony_ci}
371cb93a386Sopenharmony_ci
372cb93a386Sopenharmony_civoid ParagraphImpl::scanRTLTextCutPoint(const std::vector<TextCutRecord>& rawTextSize, size_t& start, size_t& end)
373cb93a386Sopenharmony_ci{
374cb93a386Sopenharmony_ci    size_t lastRunIndex = EMPTY_RUN;
375cb93a386Sopenharmony_ci    auto runTimeEllipsisWidth = resetEllipsisWidth(0, lastRunIndex, 0);
376cb93a386Sopenharmony_ci    float measureWidth = runTimeEllipsisWidth;
377cb93a386Sopenharmony_ci    size_t left = 0;
378cb93a386Sopenharmony_ci    size_t right = rawTextSize.size() - 1;
379cb93a386Sopenharmony_ci    while (left < rawTextSize.size() && measureWidth < fOldMaxWidth && left <= right) {
380cb93a386Sopenharmony_ci        measureWidth += rawTextSize[left++].phraseWidth;
381cb93a386Sopenharmony_ci        if (right > left && measureWidth < fOldMaxWidth) {
382cb93a386Sopenharmony_ci            measureWidth += rawTextSize[right--].phraseWidth;
383cb93a386Sopenharmony_ci        }
384cb93a386Sopenharmony_ci        measureWidth -= runTimeEllipsisWidth;
385cb93a386Sopenharmony_ci        runTimeEllipsisWidth = resetEllipsisWidth(runTimeEllipsisWidth, lastRunIndex, left);
386cb93a386Sopenharmony_ci        measureWidth += runTimeEllipsisWidth;
387cb93a386Sopenharmony_ci    }
388cb93a386Sopenharmony_ci
389cb93a386Sopenharmony_ci    if (right < left) {
390cb93a386Sopenharmony_ci        right = left;
391cb93a386Sopenharmony_ci    }
392cb93a386Sopenharmony_ci
393cb93a386Sopenharmony_ci    if (measureWidth >= fOldMaxWidth || fParagraphStyle.getTextOverflower()) {
394cb93a386Sopenharmony_ci        start = left;
395cb93a386Sopenharmony_ci        end = right;
396cb93a386Sopenharmony_ci    } else {
397cb93a386Sopenharmony_ci        start = 0;
398cb93a386Sopenharmony_ci        end = 0;
399cb93a386Sopenharmony_ci    }
400cb93a386Sopenharmony_ci}
401cb93a386Sopenharmony_ci
402cb93a386Sopenharmony_civoid ParagraphImpl::scanLTRTextCutPoint(const std::vector<TextCutRecord>& rawTextSize, size_t& start, size_t& end)
403cb93a386Sopenharmony_ci{
404cb93a386Sopenharmony_ci    size_t lastRunIndex = EMPTY_RUN;
405cb93a386Sopenharmony_ci    auto runTimeEllipsisWidth = resetEllipsisWidth(0, lastRunIndex, 0);
406cb93a386Sopenharmony_ci    float measureWidth = runTimeEllipsisWidth;
407cb93a386Sopenharmony_ci    size_t begin = 0;
408cb93a386Sopenharmony_ci    size_t last = rawTextSize.size() - 1;
409cb93a386Sopenharmony_ci    bool rightExit = false;
410cb93a386Sopenharmony_ci    while (begin < last && !rightExit && measureWidth < fOldMaxWidth) {
411cb93a386Sopenharmony_ci        measureWidth += rawTextSize[begin++].phraseWidth;
412cb93a386Sopenharmony_ci        if (measureWidth > fOldMaxWidth) {
413cb93a386Sopenharmony_ci            --begin;
414cb93a386Sopenharmony_ci            break;
415cb93a386Sopenharmony_ci        }
416cb93a386Sopenharmony_ci        if (last > begin && measureWidth < fOldMaxWidth) {
417cb93a386Sopenharmony_ci            measureWidth += rawTextSize[last--].phraseWidth;
418cb93a386Sopenharmony_ci            if (measureWidth > fOldMaxWidth) {
419cb93a386Sopenharmony_ci                rightExit = true;
420cb93a386Sopenharmony_ci                ++last;
421cb93a386Sopenharmony_ci            }
422cb93a386Sopenharmony_ci        }
423cb93a386Sopenharmony_ci        measureWidth -= runTimeEllipsisWidth;
424cb93a386Sopenharmony_ci        runTimeEllipsisWidth = resetEllipsisWidth(runTimeEllipsisWidth, lastRunIndex, begin);
425cb93a386Sopenharmony_ci        measureWidth += runTimeEllipsisWidth;
426cb93a386Sopenharmony_ci    }
427cb93a386Sopenharmony_ci
428cb93a386Sopenharmony_ci    if (measureWidth >= fOldMaxWidth || fParagraphStyle.getTextOverflower()) {
429cb93a386Sopenharmony_ci        start = begin;
430cb93a386Sopenharmony_ci        end = last;
431cb93a386Sopenharmony_ci    } else {
432cb93a386Sopenharmony_ci        start = 0;
433cb93a386Sopenharmony_ci        end = 0;
434cb93a386Sopenharmony_ci    }
435cb93a386Sopenharmony_ci}
436cb93a386Sopenharmony_ci
437cb93a386Sopenharmony_civoid ParagraphImpl::scanTextCutPoint(const std::vector<TextCutRecord>& rawTextSize, size_t& start, size_t& end)
438cb93a386Sopenharmony_ci{
439cb93a386Sopenharmony_ci    if (allTextWidth <= fOldMaxWidth || !rawTextSize.size()) {
440cb93a386Sopenharmony_ci        allTextWidth = 0;
441cb93a386Sopenharmony_ci        return;
442cb93a386Sopenharmony_ci    }
443cb93a386Sopenharmony_ci
444cb93a386Sopenharmony_ci    if (fRuns.begin()->leftToRight()) {
445cb93a386Sopenharmony_ci        scanLTRTextCutPoint(rawTextSize, start, end);
446cb93a386Sopenharmony_ci    } else {
447cb93a386Sopenharmony_ci        scanRTLTextCutPoint(rawTextSize, start, end);
448cb93a386Sopenharmony_ci    }
449cb93a386Sopenharmony_ci}
450cb93a386Sopenharmony_ci
451cb93a386Sopenharmony_cibool ParagraphImpl::shapeForMiddleEllipsis(SkScalar rawWidth)
452cb93a386Sopenharmony_ci{
453cb93a386Sopenharmony_ci    if (fParagraphStyle.getMaxLines() != 1 || fParagraphStyle.getEllipsisMod() != EllipsisModal::MIDDLE ||
454cb93a386Sopenharmony_ci        !fParagraphStyle.ellipsized()) {
455cb93a386Sopenharmony_ci        return true;
456cb93a386Sopenharmony_ci    }
457cb93a386Sopenharmony_ci    fOldMaxWidth = rawWidth;
458cb93a386Sopenharmony_ci    isMiddleEllipsis = true;
459cb93a386Sopenharmony_ci    allTextWidth = 0;
460cb93a386Sopenharmony_ci    this->computeCodeUnitProperties();
461cb93a386Sopenharmony_ci    this->fRuns.reset();
462cb93a386Sopenharmony_ci    this->fClusters.reset();
463cb93a386Sopenharmony_ci    this->fClustersIndexFromCodeUnit.reset();
464cb93a386Sopenharmony_ci    this->fClustersIndexFromCodeUnit.push_back_n(fText.size() + 1, EMPTY_INDEX);
465cb93a386Sopenharmony_ci    if (!this->shapeTextIntoEndlessLine()) {
466cb93a386Sopenharmony_ci        return false;
467cb93a386Sopenharmony_ci    }
468cb93a386Sopenharmony_ci    return middleEllipsisDeal();
469cb93a386Sopenharmony_ci}
470cb93a386Sopenharmony_ci
471cb93a386Sopenharmony_civoid ParagraphImpl::prepareForMiddleEllipsis(SkScalar rawWidth)
472cb93a386Sopenharmony_ci{
473cb93a386Sopenharmony_ci    if (fParagraphStyle.getMaxLines() != 1 || fParagraphStyle.getEllipsisMod() != EllipsisModal::MIDDLE ||
474cb93a386Sopenharmony_ci        !fParagraphStyle.ellipsized()) {
475cb93a386Sopenharmony_ci        return;
476cb93a386Sopenharmony_ci    }
477cb93a386Sopenharmony_ci    std::shared_ptr<ParagraphImpl> tmpParagraph = std::make_shared<ParagraphImpl>(fText, fParagraphStyle, fTextStyles,
478cb93a386Sopenharmony_ci        fPlaceholders, fFontCollection, fUnicode);
479cb93a386Sopenharmony_ci    if (tmpParagraph->shapeForMiddleEllipsis(rawWidth)) {
480cb93a386Sopenharmony_ci        fText = tmpParagraph->fText;
481cb93a386Sopenharmony_ci        fTextStyles = tmpParagraph->fTextStyles;
482cb93a386Sopenharmony_ci        fPlaceholders = tmpParagraph->fPlaceholders;
483cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
484cb93a386Sopenharmony_ci        fEllipsisRange = tmpParagraph->fEllipsisRange;
485cb93a386Sopenharmony_ci#endif
486cb93a386Sopenharmony_ci    }
487cb93a386Sopenharmony_ci}
488cb93a386Sopenharmony_ci
489cb93a386Sopenharmony_civoid ParagraphImpl::layout(SkScalar rawWidth) {
490cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
491cb93a386Sopenharmony_ci    TEXT_TRACE_FUNC();
492cb93a386Sopenharmony_ci#endif
493cb93a386Sopenharmony_ci    fLineNumber = 1;
494cb93a386Sopenharmony_ci    allTextWidth = 0;
495cb93a386Sopenharmony_ci    fLayoutRawWidth = rawWidth;
496cb93a386Sopenharmony_ci    // TODO: This rounding is done to match Flutter tests. Must be removed...
497cb93a386Sopenharmony_ci    auto floorWidth = rawWidth;
498cb93a386Sopenharmony_ci
499cb93a386Sopenharmony_ci    if (fParagraphStyle.getMaxLines() == 1 &&
500cb93a386Sopenharmony_ci        fParagraphStyle.getEllipsisMod() == EllipsisModal::MIDDLE) {
501cb93a386Sopenharmony_ci        fOldMaxWidth = rawWidth;
502cb93a386Sopenharmony_ci        isMiddleEllipsis = true;
503cb93a386Sopenharmony_ci    }
504cb93a386Sopenharmony_ci    if (getApplyRoundingHack()) {
505cb93a386Sopenharmony_ci        floorWidth = SkScalarFloorToScalar(floorWidth);
506cb93a386Sopenharmony_ci    }
507cb93a386Sopenharmony_ci
508cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
509cb93a386Sopenharmony_ci    bool isMaxLinesZero = false;
510cb93a386Sopenharmony_ci#endif
511cb93a386Sopenharmony_ci    if (fParagraphStyle.getMaxLines() == 0) {
512cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
513cb93a386Sopenharmony_ci        if (fText.size() != 0) {
514cb93a386Sopenharmony_ci            isMaxLinesZero = true;
515cb93a386Sopenharmony_ci        }
516cb93a386Sopenharmony_ci#endif
517cb93a386Sopenharmony_ci        fText.reset();
518cb93a386Sopenharmony_ci    }
519cb93a386Sopenharmony_ci
520cb93a386Sopenharmony_ci    if ((!SkScalarIsFinite(rawWidth) || fLongestLine <= floorWidth) &&
521cb93a386Sopenharmony_ci        fState >= kLineBroken &&
522cb93a386Sopenharmony_ci         fLines.size() == 1 && fLines.front().ellipsis() == nullptr) {
523cb93a386Sopenharmony_ci        // Most common case: one line of text (and one line is never justified, so no cluster shifts)
524cb93a386Sopenharmony_ci        // We cannot mark it as kLineBroken because the new width can be bigger than the old width
525cb93a386Sopenharmony_ci        fWidth = floorWidth;
526cb93a386Sopenharmony_ci        fState = kShaped;
527cb93a386Sopenharmony_ci    } else if (fState >= kLineBroken && fOldWidth != floorWidth) {
528cb93a386Sopenharmony_ci        // We can use the results from SkShaper but have to do EVERYTHING ELSE again
529cb93a386Sopenharmony_ci        fState = kShaped;
530cb93a386Sopenharmony_ci    } else {
531cb93a386Sopenharmony_ci        // Nothing changed case: we can reuse the data from the last layout
532cb93a386Sopenharmony_ci    }
533cb93a386Sopenharmony_ci
534cb93a386Sopenharmony_ci    this->prepareForMiddleEllipsis(rawWidth);
535cb93a386Sopenharmony_ci    this->fUnicodeText = convertUtf8ToUnicode(fText);
536cb93a386Sopenharmony_ci    auto paragraphCache = fFontCollection->getParagraphCache();
537cb93a386Sopenharmony_ci
538cb93a386Sopenharmony_ci    if (fState < kShaped) {
539cb93a386Sopenharmony_ci        // Check if we have the text in the cache and don't need to shape it again
540cb93a386Sopenharmony_ci        if (!paragraphCache->findParagraph(this)) {
541cb93a386Sopenharmony_ci            if (fState < kIndexed) {
542cb93a386Sopenharmony_ci                // This only happens once at the first layout; the text is immutable
543cb93a386Sopenharmony_ci                // and there is no reason to repeat it
544cb93a386Sopenharmony_ci                if (this->computeCodeUnitProperties()) {
545cb93a386Sopenharmony_ci                    fState = kIndexed;
546cb93a386Sopenharmony_ci                }
547cb93a386Sopenharmony_ci            }
548cb93a386Sopenharmony_ci            this->fRuns.reset();
549cb93a386Sopenharmony_ci            this->fClusters.reset();
550cb93a386Sopenharmony_ci            this->fClustersIndexFromCodeUnit.reset();
551cb93a386Sopenharmony_ci            this->fClustersIndexFromCodeUnit.push_back_n(fText.size() + 1, EMPTY_INDEX);
552cb93a386Sopenharmony_ci            if (!this->shapeTextIntoEndlessLine()) {
553cb93a386Sopenharmony_ci                this->resetContext();
554cb93a386Sopenharmony_ci
555cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
556cb93a386Sopenharmony_ci                if (isMaxLinesZero) {
557cb93a386Sopenharmony_ci                    fExceededMaxLines  = true;
558cb93a386Sopenharmony_ci                }
559cb93a386Sopenharmony_ci#endif
560cb93a386Sopenharmony_ci                // TODO: merge the two next calls - they always come together
561cb93a386Sopenharmony_ci                this->resolveStrut();
562cb93a386Sopenharmony_ci                this->computeEmptyMetrics();
563cb93a386Sopenharmony_ci                this->fLines.reset();
564cb93a386Sopenharmony_ci
565cb93a386Sopenharmony_ci                // Set the important values that are not zero
566cb93a386Sopenharmony_ci                fWidth = floorWidth;
567cb93a386Sopenharmony_ci                fHeight = fEmptyMetrics.height();
568cb93a386Sopenharmony_ci                if (fParagraphStyle.getStrutStyle().getStrutEnabled() &&
569cb93a386Sopenharmony_ci                    fParagraphStyle.getStrutStyle().getForceStrutHeight()) {
570cb93a386Sopenharmony_ci                    fHeight = fStrutMetrics.height();
571cb93a386Sopenharmony_ci                }
572cb93a386Sopenharmony_ci                if (fParagraphStyle.getMaxLines() == 0) {
573cb93a386Sopenharmony_ci                    fHeight = 0;
574cb93a386Sopenharmony_ci                }
575cb93a386Sopenharmony_ci                fAlphabeticBaseline = fEmptyMetrics.alphabeticBaseline();
576cb93a386Sopenharmony_ci                fIdeographicBaseline = fEmptyMetrics.ideographicBaseline();
577cb93a386Sopenharmony_ci                fLongestLine = FLT_MIN - FLT_MAX;  // That is what flutter has
578cb93a386Sopenharmony_ci                fMinIntrinsicWidth = 0;
579cb93a386Sopenharmony_ci                fMaxIntrinsicWidth = 0;
580cb93a386Sopenharmony_ci                this->fOldWidth = floorWidth;
581cb93a386Sopenharmony_ci                this->fOldHeight = this->fHeight;
582cb93a386Sopenharmony_ci
583cb93a386Sopenharmony_ci                return;
584cb93a386Sopenharmony_ci            } else if (!(fParagraphStyle.getMaxLines() == 1 &&
585cb93a386Sopenharmony_ci                fParagraphStyle.getEllipsisMod() == EllipsisModal::MIDDLE)) {
586cb93a386Sopenharmony_ci                // Add the paragraph to the cache
587cb93a386Sopenharmony_ci                paragraphCache->updateParagraph(this);
588cb93a386Sopenharmony_ci            }
589cb93a386Sopenharmony_ci        }
590cb93a386Sopenharmony_ci        fState = kShaped;
591cb93a386Sopenharmony_ci    }
592cb93a386Sopenharmony_ci
593cb93a386Sopenharmony_ci    if (fState == kShaped) {
594cb93a386Sopenharmony_ci        this->resetContext();
595cb93a386Sopenharmony_ci        this->resolveStrut();
596cb93a386Sopenharmony_ci        this->computeEmptyMetrics();
597cb93a386Sopenharmony_ci        this->fLines.reset();
598cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
599cb93a386Sopenharmony_ci        // fast path
600cb93a386Sopenharmony_ci        if (!fHasLineBreaks &&
601cb93a386Sopenharmony_ci            !fHasWhitespacesInside &&
602cb93a386Sopenharmony_ci            fPlaceholders.size() == 1 &&
603cb93a386Sopenharmony_ci            (fRuns.size() == 1 && fRuns[0].fAdvance.fX <= floorWidth - this->detectIndents(0))) {
604cb93a386Sopenharmony_ci            positionShapedTextIntoLine(floorWidth);
605cb93a386Sopenharmony_ci        } else if (!paragraphCache->GetStoredLayout(*this)) {
606cb93a386Sopenharmony_ci            breakShapedTextIntoLines(floorWidth);
607cb93a386Sopenharmony_ci            // text breaking did not go to fast path and we did not have cached layout
608cb93a386Sopenharmony_ci            paragraphCache->SetStoredLayout(*this);
609cb93a386Sopenharmony_ci        }
610cb93a386Sopenharmony_ci#else
611cb93a386Sopenharmony_ci        this->breakShapedTextIntoLines(floorWidth);
612cb93a386Sopenharmony_ci#endif
613cb93a386Sopenharmony_ci        fState = kLineBroken;
614cb93a386Sopenharmony_ci    }
615cb93a386Sopenharmony_ci
616cb93a386Sopenharmony_ci    if (fState == kLineBroken) {
617cb93a386Sopenharmony_ci        // Build the picture lazily not until we actually have to paint (or never)
618cb93a386Sopenharmony_ci        this->resetShifts();
619cb93a386Sopenharmony_ci        this->formatLines(fWidth);
620cb93a386Sopenharmony_ci        fState = kFormatted;
621cb93a386Sopenharmony_ci    }
622cb93a386Sopenharmony_ci
623cb93a386Sopenharmony_ci    if (fParagraphStyle.getMaxLines() == 0) {
624cb93a386Sopenharmony_ci        fHeight = 0;
625cb93a386Sopenharmony_ci    }
626cb93a386Sopenharmony_ci
627cb93a386Sopenharmony_ci    this->fOldWidth = floorWidth;
628cb93a386Sopenharmony_ci    this->fOldHeight = this->fHeight;
629cb93a386Sopenharmony_ci
630cb93a386Sopenharmony_ci    if (getApplyRoundingHack()) {
631cb93a386Sopenharmony_ci        // TODO: This rounding is done to match Flutter tests. Must be removed...
632cb93a386Sopenharmony_ci        fMinIntrinsicWidth = littleRound(fMinIntrinsicWidth);
633cb93a386Sopenharmony_ci        fMaxIntrinsicWidth = littleRound(fMaxIntrinsicWidth);
634cb93a386Sopenharmony_ci    }
635cb93a386Sopenharmony_ci
636cb93a386Sopenharmony_ci    // TODO: This is strictly Flutter thing. Must be factored out into some flutter code
637cb93a386Sopenharmony_ci    if (fParagraphStyle.getMaxLines() == 1 ||
638cb93a386Sopenharmony_ci        (fParagraphStyle.unlimited_lines() && fParagraphStyle.ellipsized())) {
639cb93a386Sopenharmony_ci        fMinIntrinsicWidth = fMaxIntrinsicWidth;
640cb93a386Sopenharmony_ci    }
641cb93a386Sopenharmony_ci
642cb93a386Sopenharmony_ci    // TODO: Since min and max are calculated differently it's possible to get a rounding error
643cb93a386Sopenharmony_ci    //  that would make min > max. Sort it out later, make it the same for now
644cb93a386Sopenharmony_ci    if (fMaxIntrinsicWidth < fMinIntrinsicWidth) {
645cb93a386Sopenharmony_ci        fMaxIntrinsicWidth = fMinIntrinsicWidth;
646cb93a386Sopenharmony_ci    }
647cb93a386Sopenharmony_ci    if (fParagraphStyle.getMaxLines() == 0) {
648cb93a386Sopenharmony_ci        fLineNumber = 0;
649cb93a386Sopenharmony_ci    } else {
650cb93a386Sopenharmony_ci        fLineNumber = std::max(size_t(1), fLines.size());
651cb93a386Sopenharmony_ci    }
652cb93a386Sopenharmony_ci    //SkDebugf("layout('%s', %f): %f %f\n", fText.c_str(), rawWidth, fMinIntrinsicWidth, fMaxIntrinsicWidth);
653cb93a386Sopenharmony_ci}
654cb93a386Sopenharmony_ci
655cb93a386Sopenharmony_civoid ParagraphImpl::paint(SkCanvas* canvas, SkScalar x, SkScalar y) {
656cb93a386Sopenharmony_ci    CanvasParagraphPainter painter(canvas);
657cb93a386Sopenharmony_ci    paint(&painter, x, y);
658cb93a386Sopenharmony_ci}
659cb93a386Sopenharmony_ci
660cb93a386Sopenharmony_civoid ParagraphImpl::paint(ParagraphPainter* painter, SkScalar x, SkScalar y) {
661cb93a386Sopenharmony_ci    for (auto& line : fLines) {
662cb93a386Sopenharmony_ci        line.paint(painter, x, y);
663cb93a386Sopenharmony_ci    }
664cb93a386Sopenharmony_ci}
665cb93a386Sopenharmony_ci
666cb93a386Sopenharmony_civoid ParagraphImpl::paint(ParagraphPainter* painter, RSPath* path, SkScalar hOffset, SkScalar vOffset) {
667cb93a386Sopenharmony_ci    auto& style = fTextStyles[0].fStyle;
668cb93a386Sopenharmony_ci    float align = 0.0f;
669cb93a386Sopenharmony_ci    switch (paragraphStyle().getTextAlign()) {
670cb93a386Sopenharmony_ci        case TextAlign::kCenter:
671cb93a386Sopenharmony_ci            align = -0.5f;
672cb93a386Sopenharmony_ci            break;
673cb93a386Sopenharmony_ci        case TextAlign::kRight:
674cb93a386Sopenharmony_ci            align = -1.0f;
675cb93a386Sopenharmony_ci            break;
676cb93a386Sopenharmony_ci        default:
677cb93a386Sopenharmony_ci            break;
678cb93a386Sopenharmony_ci    }
679cb93a386Sopenharmony_ci    hOffset += align * (fMaxIntrinsicWidth - style.getLetterSpacing() - path->GetLength(false));
680cb93a386Sopenharmony_ci    for (auto& line : fLines) {
681cb93a386Sopenharmony_ci        line.paint(painter, path, hOffset, vOffset);
682cb93a386Sopenharmony_ci    }
683cb93a386Sopenharmony_ci}
684cb93a386Sopenharmony_ci
685cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
686cb93a386Sopenharmony_ciTextRange ParagraphImpl::getEllipsisTextRange() {
687cb93a386Sopenharmony_ci    if (fState < kLineBroken) {
688cb93a386Sopenharmony_ci        return EMPTY_RANGE;
689cb93a386Sopenharmony_ci    }
690cb93a386Sopenharmony_ci    if (!fEllipsisRange.empty()) {
691cb93a386Sopenharmony_ci        return fEllipsisRange;
692cb93a386Sopenharmony_ci    }
693cb93a386Sopenharmony_ci    this->ensureUTF16Mapping();
694cb93a386Sopenharmony_ci    for (const auto& line: fLines) {
695cb93a386Sopenharmony_ci        if (line.getTextRangeReplacedByEllipsis().empty()) {
696cb93a386Sopenharmony_ci            continue;
697cb93a386Sopenharmony_ci        }
698cb93a386Sopenharmony_ci        auto ellipsisClusterRange = line.getTextRangeReplacedByEllipsis();
699cb93a386Sopenharmony_ci        return TextRange(getUTF16Index(ellipsisClusterRange.start),
700cb93a386Sopenharmony_ci                                      getUTF16Index(ellipsisClusterRange.end));
701cb93a386Sopenharmony_ci    }
702cb93a386Sopenharmony_ci    return EMPTY_RANGE;
703cb93a386Sopenharmony_ci}
704cb93a386Sopenharmony_ci#endif
705cb93a386Sopenharmony_ci
706cb93a386Sopenharmony_civoid ParagraphImpl::resetContext() {
707cb93a386Sopenharmony_ci    fAlphabeticBaseline = 0;
708cb93a386Sopenharmony_ci    fHeight = 0;
709cb93a386Sopenharmony_ci    fWidth = 0;
710cb93a386Sopenharmony_ci    fIdeographicBaseline = 0;
711cb93a386Sopenharmony_ci    fMaxIntrinsicWidth = 0;
712cb93a386Sopenharmony_ci    fMinIntrinsicWidth = 0;
713cb93a386Sopenharmony_ci    fLongestLine = 0;
714cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
715cb93a386Sopenharmony_ci    fLongestLineWithIndent = 0;
716cb93a386Sopenharmony_ci#endif
717cb93a386Sopenharmony_ci    fMaxWidthWithTrailingSpaces = 0;
718cb93a386Sopenharmony_ci    fExceededMaxLines = false;
719cb93a386Sopenharmony_ci}
720cb93a386Sopenharmony_ci
721cb93a386Sopenharmony_ci// shapeTextIntoEndlessLine is the thing that calls this method
722cb93a386Sopenharmony_cibool ParagraphImpl::computeCodeUnitProperties() {
723cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
724cb93a386Sopenharmony_ci    TEXT_TRACE_FUNC();
725cb93a386Sopenharmony_ci#endif
726cb93a386Sopenharmony_ci    if (nullptr == fUnicode) {
727cb93a386Sopenharmony_ci        return false;
728cb93a386Sopenharmony_ci    }
729cb93a386Sopenharmony_ci
730cb93a386Sopenharmony_ci    // Get bidi regions
731cb93a386Sopenharmony_ci    auto textDirection = fParagraphStyle.getTextDirection() == TextDirection::kLtr
732cb93a386Sopenharmony_ci                              ? SkUnicode::TextDirection::kLTR
733cb93a386Sopenharmony_ci                              : SkUnicode::TextDirection::kRTL;
734cb93a386Sopenharmony_ci    if (!fUnicode->getBidiRegions(fText.c_str(), fText.size(), textDirection, &fBidiRegions)) {
735cb93a386Sopenharmony_ci        return false;
736cb93a386Sopenharmony_ci    }
737cb93a386Sopenharmony_ci
738cb93a386Sopenharmony_ci    // Collect all spaces and some extra information
739cb93a386Sopenharmony_ci    // (and also substitute \t with a space while we are at it)
740cb93a386Sopenharmony_ci    if (!fUnicode->computeCodeUnitFlags(&fText[0],
741cb93a386Sopenharmony_ci                                        fText.size(),
742cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
743cb93a386Sopenharmony_ci                                        this->paragraphStyle().getReplaceTabCharacters() ||
744cb93a386Sopenharmony_ci                                        (!(this->paragraphStyle().getTextTab().location < 1.0)),
745cb93a386Sopenharmony_ci#else
746cb93a386Sopenharmony_ci                                        this->paragraphStyle().getReplaceTabCharacters(),
747cb93a386Sopenharmony_ci#endif
748cb93a386Sopenharmony_ci                                        &fCodeUnitProperties)) {
749cb93a386Sopenharmony_ci        return false;
750cb93a386Sopenharmony_ci    }
751cb93a386Sopenharmony_ci
752cb93a386Sopenharmony_ci    // Get some information about trailing spaces / hard line breaks
753cb93a386Sopenharmony_ci    fTrailingSpaces = fText.size();
754cb93a386Sopenharmony_ci    TextIndex firstWhitespace = EMPTY_INDEX;
755cb93a386Sopenharmony_ci    for (int i = 0; i < fCodeUnitProperties.size(); ++i) {
756cb93a386Sopenharmony_ci        auto flags = fCodeUnitProperties[i];
757cb93a386Sopenharmony_ci        if (SkUnicode::isPartOfWhiteSpaceBreak(flags)) {
758cb93a386Sopenharmony_ci            if (fTrailingSpaces  == fText.size()) {
759cb93a386Sopenharmony_ci                fTrailingSpaces = i;
760cb93a386Sopenharmony_ci            }
761cb93a386Sopenharmony_ci            if (firstWhitespace == EMPTY_INDEX) {
762cb93a386Sopenharmony_ci                firstWhitespace = i;
763cb93a386Sopenharmony_ci            }
764cb93a386Sopenharmony_ci        } else {
765cb93a386Sopenharmony_ci            fTrailingSpaces = fText.size();
766cb93a386Sopenharmony_ci        }
767cb93a386Sopenharmony_ci        if (SkUnicode::isHardLineBreak(flags)) {
768cb93a386Sopenharmony_ci            fHasLineBreaks = true;
769cb93a386Sopenharmony_ci        }
770cb93a386Sopenharmony_ci    }
771cb93a386Sopenharmony_ci
772cb93a386Sopenharmony_ci    if (firstWhitespace < fTrailingSpaces) {
773cb93a386Sopenharmony_ci        fHasWhitespacesInside = true;
774cb93a386Sopenharmony_ci    }
775cb93a386Sopenharmony_ci
776cb93a386Sopenharmony_ci    return true;
777cb93a386Sopenharmony_ci}
778cb93a386Sopenharmony_ci
779cb93a386Sopenharmony_cistatic bool is_ascii_7bit_space(int c) {
780cb93a386Sopenharmony_ci    SkASSERT(c >= 0 && c <= 127);
781cb93a386Sopenharmony_ci
782cb93a386Sopenharmony_ci    // Extracted from https://en.wikipedia.org/wiki/Whitespace_character
783cb93a386Sopenharmony_ci    //
784cb93a386Sopenharmony_ci    enum WS {
785cb93a386Sopenharmony_ci        kHT    = 9,
786cb93a386Sopenharmony_ci        kLF    = 10,
787cb93a386Sopenharmony_ci        kVT    = 11,
788cb93a386Sopenharmony_ci        kFF    = 12,
789cb93a386Sopenharmony_ci        kCR    = 13,
790cb93a386Sopenharmony_ci        kSP    = 32,    // too big to use as shift
791cb93a386Sopenharmony_ci    };
792cb93a386Sopenharmony_ci#define M(shift)    (1 << (shift))
793cb93a386Sopenharmony_ci    constexpr uint32_t kSpaceMask = M(kHT) | M(kLF) | M(kVT) | M(kFF) | M(kCR);
794cb93a386Sopenharmony_ci    // we check for Space (32) explicitly, since it is too large to shift
795cb93a386Sopenharmony_ci    return (c == kSP) || (c <= 31 && (kSpaceMask & M(c)));
796cb93a386Sopenharmony_ci#undef M
797cb93a386Sopenharmony_ci}
798cb93a386Sopenharmony_ci
799cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
800cb93a386Sopenharmony_cistatic std::vector<SkRange<SkUnichar>> CJK_UNICODE_SET = {
801cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x4E00, 0x9FFF),
802cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x3400, 0x4DBF),
803cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x20000, 0x2A6DF),
804cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x2A700, 0x2B73F),
805cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x2B740, 0x2B81F),
806cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x2B820, 0x2CEAF),
807cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x2CEB0, 0x2EBEF),
808cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x30000, 0x3134F),
809cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0xF900, 0xFAFF),
810cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x3040, 0x309F),
811cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x30A0, 0x30FF),
812cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x31F0, 0x31FF),
813cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x1100, 0x11FF),
814cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x3130, 0x318F),
815cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0xAC00, 0xD7AF),
816cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x31C0, 0x31EF),
817cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x2E80, 0x2EFF),
818cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x2F800, 0x2FA1F),
819cb93a386Sopenharmony_ci};
820cb93a386Sopenharmony_ci
821cb93a386Sopenharmony_cistatic std::vector<SkRange<SkUnichar>> WESTERN_UNICODE_SET = {
822cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x0041, 0x005A),
823cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x0061, 0x007A),
824cb93a386Sopenharmony_ci    SkRange<SkUnichar>(0x0030, 0x0039),
825cb93a386Sopenharmony_ci};
826cb93a386Sopenharmony_ci
827cb93a386Sopenharmony_ciconstexpr SkUnichar COPYRIGHT_UNICODE = 0x00A9;
828cb93a386Sopenharmony_ci
829cb93a386Sopenharmony_cistruct UnicodeSet {
830cb93a386Sopenharmony_ci    std::unordered_set<SkUnichar> set_;
831cb93a386Sopenharmony_ci    explicit UnicodeSet(const std::vector<SkRange<SkUnichar>>& unicodeSet) {
832cb93a386Sopenharmony_ci        if (!TextParameter::GetAutoSpacingEnable()) {
833cb93a386Sopenharmony_ci            return;
834cb93a386Sopenharmony_ci        }
835cb93a386Sopenharmony_ci        for (auto unicodeSetRange : unicodeSet) {
836cb93a386Sopenharmony_ci            for (auto i = unicodeSetRange.start; i <= unicodeSetRange.end; ++i) {
837cb93a386Sopenharmony_ci                set_.insert(i);
838cb93a386Sopenharmony_ci            }
839cb93a386Sopenharmony_ci        }
840cb93a386Sopenharmony_ci    }
841cb93a386Sopenharmony_ci    bool exist(SkUnichar c) const {
842cb93a386Sopenharmony_ci        return set_.find(c) != set_.end();
843cb93a386Sopenharmony_ci    }
844cb93a386Sopenharmony_ci};
845cb93a386Sopenharmony_ci
846cb93a386Sopenharmony_cistatic const UnicodeSet CJK_SET(CJK_UNICODE_SET);
847cb93a386Sopenharmony_cistatic const UnicodeSet WESTERN_SET(WESTERN_UNICODE_SET);
848cb93a386Sopenharmony_ci#endif
849cb93a386Sopenharmony_ci
850cb93a386Sopenharmony_ciCluster::Cluster(ParagraphImpl* owner,
851cb93a386Sopenharmony_ci                 RunIndex runIndex,
852cb93a386Sopenharmony_ci                 size_t start,
853cb93a386Sopenharmony_ci                 size_t end,
854cb93a386Sopenharmony_ci                 SkSpan<const char> text,
855cb93a386Sopenharmony_ci                 SkScalar width,
856cb93a386Sopenharmony_ci                 SkScalar height)
857cb93a386Sopenharmony_ci        : fOwner(owner)
858cb93a386Sopenharmony_ci        , fRunIndex(runIndex)
859cb93a386Sopenharmony_ci        , fTextRange(text.begin() - fOwner->text().begin(), text.end() - fOwner->text().begin())
860cb93a386Sopenharmony_ci        , fGraphemeRange(EMPTY_RANGE)
861cb93a386Sopenharmony_ci        , fStart(start)
862cb93a386Sopenharmony_ci        , fEnd(end)
863cb93a386Sopenharmony_ci        , fWidth(width)
864cb93a386Sopenharmony_ci        , fHeight(height)
865cb93a386Sopenharmony_ci        , fHalfLetterSpacing(0.0)
866cb93a386Sopenharmony_ci        , fIsIdeographic(false) {
867cb93a386Sopenharmony_ci    size_t whiteSpacesBreakLen = 0;
868cb93a386Sopenharmony_ci    size_t intraWordBreakLen = 0;
869cb93a386Sopenharmony_ci
870cb93a386Sopenharmony_ci    const char* ch = text.begin();
871cb93a386Sopenharmony_ci    if (text.end() - ch == 1 && *(unsigned char*)ch <= 0x7F) {
872cb93a386Sopenharmony_ci        // I am not even sure it's worth it if we do not save a unicode call
873cb93a386Sopenharmony_ci        if (is_ascii_7bit_space(*ch)) {
874cb93a386Sopenharmony_ci            ++whiteSpacesBreakLen;
875cb93a386Sopenharmony_ci        }
876cb93a386Sopenharmony_ci    } else {
877cb93a386Sopenharmony_ci        for (auto i = fTextRange.start; i < fTextRange.end; ++i) {
878cb93a386Sopenharmony_ci            if (fOwner->codeUnitHasProperty(i, SkUnicode::CodeUnitFlags::kPartOfWhiteSpaceBreak)) {
879cb93a386Sopenharmony_ci                ++whiteSpacesBreakLen;
880cb93a386Sopenharmony_ci            }
881cb93a386Sopenharmony_ci            if (fOwner->codeUnitHasProperty(i, SkUnicode::CodeUnitFlags::kPartOfIntraWordBreak)) {
882cb93a386Sopenharmony_ci                ++intraWordBreakLen;
883cb93a386Sopenharmony_ci            }
884cb93a386Sopenharmony_ci            if (fOwner->codeUnitHasProperty(i, SkUnicode::CodeUnitFlags::kIdeographic)) {
885cb93a386Sopenharmony_ci                fIsIdeographic = true;
886cb93a386Sopenharmony_ci            }
887cb93a386Sopenharmony_ci        }
888cb93a386Sopenharmony_ci    }
889cb93a386Sopenharmony_ci
890cb93a386Sopenharmony_ci    fIsWhiteSpaceBreak = whiteSpacesBreakLen == fTextRange.width();
891cb93a386Sopenharmony_ci    fIsIntraWordBreak = intraWordBreakLen == fTextRange.width();
892cb93a386Sopenharmony_ci    fIsHardBreak = fOwner->codeUnitHasProperty(fTextRange.end,
893cb93a386Sopenharmony_ci                                               SkUnicode::CodeUnitFlags::kHardLineBreakBefore);
894cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
895cb93a386Sopenharmony_ci    fIsTabulation = fOwner->codeUnitHasProperty(fTextRange.start,
896cb93a386Sopenharmony_ci                                                SkUnicode::CodeUnitFlags::kTabulation);
897cb93a386Sopenharmony_ci#endif
898cb93a386Sopenharmony_ci    auto unicodeStart = fOwner->getUnicodeIndex(fTextRange.start);
899cb93a386Sopenharmony_ci    auto unicodeEnd = fOwner->getUnicodeIndex(fTextRange.end);
900cb93a386Sopenharmony_ci    SkUnichar unicode = 0;
901cb93a386Sopenharmony_ci    if (unicodeEnd - unicodeStart == 1 && unicodeStart < fOwner->unicodeText().size()) {
902cb93a386Sopenharmony_ci        unicode = fOwner->unicodeText()[unicodeStart];
903cb93a386Sopenharmony_ci    }
904cb93a386Sopenharmony_ci    fIsCopyright = unicode == COPYRIGHT_UNICODE;
905cb93a386Sopenharmony_ci    fIsCJK = CJK_SET.exist(unicode);
906cb93a386Sopenharmony_ci    fIsWestern = WESTERN_SET.exist(unicode);
907cb93a386Sopenharmony_ci}
908cb93a386Sopenharmony_ci
909cb93a386Sopenharmony_ciSkScalar Run::calculateWidth(size_t start, size_t end, bool clip) const {
910cb93a386Sopenharmony_ci    SkASSERT(start <= end);
911cb93a386Sopenharmony_ci    // clip |= end == size();  // Clip at the end of the run?
912cb93a386Sopenharmony_ci    auto correction = 0.0f;
913cb93a386Sopenharmony_ci    if (end > start && !fJustificationShifts.empty()) {
914cb93a386Sopenharmony_ci        // This is not a typo: we are using Point as a pair of SkScalars
915cb93a386Sopenharmony_ci        correction = fJustificationShifts[end - 1].fX -
916cb93a386Sopenharmony_ci                     fJustificationShifts[start].fY;
917cb93a386Sopenharmony_ci    }
918cb93a386Sopenharmony_ci    if (end > start && !fAutoSpacings.empty()) {
919cb93a386Sopenharmony_ci        // This is not a tyopo: we are using Point as a pair of SkScalars
920cb93a386Sopenharmony_ci        correction += fAutoSpacings[end - 1].fX - fAutoSpacings[start].fY;
921cb93a386Sopenharmony_ci    }
922cb93a386Sopenharmony_ci    return posX(end) - posX(start) + correction;
923cb93a386Sopenharmony_ci}
924cb93a386Sopenharmony_ci
925cb93a386Sopenharmony_ci// In some cases we apply spacing to glyphs first and then build the cluster table, in some we do
926cb93a386Sopenharmony_ci// the opposite - just to optimize the most common case.
927cb93a386Sopenharmony_civoid ParagraphImpl::applySpacingAndBuildClusterTable() {
928cb93a386Sopenharmony_ci
929cb93a386Sopenharmony_ci    // Check all text styles to see what we have to do (if anything)
930cb93a386Sopenharmony_ci    size_t letterSpacingStyles = 0;
931cb93a386Sopenharmony_ci    bool hasWordSpacing = false;
932cb93a386Sopenharmony_ci    for (auto& block : fTextStyles) {
933cb93a386Sopenharmony_ci        if (block.fRange.width() > 0) {
934cb93a386Sopenharmony_ci            if (!SkScalarNearlyZero(block.fStyle.getLetterSpacing())) {
935cb93a386Sopenharmony_ci                ++letterSpacingStyles;
936cb93a386Sopenharmony_ci            }
937cb93a386Sopenharmony_ci            if (!SkScalarNearlyZero(block.fStyle.getWordSpacing())) {
938cb93a386Sopenharmony_ci                hasWordSpacing = true;
939cb93a386Sopenharmony_ci            }
940cb93a386Sopenharmony_ci        }
941cb93a386Sopenharmony_ci    }
942cb93a386Sopenharmony_ci
943cb93a386Sopenharmony_ci    if (letterSpacingStyles == 0 && !hasWordSpacing) {
944cb93a386Sopenharmony_ci        // We don't have to do anything about spacing (most common case)
945cb93a386Sopenharmony_ci        this->buildClusterTable();
946cb93a386Sopenharmony_ci        return;
947cb93a386Sopenharmony_ci    }
948cb93a386Sopenharmony_ci
949cb93a386Sopenharmony_ci    if (letterSpacingStyles == 1 && !hasWordSpacing && fTextStyles.size() == 1 &&
950cb93a386Sopenharmony_ci        fTextStyles[0].fRange.width() == fText.size() && fRuns.size() == 1) {
951cb93a386Sopenharmony_ci        // We have to letter space the entire paragraph (second most common case)
952cb93a386Sopenharmony_ci        auto& run = fRuns[0];
953cb93a386Sopenharmony_ci        auto& style = fTextStyles[0].fStyle;
954cb93a386Sopenharmony_ci        this->buildClusterTable();
955cb93a386Sopenharmony_ci        SkScalar shift = 0;
956cb93a386Sopenharmony_ci        run.iterateThroughClusters([this, &run, &shift, &style](Cluster* cluster) {
957cb93a386Sopenharmony_ci            run.shift(cluster, shift);
958cb93a386Sopenharmony_ci            shift += run.addSpacesEvenly(style.getLetterSpacing(), cluster);
959cb93a386Sopenharmony_ci        });
960cb93a386Sopenharmony_ci        return;
961cb93a386Sopenharmony_ci    }
962cb93a386Sopenharmony_ci
963cb93a386Sopenharmony_ci    // The complex case: many text styles with spacing (possibly not adjusted to glyphs)
964cb93a386Sopenharmony_ci    this->buildClusterTable();
965cb93a386Sopenharmony_ci
966cb93a386Sopenharmony_ci    // Walk through all the clusters in the direction of shaped text
967cb93a386Sopenharmony_ci    // (we have to walk through the styles in the same order, too)
968cb93a386Sopenharmony_ci    SkScalar shift = 0;
969cb93a386Sopenharmony_ci    for (auto& run : fRuns) {
970cb93a386Sopenharmony_ci
971cb93a386Sopenharmony_ci        // Skip placeholder runs
972cb93a386Sopenharmony_ci        if (run.isPlaceholder()) {
973cb93a386Sopenharmony_ci            continue;
974cb93a386Sopenharmony_ci        }
975cb93a386Sopenharmony_ci        bool soFarWhitespacesOnly = true;
976cb93a386Sopenharmony_ci        bool wordSpacingPending = false;
977cb93a386Sopenharmony_ci        Cluster* lastSpaceCluster = nullptr;
978cb93a386Sopenharmony_ci        run.iterateThroughClusters([this, &run, &shift, &soFarWhitespacesOnly, &wordSpacingPending, &lastSpaceCluster](Cluster* cluster) {
979cb93a386Sopenharmony_ci            // Shift the cluster (shift collected from the previous clusters)
980cb93a386Sopenharmony_ci            run.shift(cluster, shift);
981cb93a386Sopenharmony_ci
982cb93a386Sopenharmony_ci            // Synchronize styles (one cluster can be covered by few styles)
983cb93a386Sopenharmony_ci            Block* currentStyle = fTextStyles.begin();
984cb93a386Sopenharmony_ci            while (!cluster->startsIn(currentStyle->fRange)) {
985cb93a386Sopenharmony_ci                currentStyle++;
986cb93a386Sopenharmony_ci                SkASSERT(currentStyle != fTextStyles.end());
987cb93a386Sopenharmony_ci            }
988cb93a386Sopenharmony_ci
989cb93a386Sopenharmony_ci            SkASSERT(!currentStyle->fStyle.isPlaceholder());
990cb93a386Sopenharmony_ci
991cb93a386Sopenharmony_ci            // Process word spacing
992cb93a386Sopenharmony_ci            if (currentStyle->fStyle.getWordSpacing() != 0) {
993cb93a386Sopenharmony_ci                if (cluster->isWhitespaceBreak() && cluster->isSoftBreak()) {
994cb93a386Sopenharmony_ci                    if (!soFarWhitespacesOnly) {
995cb93a386Sopenharmony_ci                        lastSpaceCluster = cluster;
996cb93a386Sopenharmony_ci                        wordSpacingPending = true;
997cb93a386Sopenharmony_ci                    }
998cb93a386Sopenharmony_ci                } else if (wordSpacingPending) {
999cb93a386Sopenharmony_ci                    SkScalar spacing = currentStyle->fStyle.getWordSpacing();
1000cb93a386Sopenharmony_ci                    run.addSpacesAtTheEnd(spacing, lastSpaceCluster);
1001cb93a386Sopenharmony_ci                    run.shift(cluster, spacing);
1002cb93a386Sopenharmony_ci                    shift += spacing;
1003cb93a386Sopenharmony_ci                    wordSpacingPending = false;
1004cb93a386Sopenharmony_ci                }
1005cb93a386Sopenharmony_ci            }
1006cb93a386Sopenharmony_ci            // Process letter spacing
1007cb93a386Sopenharmony_ci            if (currentStyle->fStyle.getLetterSpacing() != 0) {
1008cb93a386Sopenharmony_ci                shift += run.addSpacesEvenly(currentStyle->fStyle.getLetterSpacing(), cluster);
1009cb93a386Sopenharmony_ci            }
1010cb93a386Sopenharmony_ci
1011cb93a386Sopenharmony_ci            if (soFarWhitespacesOnly && !cluster->isWhitespaceBreak()) {
1012cb93a386Sopenharmony_ci                soFarWhitespacesOnly = false;
1013cb93a386Sopenharmony_ci            }
1014cb93a386Sopenharmony_ci        });
1015cb93a386Sopenharmony_ci    }
1016cb93a386Sopenharmony_ci}
1017cb93a386Sopenharmony_ci
1018cb93a386Sopenharmony_civoid ParagraphImpl::middleEllipsisAddText(size_t charStart,
1019cb93a386Sopenharmony_ci                                          size_t charEnd,
1020cb93a386Sopenharmony_ci                                          SkScalar& allTextWidth,
1021cb93a386Sopenharmony_ci                                          SkScalar width,
1022cb93a386Sopenharmony_ci                                          bool isLeftToRight) {
1023cb93a386Sopenharmony_ci    if (isMiddleEllipsis) {
1024cb93a386Sopenharmony_ci        TextCutRecord textCount;
1025cb93a386Sopenharmony_ci        textCount.charbegin = charStart;
1026cb93a386Sopenharmony_ci        textCount.charOver = charEnd;
1027cb93a386Sopenharmony_ci        textCount.phraseWidth = width;
1028cb93a386Sopenharmony_ci        allTextWidth += width;
1029cb93a386Sopenharmony_ci        if (isLeftToRight) {
1030cb93a386Sopenharmony_ci            this->ltrTextSize.emplace_back(textCount);
1031cb93a386Sopenharmony_ci        } else {
1032cb93a386Sopenharmony_ci            this->rtlTextSize.emplace_back(textCount);
1033cb93a386Sopenharmony_ci        }
1034cb93a386Sopenharmony_ci    }
1035cb93a386Sopenharmony_ci}
1036cb93a386Sopenharmony_ci
1037cb93a386Sopenharmony_ci// Clusters in the order of the input text
1038cb93a386Sopenharmony_civoid ParagraphImpl::buildClusterTable() {
1039cb93a386Sopenharmony_ci    // It's possible that one grapheme includes few runs; we cannot handle it
1040cb93a386Sopenharmony_ci    // so we break graphemes by the runs instead
1041cb93a386Sopenharmony_ci    // It's not the ideal solution and has to be revisited later
1042cb93a386Sopenharmony_ci    int cluster_count = 1;
1043cb93a386Sopenharmony_ci    for (auto& run : fRuns) {
1044cb93a386Sopenharmony_ci        cluster_count += run.isPlaceholder() ? 1 : run.size();
1045cb93a386Sopenharmony_ci        fCodeUnitProperties[run.fTextRange.start] |= SkUnicode::CodeUnitFlags::kGraphemeStart;
1046cb93a386Sopenharmony_ci        fCodeUnitProperties[run.fTextRange.start] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart;
1047cb93a386Sopenharmony_ci    }
1048cb93a386Sopenharmony_ci    if (!fRuns.empty()) {
1049cb93a386Sopenharmony_ci        fCodeUnitProperties[fRuns.back().textRange().end] |= SkUnicode::CodeUnitFlags::kGraphemeStart;
1050cb93a386Sopenharmony_ci        fCodeUnitProperties[fRuns.back().textRange().end] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart;
1051cb93a386Sopenharmony_ci    }
1052cb93a386Sopenharmony_ci    fClusters.reserve_back(fClusters.size() + cluster_count);
1053cb93a386Sopenharmony_ci
1054cb93a386Sopenharmony_ci    // Walk through all the run in the direction of input text
1055cb93a386Sopenharmony_ci    for (auto& run : fRuns) {
1056cb93a386Sopenharmony_ci        auto runIndex = run.index();
1057cb93a386Sopenharmony_ci        auto runStart = fClusters.size();
1058cb93a386Sopenharmony_ci        if (run.isPlaceholder()) {
1059cb93a386Sopenharmony_ci            // Add info to cluster indexes table (text -> cluster)
1060cb93a386Sopenharmony_ci            for (auto i = run.textRange().start; i < run.textRange().end; ++i) {
1061cb93a386Sopenharmony_ci              fClustersIndexFromCodeUnit[i] = fClusters.size();
1062cb93a386Sopenharmony_ci            }
1063cb93a386Sopenharmony_ci            // There are no glyphs but we want to have one cluster
1064cb93a386Sopenharmony_ci            fClusters.emplace_back(this, runIndex, 0ul, 1ul, this->text(run.textRange()), run.advance().fX, run.advance().fY);
1065cb93a386Sopenharmony_ci            fCodeUnitProperties[run.textRange().start] |= SkUnicode::CodeUnitFlags::kSoftLineBreakBefore;
1066cb93a386Sopenharmony_ci            fCodeUnitProperties[run.textRange().end] |= SkUnicode::CodeUnitFlags::kSoftLineBreakBefore;
1067cb93a386Sopenharmony_ci        } else {
1068cb93a386Sopenharmony_ci            // Walk through the glyph in the direction of input text
1069cb93a386Sopenharmony_ci            run.iterateThroughClustersInTextOrder([&run, runIndex, this](size_t glyphStart,
1070cb93a386Sopenharmony_ci                                                                   size_t glyphEnd,
1071cb93a386Sopenharmony_ci                                                                   size_t charStart,
1072cb93a386Sopenharmony_ci                                                                   size_t charEnd,
1073cb93a386Sopenharmony_ci                                                                   SkScalar width,
1074cb93a386Sopenharmony_ci                                                                   SkScalar height) {
1075cb93a386Sopenharmony_ci                SkASSERT(charEnd >= charStart);
1076cb93a386Sopenharmony_ci                // Add info to cluster indexes table (text -> cluster)
1077cb93a386Sopenharmony_ci                for (auto i = charStart; i < charEnd; ++i) {
1078cb93a386Sopenharmony_ci                  fClustersIndexFromCodeUnit[i] = fClusters.size();
1079cb93a386Sopenharmony_ci                }
1080cb93a386Sopenharmony_ci
1081cb93a386Sopenharmony_ci                middleEllipsisAddText(charStart, charEnd, allTextWidth, width, run.leftToRight());
1082cb93a386Sopenharmony_ci                SkSpan<const char> text(fText.c_str() + charStart, charEnd - charStart);
1083cb93a386Sopenharmony_ci                fClusters.emplace_back(this, runIndex, glyphStart, glyphEnd, text, width, height);
1084cb93a386Sopenharmony_ci                fCodeUnitProperties[charStart] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart;
1085cb93a386Sopenharmony_ci            });
1086cb93a386Sopenharmony_ci        }
1087cb93a386Sopenharmony_ci        fCodeUnitProperties[run.textRange().start] |= SkUnicode::CodeUnitFlags::kGlyphClusterStart;
1088cb93a386Sopenharmony_ci
1089cb93a386Sopenharmony_ci        run.setClusterRange(runStart, fClusters.size());
1090cb93a386Sopenharmony_ci        fMaxIntrinsicWidth += run.advance().fX;
1091cb93a386Sopenharmony_ci    }
1092cb93a386Sopenharmony_ci    fClustersIndexFromCodeUnit[fText.size()] = fClusters.size();
1093cb93a386Sopenharmony_ci    fClusters.emplace_back(this, EMPTY_RUN, 0, 0, this->text({fText.size(), fText.size()}), 0, 0);
1094cb93a386Sopenharmony_ci}
1095cb93a386Sopenharmony_ci
1096cb93a386Sopenharmony_cibool ParagraphImpl::shapeTextIntoEndlessLine() {
1097cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1098cb93a386Sopenharmony_ci    TEXT_TRACE_FUNC();
1099cb93a386Sopenharmony_ci#endif
1100cb93a386Sopenharmony_ci    if (fText.size() == 0) {
1101cb93a386Sopenharmony_ci        return false;
1102cb93a386Sopenharmony_ci    }
1103cb93a386Sopenharmony_ci
1104cb93a386Sopenharmony_ci    fUnresolvedCodepoints.clear();
1105cb93a386Sopenharmony_ci    fFontSwitches.reset();
1106cb93a386Sopenharmony_ci
1107cb93a386Sopenharmony_ci    OneLineShaper oneLineShaper(this);
1108cb93a386Sopenharmony_ci    auto result = oneLineShaper.shape();
1109cb93a386Sopenharmony_ci    fUnresolvedGlyphs = oneLineShaper.unresolvedGlyphs();
1110cb93a386Sopenharmony_ci
1111cb93a386Sopenharmony_ci    this->applySpacingAndBuildClusterTable();
1112cb93a386Sopenharmony_ci
1113cb93a386Sopenharmony_ci    return result;
1114cb93a386Sopenharmony_ci}
1115cb93a386Sopenharmony_ci
1116cb93a386Sopenharmony_civoid ParagraphImpl::setIndents(const std::vector<SkScalar>& indents)
1117cb93a386Sopenharmony_ci{
1118cb93a386Sopenharmony_ci    fIndents = indents;
1119cb93a386Sopenharmony_ci}
1120cb93a386Sopenharmony_ci
1121cb93a386Sopenharmony_ciSkScalar ParagraphImpl::detectIndents(size_t index)
1122cb93a386Sopenharmony_ci{
1123cb93a386Sopenharmony_ci    SkScalar indent = 0.0;
1124cb93a386Sopenharmony_ci    if (fIndents.size() > 0 && index < fIndents.size()) {
1125cb93a386Sopenharmony_ci        indent = fIndents[index];
1126cb93a386Sopenharmony_ci    } else {
1127cb93a386Sopenharmony_ci        indent = fIndents.size() > 0 ? fIndents.back() : 0.0;
1128cb93a386Sopenharmony_ci    }
1129cb93a386Sopenharmony_ci
1130cb93a386Sopenharmony_ci    return indent;
1131cb93a386Sopenharmony_ci}
1132cb93a386Sopenharmony_ci
1133cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1134cb93a386Sopenharmony_civoid ParagraphImpl::positionShapedTextIntoLine(SkScalar maxWidth) {
1135cb93a386Sopenharmony_ci    resetAutoSpacing();
1136cb93a386Sopenharmony_ci    // This is a short version of a line breaking when we know that:
1137cb93a386Sopenharmony_ci    // 1. We have only one line of text
1138cb93a386Sopenharmony_ci    // 2. It's shaped into a single run
1139cb93a386Sopenharmony_ci    // 3. There are no placeholders
1140cb93a386Sopenharmony_ci    // 4. There are no linebreaks (which will format text into multiple lines)
1141cb93a386Sopenharmony_ci    // 5. There are no whitespaces so the minIntrinsicWidth=maxIntrinsicWidth
1142cb93a386Sopenharmony_ci    // (To think about that, the last condition is not quite right;
1143cb93a386Sopenharmony_ci    // we should calculate minIntrinsicWidth by soft line breaks.
1144cb93a386Sopenharmony_ci    // However, it's how it's done in Flutter now)
1145cb93a386Sopenharmony_ci    auto& run = this->fRuns[0];
1146cb93a386Sopenharmony_ci    auto advance = run.advance();
1147cb93a386Sopenharmony_ci    auto textRange = TextRange(0, this->text().size());
1148cb93a386Sopenharmony_ci    auto textExcludingSpaces = TextRange(0, fTrailingSpaces);
1149cb93a386Sopenharmony_ci    InternalLineMetrics metrics(this->strutForceHeight());
1150cb93a386Sopenharmony_ci    metrics.add(&run);
1151cb93a386Sopenharmony_ci    auto disableFirstAscent = this->paragraphStyle().getTextHeightBehavior() &
1152cb93a386Sopenharmony_ci                              TextHeightBehavior::kDisableFirstAscent;
1153cb93a386Sopenharmony_ci    auto disableLastDescent = this->paragraphStyle().getTextHeightBehavior() &
1154cb93a386Sopenharmony_ci                              TextHeightBehavior::kDisableLastDescent;
1155cb93a386Sopenharmony_ci    if (disableFirstAscent) {
1156cb93a386Sopenharmony_ci        metrics.fAscent = metrics.fRawAscent;
1157cb93a386Sopenharmony_ci    }
1158cb93a386Sopenharmony_ci    if (disableLastDescent) {
1159cb93a386Sopenharmony_ci        metrics.fDescent = metrics.fRawDescent;
1160cb93a386Sopenharmony_ci    }
1161cb93a386Sopenharmony_ci    if (this->strutEnabled()) {
1162cb93a386Sopenharmony_ci        this->strutMetrics().updateLineMetrics(metrics);
1163cb93a386Sopenharmony_ci    }
1164cb93a386Sopenharmony_ci    ClusterIndex trailingSpaces = fClusters.size();
1165cb93a386Sopenharmony_ci    do {
1166cb93a386Sopenharmony_ci        --trailingSpaces;
1167cb93a386Sopenharmony_ci        auto& cluster = fClusters[trailingSpaces];
1168cb93a386Sopenharmony_ci        if (!cluster.isWhitespaceBreak()) {
1169cb93a386Sopenharmony_ci            ++trailingSpaces;
1170cb93a386Sopenharmony_ci            break;
1171cb93a386Sopenharmony_ci        }
1172cb93a386Sopenharmony_ci        advance.fX -= cluster.width();
1173cb93a386Sopenharmony_ci    } while (trailingSpaces != 0);
1174cb93a386Sopenharmony_ci
1175cb93a386Sopenharmony_ci    advance.fY = metrics.height();
1176cb93a386Sopenharmony_ci    auto clusterRange = ClusterRange(0, trailingSpaces);
1177cb93a386Sopenharmony_ci    auto clusterRangeWithGhosts = ClusterRange(0, this->clusters().size() - 1);
1178cb93a386Sopenharmony_ci    SkScalar offsetX = this->detectIndents(0);
1179cb93a386Sopenharmony_ci    auto &line = this->addLine(SkPoint::Make(offsetX, 0), advance,
1180cb93a386Sopenharmony_ci        textExcludingSpaces, textRange, textRange,
1181cb93a386Sopenharmony_ci        clusterRange, clusterRangeWithGhosts, run.advance().x(),
1182cb93a386Sopenharmony_ci        metrics);
1183cb93a386Sopenharmony_ci    auto spacing = line.autoSpacing();
1184cb93a386Sopenharmony_ci    auto longestLine = std::max(run.advance().fX, advance.fX) + spacing;
1185cb93a386Sopenharmony_ci    setSize(advance.fY, maxWidth, longestLine);
1186cb93a386Sopenharmony_ci    setLongestLineWithIndent(longestLine + offsetX);
1187cb93a386Sopenharmony_ci    setIntrinsicSize(run.advance().fX, advance.fX,
1188cb93a386Sopenharmony_ci        fLines.empty() ? fEmptyMetrics.alphabeticBaseline() : fLines.front().alphabeticBaseline(),
1189cb93a386Sopenharmony_ci        fLines.empty() ? fEmptyMetrics.ideographicBaseline() : fLines.front().ideographicBaseline(),
1190cb93a386Sopenharmony_ci        false);
1191cb93a386Sopenharmony_ci}
1192cb93a386Sopenharmony_ci
1193cb93a386Sopenharmony_civoid ParagraphImpl::breakShapedTextIntoLines(SkScalar maxWidth) {
1194cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1195cb93a386Sopenharmony_ci    TEXT_TRACE_FUNC();
1196cb93a386Sopenharmony_ci#endif
1197cb93a386Sopenharmony_ci    resetAutoSpacing();
1198cb93a386Sopenharmony_ci    TextWrapper textWrapper;
1199cb93a386Sopenharmony_ci    textWrapper.breakTextIntoLines(
1200cb93a386Sopenharmony_ci            this,
1201cb93a386Sopenharmony_ci            maxWidth,
1202cb93a386Sopenharmony_ci            [&](TextRange textExcludingSpaces,
1203cb93a386Sopenharmony_ci                TextRange text,
1204cb93a386Sopenharmony_ci                TextRange textWithNewlines,
1205cb93a386Sopenharmony_ci                ClusterRange clusters,
1206cb93a386Sopenharmony_ci                ClusterRange clustersWithGhosts,
1207cb93a386Sopenharmony_ci                SkScalar widthWithSpaces,
1208cb93a386Sopenharmony_ci                size_t startPos,
1209cb93a386Sopenharmony_ci                size_t endPos,
1210cb93a386Sopenharmony_ci                SkVector offset,
1211cb93a386Sopenharmony_ci                SkVector advance,
1212cb93a386Sopenharmony_ci                InternalLineMetrics metrics,
1213cb93a386Sopenharmony_ci                bool addEllipsis,
1214cb93a386Sopenharmony_ci                SkScalar indent,
1215cb93a386Sopenharmony_ci                SkScalar noIndentWidth) {
1216cb93a386Sopenharmony_ci                // TODO: Take in account clipped edges
1217cb93a386Sopenharmony_ci                auto& line = this->addLine(offset, advance, textExcludingSpaces, text, textWithNewlines, clusters, clustersWithGhosts, widthWithSpaces, metrics);
1218cb93a386Sopenharmony_ci                if (addEllipsis && this->paragraphStyle().getEllipsisMod() == EllipsisModal::TAIL) {
1219cb93a386Sopenharmony_ci                    line.createTailEllipsis(noIndentWidth, this->getEllipsis(), true, this->getWordBreakType());
1220cb93a386Sopenharmony_ci                } else if (addEllipsis && this->paragraphStyle().getEllipsisMod() == EllipsisModal::HEAD) {
1221cb93a386Sopenharmony_ci                    line.createHeadEllipsis(noIndentWidth, this->getEllipsis(), true);
1222cb93a386Sopenharmony_ci                }
1223cb93a386Sopenharmony_ci                auto spacing = line.autoSpacing();
1224cb93a386Sopenharmony_ci                auto longestLine = std::max(line.width(), line.widthWithEllipsisSpaces()) + spacing;
1225cb93a386Sopenharmony_ci                fLongestLine = std::max(fLongestLine, longestLine);
1226cb93a386Sopenharmony_ci                fLongestLineWithIndent = std::max(fLongestLineWithIndent, longestLine + indent);
1227cb93a386Sopenharmony_ci            });
1228cb93a386Sopenharmony_ci    setSize(textWrapper.height(), maxWidth, fLongestLine);
1229cb93a386Sopenharmony_ci    setIntrinsicSize(textWrapper.maxIntrinsicWidth(), textWrapper.minIntrinsicWidth(),
1230cb93a386Sopenharmony_ci        fLines.empty() ? fEmptyMetrics.alphabeticBaseline() : fLines.front().alphabeticBaseline(),
1231cb93a386Sopenharmony_ci        fLines.empty() ? fEmptyMetrics.ideographicBaseline() : fLines.front().ideographicBaseline(),
1232cb93a386Sopenharmony_ci        textWrapper.exceededMaxLines());
1233cb93a386Sopenharmony_ci}
1234cb93a386Sopenharmony_ci#else
1235cb93a386Sopenharmony_civoid ParagraphImpl::breakShapedTextIntoLines(SkScalar maxWidth) {
1236cb93a386Sopenharmony_ci
1237cb93a386Sopenharmony_ci    if (!fHasLineBreaks &&
1238cb93a386Sopenharmony_ci        !fHasWhitespacesInside &&
1239cb93a386Sopenharmony_ci        fPlaceholders.size() == 1 &&
1240cb93a386Sopenharmony_ci        fRuns.size() == 1 && fRuns[0].fAdvance.fX <= maxWidth) {
1241cb93a386Sopenharmony_ci        // This is a short version of a line breaking when we know that:
1242cb93a386Sopenharmony_ci        // 1. We have only one line of text
1243cb93a386Sopenharmony_ci        // 2. It's shaped into a single run
1244cb93a386Sopenharmony_ci        // 3. There are no placeholders
1245cb93a386Sopenharmony_ci        // 4. There are no linebreaks (which will format text into multiple lines)
1246cb93a386Sopenharmony_ci        // 5. There are no whitespaces so the minIntrinsicWidth=maxIntrinsicWidth
1247cb93a386Sopenharmony_ci        // (To think about that, the last condition is not quite right;
1248cb93a386Sopenharmony_ci        // we should calculate minIntrinsicWidth by soft line breaks.
1249cb93a386Sopenharmony_ci        // However, it's how it's done in Flutter now)
1250cb93a386Sopenharmony_ci        auto& run = this->fRuns[0];
1251cb93a386Sopenharmony_ci        auto advance = run.advance();
1252cb93a386Sopenharmony_ci        auto textRange = TextRange(0, this->text().size());
1253cb93a386Sopenharmony_ci        auto textExcludingSpaces = TextRange(0, fTrailingSpaces);
1254cb93a386Sopenharmony_ci        InternalLineMetrics metrics(this->strutForceHeight());
1255cb93a386Sopenharmony_ci        metrics.add(&run);
1256cb93a386Sopenharmony_ci        auto disableFirstAscent = this->paragraphStyle().getTextHeightBehavior() &
1257cb93a386Sopenharmony_ci                                  TextHeightBehavior::kDisableFirstAscent;
1258cb93a386Sopenharmony_ci        auto disableLastDescent = this->paragraphStyle().getTextHeightBehavior() &
1259cb93a386Sopenharmony_ci                                  TextHeightBehavior::kDisableLastDescent;
1260cb93a386Sopenharmony_ci        if (disableFirstAscent) {
1261cb93a386Sopenharmony_ci            metrics.fAscent = metrics.fRawAscent;
1262cb93a386Sopenharmony_ci        }
1263cb93a386Sopenharmony_ci        if (disableLastDescent) {
1264cb93a386Sopenharmony_ci            metrics.fDescent = metrics.fRawDescent;
1265cb93a386Sopenharmony_ci        }
1266cb93a386Sopenharmony_ci        if (this->strutEnabled()) {
1267cb93a386Sopenharmony_ci            this->strutMetrics().updateLineMetrics(metrics);
1268cb93a386Sopenharmony_ci        }
1269cb93a386Sopenharmony_ci        ClusterIndex trailingSpaces = fClusters.size();
1270cb93a386Sopenharmony_ci        do {
1271cb93a386Sopenharmony_ci            --trailingSpaces;
1272cb93a386Sopenharmony_ci            auto& cluster = fClusters[trailingSpaces];
1273cb93a386Sopenharmony_ci            if (!cluster.isWhitespaceBreak()) {
1274cb93a386Sopenharmony_ci                ++trailingSpaces;
1275cb93a386Sopenharmony_ci                break;
1276cb93a386Sopenharmony_ci            }
1277cb93a386Sopenharmony_ci            advance.fX -= cluster.width();
1278cb93a386Sopenharmony_ci        } while (trailingSpaces != 0);
1279cb93a386Sopenharmony_ci
1280cb93a386Sopenharmony_ci        advance.fY = metrics.height();
1281cb93a386Sopenharmony_ci        auto clusterRange = ClusterRange(0, trailingSpaces);
1282cb93a386Sopenharmony_ci        auto clusterRangeWithGhosts = ClusterRange(0, this->clusters().size() - 1);
1283cb93a386Sopenharmony_ci        this->addLine(SkPoint::Make(0, 0), advance,
1284cb93a386Sopenharmony_ci                      textExcludingSpaces, textRange, textRange,
1285cb93a386Sopenharmony_ci                      clusterRange, clusterRangeWithGhosts, run.advance().x(),
1286cb93a386Sopenharmony_ci                      metrics);
1287cb93a386Sopenharmony_ci
1288cb93a386Sopenharmony_ci        fLongestLine = nearlyZero(advance.fX) ? run.advance().fX : advance.fX;
1289cb93a386Sopenharmony_ci        fHeight = advance.fY;
1290cb93a386Sopenharmony_ci        fWidth = maxWidth;
1291cb93a386Sopenharmony_ci        fMaxIntrinsicWidth = run.advance().fX;
1292cb93a386Sopenharmony_ci        fMinIntrinsicWidth = advance.fX;
1293cb93a386Sopenharmony_ci        fAlphabeticBaseline = fLines.empty() ? fEmptyMetrics.alphabeticBaseline() : fLines.front().alphabeticBaseline();
1294cb93a386Sopenharmony_ci        fIdeographicBaseline = fLines.empty() ? fEmptyMetrics.ideographicBaseline() : fLines.front().ideographicBaseline();
1295cb93a386Sopenharmony_ci        fExceededMaxLines = false;
1296cb93a386Sopenharmony_ci        return;
1297cb93a386Sopenharmony_ci    }
1298cb93a386Sopenharmony_ci
1299cb93a386Sopenharmony_ci    TextWrapper textWrapper;
1300cb93a386Sopenharmony_ci    textWrapper.breakTextIntoLines(
1301cb93a386Sopenharmony_ci            this,
1302cb93a386Sopenharmony_ci            maxWidth,
1303cb93a386Sopenharmony_ci            [&](TextRange textExcludingSpaces,
1304cb93a386Sopenharmony_ci                TextRange text,
1305cb93a386Sopenharmony_ci                TextRange textWithNewlines,
1306cb93a386Sopenharmony_ci                ClusterRange clusters,
1307cb93a386Sopenharmony_ci                ClusterRange clustersWithGhosts,
1308cb93a386Sopenharmony_ci                SkScalar widthWithSpaces,
1309cb93a386Sopenharmony_ci                size_t startPos,
1310cb93a386Sopenharmony_ci                size_t endPos,
1311cb93a386Sopenharmony_ci                SkVector offset,
1312cb93a386Sopenharmony_ci                SkVector advance,
1313cb93a386Sopenharmony_ci                InternalLineMetrics metrics,
1314cb93a386Sopenharmony_ci                bool addEllipsis) {
1315cb93a386Sopenharmony_ci                // TODO: Take in account clipped edges
1316cb93a386Sopenharmony_ci                auto& line = this->addLine(offset, advance, textExcludingSpaces, text, textWithNewlines, clusters, clustersWithGhosts, widthWithSpaces, metrics);
1317cb93a386Sopenharmony_ci                if (addEllipsis) {
1318cb93a386Sopenharmony_ci                    line.createEllipsis(maxWidth, this->getEllipsis(), true);
1319cb93a386Sopenharmony_ci                }
1320cb93a386Sopenharmony_ci                fLongestLine = std::max(fLongestLine, nearlyZero(advance.fX) ? widthWithSpaces : advance.fX);
1321cb93a386Sopenharmony_ci            });
1322cb93a386Sopenharmony_ci
1323cb93a386Sopenharmony_ci    fHeight = textWrapper.height();
1324cb93a386Sopenharmony_ci    fWidth = maxWidth;
1325cb93a386Sopenharmony_ci    fMaxIntrinsicWidth = textWrapper.maxIntrinsicWidth();
1326cb93a386Sopenharmony_ci    fMinIntrinsicWidth = textWrapper.minIntrinsicWidth();
1327cb93a386Sopenharmony_ci    fAlphabeticBaseline = fLines.empty() ? fEmptyMetrics.alphabeticBaseline() : fLines.front().alphabeticBaseline();
1328cb93a386Sopenharmony_ci    fIdeographicBaseline = fLines.empty() ? fEmptyMetrics.ideographicBaseline() : fLines.front().ideographicBaseline();
1329cb93a386Sopenharmony_ci    fExceededMaxLines = textWrapper.exceededMaxLines();
1330cb93a386Sopenharmony_ci}
1331cb93a386Sopenharmony_ci#endif
1332cb93a386Sopenharmony_ci
1333cb93a386Sopenharmony_civoid ParagraphImpl::formatLines(SkScalar maxWidth) {
1334cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1335cb93a386Sopenharmony_ci    TEXT_TRACE_FUNC();
1336cb93a386Sopenharmony_ci#endif
1337cb93a386Sopenharmony_ci    auto effectiveAlign = fParagraphStyle.effective_align();
1338cb93a386Sopenharmony_ci    const bool isLeftAligned = effectiveAlign == TextAlign::kLeft
1339cb93a386Sopenharmony_ci        || (effectiveAlign == TextAlign::kJustify && fParagraphStyle.getTextDirection() == TextDirection::kLtr);
1340cb93a386Sopenharmony_ci
1341cb93a386Sopenharmony_ci    if (!SkScalarIsFinite(maxWidth) && !isLeftAligned) {
1342cb93a386Sopenharmony_ci        // Special case: clean all text in case of maxWidth == INF & align != left
1343cb93a386Sopenharmony_ci        // We had to go through shaping though because we need all the measurement numbers
1344cb93a386Sopenharmony_ci        fLines.reset();
1345cb93a386Sopenharmony_ci        return;
1346cb93a386Sopenharmony_ci    }
1347cb93a386Sopenharmony_ci
1348cb93a386Sopenharmony_ci    size_t iLineNumber = 0;
1349cb93a386Sopenharmony_ci    for (auto& line : fLines) {
1350cb93a386Sopenharmony_ci        SkScalar noIndentWidth = maxWidth - detectIndents(iLineNumber++);
1351cb93a386Sopenharmony_ci        if (fParagraphStyle.getTextDirection() == TextDirection::kRtl) {
1352cb93a386Sopenharmony_ci            line.setLineOffsetX(0);
1353cb93a386Sopenharmony_ci        }
1354cb93a386Sopenharmony_ci        line.format(effectiveAlign, noIndentWidth, this->paragraphStyle().getEllipsisMod());
1355cb93a386Sopenharmony_ci    }
1356cb93a386Sopenharmony_ci}
1357cb93a386Sopenharmony_ci
1358cb93a386Sopenharmony_civoid ParagraphImpl::resolveStrut() {
1359cb93a386Sopenharmony_ci    auto strutStyle = this->paragraphStyle().getStrutStyle();
1360cb93a386Sopenharmony_ci    if (!strutStyle.getStrutEnabled() || strutStyle.getFontSize() < 0) {
1361cb93a386Sopenharmony_ci        return;
1362cb93a386Sopenharmony_ci    }
1363cb93a386Sopenharmony_ci
1364cb93a386Sopenharmony_ci    auto typefaces = fFontCollection->findTypefaces(strutStyle.getFontFamilies(), strutStyle.getFontStyle(), std::nullopt);
1365cb93a386Sopenharmony_ci    if (typefaces.empty()) {
1366cb93a386Sopenharmony_ci        SkDEBUGF("Could not resolve strut font\n");
1367cb93a386Sopenharmony_ci        return;
1368cb93a386Sopenharmony_ci    }
1369cb93a386Sopenharmony_ci
1370cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
1371cb93a386Sopenharmony_ci    SkFont font(typefaces.front(), strutStyle.getFontSize());
1372cb93a386Sopenharmony_ci    SkFontMetrics metrics;
1373cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1374cb93a386Sopenharmony_ci    SkFont compressFont = font;
1375cb93a386Sopenharmony_ci    scaleFontWithCompressionConfig(compressFont, ScaleOP::COMPRESS);
1376cb93a386Sopenharmony_ci    compressFont.getMetrics(&metrics);
1377cb93a386Sopenharmony_ci    metricsIncludeFontPadding(&metrics, font);
1378cb93a386Sopenharmony_ci#else
1379cb93a386Sopenharmony_ci    font.getMetrics(&metrics);
1380cb93a386Sopenharmony_ci#endif
1381cb93a386Sopenharmony_ci#else
1382cb93a386Sopenharmony_ci    RSFont font(typefaces.front(), strutStyle.getFontSize(), 1, 0);
1383cb93a386Sopenharmony_ci    RSFontMetrics metrics;
1384cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1385cb93a386Sopenharmony_ci    RSFont compressFont = font;
1386cb93a386Sopenharmony_ci    scaleFontWithCompressionConfig(compressFont, ScaleOP::COMPRESS);
1387cb93a386Sopenharmony_ci    compressFont.GetMetrics(&metrics);
1388cb93a386Sopenharmony_ci    metricsIncludeFontPadding(&metrics, font);
1389cb93a386Sopenharmony_ci#else
1390cb93a386Sopenharmony_ci    font.GetMetrics(&metrics);
1391cb93a386Sopenharmony_ci#endif
1392cb93a386Sopenharmony_ci#endif
1393cb93a386Sopenharmony_ci
1394cb93a386Sopenharmony_ci    if (strutStyle.getHeightOverride()) {
1395cb93a386Sopenharmony_ci        auto strutHeight = metrics.fDescent - metrics.fAscent;
1396cb93a386Sopenharmony_ci        auto strutMultiplier = strutStyle.getHeight() * strutStyle.getFontSize();
1397cb93a386Sopenharmony_ci        fStrutMetrics = InternalLineMetrics(
1398cb93a386Sopenharmony_ci            (metrics.fAscent / strutHeight) * strutMultiplier,
1399cb93a386Sopenharmony_ci            (metrics.fDescent / strutHeight) * strutMultiplier,
1400cb93a386Sopenharmony_ci                strutStyle.getLeading() < 0 ? 0 : strutStyle.getLeading() * strutStyle.getFontSize(),
1401cb93a386Sopenharmony_ci            metrics.fAscent, metrics.fDescent, metrics.fLeading);
1402cb93a386Sopenharmony_ci    } else {
1403cb93a386Sopenharmony_ci        fStrutMetrics = InternalLineMetrics(
1404cb93a386Sopenharmony_ci                metrics.fAscent,
1405cb93a386Sopenharmony_ci                metrics.fDescent,
1406cb93a386Sopenharmony_ci                strutStyle.getLeading() < 0 ? 0 : strutStyle.getLeading() * strutStyle.getFontSize());
1407cb93a386Sopenharmony_ci    }
1408cb93a386Sopenharmony_ci    fStrutMetrics.setForceStrut(this->paragraphStyle().getStrutStyle().getForceStrutHeight());
1409cb93a386Sopenharmony_ci}
1410cb93a386Sopenharmony_ci
1411cb93a386Sopenharmony_ciBlockRange ParagraphImpl::findAllBlocks(TextRange textRange) {
1412cb93a386Sopenharmony_ci    BlockIndex begin = EMPTY_BLOCK;
1413cb93a386Sopenharmony_ci    BlockIndex end = EMPTY_BLOCK;
1414cb93a386Sopenharmony_ci    for (int index = 0; index < fTextStyles.size(); ++index) {
1415cb93a386Sopenharmony_ci        auto& block = fTextStyles[index];
1416cb93a386Sopenharmony_ci        if (block.fRange.end <= textRange.start) {
1417cb93a386Sopenharmony_ci            continue;
1418cb93a386Sopenharmony_ci        }
1419cb93a386Sopenharmony_ci        if (block.fRange.start >= textRange.end) {
1420cb93a386Sopenharmony_ci            break;
1421cb93a386Sopenharmony_ci        }
1422cb93a386Sopenharmony_ci        if (begin == EMPTY_BLOCK) {
1423cb93a386Sopenharmony_ci            begin = index;
1424cb93a386Sopenharmony_ci        }
1425cb93a386Sopenharmony_ci        end = index;
1426cb93a386Sopenharmony_ci    }
1427cb93a386Sopenharmony_ci
1428cb93a386Sopenharmony_ci    if (begin == EMPTY_INDEX || end == EMPTY_INDEX) {
1429cb93a386Sopenharmony_ci        // It's possible if some text is not covered with any text style
1430cb93a386Sopenharmony_ci        // Not in Flutter but in direct use of SkParagraph
1431cb93a386Sopenharmony_ci        return EMPTY_RANGE;
1432cb93a386Sopenharmony_ci    }
1433cb93a386Sopenharmony_ci
1434cb93a386Sopenharmony_ci    return { begin, end + 1 };
1435cb93a386Sopenharmony_ci}
1436cb93a386Sopenharmony_ci
1437cb93a386Sopenharmony_ciTextLine& ParagraphImpl::addLine(SkVector offset,
1438cb93a386Sopenharmony_ci                                 SkVector advance,
1439cb93a386Sopenharmony_ci                                 TextRange textExcludingSpaces,
1440cb93a386Sopenharmony_ci                                 TextRange text,
1441cb93a386Sopenharmony_ci                                 TextRange textIncludingNewLines,
1442cb93a386Sopenharmony_ci                                 ClusterRange clusters,
1443cb93a386Sopenharmony_ci                                 ClusterRange clustersWithGhosts,
1444cb93a386Sopenharmony_ci                                 SkScalar widthWithSpaces,
1445cb93a386Sopenharmony_ci                                 InternalLineMetrics sizes) {
1446cb93a386Sopenharmony_ci    // Define a list of styles that covers the line
1447cb93a386Sopenharmony_ci    auto blocks = findAllBlocks(textIncludingNewLines);
1448cb93a386Sopenharmony_ci    return fLines.emplace_back(this, offset, advance, blocks,
1449cb93a386Sopenharmony_ci                               textExcludingSpaces, text, textIncludingNewLines,
1450cb93a386Sopenharmony_ci                               clusters, clustersWithGhosts, widthWithSpaces, sizes);
1451cb93a386Sopenharmony_ci}
1452cb93a386Sopenharmony_ci
1453cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1454cb93a386Sopenharmony_ciTextBox ParagraphImpl::getEmptyTextRect(RectHeightStyle rectHeightStyle) const
1455cb93a386Sopenharmony_ci{
1456cb93a386Sopenharmony_ci    // get textStyle to calculate text box when text is empty(reference to ParagraphImpl::computeEmptyMetrics())
1457cb93a386Sopenharmony_ci    bool emptyParagraph = fRuns.empty();
1458cb93a386Sopenharmony_ci    TextStyle textStyle = paragraphStyle().getTextStyle();
1459cb93a386Sopenharmony_ci    if (emptyParagraph && !fTextStyles.empty()) {
1460cb93a386Sopenharmony_ci        textStyle = fTextStyles.back().fStyle;
1461cb93a386Sopenharmony_ci    }
1462cb93a386Sopenharmony_ci
1463cb93a386Sopenharmony_ci    // calculate text box(reference to TextLine::getRectsForRange(), switch(rectHeightStyle))
1464cb93a386Sopenharmony_ci    TextBox box(SkRect::MakeXYWH(0, 0, 0, fHeight), fParagraphStyle.getTextDirection());
1465cb93a386Sopenharmony_ci    auto verticalShift = fEmptyMetrics.rawAscent() - fEmptyMetrics.ascent();
1466cb93a386Sopenharmony_ci    switch (rectHeightStyle) {
1467cb93a386Sopenharmony_ci        case RectHeightStyle::kTight:
1468cb93a386Sopenharmony_ci            if (textStyle.getHeightOverride() && textStyle.getHeight() > 0) {
1469cb93a386Sopenharmony_ci                const auto effectiveBaseline = fEmptyMetrics.baseline() + fEmptyMetrics.delta();
1470cb93a386Sopenharmony_ci                box.rect.fTop = effectiveBaseline + fEmptyMetrics.rawAscent();
1471cb93a386Sopenharmony_ci                box.rect.fBottom = effectiveBaseline + fEmptyMetrics.rawDescent();
1472cb93a386Sopenharmony_ci            }
1473cb93a386Sopenharmony_ci            return box;
1474cb93a386Sopenharmony_ci        case RectHeightStyle::kMax:
1475cb93a386Sopenharmony_ci            box.rect.fBottom = fHeight;
1476cb93a386Sopenharmony_ci            box.rect.fTop = fEmptyMetrics.delta();
1477cb93a386Sopenharmony_ci            return box;
1478cb93a386Sopenharmony_ci        case RectHeightStyle::kIncludeLineSpacingMiddle:
1479cb93a386Sopenharmony_ci        case RectHeightStyle::kIncludeLineSpacingTop:
1480cb93a386Sopenharmony_ci        case RectHeightStyle::kIncludeLineSpacingBottom:
1481cb93a386Sopenharmony_ci            box.rect.fBottom = fHeight;
1482cb93a386Sopenharmony_ci            box.rect.fTop = fEmptyMetrics.delta() + verticalShift;
1483cb93a386Sopenharmony_ci            return box;
1484cb93a386Sopenharmony_ci        case RectHeightStyle::kStrut:
1485cb93a386Sopenharmony_ci            if (fParagraphStyle.getStrutStyle().getStrutEnabled() &&
1486cb93a386Sopenharmony_ci                fParagraphStyle.getStrutStyle().getFontSize() > 0) {
1487cb93a386Sopenharmony_ci                auto baseline = fEmptyMetrics.baseline();
1488cb93a386Sopenharmony_ci                box.rect.fTop = baseline + fStrutMetrics.ascent();
1489cb93a386Sopenharmony_ci                box.rect.fBottom = baseline + fStrutMetrics.descent();
1490cb93a386Sopenharmony_ci            }
1491cb93a386Sopenharmony_ci            return box;
1492cb93a386Sopenharmony_ci        default:
1493cb93a386Sopenharmony_ci            return box;
1494cb93a386Sopenharmony_ci    }
1495cb93a386Sopenharmony_ci}
1496cb93a386Sopenharmony_ci#endif
1497cb93a386Sopenharmony_ci
1498cb93a386Sopenharmony_ci// Returns a vector of bounding boxes that enclose all text between
1499cb93a386Sopenharmony_ci// start and end glyph indexes, including start and excluding end
1500cb93a386Sopenharmony_cistd::vector<TextBox> ParagraphImpl::getRectsForRange(unsigned start,
1501cb93a386Sopenharmony_ci                                                     unsigned end,
1502cb93a386Sopenharmony_ci                                                     RectHeightStyle rectHeightStyle,
1503cb93a386Sopenharmony_ci                                                     RectWidthStyle rectWidthStyle) {
1504cb93a386Sopenharmony_ci    std::vector<TextBox> results;
1505cb93a386Sopenharmony_ci    // this method should not be called before kshaped
1506cb93a386Sopenharmony_ci    if (fText.isEmpty() || fState < kShaped) {
1507cb93a386Sopenharmony_ci        if (start == 0 && end > 0) {
1508cb93a386Sopenharmony_ci            // On account of implied "\n" that is always at the end of the text
1509cb93a386Sopenharmony_ci            //SkDebugf("getRectsForRange(%d, %d): %f\n", start, end, fHeight);
1510cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1511cb93a386Sopenharmony_ci            results.emplace_back(getEmptyTextRect(rectHeightStyle));
1512cb93a386Sopenharmony_ci#else
1513cb93a386Sopenharmony_ci            results.emplace_back(SkRect::MakeXYWH(0, 0, 0, fHeight), fParagraphStyle.getTextDirection());
1514cb93a386Sopenharmony_ci#endif
1515cb93a386Sopenharmony_ci        }
1516cb93a386Sopenharmony_ci        return results;
1517cb93a386Sopenharmony_ci    }
1518cb93a386Sopenharmony_ci
1519cb93a386Sopenharmony_ci    this->ensureUTF16Mapping();
1520cb93a386Sopenharmony_ci
1521cb93a386Sopenharmony_ci    if (start >= end || start > SkToSizeT(fUTF8IndexForUTF16Index.size()) || end == 0) {
1522cb93a386Sopenharmony_ci        return results;
1523cb93a386Sopenharmony_ci    }
1524cb93a386Sopenharmony_ci
1525cb93a386Sopenharmony_ci    // Adjust the text to grapheme edges
1526cb93a386Sopenharmony_ci    // Apparently, text editor CAN move inside graphemes but CANNOT select a part of it.
1527cb93a386Sopenharmony_ci    // I don't know why - the solution I have here returns an empty box for every query that
1528cb93a386Sopenharmony_ci    // does not contain an end of a grapheme.
1529cb93a386Sopenharmony_ci    // Once a cursor is inside a complex grapheme I can press backspace and cause trouble.
1530cb93a386Sopenharmony_ci    // To avoid any problems, I will not allow any selection of a part of a grapheme.
1531cb93a386Sopenharmony_ci    // One flutter test fails because of it but the editing experience is correct
1532cb93a386Sopenharmony_ci    // (although you have to press the cursor many times before it moves to the next grapheme).
1533cb93a386Sopenharmony_ci    TextRange text(fText.size(), fText.size());
1534cb93a386Sopenharmony_ci    // TODO: This is probably a temp change that makes SkParagraph work as TxtLib
1535cb93a386Sopenharmony_ci    //  (so we can compare the results). We now include in the selection box only the graphemes
1536cb93a386Sopenharmony_ci    //  that belongs to the given [start:end) range entirely (not the ones that intersect with it)
1537cb93a386Sopenharmony_ci    if (start < SkToSizeT(fUTF8IndexForUTF16Index.size())) {
1538cb93a386Sopenharmony_ci        auto utf8 = fUTF8IndexForUTF16Index[start];
1539cb93a386Sopenharmony_ci        // If start points to a trailing surrogate, skip it
1540cb93a386Sopenharmony_ci        if (start > 0 && fUTF8IndexForUTF16Index[start - 1] == utf8) {
1541cb93a386Sopenharmony_ci            utf8 = fUTF8IndexForUTF16Index[start + 1];
1542cb93a386Sopenharmony_ci        }
1543cb93a386Sopenharmony_ci        text.start = this->findNextGraphemeBoundary(utf8);
1544cb93a386Sopenharmony_ci    }
1545cb93a386Sopenharmony_ci    if (end < SkToSizeT(fUTF8IndexForUTF16Index.size())) {
1546cb93a386Sopenharmony_ci        auto utf8 = this->findPreviousGraphemeBoundary(fUTF8IndexForUTF16Index[end]);
1547cb93a386Sopenharmony_ci        text.end = utf8;
1548cb93a386Sopenharmony_ci    }
1549cb93a386Sopenharmony_ci    //SkDebugf("getRectsForRange(%d,%d) -> (%d:%d)\n", start, end, text.start, text.end);
1550cb93a386Sopenharmony_ci    for (auto& line : fLines) {
1551cb93a386Sopenharmony_ci        auto lineText = line.textWithNewlines();
1552cb93a386Sopenharmony_ci        lineText = textRangeMergeBtoA(lineText, line.getTextRangeReplacedByEllipsis());
1553cb93a386Sopenharmony_ci        auto intersect = lineText * text;
1554cb93a386Sopenharmony_ci        if (intersect.empty() && lineText.start != text.start) {
1555cb93a386Sopenharmony_ci            continue;
1556cb93a386Sopenharmony_ci        }
1557cb93a386Sopenharmony_ci
1558cb93a386Sopenharmony_ci        line.getRectsForRange(intersect, rectHeightStyle, rectWidthStyle, results);
1559cb93a386Sopenharmony_ci    }
1560cb93a386Sopenharmony_ci/*
1561cb93a386Sopenharmony_ci    SkDebugf("getRectsForRange(%d, %d)\n", start, end);
1562cb93a386Sopenharmony_ci    for (auto& r : results) {
1563cb93a386Sopenharmony_ci        r.rect.fLeft = littleRound(r.rect.fLeft);
1564cb93a386Sopenharmony_ci        r.rect.fRight = littleRound(r.rect.fRight);
1565cb93a386Sopenharmony_ci        r.rect.fTop = littleRound(r.rect.fTop);
1566cb93a386Sopenharmony_ci        r.rect.fBottom = littleRound(r.rect.fBottom);
1567cb93a386Sopenharmony_ci        SkDebugf("[%f:%f * %f:%f]\n", r.rect.fLeft, r.rect.fRight, r.rect.fTop, r.rect.fBottom);
1568cb93a386Sopenharmony_ci    }
1569cb93a386Sopenharmony_ci*/
1570cb93a386Sopenharmony_ci    return results;
1571cb93a386Sopenharmony_ci}
1572cb93a386Sopenharmony_ci
1573cb93a386Sopenharmony_cistd::vector<TextBox> ParagraphImpl::getRectsForPlaceholders() {
1574cb93a386Sopenharmony_ci  std::vector<TextBox> boxes;
1575cb93a386Sopenharmony_ci  // this method should not be called before kshaped
1576cb93a386Sopenharmony_ci  if (fText.isEmpty() || fState < kShaped) {
1577cb93a386Sopenharmony_ci       return boxes;
1578cb93a386Sopenharmony_ci  }
1579cb93a386Sopenharmony_ci  if (fPlaceholders.size() == 1) {
1580cb93a386Sopenharmony_ci       // We always have one fake placeholder
1581cb93a386Sopenharmony_ci       return boxes;
1582cb93a386Sopenharmony_ci  }
1583cb93a386Sopenharmony_ci  for (auto& line : fLines) {
1584cb93a386Sopenharmony_ci      line.getRectsForPlaceholders(boxes);
1585cb93a386Sopenharmony_ci  }
1586cb93a386Sopenharmony_ci  /*
1587cb93a386Sopenharmony_ci  SkDebugf("getRectsForPlaceholders('%s'): %d\n", fText.c_str(), boxes.size());
1588cb93a386Sopenharmony_ci  for (auto& r : boxes) {
1589cb93a386Sopenharmony_ci      r.rect.fLeft = littleRound(r.rect.fLeft);
1590cb93a386Sopenharmony_ci      r.rect.fRight = littleRound(r.rect.fRight);
1591cb93a386Sopenharmony_ci      r.rect.fTop = littleRound(r.rect.fTop);
1592cb93a386Sopenharmony_ci      r.rect.fBottom = littleRound(r.rect.fBottom);
1593cb93a386Sopenharmony_ci      SkDebugf("[%f:%f * %f:%f] %s\n", r.rect.fLeft, r.rect.fRight, r.rect.fTop, r.rect.fBottom,
1594cb93a386Sopenharmony_ci               (r.direction == TextDirection::kLtr ? "left" : "right"));
1595cb93a386Sopenharmony_ci  }
1596cb93a386Sopenharmony_ci  */
1597cb93a386Sopenharmony_ci  return boxes;
1598cb93a386Sopenharmony_ci}
1599cb93a386Sopenharmony_ci
1600cb93a386Sopenharmony_ci// TODO: Optimize (save cluster <-> codepoint connection)
1601cb93a386Sopenharmony_ciPositionWithAffinity ParagraphImpl::getGlyphPositionAtCoordinate(SkScalar dx, SkScalar dy) {
1602cb93a386Sopenharmony_ci
1603cb93a386Sopenharmony_ci    if (fText.isEmpty()) {
1604cb93a386Sopenharmony_ci        return {0, Affinity::kDownstream};
1605cb93a386Sopenharmony_ci    }
1606cb93a386Sopenharmony_ci
1607cb93a386Sopenharmony_ci    this->ensureUTF16Mapping();
1608cb93a386Sopenharmony_ci
1609cb93a386Sopenharmony_ci    for (auto& line : fLines) {
1610cb93a386Sopenharmony_ci        // Let's figure out if we can stop looking
1611cb93a386Sopenharmony_ci        auto offsetY = line.offset().fY;
1612cb93a386Sopenharmony_ci        if (dy >= offsetY + line.height() && &line != &fLines.back()) {
1613cb93a386Sopenharmony_ci            // This line is not good enough
1614cb93a386Sopenharmony_ci            continue;
1615cb93a386Sopenharmony_ci        }
1616cb93a386Sopenharmony_ci
1617cb93a386Sopenharmony_ci        // This is so far the the line vertically closest to our coordinates
1618cb93a386Sopenharmony_ci        // (or the first one, or the only one - all the same)
1619cb93a386Sopenharmony_ci
1620cb93a386Sopenharmony_ci        auto result = line.getGlyphPositionAtCoordinate(dx);
1621cb93a386Sopenharmony_ci        //SkDebugf("getGlyphPositionAtCoordinate(%f, %f): %d %s\n", dx, dy, result.position,
1622cb93a386Sopenharmony_ci        //   result.affinity == Affinity::kUpstream ? "up" : "down");
1623cb93a386Sopenharmony_ci        return result;
1624cb93a386Sopenharmony_ci    }
1625cb93a386Sopenharmony_ci
1626cb93a386Sopenharmony_ci    return {0, Affinity::kDownstream};
1627cb93a386Sopenharmony_ci}
1628cb93a386Sopenharmony_ci
1629cb93a386Sopenharmony_ci// Finds the first and last glyphs that define a word containing
1630cb93a386Sopenharmony_ci// the glyph at index offset.
1631cb93a386Sopenharmony_ci// By "glyph" they mean a character index - indicated by Minikin's code
1632cb93a386Sopenharmony_ciSkRange<size_t> ParagraphImpl::getWordBoundary(unsigned offset) {
1633cb93a386Sopenharmony_ci
1634cb93a386Sopenharmony_ci    if (fWords.empty()) {
1635cb93a386Sopenharmony_ci        if (!fUnicode->getWords(fText.c_str(), fText.size(), nullptr, &fWords)) {
1636cb93a386Sopenharmony_ci            return {0, 0 };
1637cb93a386Sopenharmony_ci        }
1638cb93a386Sopenharmony_ci    }
1639cb93a386Sopenharmony_ci
1640cb93a386Sopenharmony_ci    int32_t start = 0;
1641cb93a386Sopenharmony_ci    int32_t end = 0;
1642cb93a386Sopenharmony_ci    for (size_t i = 0; i < fWords.size(); ++i) {
1643cb93a386Sopenharmony_ci        auto word = fWords[i];
1644cb93a386Sopenharmony_ci        if (word <= offset) {
1645cb93a386Sopenharmony_ci            start = word;
1646cb93a386Sopenharmony_ci            end = word;
1647cb93a386Sopenharmony_ci        } else if (word > offset) {
1648cb93a386Sopenharmony_ci            end = word;
1649cb93a386Sopenharmony_ci            break;
1650cb93a386Sopenharmony_ci        }
1651cb93a386Sopenharmony_ci    }
1652cb93a386Sopenharmony_ci
1653cb93a386Sopenharmony_ci    //SkDebugf("getWordBoundary(%d): %d - %d\n", offset, start, end);
1654cb93a386Sopenharmony_ci    return { SkToU32(start), SkToU32(end) };
1655cb93a386Sopenharmony_ci}
1656cb93a386Sopenharmony_ci
1657cb93a386Sopenharmony_civoid ParagraphImpl::getLineMetrics(std::vector<LineMetrics>& metrics) {
1658cb93a386Sopenharmony_ci    metrics.clear();
1659cb93a386Sopenharmony_ci    for (auto& line : fLines) {
1660cb93a386Sopenharmony_ci        metrics.emplace_back(line.getMetrics());
1661cb93a386Sopenharmony_ci    }
1662cb93a386Sopenharmony_ci}
1663cb93a386Sopenharmony_ci
1664cb93a386Sopenharmony_ciSkSpan<const char> ParagraphImpl::text(TextRange textRange) {
1665cb93a386Sopenharmony_ci    SkASSERT(textRange.start <= fText.size() && textRange.end <= fText.size());
1666cb93a386Sopenharmony_ci    auto start = fText.c_str() + textRange.start;
1667cb93a386Sopenharmony_ci    return SkSpan<const char>(start, textRange.width());
1668cb93a386Sopenharmony_ci}
1669cb93a386Sopenharmony_ci
1670cb93a386Sopenharmony_ciSkSpan<Cluster> ParagraphImpl::clusters(ClusterRange clusterRange) {
1671cb93a386Sopenharmony_ci    SkASSERT(clusterRange.start < SkToSizeT(fClusters.size()) &&
1672cb93a386Sopenharmony_ci             clusterRange.end <= SkToSizeT(fClusters.size()));
1673cb93a386Sopenharmony_ci    return SkSpan<Cluster>(&fClusters[clusterRange.start], clusterRange.width());
1674cb93a386Sopenharmony_ci}
1675cb93a386Sopenharmony_ci
1676cb93a386Sopenharmony_ciCluster& ParagraphImpl::cluster(ClusterIndex clusterIndex) {
1677cb93a386Sopenharmony_ci    SkASSERT(clusterIndex < SkToSizeT(fClusters.size()));
1678cb93a386Sopenharmony_ci    return fClusters[clusterIndex];
1679cb93a386Sopenharmony_ci}
1680cb93a386Sopenharmony_ci
1681cb93a386Sopenharmony_ciRun& ParagraphImpl::runByCluster(ClusterIndex clusterIndex) {
1682cb93a386Sopenharmony_ci    auto start = cluster(clusterIndex);
1683cb93a386Sopenharmony_ci    return this->run(start.fRunIndex);
1684cb93a386Sopenharmony_ci}
1685cb93a386Sopenharmony_ci
1686cb93a386Sopenharmony_ciSkSpan<Block> ParagraphImpl::blocks(BlockRange blockRange) {
1687cb93a386Sopenharmony_ci    SkASSERT(blockRange.start < SkToSizeT(fTextStyles.size()) &&
1688cb93a386Sopenharmony_ci             blockRange.end <= SkToSizeT(fTextStyles.size()));
1689cb93a386Sopenharmony_ci    return SkSpan<Block>(&fTextStyles[blockRange.start], blockRange.width());
1690cb93a386Sopenharmony_ci}
1691cb93a386Sopenharmony_ci
1692cb93a386Sopenharmony_ciBlock& ParagraphImpl::block(BlockIndex blockIndex) {
1693cb93a386Sopenharmony_ci    SkASSERT(blockIndex < SkToSizeT(fTextStyles.size()));
1694cb93a386Sopenharmony_ci    return fTextStyles[blockIndex];
1695cb93a386Sopenharmony_ci}
1696cb93a386Sopenharmony_ci
1697cb93a386Sopenharmony_civoid ParagraphImpl::setState(InternalState state) {
1698cb93a386Sopenharmony_ci    if (fState <= state) {
1699cb93a386Sopenharmony_ci        fState = state;
1700cb93a386Sopenharmony_ci        return;
1701cb93a386Sopenharmony_ci    }
1702cb93a386Sopenharmony_ci
1703cb93a386Sopenharmony_ci    fState = state;
1704cb93a386Sopenharmony_ci    switch (fState) {
1705cb93a386Sopenharmony_ci        case kUnknown:
1706cb93a386Sopenharmony_ci            SkASSERT(false);
1707cb93a386Sopenharmony_ci            /*
1708cb93a386Sopenharmony_ci            // The text is immutable and so are all the text indexing properties
1709cb93a386Sopenharmony_ci            // taken from SkUnicode
1710cb93a386Sopenharmony_ci            fCodeUnitProperties.reset();
1711cb93a386Sopenharmony_ci            fWords.clear();
1712cb93a386Sopenharmony_ci            fBidiRegions.clear();
1713cb93a386Sopenharmony_ci            fUTF8IndexForUTF16Index.reset();
1714cb93a386Sopenharmony_ci            fUTF16IndexForUTF8Index.reset();
1715cb93a386Sopenharmony_ci            */
1716cb93a386Sopenharmony_ci            [[fallthrough]];
1717cb93a386Sopenharmony_ci
1718cb93a386Sopenharmony_ci        case kIndexed:
1719cb93a386Sopenharmony_ci            fRuns.reset();
1720cb93a386Sopenharmony_ci            fClusters.reset();
1721cb93a386Sopenharmony_ci            [[fallthrough]];
1722cb93a386Sopenharmony_ci
1723cb93a386Sopenharmony_ci        case kShaped:
1724cb93a386Sopenharmony_ci            fLines.reset();
1725cb93a386Sopenharmony_ci            [[fallthrough]];
1726cb93a386Sopenharmony_ci
1727cb93a386Sopenharmony_ci        case kLineBroken:
1728cb93a386Sopenharmony_ci            fPicture = nullptr;
1729cb93a386Sopenharmony_ci            [[fallthrough]];
1730cb93a386Sopenharmony_ci
1731cb93a386Sopenharmony_ci        default:
1732cb93a386Sopenharmony_ci            break;
1733cb93a386Sopenharmony_ci    }
1734cb93a386Sopenharmony_ci}
1735cb93a386Sopenharmony_ci
1736cb93a386Sopenharmony_civoid ParagraphImpl::computeEmptyMetrics() {
1737cb93a386Sopenharmony_ci
1738cb93a386Sopenharmony_ci    // The empty metrics is used to define the height of the empty lines
1739cb93a386Sopenharmony_ci    // Unfortunately, Flutter has 2 different cases for that:
1740cb93a386Sopenharmony_ci    // 1. An empty line inside the text
1741cb93a386Sopenharmony_ci    // 2. An empty paragraph
1742cb93a386Sopenharmony_ci    // In the first case SkParagraph takes the metrics from the default paragraph style
1743cb93a386Sopenharmony_ci    // In the second case it should take it from the current text style
1744cb93a386Sopenharmony_ci    bool emptyParagraph = fRuns.empty();
1745cb93a386Sopenharmony_ci    TextStyle textStyle = paragraphStyle().getTextStyle();
1746cb93a386Sopenharmony_ci    if (emptyParagraph && !fTextStyles.empty()) {
1747cb93a386Sopenharmony_ci        textStyle = fTextStyles.back().fStyle;
1748cb93a386Sopenharmony_ci    }
1749cb93a386Sopenharmony_ci
1750cb93a386Sopenharmony_ci    auto typefaces = fontCollection()->findTypefaces(
1751cb93a386Sopenharmony_ci      textStyle.getFontFamilies(), textStyle.getFontStyle(), textStyle.getFontArguments());
1752cb93a386Sopenharmony_ci    auto typeface = typefaces.empty() ? nullptr : typefaces.front();
1753cb93a386Sopenharmony_ci
1754cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
1755cb93a386Sopenharmony_ci    SkFont font(typeface, textStyle.getFontSize());
1756cb93a386Sopenharmony_ci#else
1757cb93a386Sopenharmony_ci    RSFont font(typeface, textStyle.getFontSize(), 1, 0);
1758cb93a386Sopenharmony_ci#endif
1759cb93a386Sopenharmony_ci    fEmptyMetrics = InternalLineMetrics(font, paragraphStyle().getStrutStyle().getForceStrutHeight());
1760cb93a386Sopenharmony_ci
1761cb93a386Sopenharmony_ci    if (!paragraphStyle().getStrutStyle().getForceStrutHeight() &&
1762cb93a386Sopenharmony_ci        textStyle.getHeightOverride()) {
1763cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1764cb93a386Sopenharmony_ci        const auto intrinsicHeight = fEmptyMetrics.fDescent - fEmptyMetrics.fAscent + fEmptyMetrics.fLeading;
1765cb93a386Sopenharmony_ci#else
1766cb93a386Sopenharmony_ci        const auto intrinsicHeight = fEmptyMetrics.height();
1767cb93a386Sopenharmony_ci#endif
1768cb93a386Sopenharmony_ci        const auto strutHeight = textStyle.getHeight() * textStyle.getFontSize();
1769cb93a386Sopenharmony_ci        if (paragraphStyle().getStrutStyle().getHalfLeading()) {
1770cb93a386Sopenharmony_ci            fEmptyMetrics.update(
1771cb93a386Sopenharmony_ci                fEmptyMetrics.ascent(),
1772cb93a386Sopenharmony_ci                fEmptyMetrics.descent(),
1773cb93a386Sopenharmony_ci                fEmptyMetrics.leading() + strutHeight - intrinsicHeight);
1774cb93a386Sopenharmony_ci        } else {
1775cb93a386Sopenharmony_ci            const auto multiplier = strutHeight / intrinsicHeight;
1776cb93a386Sopenharmony_ci            fEmptyMetrics.update(
1777cb93a386Sopenharmony_ci                fEmptyMetrics.ascent() * multiplier,
1778cb93a386Sopenharmony_ci                fEmptyMetrics.descent() * multiplier,
1779cb93a386Sopenharmony_ci                fEmptyMetrics.leading() * multiplier);
1780cb93a386Sopenharmony_ci        }
1781cb93a386Sopenharmony_ci    }
1782cb93a386Sopenharmony_ci
1783cb93a386Sopenharmony_ci    if (emptyParagraph) {
1784cb93a386Sopenharmony_ci        // For an empty text we apply both TextHeightBehaviour flags
1785cb93a386Sopenharmony_ci        // In case of non-empty paragraph TextHeightBehaviour flags will be applied at the appropriate place
1786cb93a386Sopenharmony_ci        // We have to do it here because we skip wrapping for an empty text
1787cb93a386Sopenharmony_ci        auto disableFirstAscent = (paragraphStyle().getTextHeightBehavior() & TextHeightBehavior::kDisableFirstAscent) == TextHeightBehavior::kDisableFirstAscent;
1788cb93a386Sopenharmony_ci        auto disableLastDescent = (paragraphStyle().getTextHeightBehavior() & TextHeightBehavior::kDisableLastDescent) == TextHeightBehavior::kDisableLastDescent;
1789cb93a386Sopenharmony_ci        fEmptyMetrics.update(
1790cb93a386Sopenharmony_ci            disableFirstAscent ? fEmptyMetrics.rawAscent() : fEmptyMetrics.ascent(),
1791cb93a386Sopenharmony_ci            disableLastDescent ? fEmptyMetrics.rawDescent() : fEmptyMetrics.descent(),
1792cb93a386Sopenharmony_ci            fEmptyMetrics.leading());
1793cb93a386Sopenharmony_ci    }
1794cb93a386Sopenharmony_ci
1795cb93a386Sopenharmony_ci    if (fParagraphStyle.getStrutStyle().getStrutEnabled()) {
1796cb93a386Sopenharmony_ci        fStrutMetrics.updateLineMetrics(fEmptyMetrics);
1797cb93a386Sopenharmony_ci    }
1798cb93a386Sopenharmony_ci}
1799cb93a386Sopenharmony_ci
1800cb93a386Sopenharmony_ciSkString ParagraphImpl::getEllipsis() const {
1801cb93a386Sopenharmony_ci
1802cb93a386Sopenharmony_ci    auto ellipsis8 = fParagraphStyle.getEllipsis();
1803cb93a386Sopenharmony_ci    auto ellipsis16 = fParagraphStyle.getEllipsisUtf16();
1804cb93a386Sopenharmony_ci    if (!ellipsis8.isEmpty()) {
1805cb93a386Sopenharmony_ci        return ellipsis8;
1806cb93a386Sopenharmony_ci    } else {
1807cb93a386Sopenharmony_ci        return SkUnicode::convertUtf16ToUtf8(fParagraphStyle.getEllipsisUtf16());
1808cb93a386Sopenharmony_ci    }
1809cb93a386Sopenharmony_ci}
1810cb93a386Sopenharmony_ci
1811cb93a386Sopenharmony_ciWordBreakType ParagraphImpl::getWordBreakType() const {
1812cb93a386Sopenharmony_ci    return fParagraphStyle.getStrutStyle().getWordBreakType();
1813cb93a386Sopenharmony_ci}
1814cb93a386Sopenharmony_ci
1815cb93a386Sopenharmony_ciLineBreakStrategy ParagraphImpl::getLineBreakStrategy() const {
1816cb93a386Sopenharmony_ci    return fParagraphStyle.getStrutStyle().getLineBreakStrategy();
1817cb93a386Sopenharmony_ci}
1818cb93a386Sopenharmony_ci
1819cb93a386Sopenharmony_civoid ParagraphImpl::updateFontSize(size_t from, size_t to, SkScalar fontSize) {
1820cb93a386Sopenharmony_ci
1821cb93a386Sopenharmony_ci  SkASSERT(from == 0 && to == fText.size());
1822cb93a386Sopenharmony_ci  auto defaultStyle = fParagraphStyle.getTextStyle();
1823cb93a386Sopenharmony_ci  defaultStyle.setFontSize(fontSize);
1824cb93a386Sopenharmony_ci  fParagraphStyle.setTextStyle(defaultStyle);
1825cb93a386Sopenharmony_ci
1826cb93a386Sopenharmony_ci  for (auto& textStyle : fTextStyles) {
1827cb93a386Sopenharmony_ci    textStyle.fStyle.setFontSize(fontSize);
1828cb93a386Sopenharmony_ci  }
1829cb93a386Sopenharmony_ci
1830cb93a386Sopenharmony_ci  fState = std::min(fState, kIndexed);
1831cb93a386Sopenharmony_ci  fOldWidth = 0;
1832cb93a386Sopenharmony_ci  fOldHeight = 0;
1833cb93a386Sopenharmony_ci}
1834cb93a386Sopenharmony_ci
1835cb93a386Sopenharmony_civoid ParagraphImpl::updateTextAlign(TextAlign textAlign) {
1836cb93a386Sopenharmony_ci    fParagraphStyle.setTextAlign(textAlign);
1837cb93a386Sopenharmony_ci
1838cb93a386Sopenharmony_ci    if (fState >= kLineBroken) {
1839cb93a386Sopenharmony_ci        fState = kLineBroken;
1840cb93a386Sopenharmony_ci    }
1841cb93a386Sopenharmony_ci}
1842cb93a386Sopenharmony_ci
1843cb93a386Sopenharmony_civoid ParagraphImpl::updateForegroundPaint(size_t from, size_t to, SkPaint paint) {
1844cb93a386Sopenharmony_ci    SkASSERT(from == 0 && to == fText.size());
1845cb93a386Sopenharmony_ci    auto defaultStyle = fParagraphStyle.getTextStyle();
1846cb93a386Sopenharmony_ci    defaultStyle.setForegroundColor(paint);
1847cb93a386Sopenharmony_ci    fParagraphStyle.setTextStyle(defaultStyle);
1848cb93a386Sopenharmony_ci
1849cb93a386Sopenharmony_ci    for (auto& textStyle : fTextStyles) {
1850cb93a386Sopenharmony_ci        textStyle.fStyle.setForegroundColor(paint);
1851cb93a386Sopenharmony_ci    }
1852cb93a386Sopenharmony_ci}
1853cb93a386Sopenharmony_ci
1854cb93a386Sopenharmony_civoid ParagraphImpl::updateBackgroundPaint(size_t from, size_t to, SkPaint paint) {
1855cb93a386Sopenharmony_ci    SkASSERT(from == 0 && to == fText.size());
1856cb93a386Sopenharmony_ci    auto defaultStyle = fParagraphStyle.getTextStyle();
1857cb93a386Sopenharmony_ci    defaultStyle.setBackgroundColor(paint);
1858cb93a386Sopenharmony_ci    fParagraphStyle.setTextStyle(defaultStyle);
1859cb93a386Sopenharmony_ci
1860cb93a386Sopenharmony_ci    for (auto& textStyle : fTextStyles) {
1861cb93a386Sopenharmony_ci        textStyle.fStyle.setBackgroundColor(paint);
1862cb93a386Sopenharmony_ci    }
1863cb93a386Sopenharmony_ci}
1864cb93a386Sopenharmony_ci
1865cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1866cb93a386Sopenharmony_ciParagraphPainter::PaintID ParagraphImpl::updateTextStyleColorAndForeground(TextStyle& textStyle, SkColor color)
1867cb93a386Sopenharmony_ci{
1868cb93a386Sopenharmony_ci    textStyle.setColor(color);
1869cb93a386Sopenharmony_ci    if (textStyle.hasForeground()) {
1870cb93a386Sopenharmony_ci        auto paintOrID = textStyle.getForegroundPaintOrID();
1871cb93a386Sopenharmony_ci        SkPaint* paint = std::get_if<SkPaint>(&paintOrID);
1872cb93a386Sopenharmony_ci        if (paint) {
1873cb93a386Sopenharmony_ci            paint->setColor(color);
1874cb93a386Sopenharmony_ci            textStyle.setForegroundPaint(*paint);
1875cb93a386Sopenharmony_ci        } else {
1876cb93a386Sopenharmony_ci            auto paintID = std::get_if<ParagraphPainter::PaintID>(&paintOrID);
1877cb93a386Sopenharmony_ci            if (paintID) {
1878cb93a386Sopenharmony_ci                return *paintID;
1879cb93a386Sopenharmony_ci            }
1880cb93a386Sopenharmony_ci        }
1881cb93a386Sopenharmony_ci    }
1882cb93a386Sopenharmony_ci    return INVALID_PAINT_ID;
1883cb93a386Sopenharmony_ci}
1884cb93a386Sopenharmony_ci
1885cb93a386Sopenharmony_cistd::vector<ParagraphPainter::PaintID> ParagraphImpl::updateColor(size_t from, size_t to, SkColor color) {
1886cb93a386Sopenharmony_ci    std::vector<ParagraphPainter::PaintID> unresolvedPaintID;
1887cb93a386Sopenharmony_ci    if (from >= to) {
1888cb93a386Sopenharmony_ci        return unresolvedPaintID;
1889cb93a386Sopenharmony_ci    }
1890cb93a386Sopenharmony_ci    this->ensureUTF16Mapping();
1891cb93a386Sopenharmony_ci    from = (from < SkToSizeT(fUTF8IndexForUTF16Index.size())) ? fUTF8IndexForUTF16Index[from] : fText.size();
1892cb93a386Sopenharmony_ci    to = (to < SkToSizeT(fUTF8IndexForUTF16Index.size())) ? fUTF8IndexForUTF16Index[to] : fText.size();
1893cb93a386Sopenharmony_ci    if (from == 0 && to == fText.size()) {
1894cb93a386Sopenharmony_ci        auto defaultStyle = fParagraphStyle.getTextStyle();
1895cb93a386Sopenharmony_ci        auto paintID = updateTextStyleColorAndForeground(defaultStyle, color);
1896cb93a386Sopenharmony_ci        if (paintID != INVALID_PAINT_ID) {
1897cb93a386Sopenharmony_ci            unresolvedPaintID.emplace_back(paintID);
1898cb93a386Sopenharmony_ci        }
1899cb93a386Sopenharmony_ci        fParagraphStyle.setTextStyle(defaultStyle);
1900cb93a386Sopenharmony_ci    }
1901cb93a386Sopenharmony_ci
1902cb93a386Sopenharmony_ci    for (auto& textStyle : fTextStyles) {
1903cb93a386Sopenharmony_ci        auto& fRange = textStyle.fRange;
1904cb93a386Sopenharmony_ci        if (to < fRange.end) {
1905cb93a386Sopenharmony_ci            break;
1906cb93a386Sopenharmony_ci        }
1907cb93a386Sopenharmony_ci        if (from > fRange.start) {
1908cb93a386Sopenharmony_ci            continue;
1909cb93a386Sopenharmony_ci        }
1910cb93a386Sopenharmony_ci        auto paintID = updateTextStyleColorAndForeground(textStyle.fStyle, color);
1911cb93a386Sopenharmony_ci        if (paintID != INVALID_PAINT_ID) {
1912cb93a386Sopenharmony_ci            unresolvedPaintID.emplace_back(paintID);
1913cb93a386Sopenharmony_ci        }
1914cb93a386Sopenharmony_ci    }
1915cb93a386Sopenharmony_ci    for (auto& line : fLines) {
1916cb93a386Sopenharmony_ci        line.setTextBlobCachePopulated(false);
1917cb93a386Sopenharmony_ci    }
1918cb93a386Sopenharmony_ci    return unresolvedPaintID;
1919cb93a386Sopenharmony_ci}
1920cb93a386Sopenharmony_ci#endif
1921cb93a386Sopenharmony_ci
1922cb93a386Sopenharmony_ciSkTArray<TextIndex> ParagraphImpl::countSurroundingGraphemes(TextRange textRange) const {
1923cb93a386Sopenharmony_ci    textRange = textRange.intersection({0, fText.size()});
1924cb93a386Sopenharmony_ci    SkTArray<TextIndex> graphemes;
1925cb93a386Sopenharmony_ci    if ((fCodeUnitProperties[textRange.start] & SkUnicode::CodeUnitFlags::kGraphemeStart) == 0) {
1926cb93a386Sopenharmony_ci        // Count the previous partial grapheme
1927cb93a386Sopenharmony_ci        graphemes.emplace_back(textRange.start);
1928cb93a386Sopenharmony_ci    }
1929cb93a386Sopenharmony_ci    for (auto index = textRange.start; index < textRange.end; ++index) {
1930cb93a386Sopenharmony_ci        if ((fCodeUnitProperties[index] & SkUnicode::CodeUnitFlags::kGraphemeStart) != 0) {
1931cb93a386Sopenharmony_ci            graphemes.emplace_back(index);
1932cb93a386Sopenharmony_ci        }
1933cb93a386Sopenharmony_ci    }
1934cb93a386Sopenharmony_ci    return graphemes;
1935cb93a386Sopenharmony_ci}
1936cb93a386Sopenharmony_ci
1937cb93a386Sopenharmony_ciTextIndex ParagraphImpl::findPreviousGraphemeBoundary(TextIndex utf8) const {
1938cb93a386Sopenharmony_ci    while (utf8 > 0 &&
1939cb93a386Sopenharmony_ci          (fCodeUnitProperties[utf8] & SkUnicode::CodeUnitFlags::kGraphemeStart) == 0) {
1940cb93a386Sopenharmony_ci        --utf8;
1941cb93a386Sopenharmony_ci    }
1942cb93a386Sopenharmony_ci    return utf8;
1943cb93a386Sopenharmony_ci}
1944cb93a386Sopenharmony_ci
1945cb93a386Sopenharmony_ciTextIndex ParagraphImpl::findNextGraphemeBoundary(TextIndex utf8) const {
1946cb93a386Sopenharmony_ci    while (utf8 < fText.size() &&
1947cb93a386Sopenharmony_ci          (fCodeUnitProperties[utf8] & SkUnicode::CodeUnitFlags::kGraphemeStart) == 0) {
1948cb93a386Sopenharmony_ci        ++utf8;
1949cb93a386Sopenharmony_ci    }
1950cb93a386Sopenharmony_ci    return utf8;
1951cb93a386Sopenharmony_ci}
1952cb93a386Sopenharmony_ci
1953cb93a386Sopenharmony_ciTextIndex ParagraphImpl::findNextGlyphClusterBoundary(TextIndex utf8) const {
1954cb93a386Sopenharmony_ci    while (utf8 < fText.size() &&
1955cb93a386Sopenharmony_ci          (fCodeUnitProperties[utf8] & SkUnicode::CodeUnitFlags::kGlyphClusterStart) == 0) {
1956cb93a386Sopenharmony_ci        ++utf8;
1957cb93a386Sopenharmony_ci    }
1958cb93a386Sopenharmony_ci    return utf8;
1959cb93a386Sopenharmony_ci}
1960cb93a386Sopenharmony_ci
1961cb93a386Sopenharmony_ciTextIndex ParagraphImpl::findPreviousGlyphClusterBoundary(TextIndex utf8) const {
1962cb93a386Sopenharmony_ci    while (utf8 > 0 &&
1963cb93a386Sopenharmony_ci          (fCodeUnitProperties[utf8] & SkUnicode::CodeUnitFlags::kGlyphClusterStart) == 0) {
1964cb93a386Sopenharmony_ci        --utf8;
1965cb93a386Sopenharmony_ci    }
1966cb93a386Sopenharmony_ci    return utf8;
1967cb93a386Sopenharmony_ci}
1968cb93a386Sopenharmony_ci
1969cb93a386Sopenharmony_civoid ParagraphImpl::ensureUTF16Mapping() {
1970cb93a386Sopenharmony_ci    fillUTF16MappingOnce([&] {
1971cb93a386Sopenharmony_ci        fUnicode->extractUtfConversionMapping(
1972cb93a386Sopenharmony_ci                this->text(),
1973cb93a386Sopenharmony_ci                [&](size_t index) { fUTF8IndexForUTF16Index.emplace_back(index); },
1974cb93a386Sopenharmony_ci                [&](size_t index) { fUTF16IndexForUTF8Index.emplace_back(index); });
1975cb93a386Sopenharmony_ci    });
1976cb93a386Sopenharmony_ci}
1977cb93a386Sopenharmony_ci
1978cb93a386Sopenharmony_civoid ParagraphImpl::visit(const Visitor& visitor) {
1979cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
1980cb93a386Sopenharmony_ci    int lineNumber = 0;
1981cb93a386Sopenharmony_ci    for (auto& line : fLines) {
1982cb93a386Sopenharmony_ci        line.ensureTextBlobCachePopulated();
1983cb93a386Sopenharmony_ci        for (auto& rec : line.fTextBlobCache) {
1984cb93a386Sopenharmony_ci            SkTextBlob::Iter iter(*rec.fBlob);
1985cb93a386Sopenharmony_ci            SkTextBlob::Iter::ExperimentalRun run;
1986cb93a386Sopenharmony_ci
1987cb93a386Sopenharmony_ci            SkSTArray<128, uint32_t> clusterStorage;
1988cb93a386Sopenharmony_ci            const Run* R = rec.fVisitor_Run;
1989cb93a386Sopenharmony_ci            const uint32_t* clusterPtr = &R->fClusterIndexes[0];
1990cb93a386Sopenharmony_ci
1991cb93a386Sopenharmony_ci            if (R->fClusterStart > 0) {
1992cb93a386Sopenharmony_ci                int count = R->fClusterIndexes.size();
1993cb93a386Sopenharmony_ci                clusterStorage.reset(count);
1994cb93a386Sopenharmony_ci                for (int i = 0; i < count; ++i) {
1995cb93a386Sopenharmony_ci                    clusterStorage[i] = R->fClusterStart + R->fClusterIndexes[i];
1996cb93a386Sopenharmony_ci                }
1997cb93a386Sopenharmony_ci                clusterPtr = &clusterStorage[0];
1998cb93a386Sopenharmony_ci            }
1999cb93a386Sopenharmony_ci            clusterPtr += rec.fVisitor_Pos;
2000cb93a386Sopenharmony_ci
2001cb93a386Sopenharmony_ci            while (iter.experimentalNext(&run)) {
2002cb93a386Sopenharmony_ci                const Paragraph::VisitorInfo info = {
2003cb93a386Sopenharmony_ci                    run.font,
2004cb93a386Sopenharmony_ci                    rec.fOffset,
2005cb93a386Sopenharmony_ci                    rec.fClipRect.fRight,
2006cb93a386Sopenharmony_ci                    run.count,
2007cb93a386Sopenharmony_ci                    run.glyphs,
2008cb93a386Sopenharmony_ci                    run.positions,
2009cb93a386Sopenharmony_ci                    clusterPtr,
2010cb93a386Sopenharmony_ci                    0,  // flags
2011cb93a386Sopenharmony_ci                };
2012cb93a386Sopenharmony_ci                visitor(lineNumber, &info);
2013cb93a386Sopenharmony_ci                clusterPtr += run.count;
2014cb93a386Sopenharmony_ci            }
2015cb93a386Sopenharmony_ci        }
2016cb93a386Sopenharmony_ci        visitor(lineNumber, nullptr);   // signal end of line
2017cb93a386Sopenharmony_ci        lineNumber += 1;
2018cb93a386Sopenharmony_ci    }
2019cb93a386Sopenharmony_ci#endif
2020cb93a386Sopenharmony_ci}
2021cb93a386Sopenharmony_ci
2022cb93a386Sopenharmony_ciint ParagraphImpl::getLineNumberAt(TextIndex codeUnitIndex) const {
2023cb93a386Sopenharmony_ci    for (auto i = 0; i < fLines.size(); ++i) {
2024cb93a386Sopenharmony_ci        auto& line = fLines[i];
2025cb93a386Sopenharmony_ci        if (line.text().contains({codeUnitIndex, codeUnitIndex + 1})) {
2026cb93a386Sopenharmony_ci            return i;
2027cb93a386Sopenharmony_ci        }
2028cb93a386Sopenharmony_ci    }
2029cb93a386Sopenharmony_ci    return -1;
2030cb93a386Sopenharmony_ci}
2031cb93a386Sopenharmony_ci
2032cb93a386Sopenharmony_cibool ParagraphImpl::getLineMetricsAt(int lineNumber, LineMetrics* lineMetrics) const {
2033cb93a386Sopenharmony_ci    if (lineNumber < 0 || lineNumber >= fLines.size()) {
2034cb93a386Sopenharmony_ci        return false;
2035cb93a386Sopenharmony_ci    }
2036cb93a386Sopenharmony_ci    auto& line = fLines[lineNumber];
2037cb93a386Sopenharmony_ci    if (lineMetrics) {
2038cb93a386Sopenharmony_ci        *lineMetrics = line.getMetrics();
2039cb93a386Sopenharmony_ci    }
2040cb93a386Sopenharmony_ci    return true;
2041cb93a386Sopenharmony_ci}
2042cb93a386Sopenharmony_ci
2043cb93a386Sopenharmony_ciTextRange ParagraphImpl::getActualTextRange(int lineNumber, bool includeSpaces) const {
2044cb93a386Sopenharmony_ci    if (lineNumber < 0 || lineNumber >= fLines.size()) {
2045cb93a386Sopenharmony_ci        return EMPTY_TEXT;
2046cb93a386Sopenharmony_ci    }
2047cb93a386Sopenharmony_ci    auto& line = fLines[lineNumber];
2048cb93a386Sopenharmony_ci    return includeSpaces ? line.text() : line.trimmedText();
2049cb93a386Sopenharmony_ci}
2050cb93a386Sopenharmony_ci
2051cb93a386Sopenharmony_cibool ParagraphImpl::getGlyphClusterAt(TextIndex codeUnitIndex, GlyphClusterInfo* glyphInfo) {
2052cb93a386Sopenharmony_ci    for (auto i = 0; i < fLines.size(); ++i) {
2053cb93a386Sopenharmony_ci        auto& line = fLines[i];
2054cb93a386Sopenharmony_ci        if (!line.text().contains({codeUnitIndex, codeUnitIndex})) {
2055cb93a386Sopenharmony_ci            continue;
2056cb93a386Sopenharmony_ci        }
2057cb93a386Sopenharmony_ci        for (auto c = line.clustersWithSpaces().start; c < line.clustersWithSpaces().end; ++c) {
2058cb93a386Sopenharmony_ci            auto& cluster = fClusters[c];
2059cb93a386Sopenharmony_ci            if (cluster.contains(codeUnitIndex)) {
2060cb93a386Sopenharmony_ci                std::vector<TextBox> boxes;
2061cb93a386Sopenharmony_ci                line.getRectsForRange(cluster.textRange(),
2062cb93a386Sopenharmony_ci                                      RectHeightStyle::kTight,
2063cb93a386Sopenharmony_ci                                      RectWidthStyle::kTight,
2064cb93a386Sopenharmony_ci                                      boxes);
2065cb93a386Sopenharmony_ci                if (boxes.size() > 0) {
2066cb93a386Sopenharmony_ci                    if (glyphInfo) {
2067cb93a386Sopenharmony_ci                        *glyphInfo = {boxes[0].rect, cluster.textRange(), boxes[0].direction};
2068cb93a386Sopenharmony_ci                    }
2069cb93a386Sopenharmony_ci                    return true;
2070cb93a386Sopenharmony_ci                }
2071cb93a386Sopenharmony_ci            }
2072cb93a386Sopenharmony_ci        }
2073cb93a386Sopenharmony_ci        return false;
2074cb93a386Sopenharmony_ci    }
2075cb93a386Sopenharmony_ci    return false;
2076cb93a386Sopenharmony_ci}
2077cb93a386Sopenharmony_ci
2078cb93a386Sopenharmony_cibool ParagraphImpl::getClosestGlyphClusterAt(SkScalar dx,
2079cb93a386Sopenharmony_ci                                             SkScalar dy,
2080cb93a386Sopenharmony_ci                                             GlyphClusterInfo* glyphInfo) {
2081cb93a386Sopenharmony_ci    auto res = this->getGlyphPositionAtCoordinate(dx, dy);
2082cb93a386Sopenharmony_ci    auto textIndex = res.position + (res.affinity == Affinity::kDownstream ? 0 : 1);
2083cb93a386Sopenharmony_ci    GlyphClusterInfo gci;
2084cb93a386Sopenharmony_ci    if (this->getGlyphClusterAt(textIndex, glyphInfo ? glyphInfo : &gci)) {
2085cb93a386Sopenharmony_ci        return true;
2086cb93a386Sopenharmony_ci    } else {
2087cb93a386Sopenharmony_ci        return false;
2088cb93a386Sopenharmony_ci    }
2089cb93a386Sopenharmony_ci}
2090cb93a386Sopenharmony_ci
2091cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
2092cb93a386Sopenharmony_ciSkFont ParagraphImpl::getFontAt(TextIndex codeUnitIndex) const {
2093cb93a386Sopenharmony_ci    for (auto& run : fRuns) {
2094cb93a386Sopenharmony_ci        if (run.textRange().contains({codeUnitIndex, codeUnitIndex})) {
2095cb93a386Sopenharmony_ci            return run.font();
2096cb93a386Sopenharmony_ci        }
2097cb93a386Sopenharmony_ci    }
2098cb93a386Sopenharmony_ci    return SkFont();
2099cb93a386Sopenharmony_ci}
2100cb93a386Sopenharmony_ci#else
2101cb93a386Sopenharmony_ciRSFont ParagraphImpl::getFontAt(TextIndex codeUnitIndex) const
2102cb93a386Sopenharmony_ci{
2103cb93a386Sopenharmony_ci    for (auto& run : fRuns) {
2104cb93a386Sopenharmony_ci        if (run.textRange().contains({codeUnitIndex, codeUnitIndex})) {
2105cb93a386Sopenharmony_ci            return run.font();
2106cb93a386Sopenharmony_ci        }
2107cb93a386Sopenharmony_ci    }
2108cb93a386Sopenharmony_ci    return RSFont();
2109cb93a386Sopenharmony_ci}
2110cb93a386Sopenharmony_ci#endif
2111cb93a386Sopenharmony_ci
2112cb93a386Sopenharmony_cistd::vector<Paragraph::FontInfo> ParagraphImpl::getFonts() const {
2113cb93a386Sopenharmony_ci    std::vector<FontInfo> results;
2114cb93a386Sopenharmony_ci    for (auto& run : fRuns) {
2115cb93a386Sopenharmony_ci        results.emplace_back(run.font(), run.textRange());
2116cb93a386Sopenharmony_ci    }
2117cb93a386Sopenharmony_ci    return results;
2118cb93a386Sopenharmony_ci}
2119cb93a386Sopenharmony_ci
2120cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
2121cb93a386Sopenharmony_ciSkFontMetrics ParagraphImpl::measureText() {
2122cb93a386Sopenharmony_ci    SkFontMetrics metrics;
2123cb93a386Sopenharmony_ci    if (fRuns.empty()) {
2124cb93a386Sopenharmony_ci        return metrics;
2125cb93a386Sopenharmony_ci    }
2126cb93a386Sopenharmony_ci
2127cb93a386Sopenharmony_ci    const auto& firstFont = fRuns.front().font();
2128cb93a386Sopenharmony_ci    SkRect firstBounds;
2129cb93a386Sopenharmony_ci    auto firstStr = text(fRuns.front().textRange());
2130cb93a386Sopenharmony_ci    firstFont.getMetrics(&metrics);
2131cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
2132cb93a386Sopenharmony_ci    auto decompressFont = firstFont;
2133cb93a386Sopenharmony_ci    scaleFontWithCompressionConfig(decompressFont, ScaleOP::DECOMPRESS);
2134cb93a386Sopenharmony_ci    metricsIncludeFontPadding(&metrics, decompressFont);
2135cb93a386Sopenharmony_ci#endif
2136cb93a386Sopenharmony_ci    firstFont.measureText(firstStr.data(), firstStr.size(), SkTextEncoding::kUTF8, &firstBounds, nullptr);
2137cb93a386Sopenharmony_ci    fGlyphsBoundsTop = firstBounds.top();
2138cb93a386Sopenharmony_ci    fGlyphsBoundsBottom = firstBounds.bottom();
2139cb93a386Sopenharmony_ci    fGlyphsBoundsLeft = firstBounds.left();
2140cb93a386Sopenharmony_ci    SkScalar realWidth = 0;
2141cb93a386Sopenharmony_ci    for (size_t i = 0; i < fRuns.size(); ++i) {
2142cb93a386Sopenharmony_ci        auto run = fRuns[i];
2143cb93a386Sopenharmony_ci        const auto& font = run.font();
2144cb93a386Sopenharmony_ci        SkRect bounds;
2145cb93a386Sopenharmony_ci        auto str = text(run.textRange());
2146cb93a386Sopenharmony_ci        auto advance = font.measureText(str.data(), str.size(), SkTextEncoding::kUTF8, &bounds, nullptr);
2147cb93a386Sopenharmony_ci        realWidth += advance;
2148cb93a386Sopenharmony_ci        if (i == 0) {
2149cb93a386Sopenharmony_ci            realWidth -= ((advance - (bounds.right() - bounds.left())) / 2);
2150cb93a386Sopenharmony_ci        }
2151cb93a386Sopenharmony_ci        if (i == (fRuns.size() - 1)) {
2152cb93a386Sopenharmony_ci            realWidth -= ((advance - (bounds.right() - bounds.left())) / 2);
2153cb93a386Sopenharmony_ci        }
2154cb93a386Sopenharmony_ci        fGlyphsBoundsTop = std::min(fGlyphsBoundsTop, bounds.top());
2155cb93a386Sopenharmony_ci        fGlyphsBoundsBottom = std::max(fGlyphsBoundsBottom, bounds.bottom());
2156cb93a386Sopenharmony_ci    }
2157cb93a386Sopenharmony_ci    fGlyphsBoundsRight = realWidth + fGlyphsBoundsLeft;
2158cb93a386Sopenharmony_ci    return metrics;
2159cb93a386Sopenharmony_ci}
2160cb93a386Sopenharmony_ci#else
2161cb93a386Sopenharmony_ciRSFontMetrics ParagraphImpl::measureText()
2162cb93a386Sopenharmony_ci{
2163cb93a386Sopenharmony_ci    RSFontMetrics metrics;
2164cb93a386Sopenharmony_ci    if (fRuns.empty()) {
2165cb93a386Sopenharmony_ci        return metrics;
2166cb93a386Sopenharmony_ci    }
2167cb93a386Sopenharmony_ci
2168cb93a386Sopenharmony_ci    auto& firstFont = const_cast<RSFont&>(fRuns.front().font());
2169cb93a386Sopenharmony_ci    RSRect firstBounds;
2170cb93a386Sopenharmony_ci    auto firstStr = text(fRuns.front().textRange());
2171cb93a386Sopenharmony_ci    firstFont.GetMetrics(&metrics);
2172cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
2173cb93a386Sopenharmony_ci    auto decompressFont = firstFont;
2174cb93a386Sopenharmony_ci    scaleFontWithCompressionConfig(decompressFont, ScaleOP::DECOMPRESS);
2175cb93a386Sopenharmony_ci    metricsIncludeFontPadding(&metrics, decompressFont);
2176cb93a386Sopenharmony_ci#endif
2177cb93a386Sopenharmony_ci    firstFont.MeasureText(firstStr.data(), firstStr.size(), RSDrawing::TextEncoding::UTF8, &firstBounds);
2178cb93a386Sopenharmony_ci    fGlyphsBoundsTop = firstBounds.GetTop();
2179cb93a386Sopenharmony_ci    fGlyphsBoundsBottom = firstBounds.GetBottom();
2180cb93a386Sopenharmony_ci    fGlyphsBoundsLeft = firstBounds.GetLeft();
2181cb93a386Sopenharmony_ci    float realWidth = 0;
2182cb93a386Sopenharmony_ci    for (size_t i = 0; i < fRuns.size(); ++i) {
2183cb93a386Sopenharmony_ci        auto run = fRuns[i];
2184cb93a386Sopenharmony_ci        auto& font = const_cast<RSFont&>(run.font());
2185cb93a386Sopenharmony_ci        RSRect bounds;
2186cb93a386Sopenharmony_ci        auto str = text(run.textRange());
2187cb93a386Sopenharmony_ci        auto advance = font.MeasureText(str.data(), str.size(), RSDrawing::TextEncoding::UTF8, &bounds);
2188cb93a386Sopenharmony_ci        realWidth += advance;
2189cb93a386Sopenharmony_ci        if (i == 0) {
2190cb93a386Sopenharmony_ci            realWidth -= ((advance - (bounds.GetRight() - bounds.GetLeft())) / 2);
2191cb93a386Sopenharmony_ci        }
2192cb93a386Sopenharmony_ci        if (i == (fRuns.size() - 1)) {
2193cb93a386Sopenharmony_ci            realWidth -= ((advance - (bounds.GetRight() - bounds.GetLeft())) / 2);
2194cb93a386Sopenharmony_ci        }
2195cb93a386Sopenharmony_ci        fGlyphsBoundsTop = std::min(fGlyphsBoundsTop, bounds.GetTop());
2196cb93a386Sopenharmony_ci        fGlyphsBoundsBottom = std::max(fGlyphsBoundsBottom, bounds.GetBottom());
2197cb93a386Sopenharmony_ci    }
2198cb93a386Sopenharmony_ci    fGlyphsBoundsRight = realWidth + fGlyphsBoundsLeft;
2199cb93a386Sopenharmony_ci    return metrics;
2200cb93a386Sopenharmony_ci}
2201cb93a386Sopenharmony_ci#endif
2202cb93a386Sopenharmony_ci
2203cb93a386Sopenharmony_cistd::vector<std::unique_ptr<TextLineBase>> ParagraphImpl::GetTextLines() {
2204cb93a386Sopenharmony_ci    std::vector<std::unique_ptr<TextLineBase>> textLineBases;
2205cb93a386Sopenharmony_ci    for (auto& line: fLines) {
2206cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
2207cb93a386Sopenharmony_ci        std::unique_ptr<TextLineBaseImpl> textLineBaseImplPtr =
2208cb93a386Sopenharmony_ci            std::make_unique<TextLineBaseImpl>(std::make_unique<TextLine>(std::move(line)));
2209cb93a386Sopenharmony_ci#else
2210cb93a386Sopenharmony_ci        std::unique_ptr<TextLineBaseImpl> textLineBaseImplPtr = std::make_unique<TextLineBaseImpl>(&line);
2211cb93a386Sopenharmony_ci#endif
2212cb93a386Sopenharmony_ci        textLineBases.emplace_back(std::move(textLineBaseImplPtr));
2213cb93a386Sopenharmony_ci    }
2214cb93a386Sopenharmony_ci
2215cb93a386Sopenharmony_ci    return textLineBases;
2216cb93a386Sopenharmony_ci}
2217cb93a386Sopenharmony_ci
2218cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
2219cb93a386Sopenharmony_cisize_t ParagraphImpl::prefixByteCountUntilChar(size_t index) {
2220cb93a386Sopenharmony_ci    convertUtf8ToUnicode(fText);
2221cb93a386Sopenharmony_ci    if (fUnicodeIndexForUTF8Index.empty()) {
2222cb93a386Sopenharmony_ci        return std::numeric_limits<size_t>::max();
2223cb93a386Sopenharmony_ci    }
2224cb93a386Sopenharmony_ci    auto it = std::lower_bound(fUnicodeIndexForUTF8Index.begin(), fUnicodeIndexForUTF8Index.end(), index);
2225cb93a386Sopenharmony_ci    if (it != fUnicodeIndexForUTF8Index.end() && *it == index) {
2226cb93a386Sopenharmony_ci        return std::distance(fUnicodeIndexForUTF8Index.begin(), it);
2227cb93a386Sopenharmony_ci    } else {
2228cb93a386Sopenharmony_ci        return std::numeric_limits<size_t>::max();
2229cb93a386Sopenharmony_ci    }
2230cb93a386Sopenharmony_ci}
2231cb93a386Sopenharmony_ci
2232cb93a386Sopenharmony_civoid ParagraphImpl::copyProperties(const ParagraphImpl& source) {
2233cb93a386Sopenharmony_ci    fText = source.fText;
2234cb93a386Sopenharmony_ci    fTextStyles = source.fTextStyles;
2235cb93a386Sopenharmony_ci    fPlaceholders = source.fPlaceholders;
2236cb93a386Sopenharmony_ci    fParagraphStyle = source.fParagraphStyle;
2237cb93a386Sopenharmony_ci    fFontCollection = source.fFontCollection;
2238cb93a386Sopenharmony_ci    fUnicode = source.fUnicode;
2239cb93a386Sopenharmony_ci
2240cb93a386Sopenharmony_ci    fState = kUnknown;
2241cb93a386Sopenharmony_ci    fUnresolvedGlyphs = 0;
2242cb93a386Sopenharmony_ci    fPicture = nullptr;
2243cb93a386Sopenharmony_ci    fStrutMetrics = false;
2244cb93a386Sopenharmony_ci    fOldWidth = 0;
2245cb93a386Sopenharmony_ci    fOldHeight = 0;
2246cb93a386Sopenharmony_ci    fHasLineBreaks = false;
2247cb93a386Sopenharmony_ci    fHasWhitespacesInside = false;
2248cb93a386Sopenharmony_ci    fTrailingSpaces = 0;
2249cb93a386Sopenharmony_ci}
2250cb93a386Sopenharmony_ci
2251cb93a386Sopenharmony_cistd::unique_ptr<Paragraph> ParagraphImpl::createCroppedCopy(size_t startIndex, size_t count) {
2252cb93a386Sopenharmony_ci    std::unique_ptr<ParagraphImpl> paragraph = std::make_unique<ParagraphImpl>();
2253cb93a386Sopenharmony_ci    paragraph->copyProperties(*this);
2254cb93a386Sopenharmony_ci
2255cb93a386Sopenharmony_ci    // change range
2256cb93a386Sopenharmony_ci    auto validStart = prefixByteCountUntilChar(startIndex);
2257cb93a386Sopenharmony_ci    if (validStart == std::numeric_limits<size_t>::max()) {
2258cb93a386Sopenharmony_ci        return nullptr;
2259cb93a386Sopenharmony_ci    }
2260cb93a386Sopenharmony_ci    // For example, when the clipped string str1 is "123456789"
2261cb93a386Sopenharmony_ci    // startIndex=2, count=std:: numeric_imits<size_t>:: max(), the resulting string str2 is "3456789".
2262cb93a386Sopenharmony_ci    // When startIndex=3 and count=3, crop the generated string str3 to "456"
2263cb93a386Sopenharmony_ci    TextRange firstDeleteRange(0, validStart);
2264cb93a386Sopenharmony_ci    paragraph->fText.remove(0, validStart);
2265cb93a386Sopenharmony_ci    paragraph->resetTextStyleRange(firstDeleteRange);
2266cb93a386Sopenharmony_ci    paragraph->resetPlaceholderRange(firstDeleteRange);
2267cb93a386Sopenharmony_ci
2268cb93a386Sopenharmony_ci    if (count != std::numeric_limits<size_t>::max()) {
2269cb93a386Sopenharmony_ci        auto invalidStart = paragraph->prefixByteCountUntilChar(count);
2270cb93a386Sopenharmony_ci        if (invalidStart == std::numeric_limits<size_t>::max()) {
2271cb93a386Sopenharmony_ci            return nullptr;
2272cb93a386Sopenharmony_ci        }
2273cb93a386Sopenharmony_ci        auto invalidEnd = paragraph->fText.size();
2274cb93a386Sopenharmony_ci        TextRange secodeDeleteRange(invalidStart, invalidEnd);
2275cb93a386Sopenharmony_ci        paragraph->fText.remove(invalidStart, invalidEnd - invalidStart);
2276cb93a386Sopenharmony_ci        paragraph->resetTextStyleRange(secodeDeleteRange);
2277cb93a386Sopenharmony_ci        paragraph->resetPlaceholderRange(secodeDeleteRange);
2278cb93a386Sopenharmony_ci    }
2279cb93a386Sopenharmony_ci    return paragraph;
2280cb93a386Sopenharmony_ci}
2281cb93a386Sopenharmony_ci
2282cb93a386Sopenharmony_civoid ParagraphImpl::initUnicodeText() {
2283cb93a386Sopenharmony_ci    this->fUnicodeText = convertUtf8ToUnicode(fText);
2284cb93a386Sopenharmony_ci}
2285cb93a386Sopenharmony_ci#endif
2286cb93a386Sopenharmony_ci
2287cb93a386Sopenharmony_cistd::unique_ptr<Paragraph> ParagraphImpl::CloneSelf()
2288cb93a386Sopenharmony_ci{
2289cb93a386Sopenharmony_ci    std::unique_ptr<ParagraphImpl> paragraph = std::make_unique<ParagraphImpl>();
2290cb93a386Sopenharmony_ci
2291cb93a386Sopenharmony_ci    paragraph->fFontCollection = this->fFontCollection;
2292cb93a386Sopenharmony_ci    paragraph->fParagraphStyle = this->fParagraphStyle;
2293cb93a386Sopenharmony_ci    paragraph->fAlphabeticBaseline = this->fAlphabeticBaseline;
2294cb93a386Sopenharmony_ci    paragraph->fIdeographicBaseline = this->fIdeographicBaseline;
2295cb93a386Sopenharmony_ci    paragraph->fGlyphsBoundsTop = this->fGlyphsBoundsTop;
2296cb93a386Sopenharmony_ci    paragraph->fGlyphsBoundsBottom = this->fGlyphsBoundsBottom;
2297cb93a386Sopenharmony_ci    paragraph->fGlyphsBoundsLeft = this->fGlyphsBoundsLeft;
2298cb93a386Sopenharmony_ci    paragraph->fGlyphsBoundsRight = this->fGlyphsBoundsRight;
2299cb93a386Sopenharmony_ci    paragraph->fHeight = this->fHeight;
2300cb93a386Sopenharmony_ci    paragraph->fWidth = this->fWidth;
2301cb93a386Sopenharmony_ci    paragraph->fMaxIntrinsicWidth = this->fMaxIntrinsicWidth;
2302cb93a386Sopenharmony_ci    paragraph->fMinIntrinsicWidth = this->fMinIntrinsicWidth;
2303cb93a386Sopenharmony_ci    paragraph->fLongestLine = this->fLongestLine;
2304cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
2305cb93a386Sopenharmony_ci    paragraph->fLongestLineWithIndent = this->fLongestLineWithIndent;
2306cb93a386Sopenharmony_ci#endif
2307cb93a386Sopenharmony_ci    paragraph->fExceededMaxLines = this->fExceededMaxLines;
2308cb93a386Sopenharmony_ci
2309cb93a386Sopenharmony_ci    paragraph->fLetterSpaceStyles = this->fLetterSpaceStyles;
2310cb93a386Sopenharmony_ci    paragraph->fWordSpaceStyles = this->fWordSpaceStyles;
2311cb93a386Sopenharmony_ci    paragraph->fBackgroundStyles = this->fBackgroundStyles;
2312cb93a386Sopenharmony_ci    paragraph->fForegroundStyles = this->fForegroundStyles;
2313cb93a386Sopenharmony_ci    paragraph->fShadowStyles = this->fShadowStyles;
2314cb93a386Sopenharmony_ci    paragraph->fDecorationStyles = this->fDecorationStyles;
2315cb93a386Sopenharmony_ci    paragraph->fTextStyles = this->fTextStyles;
2316cb93a386Sopenharmony_ci    paragraph->fPlaceholders = this->fPlaceholders;
2317cb93a386Sopenharmony_ci    paragraph->fText = this->fText;
2318cb93a386Sopenharmony_ci
2319cb93a386Sopenharmony_ci    paragraph->fState = this->fState;
2320cb93a386Sopenharmony_ci    paragraph->fRuns = this->fRuns;
2321cb93a386Sopenharmony_ci    paragraph->fClusters = this->fClusters;
2322cb93a386Sopenharmony_ci    paragraph->fCodeUnitProperties = this->fCodeUnitProperties;
2323cb93a386Sopenharmony_ci    paragraph->fClustersIndexFromCodeUnit = this->fClustersIndexFromCodeUnit;
2324cb93a386Sopenharmony_ci
2325cb93a386Sopenharmony_ci    paragraph->fWords = this->fWords;
2326cb93a386Sopenharmony_ci    paragraph->fIndents = this->fIndents;
2327cb93a386Sopenharmony_ci    paragraph->rtlTextSize = this->rtlTextSize;
2328cb93a386Sopenharmony_ci    paragraph->ltrTextSize = this->ltrTextSize;
2329cb93a386Sopenharmony_ci    paragraph->fBidiRegions = this->fBidiRegions;
2330cb93a386Sopenharmony_ci
2331cb93a386Sopenharmony_ci    paragraph->fUTF8IndexForUTF16Index = this->fUTF8IndexForUTF16Index;
2332cb93a386Sopenharmony_ci    paragraph->fUTF16IndexForUTF8Index = this->fUTF16IndexForUTF8Index;
2333cb93a386Sopenharmony_ci    paragraph->fUnresolvedGlyphs = this->fUnresolvedGlyphs;
2334cb93a386Sopenharmony_ci    paragraph->isMiddleEllipsis = this->isMiddleEllipsis;
2335cb93a386Sopenharmony_ci    paragraph->fUnresolvedCodepoints = this->fUnresolvedCodepoints;
2336cb93a386Sopenharmony_ci
2337cb93a386Sopenharmony_ci    for (auto& line : this->fLines) {
2338cb93a386Sopenharmony_ci        paragraph->fLines.emplace_back(line.CloneSelf());
2339cb93a386Sopenharmony_ci    }
2340cb93a386Sopenharmony_ci
2341cb93a386Sopenharmony_ci    paragraph->fPicture = this->fPicture;
2342cb93a386Sopenharmony_ci    paragraph->fFontSwitches = this->fFontSwitches;
2343cb93a386Sopenharmony_ci    paragraph->fEmptyMetrics = this->fEmptyMetrics;
2344cb93a386Sopenharmony_ci    paragraph->fStrutMetrics = this->fStrutMetrics;
2345cb93a386Sopenharmony_ci
2346cb93a386Sopenharmony_ci    paragraph->fOldWidth = this->fOldWidth;
2347cb93a386Sopenharmony_ci    paragraph->fOldHeight = this->fOldHeight;
2348cb93a386Sopenharmony_ci    paragraph->fMaxWidthWithTrailingSpaces = this->fMaxWidthWithTrailingSpaces;
2349cb93a386Sopenharmony_ci    paragraph->fOldMaxWidth = this->fOldMaxWidth;
2350cb93a386Sopenharmony_ci    paragraph->allTextWidth = this->allTextWidth;
2351cb93a386Sopenharmony_ci
2352cb93a386Sopenharmony_ci    paragraph->fUnicode = this->fUnicode;
2353cb93a386Sopenharmony_ci    paragraph->fHasLineBreaks = this->fHasLineBreaks;
2354cb93a386Sopenharmony_ci    paragraph->fHasWhitespacesInside = this->fHasWhitespacesInside;
2355cb93a386Sopenharmony_ci    paragraph->fTrailingSpaces = this->fTrailingSpaces;
2356cb93a386Sopenharmony_ci    paragraph->fLineNumber = this->fLineNumber;
2357cb93a386Sopenharmony_ci    paragraph->fEllipsisRange = this->fEllipsisRange;
2358cb93a386Sopenharmony_ci
2359cb93a386Sopenharmony_ci    for (auto& run : paragraph->fRuns) {
2360cb93a386Sopenharmony_ci        run.setOwner(paragraph.get());
2361cb93a386Sopenharmony_ci    }
2362cb93a386Sopenharmony_ci    for (auto& cluster : paragraph->fClusters) {
2363cb93a386Sopenharmony_ci        cluster.setOwner(paragraph.get());
2364cb93a386Sopenharmony_ci    }
2365cb93a386Sopenharmony_ci    for (auto& line : paragraph->fLines) {
2366cb93a386Sopenharmony_ci        line.setParagraphImpl(paragraph.get());
2367cb93a386Sopenharmony_ci    }
2368cb93a386Sopenharmony_ci    return paragraph;
2369cb93a386Sopenharmony_ci}
2370cb93a386Sopenharmony_ci
2371cb93a386Sopenharmony_ci}  // namespace textlayout
2372cb93a386Sopenharmony_ci}  // namespace skia
2373