1cb93a386Sopenharmony_ci// Copyright 2019 Google LLC.
2cb93a386Sopenharmony_ci
3cb93a386Sopenharmony_ci#include "include/core/SkBlurTypes.h"
4cb93a386Sopenharmony_ci#include "include/core/SkFont.h"
5cb93a386Sopenharmony_ci#include "include/core/SkFontMetrics.h"
6cb93a386Sopenharmony_ci#include "include/core/SkMaskFilter.h"
7cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
8cb93a386Sopenharmony_ci#include "include/core/SkSpan.h"
9cb93a386Sopenharmony_ci#include "include/core/SkString.h"
10cb93a386Sopenharmony_ci#include "include/core/SkTextBlob.h"
11cb93a386Sopenharmony_ci#include "include/core/SkTypes.h"
12cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h"
13cb93a386Sopenharmony_ci#include "include/private/SkTo.h"
14cb93a386Sopenharmony_ci#include "modules/skparagraph/include/DartTypes.h"
15cb93a386Sopenharmony_ci#include "modules/skparagraph/include/Metrics.h"
16cb93a386Sopenharmony_ci#include "modules/skparagraph/include/ParagraphPainter.h"
17cb93a386Sopenharmony_ci#include "modules/skparagraph/include/ParagraphStyle.h"
18cb93a386Sopenharmony_ci#include "modules/skparagraph/include/TextShadow.h"
19cb93a386Sopenharmony_ci#include "modules/skparagraph/include/TextStyle.h"
20cb93a386Sopenharmony_ci#include "modules/skparagraph/src/Decorations.h"
21cb93a386Sopenharmony_ci#include "modules/skparagraph/src/ParagraphImpl.h"
22cb93a386Sopenharmony_ci#include "modules/skparagraph/src/ParagraphPainterImpl.h"
23cb93a386Sopenharmony_ci#include "modules/skparagraph/src/TextLine.h"
24cb93a386Sopenharmony_ci#include "modules/skshaper/include/SkShaper.h"
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci#include <algorithm>
27cb93a386Sopenharmony_ci#include <iterator>
28cb93a386Sopenharmony_ci#include <limits>
29cb93a386Sopenharmony_ci#include <map>
30cb93a386Sopenharmony_ci#include <memory>
31cb93a386Sopenharmony_ci#include <tuple>
32cb93a386Sopenharmony_ci#include <type_traits>
33cb93a386Sopenharmony_ci#include <utility>
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
36cb93a386Sopenharmony_ci#include "log.h"
37cb93a386Sopenharmony_ci#include "modules/skparagraph/src/RunBaseImpl.h"
38cb93a386Sopenharmony_ci#include "modules/skparagraph/src/TextLineBaseImpl.h"
39cb93a386Sopenharmony_ci#include "TextParameter.h"
40cb93a386Sopenharmony_ci#endif
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_cinamespace skia {
43cb93a386Sopenharmony_cinamespace textlayout {
44cb93a386Sopenharmony_ci#define MAX_INT_VALUE 0x7FFFFFFF
45cb93a386Sopenharmony_ci#define EMOJI_UNICODE_START 0x1F300
46cb93a386Sopenharmony_ci#define EMOJI_UNICODE_END 0x1F9EF
47cb93a386Sopenharmony_ci#define EMOJI_WIDTH 4
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_cinamespace {
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ci// TODO: deal with all the intersection functionality
52cb93a386Sopenharmony_ciTextRange intersected(const TextRange& a, const TextRange& b) {
53cb93a386Sopenharmony_ci    if (a.start == b.start && a.end == b.end) return a;
54cb93a386Sopenharmony_ci    auto begin = std::max(a.start, b.start);
55cb93a386Sopenharmony_ci    auto end = std::min(a.end, b.end);
56cb93a386Sopenharmony_ci    return end >= begin ? TextRange(begin, end) : EMPTY_TEXT;
57cb93a386Sopenharmony_ci}
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ciSkScalar littleRound(SkScalar a) {
60cb93a386Sopenharmony_ci    // This rounding is done to match Flutter tests. Must be removed..
61cb93a386Sopenharmony_ci  return SkScalarRoundToScalar(a * 100.0)/100.0;
62cb93a386Sopenharmony_ci}
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ciTextRange operator*(const TextRange& a, const TextRange& b) {
65cb93a386Sopenharmony_ci    if (a.start == b.start && a.end == b.end) return a;
66cb93a386Sopenharmony_ci    auto begin = std::max(a.start, b.start);
67cb93a386Sopenharmony_ci    auto end = std::min(a.end, b.end);
68cb93a386Sopenharmony_ci    return end > begin ? TextRange(begin, end) : EMPTY_TEXT;
69cb93a386Sopenharmony_ci}
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_ciint compareRound(SkScalar a, SkScalar b, bool applyRoundingHack) {
72cb93a386Sopenharmony_ci    // There is a rounding error that gets bigger when maxWidth gets bigger
73cb93a386Sopenharmony_ci    // VERY long zalgo text (> 100000) on a VERY long line (> 10000)
74cb93a386Sopenharmony_ci    // Canvas scaling affects it
75cb93a386Sopenharmony_ci    // Letter spacing affects it
76cb93a386Sopenharmony_ci    // It has to be relative to be useful
77cb93a386Sopenharmony_ci    auto base = std::max(SkScalarAbs(a), SkScalarAbs(b));
78cb93a386Sopenharmony_ci    auto diff = SkScalarAbs(a - b);
79cb93a386Sopenharmony_ci    if (nearlyZero(base) || diff / base < 0.001f) {
80cb93a386Sopenharmony_ci        return 0;
81cb93a386Sopenharmony_ci    }
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci    auto ra = a;
84cb93a386Sopenharmony_ci    auto rb = b;
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci    if (applyRoundingHack) {
87cb93a386Sopenharmony_ci        ra = littleRound(a);
88cb93a386Sopenharmony_ci        rb = littleRound(b);
89cb93a386Sopenharmony_ci    }
90cb93a386Sopenharmony_ci    if (ra < rb) {
91cb93a386Sopenharmony_ci        return -1;
92cb93a386Sopenharmony_ci    } else {
93cb93a386Sopenharmony_ci        return 1;
94cb93a386Sopenharmony_ci    }
95cb93a386Sopenharmony_ci}
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ci#ifdef USE_SKIA_TXT
98cb93a386Sopenharmony_cibool IsRSFontEquals(const RSFont& font0, const RSFont& font1) {
99cb93a386Sopenharmony_ci    auto f0 = const_cast<RSFont&>(font0);
100cb93a386Sopenharmony_ci    auto f1 = const_cast<RSFont&>(font1);
101cb93a386Sopenharmony_ci    return f0.GetTypeface().get() == f1.GetTypeface().get() &&
102cb93a386Sopenharmony_ci        f0.GetSize() == f1.GetSize() &&
103cb93a386Sopenharmony_ci        f0.GetScaleX() == f1.GetScaleX() &&
104cb93a386Sopenharmony_ci        f0.GetSkewX() == f1.GetSkewX() &&
105cb93a386Sopenharmony_ci        f0.GetEdging() == f1.GetEdging() &&
106cb93a386Sopenharmony_ci        f0.GetHinting() == f1.GetHinting();
107cb93a386Sopenharmony_ci}
108cb93a386Sopenharmony_ci#endif
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_ci}  // namespace
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ciTextLine::TextLine(ParagraphImpl* owner,
113cb93a386Sopenharmony_ci                   SkVector offset,
114cb93a386Sopenharmony_ci                   SkVector advance,
115cb93a386Sopenharmony_ci                   BlockRange blocks,
116cb93a386Sopenharmony_ci                   TextRange textExcludingSpaces,
117cb93a386Sopenharmony_ci                   TextRange text,
118cb93a386Sopenharmony_ci                   TextRange textIncludingNewlines,
119cb93a386Sopenharmony_ci                   ClusterRange clusters,
120cb93a386Sopenharmony_ci                   ClusterRange clustersWithGhosts,
121cb93a386Sopenharmony_ci                   SkScalar widthWithSpaces,
122cb93a386Sopenharmony_ci                   InternalLineMetrics sizes)
123cb93a386Sopenharmony_ci        : fOwner(owner)
124cb93a386Sopenharmony_ci        , fBlockRange(blocks)
125cb93a386Sopenharmony_ci        , fTextExcludingSpaces(textExcludingSpaces)
126cb93a386Sopenharmony_ci        , fText(text)
127cb93a386Sopenharmony_ci        , fTextIncludingNewlines(textIncludingNewlines)
128cb93a386Sopenharmony_ci        , fClusterRange(clusters)
129cb93a386Sopenharmony_ci        , fGhostClusterRange(clustersWithGhosts)
130cb93a386Sopenharmony_ci        , fRunsInVisualOrder()
131cb93a386Sopenharmony_ci        , fAdvance(advance)
132cb93a386Sopenharmony_ci        , fOffset(offset)
133cb93a386Sopenharmony_ci        , fShift(0.0)
134cb93a386Sopenharmony_ci        , fWidthWithSpaces(widthWithSpaces)
135cb93a386Sopenharmony_ci        , fEllipsis(nullptr)
136cb93a386Sopenharmony_ci        , fSizes(sizes)
137cb93a386Sopenharmony_ci        , fHasBackground(false)
138cb93a386Sopenharmony_ci        , fHasShadows(false)
139cb93a386Sopenharmony_ci        , fHasDecorations(false)
140cb93a386Sopenharmony_ci        , fIsArcText(false)
141cb93a386Sopenharmony_ci        , fArcTextState(false)
142cb93a386Sopenharmony_ci        , fAscentStyle(LineMetricStyle::CSS)
143cb93a386Sopenharmony_ci        , fDescentStyle(LineMetricStyle::CSS)
144cb93a386Sopenharmony_ci        , fTextBlobCachePopulated(false) {
145cb93a386Sopenharmony_ci    // Reorder visual runs
146cb93a386Sopenharmony_ci    auto& start = owner->cluster(fGhostClusterRange.start);
147cb93a386Sopenharmony_ci    auto& end = owner->cluster(fGhostClusterRange.end - 1);
148cb93a386Sopenharmony_ci    size_t numRuns = end.runIndex() - start.runIndex() + 1;
149cb93a386Sopenharmony_ci
150cb93a386Sopenharmony_ci    for (BlockIndex index = fBlockRange.start; index < fBlockRange.end; ++index) {
151cb93a386Sopenharmony_ci        auto b = fOwner->styles().begin() + index;
152cb93a386Sopenharmony_ci        if (b->fStyle.hasBackground()) {
153cb93a386Sopenharmony_ci            fHasBackground = true;
154cb93a386Sopenharmony_ci        }
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
157cb93a386Sopenharmony_ci        if (b->fStyle.getDecorationType() != TextDecoration::kNoDecoration &&
158cb93a386Sopenharmony_ci            b->fStyle.getDecorationThicknessMultiplier() > 0) {
159cb93a386Sopenharmony_ci#else
160cb93a386Sopenharmony_ci        if (b->fStyle.getDecorationType() != TextDecoration::kNoDecoration) {
161cb93a386Sopenharmony_ci#endif
162cb93a386Sopenharmony_ci            fHasDecorations = true;
163cb93a386Sopenharmony_ci        }
164cb93a386Sopenharmony_ci        if (b->fStyle.getShadowNumber() > 0) {
165cb93a386Sopenharmony_ci            fHasShadows = true;
166cb93a386Sopenharmony_ci        }
167cb93a386Sopenharmony_ci    }
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_ci    // Get the logical order
170cb93a386Sopenharmony_ci
171cb93a386Sopenharmony_ci    // This is just chosen to catch the common/fast cases. Feel free to tweak.
172cb93a386Sopenharmony_ci    constexpr int kPreallocCount = 4;
173cb93a386Sopenharmony_ci    SkAutoSTArray<kPreallocCount, SkUnicode::BidiLevel> runLevels(numRuns);
174cb93a386Sopenharmony_ci    std::vector<RunIndex> placeholdersInOriginalOrder;
175cb93a386Sopenharmony_ci    size_t runLevelsIndex = 0;
176cb93a386Sopenharmony_ci    // Placeholders must be laid out using the original order in which they were added
177cb93a386Sopenharmony_ci    // in the input. The API does not provide a way to indicate that a placeholder
178cb93a386Sopenharmony_ci    // position was moved due to bidi reordering.
179cb93a386Sopenharmony_ci    for (auto runIndex = start.runIndex(); runIndex <= end.runIndex(); ++runIndex) {
180cb93a386Sopenharmony_ci        auto& run = fOwner->run(runIndex);
181cb93a386Sopenharmony_ci        runLevels[runLevelsIndex++] = run.fBidiLevel;
182cb93a386Sopenharmony_ci        fMaxRunMetrics.add(
183cb93a386Sopenharmony_ci            InternalLineMetrics(run.correctAscent(), run.correctDescent(), run.fFontMetrics.fLeading));
184cb93a386Sopenharmony_ci        if (run.isPlaceholder()) {
185cb93a386Sopenharmony_ci            placeholdersInOriginalOrder.push_back(runIndex);
186cb93a386Sopenharmony_ci        }
187cb93a386Sopenharmony_ci    }
188cb93a386Sopenharmony_ci    SkASSERT(runLevelsIndex == numRuns);
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_ci    SkAutoSTArray<kPreallocCount, int32_t> logicalOrder(numRuns);
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci    // TODO: hide all these logic in SkUnicode?
193cb93a386Sopenharmony_ci    fOwner->getUnicode()->reorderVisual(runLevels.data(), numRuns, logicalOrder.data());
194cb93a386Sopenharmony_ci    auto firstRunIndex = start.runIndex();
195cb93a386Sopenharmony_ci    auto placeholderIter = placeholdersInOriginalOrder.begin();
196cb93a386Sopenharmony_ci    for (auto index : logicalOrder) {
197cb93a386Sopenharmony_ci        auto runIndex = firstRunIndex + index;
198cb93a386Sopenharmony_ci        if (fOwner->run(runIndex).isPlaceholder()) {
199cb93a386Sopenharmony_ci            fRunsInVisualOrder.push_back(*placeholderIter++);
200cb93a386Sopenharmony_ci        } else {
201cb93a386Sopenharmony_ci            fRunsInVisualOrder.push_back(runIndex);
202cb93a386Sopenharmony_ci        }
203cb93a386Sopenharmony_ci    }
204cb93a386Sopenharmony_ci
205cb93a386Sopenharmony_ci    fTextRangeReplacedByEllipsis = EMPTY_RANGE;
206cb93a386Sopenharmony_ci    fEllipsisIndex = EMPTY_INDEX;
207cb93a386Sopenharmony_ci    fLastClipRunLtr = false;
208cb93a386Sopenharmony_ci}
209cb93a386Sopenharmony_ci
210cb93a386Sopenharmony_civoid TextLine::paint(ParagraphPainter* painter, const RSPath* path, SkScalar hOffset, SkScalar vOffset) {
211cb93a386Sopenharmony_ci    prepareRoundRect();
212cb93a386Sopenharmony_ci    fIsArcText = true;
213cb93a386Sopenharmony_ci    if (pathParameters.hOffset != hOffset || pathParameters.vOffset != vOffset) {
214cb93a386Sopenharmony_ci        fTextBlobCachePopulated = false;
215cb93a386Sopenharmony_ci    }
216cb93a386Sopenharmony_ci    pathParameters.recordPath = path;
217cb93a386Sopenharmony_ci    pathParameters.hOffset = hOffset;
218cb93a386Sopenharmony_ci    pathParameters.vOffset = vOffset;
219cb93a386Sopenharmony_ci    this->ensureTextBlobCachePopulated();
220cb93a386Sopenharmony_ci    for (auto& record : fTextBlobCache) {
221cb93a386Sopenharmony_ci        record.paint(painter);
222cb93a386Sopenharmony_ci    }
223cb93a386Sopenharmony_ci}
224cb93a386Sopenharmony_ci
225cb93a386Sopenharmony_civoid TextLine::paint(ParagraphPainter* painter, SkScalar x, SkScalar y) {
226cb93a386Sopenharmony_ci    prepareRoundRect();
227cb93a386Sopenharmony_ci    fIsArcText = false;
228cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
229cb93a386Sopenharmony_ci    this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, true,
230cb93a386Sopenharmony_ci#else
231cb93a386Sopenharmony_ci    this->iterateThroughVisualRuns(false,
232cb93a386Sopenharmony_ci#endif
233cb93a386Sopenharmony_ci        [painter, x, y, this]
234cb93a386Sopenharmony_ci        (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) {
235cb93a386Sopenharmony_ci            *runWidthInLine = this->iterateThroughSingleRunByStyles(
236cb93a386Sopenharmony_ci            TextAdjustment::GlyphCluster, run, runOffsetInLine, textRange, StyleType::kBackground,
237cb93a386Sopenharmony_ci            [painter, x, y, run, this](TextRange textRange, const TextStyle& style, const ClipContext& context) {
238cb93a386Sopenharmony_ci                if (fHasBackground) {
239cb93a386Sopenharmony_ci                    this->paintBackground(painter, x, y, textRange, style, context);
240cb93a386Sopenharmony_ci                }
241cb93a386Sopenharmony_ci                paintRoundRect(painter, x, y, run);
242cb93a386Sopenharmony_ci            });
243cb93a386Sopenharmony_ci        return true;
244cb93a386Sopenharmony_ci        });
245cb93a386Sopenharmony_ci
246cb93a386Sopenharmony_ci    if (fHasShadows) {
247cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
248cb93a386Sopenharmony_ci        this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, false,
249cb93a386Sopenharmony_ci#else
250cb93a386Sopenharmony_ci        this->iterateThroughVisualRuns(false,
251cb93a386Sopenharmony_ci#endif
252cb93a386Sopenharmony_ci            [painter, x, y, this]
253cb93a386Sopenharmony_ci            (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) {
254cb93a386Sopenharmony_ci            *runWidthInLine = this->iterateThroughSingleRunByStyles(
255cb93a386Sopenharmony_ci                TextAdjustment::GlyphCluster, run, runOffsetInLine, textRange, StyleType::kShadow,
256cb93a386Sopenharmony_ci                [painter, x, y, this]
257cb93a386Sopenharmony_ci                (TextRange textRange, const TextStyle& style, const ClipContext& context) {
258cb93a386Sopenharmony_ci                    this->paintShadow(painter, x, y, textRange, style, context);
259cb93a386Sopenharmony_ci                });
260cb93a386Sopenharmony_ci            return true;
261cb93a386Sopenharmony_ci            });
262cb93a386Sopenharmony_ci    }
263cb93a386Sopenharmony_ci
264cb93a386Sopenharmony_ci    this->ensureTextBlobCachePopulated();
265cb93a386Sopenharmony_ci
266cb93a386Sopenharmony_ci    for (auto& record : fTextBlobCache) {
267cb93a386Sopenharmony_ci        record.paint(painter, x, y);
268cb93a386Sopenharmony_ci    }
269cb93a386Sopenharmony_ci
270cb93a386Sopenharmony_ci    if (fHasDecorations) {
271cb93a386Sopenharmony_ci        this->fDecorationContext = {0.0f, 0.0f, 0.0f};
272cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
273cb93a386Sopenharmony_ci        this->iterateThroughVisualRuns(EllipsisReadStrategy::DEFAULT, true,
274cb93a386Sopenharmony_ci#else
275cb93a386Sopenharmony_ci        this->iterateThroughVisualRuns(false,
276cb93a386Sopenharmony_ci#endif
277cb93a386Sopenharmony_ci            [painter, x, y, this]
278cb93a386Sopenharmony_ci            (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) {
279cb93a386Sopenharmony_ci                *runWidthInLine = this->iterateThroughSingleRunByStyles(
280cb93a386Sopenharmony_ci                    TextAdjustment::GlyphCluster, run, runOffsetInLine, textRange,
281cb93a386Sopenharmony_ci                    StyleType::kDecorations, [painter, x, y, this]
282cb93a386Sopenharmony_ci                    (TextRange textRange, const TextStyle& style, const ClipContext& context) {
283cb93a386Sopenharmony_ci                    if (style.getDecoration().fType == TextDecoration::kUnderline) {
284cb93a386Sopenharmony_ci                        SkScalar tmpThick = this->calculateThickness(style, context);
285cb93a386Sopenharmony_ci                        fDecorationContext.thickness = fDecorationContext.thickness > tmpThick ?
286cb93a386Sopenharmony_ci                            fDecorationContext.thickness : tmpThick;
287cb93a386Sopenharmony_ci                    }
288cb93a386Sopenharmony_ci                });
289cb93a386Sopenharmony_ci                return true;
290cb93a386Sopenharmony_ci        });
291cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
292cb93a386Sopenharmony_ci        this->iterateThroughVisualRuns(EllipsisReadStrategy::DEFAULT, true,
293cb93a386Sopenharmony_ci#else
294cb93a386Sopenharmony_ci        this->iterateThroughVisualRuns(false,
295cb93a386Sopenharmony_ci#endif
296cb93a386Sopenharmony_ci            [painter, x, y, this]
297cb93a386Sopenharmony_ci            (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) {
298cb93a386Sopenharmony_ci                *runWidthInLine = this->iterateThroughSingleRunByStyles(
299cb93a386Sopenharmony_ci                TextAdjustment::GlyphCluster, run, runOffsetInLine, textRange, StyleType::kDecorations,
300cb93a386Sopenharmony_ci                [painter, x, y, this]
301cb93a386Sopenharmony_ci                (TextRange textRange, const TextStyle& style, const ClipContext& context) {
302cb93a386Sopenharmony_ci                    // 12% of row height.
303cb93a386Sopenharmony_ci                    fDecorationContext.underlinePosition = (fSizes.height() * 0.12 + this->baseline());
304cb93a386Sopenharmony_ci                    fDecorationContext.textBlobTop = fSizes.height() * 0.12;
305cb93a386Sopenharmony_ci                    this->paintDecorations(painter, x, y, textRange, style, context);
306cb93a386Sopenharmony_ci                });
307cb93a386Sopenharmony_ci                return true;
308cb93a386Sopenharmony_ci        });
309cb93a386Sopenharmony_ci    }
310cb93a386Sopenharmony_ci}
311cb93a386Sopenharmony_ci
312cb93a386Sopenharmony_cibool TextLine::hasBackgroundRect(const RoundRectAttr& attr) {
313cb93a386Sopenharmony_ci    return attr.roundRectStyle.color != 0 && attr.rect.width() > 0;
314cb93a386Sopenharmony_ci}
315cb93a386Sopenharmony_ci
316cb93a386Sopenharmony_civoid TextLine::computeRoundRect(int& index, int& preIndex, std::vector<Run*>& groupRuns, Run* run) {
317cb93a386Sopenharmony_ci    int runCount = roundRectAttrs.size();
318cb93a386Sopenharmony_ci    if (index >= runCount) {
319cb93a386Sopenharmony_ci        return;
320cb93a386Sopenharmony_ci    }
321cb93a386Sopenharmony_ci
322cb93a386Sopenharmony_ci    bool leftRound = false;
323cb93a386Sopenharmony_ci    bool rightRound = false;
324cb93a386Sopenharmony_ci    if (hasBackgroundRect(roundRectAttrs[index])) {
325cb93a386Sopenharmony_ci        int styleId = roundRectAttrs[index].styleId;
326cb93a386Sopenharmony_ci        // index - 1 is previous index, -1 is the invalid styleId
327cb93a386Sopenharmony_ci        int preStyleId = index == 0 ? -1 : roundRectAttrs[index - 1].styleId;
328cb93a386Sopenharmony_ci        // runCount - 1 is the last run index, index + 1 is next run index, -1 is the invalid styleId
329cb93a386Sopenharmony_ci        int nextStyleId = index == runCount - 1 ? -1 : roundRectAttrs[index + 1].styleId;
330cb93a386Sopenharmony_ci        // index - preIndex > 1 means the left run has no background rect
331cb93a386Sopenharmony_ci        leftRound = (preIndex < 0 || index - preIndex > 1 || preStyleId != styleId);
332cb93a386Sopenharmony_ci        // runCount - 1 is the last run index
333cb93a386Sopenharmony_ci        rightRound = (index == runCount - 1 || !hasBackgroundRect(roundRectAttrs[index + 1]) ||
334cb93a386Sopenharmony_ci            nextStyleId != styleId);
335cb93a386Sopenharmony_ci        preIndex = index;
336cb93a386Sopenharmony_ci        groupRuns.push_back(run);
337cb93a386Sopenharmony_ci    } else if (!groupRuns.empty()) {
338cb93a386Sopenharmony_ci        groupRuns.erase(groupRuns.begin(), groupRuns.end());
339cb93a386Sopenharmony_ci    }
340cb93a386Sopenharmony_ci    if (leftRound && rightRound) {
341cb93a386Sopenharmony_ci        run->setRoundRectType(RoundRectType::ALL);
342cb93a386Sopenharmony_ci    } else if (leftRound) {
343cb93a386Sopenharmony_ci        run->setRoundRectType(RoundRectType::LEFT_ONLY);
344cb93a386Sopenharmony_ci    } else if (rightRound) {
345cb93a386Sopenharmony_ci        run->setRoundRectType(RoundRectType::RIGHT_ONLY);
346cb93a386Sopenharmony_ci    } else {
347cb93a386Sopenharmony_ci        run->setRoundRectType(RoundRectType::NONE);
348cb93a386Sopenharmony_ci    }
349cb93a386Sopenharmony_ci
350cb93a386Sopenharmony_ci    if (rightRound && !groupRuns.empty()) {
351cb93a386Sopenharmony_ci        double maxRoundRectRadius = MAX_INT_VALUE;
352cb93a386Sopenharmony_ci        double minTop = MAX_INT_VALUE;
353cb93a386Sopenharmony_ci        double maxBottom = 0;
354cb93a386Sopenharmony_ci        for (auto &gRun : groupRuns) {
355cb93a386Sopenharmony_ci            RoundRectAttr& attr = roundRectAttrs[gRun->getIndexInLine()];
356cb93a386Sopenharmony_ci            maxRoundRectRadius = std::fmin(std::fmin(attr.rect.width(), attr.rect.height()), maxRoundRectRadius);
357cb93a386Sopenharmony_ci            minTop = std::fmin(minTop, attr.rect.top());
358cb93a386Sopenharmony_ci            maxBottom = std::fmax(maxBottom, attr.rect.bottom());
359cb93a386Sopenharmony_ci        }
360cb93a386Sopenharmony_ci        for (auto &gRun : groupRuns) {
361cb93a386Sopenharmony_ci            gRun->setMaxRoundRectRadius(maxRoundRectRadius);
362cb93a386Sopenharmony_ci            gRun->setTopInGroup(minTop - gRun->offset().y());
363cb93a386Sopenharmony_ci            gRun->setBottomInGroup(maxBottom - gRun->offset().y());
364cb93a386Sopenharmony_ci        }
365cb93a386Sopenharmony_ci        groupRuns.erase(groupRuns.begin(), groupRuns.end());
366cb93a386Sopenharmony_ci    }
367cb93a386Sopenharmony_ci    index++;
368cb93a386Sopenharmony_ci}
369cb93a386Sopenharmony_ci
370cb93a386Sopenharmony_civoid TextLine::prepareRoundRect() {
371cb93a386Sopenharmony_ci    roundRectAttrs.clear();
372cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
373cb93a386Sopenharmony_ci        this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, true,
374cb93a386Sopenharmony_ci#else
375cb93a386Sopenharmony_ci        this->iterateThroughVisualRuns(true,
376cb93a386Sopenharmony_ci#endif
377cb93a386Sopenharmony_ci        [this](const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) {
378cb93a386Sopenharmony_ci            *runWidthInLine = this->iterateThroughSingleRunByStyles(
379cb93a386Sopenharmony_ci            TextAdjustment::GlyphCluster, run, runOffsetInLine, textRange, StyleType::kBackground,
380cb93a386Sopenharmony_ci            [run, this](TextRange textRange, const TextStyle& style, const ClipContext& context) {
381cb93a386Sopenharmony_ci                roundRectAttrs.push_back({style.getStyleId(), style.getBackgroundRect(), context.clip});
382cb93a386Sopenharmony_ci            });
383cb93a386Sopenharmony_ci            return true;
384cb93a386Sopenharmony_ci        });
385cb93a386Sopenharmony_ci
386cb93a386Sopenharmony_ci    std::vector<Run*> groupRuns;
387cb93a386Sopenharmony_ci    int index = 0;
388cb93a386Sopenharmony_ci    int preIndex = -1;
389cb93a386Sopenharmony_ci    for (auto& runIndex : fRunsInVisualOrder) {
390cb93a386Sopenharmony_ci        auto run = &this->fOwner->run(runIndex);
391cb93a386Sopenharmony_ci        run->setIndexInLine(static_cast<size_t>(index));
392cb93a386Sopenharmony_ci        computeRoundRect(index, preIndex, groupRuns, run);
393cb93a386Sopenharmony_ci    }
394cb93a386Sopenharmony_ci}
395cb93a386Sopenharmony_ci
396cb93a386Sopenharmony_civoid TextLine::ensureTextBlobCachePopulated() {
397cb93a386Sopenharmony_ci    if (fTextBlobCachePopulated && fArcTextState == fIsArcText) {
398cb93a386Sopenharmony_ci        return;
399cb93a386Sopenharmony_ci    }
400cb93a386Sopenharmony_ci    fTextBlobCache.clear();
401cb93a386Sopenharmony_ci    if (fBlockRange.width() == 1 &&
402cb93a386Sopenharmony_ci        fRunsInVisualOrder.size() == 1 &&
403cb93a386Sopenharmony_ci        fEllipsis == nullptr &&
404cb93a386Sopenharmony_ci        fOwner->run(fRunsInVisualOrder[0]).placeholderStyle() == nullptr) {
405cb93a386Sopenharmony_ci        if (fClusterRange.width() == 0) {
406cb93a386Sopenharmony_ci            return;
407cb93a386Sopenharmony_ci        }
408cb93a386Sopenharmony_ci        // Most common and most simple case
409cb93a386Sopenharmony_ci        const auto& style = fOwner->block(fBlockRange.start).fStyle;
410cb93a386Sopenharmony_ci        const auto& run = fOwner->run(fRunsInVisualOrder[0]);
411cb93a386Sopenharmony_ci        auto clip = SkRect::MakeXYWH(0.0f, this->sizes().runTop(&run, this->fAscentStyle),
412cb93a386Sopenharmony_ci                                     fAdvance.fX,
413cb93a386Sopenharmony_ci                                     run.calculateHeight(this->fAscentStyle, this->fDescentStyle));
414cb93a386Sopenharmony_ci
415cb93a386Sopenharmony_ci        auto& start = fOwner->cluster(fClusterRange.start);
416cb93a386Sopenharmony_ci        auto& end = fOwner->cluster(fClusterRange.end - 1);
417cb93a386Sopenharmony_ci        SkASSERT(start.runIndex() == end.runIndex());
418cb93a386Sopenharmony_ci        GlyphRange glyphs;
419cb93a386Sopenharmony_ci        if (run.leftToRight()) {
420cb93a386Sopenharmony_ci            glyphs = GlyphRange(start.startPos(),
421cb93a386Sopenharmony_ci                                end.isHardBreak() ? end.startPos() : end.endPos());
422cb93a386Sopenharmony_ci        } else {
423cb93a386Sopenharmony_ci            glyphs = GlyphRange(end.startPos(),
424cb93a386Sopenharmony_ci                                start.isHardBreak() ? start.startPos() : start.endPos());
425cb93a386Sopenharmony_ci        }
426cb93a386Sopenharmony_ci        ClipContext context = {/*run=*/&run,
427cb93a386Sopenharmony_ci                               /*pos=*/glyphs.start,
428cb93a386Sopenharmony_ci                               /*size=*/glyphs.width(),
429cb93a386Sopenharmony_ci                               /*fTextShift=*/-run.positionX(glyphs.start), // starting position
430cb93a386Sopenharmony_ci                               /*clip=*/clip,                               // entire line
431cb93a386Sopenharmony_ci                               /*fExcludedTrailingSpaces=*/0.0f,            // no need for that
432cb93a386Sopenharmony_ci                               /*clippingNeeded=*/false};                   // no need for that
433cb93a386Sopenharmony_ci        this->buildTextBlob(fTextExcludingSpaces, style, context);
434cb93a386Sopenharmony_ci    } else {
435cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
436cb93a386Sopenharmony_ci        this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_ELLIPSIS_WORD, false,
437cb93a386Sopenharmony_ci#else
438cb93a386Sopenharmony_ci        this->iterateThroughVisualRuns(false,
439cb93a386Sopenharmony_ci#endif
440cb93a386Sopenharmony_ci           [this](const Run* run,
441cb93a386Sopenharmony_ci                  SkScalar runOffsetInLine,
442cb93a386Sopenharmony_ci                  TextRange textRange,
443cb93a386Sopenharmony_ci                  SkScalar* runWidthInLine) {
444cb93a386Sopenharmony_ci               if (run->placeholderStyle() != nullptr) {
445cb93a386Sopenharmony_ci                   *runWidthInLine = run->advance().fX;
446cb93a386Sopenharmony_ci                   return true;
447cb93a386Sopenharmony_ci               }
448cb93a386Sopenharmony_ci               *runWidthInLine = this->iterateThroughSingleRunByStyles(
449cb93a386Sopenharmony_ci                   TextAdjustment::GlyphCluster,
450cb93a386Sopenharmony_ci                   run,
451cb93a386Sopenharmony_ci                   runOffsetInLine,
452cb93a386Sopenharmony_ci                   textRange,
453cb93a386Sopenharmony_ci                   StyleType::kForeground,
454cb93a386Sopenharmony_ci                   [this](TextRange textRange, const TextStyle& style, const ClipContext& context) {
455cb93a386Sopenharmony_ci                       this->buildTextBlob(textRange, style, context);
456cb93a386Sopenharmony_ci                   });
457cb93a386Sopenharmony_ci               return true;
458cb93a386Sopenharmony_ci           });
459cb93a386Sopenharmony_ci    }
460cb93a386Sopenharmony_ci    fTextBlobCachePopulated = true;
461cb93a386Sopenharmony_ci    fArcTextState = fIsArcText;
462cb93a386Sopenharmony_ci    pathParameters.recordPath = nullptr;
463cb93a386Sopenharmony_ci}
464cb93a386Sopenharmony_ci
465cb93a386Sopenharmony_civoid TextLine::format(TextAlign align, SkScalar maxWidth, EllipsisModal ellipsisModal) {
466cb93a386Sopenharmony_ci    SkScalar delta = maxWidth - this->widthWithEllipsisSpaces();
467cb93a386Sopenharmony_ci    if (delta <= 0) {
468cb93a386Sopenharmony_ci        return;
469cb93a386Sopenharmony_ci    }
470cb93a386Sopenharmony_ci
471cb93a386Sopenharmony_ci    // We do nothing for left align
472cb93a386Sopenharmony_ci    if (align == TextAlign::kJustify) {
473cb93a386Sopenharmony_ci        if (!this->endsWithHardLineBreak()) {
474cb93a386Sopenharmony_ci            this->justify(maxWidth);
475cb93a386Sopenharmony_ci        } else if (fOwner->paragraphStyle().getTextDirection() == TextDirection::kRtl) {
476cb93a386Sopenharmony_ci            // Justify -> Right align
477cb93a386Sopenharmony_ci            fShift = delta;
478cb93a386Sopenharmony_ci        }
479cb93a386Sopenharmony_ci    } else if (align == TextAlign::kRight) {
480cb93a386Sopenharmony_ci        fShift = delta;
481cb93a386Sopenharmony_ci    } else if (align == TextAlign::kCenter) {
482cb93a386Sopenharmony_ci        fShift = delta / 2;
483cb93a386Sopenharmony_ci    }
484cb93a386Sopenharmony_ci}
485cb93a386Sopenharmony_ci
486cb93a386Sopenharmony_ciSkScalar TextLine::calculateSpacing(const Cluster prevCluster, const Cluster curCluster)
487cb93a386Sopenharmony_ci{
488cb93a386Sopenharmony_ci    if (prevCluster.isWhitespaceBreak() || curCluster.isWhitespaceBreak()) {
489cb93a386Sopenharmony_ci        return 0;
490cb93a386Sopenharmony_ci    }
491cb93a386Sopenharmony_ci    if (prevCluster.isHardBreak() || curCluster.isHardBreak()) {
492cb93a386Sopenharmony_ci        return 0;
493cb93a386Sopenharmony_ci    }
494cb93a386Sopenharmony_ci    if (prevCluster.isCopyright() || curCluster.isCopyright()) {
495cb93a386Sopenharmony_ci        return prevCluster.getFontSize() / AUTO_SPACING_WIDTH_RATIO;
496cb93a386Sopenharmony_ci    }
497cb93a386Sopenharmony_ci    if ((curCluster.isCJK() && prevCluster.isWestern()) || (curCluster.isWestern() && prevCluster.isCJK())) {
498cb93a386Sopenharmony_ci        return prevCluster.getFontSize() / AUTO_SPACING_WIDTH_RATIO;
499cb93a386Sopenharmony_ci    }
500cb93a386Sopenharmony_ci    return 0;
501cb93a386Sopenharmony_ci}
502cb93a386Sopenharmony_ci
503cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
504cb93a386Sopenharmony_ciSkScalar TextLine::autoSpacing() {
505cb93a386Sopenharmony_ci    if (!TextParameter::GetAutoSpacingEnable()) {
506cb93a386Sopenharmony_ci        return 0;
507cb93a386Sopenharmony_ci    }
508cb93a386Sopenharmony_ci    SkScalar spacing = 0.0;
509cb93a386Sopenharmony_ci    auto prevCluster = fOwner->cluster(fClusterRange.start);
510cb93a386Sopenharmony_ci    for (auto clusterIndex = fClusterRange.start + 1; clusterIndex < fClusterRange.end; ++clusterIndex) {
511cb93a386Sopenharmony_ci        auto prevSpacing = spacing;
512cb93a386Sopenharmony_ci        auto& cluster = fOwner->cluster(clusterIndex);
513cb93a386Sopenharmony_ci        spacing += calculateSpacing(prevCluster, cluster);
514cb93a386Sopenharmony_ci        spacingCluster(&cluster, spacing, prevSpacing);
515cb93a386Sopenharmony_ci        prevCluster = cluster;
516cb93a386Sopenharmony_ci    }
517cb93a386Sopenharmony_ci    this->fWidthWithSpaces += spacing;
518cb93a386Sopenharmony_ci    this->fAdvance.fX += spacing;
519cb93a386Sopenharmony_ci    return spacing;
520cb93a386Sopenharmony_ci}
521cb93a386Sopenharmony_ci#endif
522cb93a386Sopenharmony_ci
523cb93a386Sopenharmony_civoid TextLine::scanStyles(StyleType styleType, const RunStyleVisitor& visitor) {
524cb93a386Sopenharmony_ci    if (this->empty()) {
525cb93a386Sopenharmony_ci        return;
526cb93a386Sopenharmony_ci    }
527cb93a386Sopenharmony_ci
528cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
529cb93a386Sopenharmony_ci    this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, false,
530cb93a386Sopenharmony_ci#else
531cb93a386Sopenharmony_ci    this->iterateThroughVisualRuns(false,
532cb93a386Sopenharmony_ci#endif
533cb93a386Sopenharmony_ci            [this, visitor, styleType](
534cb93a386Sopenharmony_ci                    const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width) {
535cb93a386Sopenharmony_ci                *width = this->iterateThroughSingleRunByStyles(
536cb93a386Sopenharmony_ci                        TextAdjustment::GlyphCluster,
537cb93a386Sopenharmony_ci                        run,
538cb93a386Sopenharmony_ci                        runOffset,
539cb93a386Sopenharmony_ci                        textRange,
540cb93a386Sopenharmony_ci                        styleType,
541cb93a386Sopenharmony_ci                        [visitor](TextRange textRange,
542cb93a386Sopenharmony_ci                                  const TextStyle& style,
543cb93a386Sopenharmony_ci                                  const ClipContext& context) {
544cb93a386Sopenharmony_ci                            visitor(textRange, style, context);
545cb93a386Sopenharmony_ci                        });
546cb93a386Sopenharmony_ci                return true;
547cb93a386Sopenharmony_ci            });
548cb93a386Sopenharmony_ci}
549cb93a386Sopenharmony_ci
550cb93a386Sopenharmony_ciSkRect TextLine::extendHeight(const ClipContext& context) const {
551cb93a386Sopenharmony_ci    SkRect result = context.clip;
552cb93a386Sopenharmony_ci    result.fBottom += std::max(this->fMaxRunMetrics.height() - this->height(), 0.0f);
553cb93a386Sopenharmony_ci    return result;
554cb93a386Sopenharmony_ci}
555cb93a386Sopenharmony_ci
556cb93a386Sopenharmony_civoid TextLine::buildTextBlob(TextRange textRange, const TextStyle& style, const ClipContext& context) {
557cb93a386Sopenharmony_ci    if (context.run->placeholderStyle() != nullptr) {
558cb93a386Sopenharmony_ci        return;
559cb93a386Sopenharmony_ci    }
560cb93a386Sopenharmony_ci
561cb93a386Sopenharmony_ci    fTextBlobCache.emplace_back();
562cb93a386Sopenharmony_ci    TextBlobRecord& record = fTextBlobCache.back();
563cb93a386Sopenharmony_ci
564cb93a386Sopenharmony_ci    if (style.hasForeground()) {
565cb93a386Sopenharmony_ci        record.fPaint = style.getForegroundPaintOrID();
566cb93a386Sopenharmony_ci    } else {
567cb93a386Sopenharmony_ci        std::get<SkPaint>(record.fPaint).setColor(style.getColor());
568cb93a386Sopenharmony_ci    }
569cb93a386Sopenharmony_ci    record.fVisitor_Run = context.run;
570cb93a386Sopenharmony_ci    record.fVisitor_Pos = context.pos;
571cb93a386Sopenharmony_ci    record.fVisitor_Size = context.size;
572cb93a386Sopenharmony_ci
573cb93a386Sopenharmony_ci    // TODO: This is the change for flutter, must be removed later
574cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
575cb93a386Sopenharmony_ci    SkTextBlobBuilder builder;
576cb93a386Sopenharmony_ci#else
577cb93a386Sopenharmony_ci    RSTextBlobBuilder builder;
578cb93a386Sopenharmony_ci#endif
579cb93a386Sopenharmony_ci    if (pathParameters.recordPath) {
580cb93a386Sopenharmony_ci        context.run->copyTo(builder,
581cb93a386Sopenharmony_ci                            pathParameters.recordPath,
582cb93a386Sopenharmony_ci                            pathParameters.hOffset,
583cb93a386Sopenharmony_ci                            pathParameters.vOffset,
584cb93a386Sopenharmony_ci                            context.fTextShift,
585cb93a386Sopenharmony_ci                            SkToU32(context.pos),
586cb93a386Sopenharmony_ci                            context.size);
587cb93a386Sopenharmony_ci    } else {
588cb93a386Sopenharmony_ci        context.run->copyTo(builder, SkToU32(context.pos), context.size);
589cb93a386Sopenharmony_ci    }
590cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
591cb93a386Sopenharmony_ci    // when letterspacing < 0, it causes the font is cliped. so the record fClippingNeeded is set false
592cb93a386Sopenharmony_ci#else
593cb93a386Sopenharmony_ci    record.fClippingNeeded = context.clippingNeeded;
594cb93a386Sopenharmony_ci#endif
595cb93a386Sopenharmony_ci    if (context.clippingNeeded) {
596cb93a386Sopenharmony_ci        record.fClipRect = extendHeight(context).makeOffset(this->offset());
597cb93a386Sopenharmony_ci    } else {
598cb93a386Sopenharmony_ci        record.fClipRect = context.clip.makeOffset(this->offset());
599cb93a386Sopenharmony_ci    }
600cb93a386Sopenharmony_ci
601cb93a386Sopenharmony_ci    SkASSERT(nearlyEqual(context.run->baselineShift(), style.getBaselineShift()));
602cb93a386Sopenharmony_ci    SkScalar correctedBaseline = SkScalarFloorToScalar(this->baseline() + style.getBaselineShift() +  0.5);
603cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
604cb93a386Sopenharmony_ci    record.fBlob = builder.make();
605cb93a386Sopenharmony_ci    if (record.fBlob != nullptr) {
606cb93a386Sopenharmony_ci        record.fBounds.joinPossiblyEmptyRect(record.fBlob->bounds());
607cb93a386Sopenharmony_ci    }
608cb93a386Sopenharmony_ci#else
609cb93a386Sopenharmony_ci    record.fBlob = builder.Make();
610cb93a386Sopenharmony_ci    if (record.fBlob != nullptr) {
611cb93a386Sopenharmony_ci        auto bounds = record.fBlob->Bounds();
612cb93a386Sopenharmony_ci        if (bounds) {
613cb93a386Sopenharmony_ci            record.fBounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(
614cb93a386Sopenharmony_ci                bounds->left_, bounds->top_, bounds->right_, bounds->bottom_
615cb93a386Sopenharmony_ci            ));
616cb93a386Sopenharmony_ci        }
617cb93a386Sopenharmony_ci    }
618cb93a386Sopenharmony_ci#endif
619cb93a386Sopenharmony_ci
620cb93a386Sopenharmony_ci    record.fOffset = SkPoint::Make(this->offset().fX + context.fTextShift,
621cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
622cb93a386Sopenharmony_ci        this->offset().fY + correctedBaseline - (context.run ? context.run->fCompressionBaselineShift : 0));
623cb93a386Sopenharmony_ci#else
624cb93a386Sopenharmony_ci                                   this->offset().fY + correctedBaseline);
625cb93a386Sopenharmony_ci#endif
626cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
627cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
628cb93a386Sopenharmony_ci    SkFont font;
629cb93a386Sopenharmony_ci#else
630cb93a386Sopenharmony_ci    RSFont font;
631cb93a386Sopenharmony_ci#endif
632cb93a386Sopenharmony_ci    if (record.fBlob != nullptr && record.fVisitor_Run != nullptr) {
633cb93a386Sopenharmony_ci        font = record.fVisitor_Run->font();
634cb93a386Sopenharmony_ci        if (font.GetTypeface() != nullptr &&
635cb93a386Sopenharmony_ci            (font.GetTypeface()->GetFamilyName().find("Emoji") != std::string::npos ||
636cb93a386Sopenharmony_ci            font.GetTypeface()->GetFamilyName().find("emoji") != std::string::npos)) {
637cb93a386Sopenharmony_ci                record.fBlob->SetEmoji(true);
638cb93a386Sopenharmony_ci        }
639cb93a386Sopenharmony_ci    }
640cb93a386Sopenharmony_ci#endif
641cb93a386Sopenharmony_ci}
642cb93a386Sopenharmony_ci
643cb93a386Sopenharmony_civoid TextLine::TextBlobRecord::paint(ParagraphPainter* painter, SkScalar x, SkScalar y) {
644cb93a386Sopenharmony_ci    if (fClippingNeeded) {
645cb93a386Sopenharmony_ci        painter->save();
646cb93a386Sopenharmony_ci        painter->clipRect(fClipRect.makeOffset(x, y));
647cb93a386Sopenharmony_ci    }
648cb93a386Sopenharmony_ci    painter->drawTextBlob(fBlob, x + fOffset.x(), y + fOffset.y(), fPaint);
649cb93a386Sopenharmony_ci    if (fClippingNeeded) {
650cb93a386Sopenharmony_ci        painter->restore();
651cb93a386Sopenharmony_ci    }
652cb93a386Sopenharmony_ci}
653cb93a386Sopenharmony_ci
654cb93a386Sopenharmony_civoid TextLine::TextBlobRecord::paint(ParagraphPainter* painter) {
655cb93a386Sopenharmony_ci    if (fClippingNeeded) {
656cb93a386Sopenharmony_ci        painter->save();
657cb93a386Sopenharmony_ci    }
658cb93a386Sopenharmony_ci    painter->drawTextBlob(fBlob, 0, 0, fPaint);
659cb93a386Sopenharmony_ci    if (fClippingNeeded) {
660cb93a386Sopenharmony_ci        painter->restore();
661cb93a386Sopenharmony_ci    }
662cb93a386Sopenharmony_ci}
663cb93a386Sopenharmony_ci
664cb93a386Sopenharmony_civoid TextLine::paintBackground(ParagraphPainter* painter,
665cb93a386Sopenharmony_ci                               SkScalar x,
666cb93a386Sopenharmony_ci                               SkScalar y,
667cb93a386Sopenharmony_ci                               TextRange textRange,
668cb93a386Sopenharmony_ci                               const TextStyle& style,
669cb93a386Sopenharmony_ci                               const ClipContext& context) const {
670cb93a386Sopenharmony_ci    if (style.hasBackground()) {
671cb93a386Sopenharmony_ci        painter->drawRect(context.clip.makeOffset(this->offset() + SkPoint::Make(x, y)),
672cb93a386Sopenharmony_ci                          style.getBackgroundPaintOrID());
673cb93a386Sopenharmony_ci    }
674cb93a386Sopenharmony_ci}
675cb93a386Sopenharmony_ci
676cb93a386Sopenharmony_civoid TextLine::paintRoundRect(ParagraphPainter* painter, SkScalar x, SkScalar y, const Run* run) const {
677cb93a386Sopenharmony_ci    size_t index = run->getIndexInLine();
678cb93a386Sopenharmony_ci    if (index >= roundRectAttrs.size()) {
679cb93a386Sopenharmony_ci        return;
680cb93a386Sopenharmony_ci    }
681cb93a386Sopenharmony_ci
682cb93a386Sopenharmony_ci    const RoundRectAttr& attr = roundRectAttrs[index];
683cb93a386Sopenharmony_ci    if (attr.roundRectStyle.color == 0) {
684cb93a386Sopenharmony_ci        return;
685cb93a386Sopenharmony_ci    }
686cb93a386Sopenharmony_ci
687cb93a386Sopenharmony_ci    SkScalar ltRadius = 0.0f;
688cb93a386Sopenharmony_ci    SkScalar rtRadius = 0.0f;
689cb93a386Sopenharmony_ci    SkScalar rbRadius = 0.0f;
690cb93a386Sopenharmony_ci    SkScalar lbRadius = 0.0f;
691cb93a386Sopenharmony_ci    RoundRectType rType = run->getRoundRectType();
692cb93a386Sopenharmony_ci    if (rType == RoundRectType::ALL || rType == RoundRectType::LEFT_ONLY) {
693cb93a386Sopenharmony_ci        ltRadius = std::fmin(attr.roundRectStyle.leftTopRadius, run->getMaxRoundRectRadius());
694cb93a386Sopenharmony_ci        lbRadius = std::fmin(attr.roundRectStyle.leftBottomRadius, run->getMaxRoundRectRadius());
695cb93a386Sopenharmony_ci    }
696cb93a386Sopenharmony_ci    if (rType == RoundRectType::ALL || rType == RoundRectType::RIGHT_ONLY) {
697cb93a386Sopenharmony_ci        rtRadius = std::fmin(attr.roundRectStyle.rightTopRadius, run->getMaxRoundRectRadius());
698cb93a386Sopenharmony_ci        rbRadius = std::fmin(attr.roundRectStyle.rightBottomRadius, run->getMaxRoundRectRadius());
699cb93a386Sopenharmony_ci    }
700cb93a386Sopenharmony_ci    const SkVector radii[4] = {{ltRadius, ltRadius}, {rtRadius, rtRadius}, {rbRadius, rbRadius}, {lbRadius, lbRadius}};
701cb93a386Sopenharmony_ci    SkRect skRect(SkRect::MakeLTRB(attr.rect.left(), run->getTopInGroup(), attr.rect.right(),
702cb93a386Sopenharmony_ci        run->getBottomInGroup()));
703cb93a386Sopenharmony_ci    SkRRect skRRect;
704cb93a386Sopenharmony_ci    skRRect.setRectRadii(skRect, radii);
705cb93a386Sopenharmony_ci    skRRect.offset(x + this->offset().x(), y + this->offset().y());
706cb93a386Sopenharmony_ci    painter->drawRRect(skRRect, attr.roundRectStyle.color);
707cb93a386Sopenharmony_ci}
708cb93a386Sopenharmony_ci
709cb93a386Sopenharmony_civoid TextLine::paintShadow(ParagraphPainter* painter,
710cb93a386Sopenharmony_ci                           SkScalar x,
711cb93a386Sopenharmony_ci                           SkScalar y,
712cb93a386Sopenharmony_ci                           TextRange textRange,
713cb93a386Sopenharmony_ci                           const TextStyle& style,
714cb93a386Sopenharmony_ci                           const ClipContext& context) const {
715cb93a386Sopenharmony_ci    SkScalar correctedBaseline = SkScalarFloorToScalar(this->baseline() + style.getBaselineShift() + 0.5);
716cb93a386Sopenharmony_ci
717cb93a386Sopenharmony_ci    for (TextShadow shadow : style.getShadows()) {
718cb93a386Sopenharmony_ci        if (!shadow.hasShadow()) continue;
719cb93a386Sopenharmony_ci
720cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
721cb93a386Sopenharmony_ci        SkTextBlobBuilder builder;
722cb93a386Sopenharmony_ci#else
723cb93a386Sopenharmony_ci        RSTextBlobBuilder builder;
724cb93a386Sopenharmony_ci#endif
725cb93a386Sopenharmony_ci        context.run->copyTo(builder, context.pos, context.size);
726cb93a386Sopenharmony_ci
727cb93a386Sopenharmony_ci        if (context.clippingNeeded) {
728cb93a386Sopenharmony_ci            painter->save();
729cb93a386Sopenharmony_ci            SkRect clip = extendHeight(context);
730cb93a386Sopenharmony_ci            clip.offset(x, y);
731cb93a386Sopenharmony_ci            clip.offset(this->offset());
732cb93a386Sopenharmony_ci            painter->clipRect(clip);
733cb93a386Sopenharmony_ci        }
734cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
735cb93a386Sopenharmony_ci        auto blob = builder.make();
736cb93a386Sopenharmony_ci#else
737cb93a386Sopenharmony_ci        auto blob = builder.Make();
738cb93a386Sopenharmony_ci#endif
739cb93a386Sopenharmony_ci        painter->drawTextShadow(blob,
740cb93a386Sopenharmony_ci            x + this->offset().fX + shadow.fOffset.x() + context.fTextShift,
741cb93a386Sopenharmony_ci            y + this->offset().fY + shadow.fOffset.y() + correctedBaseline,
742cb93a386Sopenharmony_ci            shadow.fColor,
743cb93a386Sopenharmony_ci            SkDoubleToScalar(shadow.fBlurSigma));
744cb93a386Sopenharmony_ci        if (context.clippingNeeded) {
745cb93a386Sopenharmony_ci            painter->restore();
746cb93a386Sopenharmony_ci        }
747cb93a386Sopenharmony_ci    }
748cb93a386Sopenharmony_ci}
749cb93a386Sopenharmony_ci
750cb93a386Sopenharmony_ciSkScalar TextLine::calculateThickness(const TextStyle& style, const ClipContext& content)
751cb93a386Sopenharmony_ci{
752cb93a386Sopenharmony_ci    Decorations decoration;
753cb93a386Sopenharmony_ci    return decoration.calculateThickness(style, content);
754cb93a386Sopenharmony_ci}
755cb93a386Sopenharmony_ci
756cb93a386Sopenharmony_civoid TextLine::paintDecorations(ParagraphPainter* painter, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const {
757cb93a386Sopenharmony_ci    ParagraphPainterAutoRestore ppar(painter);
758cb93a386Sopenharmony_ci    painter->translate(x + this->offset().fX, y + this->offset().fY + style.getBaselineShift());
759cb93a386Sopenharmony_ci    Decorations decorations;
760cb93a386Sopenharmony_ci    decorations.setDecorationContext(fDecorationContext);
761cb93a386Sopenharmony_ci    SkScalar correctedBaseline = SkScalarFloorToScalar(-this->sizes().rawAscent() + style.getBaselineShift() + 0.5);
762cb93a386Sopenharmony_ci    decorations.paint(painter, style, context, correctedBaseline);
763cb93a386Sopenharmony_ci}
764cb93a386Sopenharmony_ci
765cb93a386Sopenharmony_civoid TextLine::justify(SkScalar maxWidth) {
766cb93a386Sopenharmony_ci    int whitespacePatches = 0;
767cb93a386Sopenharmony_ci    SkScalar textLen = 0;
768cb93a386Sopenharmony_ci    bool whitespacePatch = false;
769cb93a386Sopenharmony_ci    // Take leading whitespaces width but do not increment a whitespace patch number
770cb93a386Sopenharmony_ci    bool leadingWhitespaces = false;
771cb93a386Sopenharmony_ci    this->iterateThroughClustersInGlyphsOrder(false, false,
772cb93a386Sopenharmony_ci        [&](const Cluster* cluster, ClusterIndex index, bool ghost) {
773cb93a386Sopenharmony_ci            if (cluster->isWhitespaceBreak()) {
774cb93a386Sopenharmony_ci                if (index == 0) {
775cb93a386Sopenharmony_ci                    leadingWhitespaces = true;
776cb93a386Sopenharmony_ci                } else if (!whitespacePatch && !leadingWhitespaces) {
777cb93a386Sopenharmony_ci                    // We only count patches BETWEEN words, not before
778cb93a386Sopenharmony_ci                    ++whitespacePatches;
779cb93a386Sopenharmony_ci                }
780cb93a386Sopenharmony_ci                whitespacePatch = !leadingWhitespaces;
781cb93a386Sopenharmony_ci            } else if (cluster->isIdeographic()) {
782cb93a386Sopenharmony_ci                // Whitespace break before and after
783cb93a386Sopenharmony_ci                if (!whitespacePatch && index != 0) {
784cb93a386Sopenharmony_ci                    // We only count patches BETWEEN words, not before
785cb93a386Sopenharmony_ci                    ++whitespacePatches; // before
786cb93a386Sopenharmony_ci                }
787cb93a386Sopenharmony_ci                whitespacePatch = true;
788cb93a386Sopenharmony_ci                leadingWhitespaces = false;
789cb93a386Sopenharmony_ci                ++whitespacePatches;    // after
790cb93a386Sopenharmony_ci            } else {
791cb93a386Sopenharmony_ci                whitespacePatch = false;
792cb93a386Sopenharmony_ci                leadingWhitespaces = false;
793cb93a386Sopenharmony_ci            }
794cb93a386Sopenharmony_ci            textLen += cluster->width();
795cb93a386Sopenharmony_ci            return true;
796cb93a386Sopenharmony_ci        });
797cb93a386Sopenharmony_ci
798cb93a386Sopenharmony_ci    if (whitespacePatch) {
799cb93a386Sopenharmony_ci        // We only count patches BETWEEN words, not after
800cb93a386Sopenharmony_ci        --whitespacePatches;
801cb93a386Sopenharmony_ci    }
802cb93a386Sopenharmony_ci    if (whitespacePatches == 0) {
803cb93a386Sopenharmony_ci        if (fOwner->paragraphStyle().getTextDirection() == TextDirection::kRtl) {
804cb93a386Sopenharmony_ci            // Justify -> Right align
805cb93a386Sopenharmony_ci            fShift = maxWidth - textLen;
806cb93a386Sopenharmony_ci        }
807cb93a386Sopenharmony_ci        return;
808cb93a386Sopenharmony_ci    }
809cb93a386Sopenharmony_ci
810cb93a386Sopenharmony_ci    SkScalar step = (maxWidth - textLen) / whitespacePatches;
811cb93a386Sopenharmony_ci    SkScalar shift = 0.0f;
812cb93a386Sopenharmony_ci    SkScalar prevShift = 0.0f;
813cb93a386Sopenharmony_ci
814cb93a386Sopenharmony_ci    // Deal with the ghost spaces
815cb93a386Sopenharmony_ci    auto ghostShift = maxWidth - this->fAdvance.fX;
816cb93a386Sopenharmony_ci    // Spread the extra whitespaces
817cb93a386Sopenharmony_ci    whitespacePatch = false;
818cb93a386Sopenharmony_ci    // Do not break on leading whitespaces
819cb93a386Sopenharmony_ci    leadingWhitespaces = false;
820cb93a386Sopenharmony_ci    this->iterateThroughClustersInGlyphsOrder(false, true, [&](const Cluster* cluster, ClusterIndex index, bool ghost) {
821cb93a386Sopenharmony_ci
822cb93a386Sopenharmony_ci        if (ghost) {
823cb93a386Sopenharmony_ci            if (cluster->run().leftToRight()) {
824cb93a386Sopenharmony_ci                this->shiftCluster(cluster, ghostShift, ghostShift);
825cb93a386Sopenharmony_ci            }
826cb93a386Sopenharmony_ci            return true;
827cb93a386Sopenharmony_ci        }
828cb93a386Sopenharmony_ci
829cb93a386Sopenharmony_ci        if (cluster->isWhitespaceBreak()) {
830cb93a386Sopenharmony_ci            if (index == 0) {
831cb93a386Sopenharmony_ci                leadingWhitespaces = true;
832cb93a386Sopenharmony_ci            } else if (!whitespacePatch && !leadingWhitespaces) {
833cb93a386Sopenharmony_ci                shift += step;
834cb93a386Sopenharmony_ci                whitespacePatch = true;
835cb93a386Sopenharmony_ci                --whitespacePatches;
836cb93a386Sopenharmony_ci            }
837cb93a386Sopenharmony_ci        } else if (cluster->isIdeographic()) {
838cb93a386Sopenharmony_ci            if (!whitespacePatch && index != 0) {
839cb93a386Sopenharmony_ci                shift += step;
840cb93a386Sopenharmony_ci               --whitespacePatches;
841cb93a386Sopenharmony_ci            }
842cb93a386Sopenharmony_ci            whitespacePatch = false;
843cb93a386Sopenharmony_ci            leadingWhitespaces = false;
844cb93a386Sopenharmony_ci        } else {
845cb93a386Sopenharmony_ci            whitespacePatch = false;
846cb93a386Sopenharmony_ci            leadingWhitespaces = false;
847cb93a386Sopenharmony_ci        }
848cb93a386Sopenharmony_ci        this->shiftCluster(cluster, shift, prevShift);
849cb93a386Sopenharmony_ci        prevShift = shift;
850cb93a386Sopenharmony_ci        // We skip ideographic whitespaces
851cb93a386Sopenharmony_ci        if (!cluster->isWhitespaceBreak() && cluster->isIdeographic()) {
852cb93a386Sopenharmony_ci            shift += step;
853cb93a386Sopenharmony_ci            whitespacePatch = true;
854cb93a386Sopenharmony_ci            --whitespacePatches;
855cb93a386Sopenharmony_ci        }
856cb93a386Sopenharmony_ci        return true;
857cb93a386Sopenharmony_ci    });
858cb93a386Sopenharmony_ci
859cb93a386Sopenharmony_ci    if (whitespacePatch && whitespacePatches < 0) {
860cb93a386Sopenharmony_ci        whitespacePatches++;
861cb93a386Sopenharmony_ci        shift -= step;
862cb93a386Sopenharmony_ci    }
863cb93a386Sopenharmony_ci
864cb93a386Sopenharmony_ci    SkAssertResult(nearlyEqual(shift, maxWidth - textLen));
865cb93a386Sopenharmony_ci    SkASSERT(whitespacePatches == 0);
866cb93a386Sopenharmony_ci
867cb93a386Sopenharmony_ci    this->fWidthWithSpaces += ghostShift;
868cb93a386Sopenharmony_ci    this->fAdvance.fX = maxWidth;
869cb93a386Sopenharmony_ci}
870cb93a386Sopenharmony_ci
871cb93a386Sopenharmony_civoid TextLine::shiftCluster(const Cluster* cluster, SkScalar shift, SkScalar prevShift) {
872cb93a386Sopenharmony_ci
873cb93a386Sopenharmony_ci    auto& run = cluster->run();
874cb93a386Sopenharmony_ci    auto start = cluster->startPos();
875cb93a386Sopenharmony_ci    auto end = cluster->endPos();
876cb93a386Sopenharmony_ci
877cb93a386Sopenharmony_ci    if (end == run.size()) {
878cb93a386Sopenharmony_ci        // Set the same shift for the fake last glyph (to avoid all extra checks)
879cb93a386Sopenharmony_ci        ++end;
880cb93a386Sopenharmony_ci    }
881cb93a386Sopenharmony_ci
882cb93a386Sopenharmony_ci    if (run.fJustificationShifts.empty()) {
883cb93a386Sopenharmony_ci        // Do not fill this array until needed
884cb93a386Sopenharmony_ci        run.fJustificationShifts.push_back_n(run.size() + 1, { 0, 0 });
885cb93a386Sopenharmony_ci    }
886cb93a386Sopenharmony_ci
887cb93a386Sopenharmony_ci    for (size_t pos = start; pos < end; ++pos) {
888cb93a386Sopenharmony_ci        run.fJustificationShifts[pos] = { shift, prevShift };
889cb93a386Sopenharmony_ci    }
890cb93a386Sopenharmony_ci}
891cb93a386Sopenharmony_ci
892cb93a386Sopenharmony_civoid TextLine::spacingCluster(const Cluster* cluster, SkScalar spacing, SkScalar prevSpacing) {
893cb93a386Sopenharmony_ci    auto& run = cluster->run();
894cb93a386Sopenharmony_ci    auto start = cluster->startPos();
895cb93a386Sopenharmony_ci    auto end = cluster->endPos();
896cb93a386Sopenharmony_ci    if (end == run.size()) {
897cb93a386Sopenharmony_ci        // Set the same shift for the fake last glyph (to avoid all extra checks)
898cb93a386Sopenharmony_ci        ++end;
899cb93a386Sopenharmony_ci    }
900cb93a386Sopenharmony_ci
901cb93a386Sopenharmony_ci    if (run.fAutoSpacings.empty()) {
902cb93a386Sopenharmony_ci        // Do not fill this array until needed
903cb93a386Sopenharmony_ci        run.fAutoSpacings.push_back_n(run.size() + 1, { 0, 0 });
904cb93a386Sopenharmony_ci    }
905cb93a386Sopenharmony_ci
906cb93a386Sopenharmony_ci    for (size_t pos = start; pos < end; ++pos) {
907cb93a386Sopenharmony_ci        run.fAutoSpacings[pos] = { spacing, prevSpacing};
908cb93a386Sopenharmony_ci    }
909cb93a386Sopenharmony_ci}
910cb93a386Sopenharmony_ci
911cb93a386Sopenharmony_civoid TextLine::countWord(int& wordCount, bool& inWord) {
912cb93a386Sopenharmony_ci    for (auto clusterIndex = fGhostClusterRange.start; clusterIndex < fGhostClusterRange.end; ++clusterIndex) {
913cb93a386Sopenharmony_ci        auto& cluster = fOwner->cluster(clusterIndex);
914cb93a386Sopenharmony_ci        if (cluster.isWordBreak()) {
915cb93a386Sopenharmony_ci            inWord = false;
916cb93a386Sopenharmony_ci        } else if (!inWord) {
917cb93a386Sopenharmony_ci            ++wordCount;
918cb93a386Sopenharmony_ci            inWord = true;
919cb93a386Sopenharmony_ci        }
920cb93a386Sopenharmony_ci    }
921cb93a386Sopenharmony_ci}
922cb93a386Sopenharmony_ci
923cb93a386Sopenharmony_civoid TextLine::ellipsisNotFitProcess(EllipsisModal ellipsisModal) {
924cb93a386Sopenharmony_ci    if (fEllipsis) {
925cb93a386Sopenharmony_ci        return;
926cb93a386Sopenharmony_ci    }
927cb93a386Sopenharmony_ci
928cb93a386Sopenharmony_ci    // Weird situation: ellipsis does not fit; no ellipsis then
929cb93a386Sopenharmony_ci    switch (ellipsisModal) {
930cb93a386Sopenharmony_ci        case EllipsisModal::TAIL:
931cb93a386Sopenharmony_ci            fClusterRange.end = fClusterRange.start;
932cb93a386Sopenharmony_ci            fGhostClusterRange.end = fClusterRange.start;
933cb93a386Sopenharmony_ci            fText.end = fText.start;
934cb93a386Sopenharmony_ci            fTextIncludingNewlines.end = fTextIncludingNewlines.start;
935cb93a386Sopenharmony_ci            fTextExcludingSpaces.end = fTextExcludingSpaces.start;
936cb93a386Sopenharmony_ci            fAdvance.fX = 0;
937cb93a386Sopenharmony_ci            break;
938cb93a386Sopenharmony_ci        case EllipsisModal::HEAD:
939cb93a386Sopenharmony_ci            fClusterRange.start = fClusterRange.end;
940cb93a386Sopenharmony_ci            fGhostClusterRange.start = fClusterRange.end;
941cb93a386Sopenharmony_ci            fText.start = fText.end;
942cb93a386Sopenharmony_ci            fTextIncludingNewlines.start = fTextIncludingNewlines.end;
943cb93a386Sopenharmony_ci            fTextExcludingSpaces.start = fTextExcludingSpaces.end;
944cb93a386Sopenharmony_ci            fAdvance.fX = 0;
945cb93a386Sopenharmony_ci            break;
946cb93a386Sopenharmony_ci        default:
947cb93a386Sopenharmony_ci            return;
948cb93a386Sopenharmony_ci    }
949cb93a386Sopenharmony_ci}
950cb93a386Sopenharmony_ci
951cb93a386Sopenharmony_civoid TextLine::createTailEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr, WordBreakType wordBreakType) {
952cb93a386Sopenharmony_ci    // Replace some clusters with the ellipsis
953cb93a386Sopenharmony_ci    // Go through the clusters in the reverse logical order
954cb93a386Sopenharmony_ci    // taking off cluster by cluster until the ellipsis fits
955cb93a386Sopenharmony_ci    SkScalar width = fAdvance.fX;
956cb93a386Sopenharmony_ci    RunIndex lastRun = EMPTY_RUN;
957cb93a386Sopenharmony_ci    std::unique_ptr<Run> ellipsisRun;
958cb93a386Sopenharmony_ci    int wordCount = 0;
959cb93a386Sopenharmony_ci    bool inWord = false;
960cb93a386Sopenharmony_ci
961cb93a386Sopenharmony_ci    countWord(wordCount, inWord);
962cb93a386Sopenharmony_ci
963cb93a386Sopenharmony_ci    bool iterForWord = false;
964cb93a386Sopenharmony_ci
965cb93a386Sopenharmony_ci    for (auto clusterIndex = fGhostClusterRange.end; clusterIndex > fGhostClusterRange.start; --clusterIndex) {
966cb93a386Sopenharmony_ci        auto& cluster = fOwner->cluster(clusterIndex - 1);
967cb93a386Sopenharmony_ci        // Shape the ellipsis if the run has changed
968cb93a386Sopenharmony_ci        if (lastRun != cluster.runIndex()) {
969cb93a386Sopenharmony_ci            ellipsisRun = this->shapeEllipsis(ellipsis, &cluster);
970cb93a386Sopenharmony_ci            // We may need to continue
971cb93a386Sopenharmony_ci            lastRun = cluster.runIndex();
972cb93a386Sopenharmony_ci        }
973cb93a386Sopenharmony_ci
974cb93a386Sopenharmony_ci        if (!cluster.isWordBreak()) {
975cb93a386Sopenharmony_ci            inWord = true;
976cb93a386Sopenharmony_ci        } else if (inWord) {
977cb93a386Sopenharmony_ci            --wordCount;
978cb93a386Sopenharmony_ci            inWord = false;
979cb93a386Sopenharmony_ci        }
980cb93a386Sopenharmony_ci        // See if it fits
981cb93a386Sopenharmony_ci        if (width + ellipsisRun->advance().fX > maxWidth) {
982cb93a386Sopenharmony_ci            if (!cluster.isHardBreak()) {
983cb93a386Sopenharmony_ci                width -= cluster.width();
984cb93a386Sopenharmony_ci            }
985cb93a386Sopenharmony_ci            // Continue if the ellipsis does not fit
986cb93a386Sopenharmony_ci            iterForWord = (wordCount != 1 && wordBreakType != WordBreakType::BREAK_ALL && !cluster.isWordBreak());
987cb93a386Sopenharmony_ci            if (std::floor(width) > 0) {
988cb93a386Sopenharmony_ci                continue;
989cb93a386Sopenharmony_ci            }
990cb93a386Sopenharmony_ci        }
991cb93a386Sopenharmony_ci
992cb93a386Sopenharmony_ci        if (iterForWord && !cluster.isWordBreak()) {
993cb93a386Sopenharmony_ci            width -= cluster.width();
994cb93a386Sopenharmony_ci            if (std::floor(width) > 0) {
995cb93a386Sopenharmony_ci                continue;
996cb93a386Sopenharmony_ci            }
997cb93a386Sopenharmony_ci        }
998cb93a386Sopenharmony_ci
999cb93a386Sopenharmony_ci        // Get the last run directions after clipping
1000cb93a386Sopenharmony_ci        fEllipsisIndex = cluster.runIndex();
1001cb93a386Sopenharmony_ci        fLastClipRunLtr = fOwner->run(fEllipsisIndex).leftToRight();
1002cb93a386Sopenharmony_ci
1003cb93a386Sopenharmony_ci        // We found enough room for the ellipsis
1004cb93a386Sopenharmony_ci        fAdvance.fX = width;
1005cb93a386Sopenharmony_ci        fEllipsis = std::move(ellipsisRun);
1006cb93a386Sopenharmony_ci        fEllipsis->setOwner(fOwner);
1007cb93a386Sopenharmony_ci        fTextRangeReplacedByEllipsis = TextRange(cluster.textRange().end, fOwner->text().size());
1008cb93a386Sopenharmony_ci
1009cb93a386Sopenharmony_ci        // Let's update the line
1010cb93a386Sopenharmony_ci        fClusterRange.end = clusterIndex;
1011cb93a386Sopenharmony_ci        fGhostClusterRange.end = fClusterRange.end;
1012cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1013cb93a386Sopenharmony_ci        fEllipsis->fTextRange =
1014cb93a386Sopenharmony_ci                TextRange(cluster.textRange().end, cluster.textRange().end + ellipsis.size());
1015cb93a386Sopenharmony_ci        fEllipsis->fClusterStart = cluster.textRange().end;
1016cb93a386Sopenharmony_ci#else
1017cb93a386Sopenharmony_ci        fEllipsis->fClusterStart = cluster.textRange().start;
1018cb93a386Sopenharmony_ci#endif
1019cb93a386Sopenharmony_ci        fText.end = cluster.textRange().end;
1020cb93a386Sopenharmony_ci        fTextIncludingNewlines.end = cluster.textRange().end;
1021cb93a386Sopenharmony_ci        fTextExcludingSpaces.end = cluster.textRange().end;
1022cb93a386Sopenharmony_ci
1023cb93a386Sopenharmony_ci        if (SkScalarNearlyZero(width)) {
1024cb93a386Sopenharmony_ci            fRunsInVisualOrder.reset();
1025cb93a386Sopenharmony_ci        }
1026cb93a386Sopenharmony_ci
1027cb93a386Sopenharmony_ci        break;
1028cb93a386Sopenharmony_ci    }
1029cb93a386Sopenharmony_ci
1030cb93a386Sopenharmony_ci    fWidthWithSpaces = width;
1031cb93a386Sopenharmony_ci
1032cb93a386Sopenharmony_ci    ellipsisNotFitProcess(EllipsisModal::TAIL);
1033cb93a386Sopenharmony_ci}
1034cb93a386Sopenharmony_ci
1035cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1036cb93a386Sopenharmony_civoid TextLine::createHeadEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool) {
1037cb93a386Sopenharmony_ci    if (fAdvance.fX <= maxWidth) {
1038cb93a386Sopenharmony_ci        return;
1039cb93a386Sopenharmony_ci    }
1040cb93a386Sopenharmony_ci    SkScalar width = fAdvance.fX;
1041cb93a386Sopenharmony_ci    std::unique_ptr<Run> ellipsisRun;
1042cb93a386Sopenharmony_ci    RunIndex lastRun = EMPTY_RUN;
1043cb93a386Sopenharmony_ci    for (auto clusterIndex = fGhostClusterRange.start; clusterIndex < fGhostClusterRange.end; ++clusterIndex) {
1044cb93a386Sopenharmony_ci        auto& cluster = fOwner->cluster(clusterIndex);
1045cb93a386Sopenharmony_ci        // Shape the ellipsis if the run has changed
1046cb93a386Sopenharmony_ci        if (lastRun != cluster.runIndex()) {
1047cb93a386Sopenharmony_ci            ellipsisRun = this->shapeEllipsis(ellipsis, &cluster);
1048cb93a386Sopenharmony_ci            // We may need to continue
1049cb93a386Sopenharmony_ci            lastRun = cluster.runIndex();
1050cb93a386Sopenharmony_ci        }
1051cb93a386Sopenharmony_ci        // See if it fits
1052cb93a386Sopenharmony_ci        if (width + ellipsisRun->advance().fX > maxWidth) {
1053cb93a386Sopenharmony_ci            width -= cluster.width();
1054cb93a386Sopenharmony_ci            // Continue if the ellipsis does not fit
1055cb93a386Sopenharmony_ci            if (std::floor(width) > 0) {
1056cb93a386Sopenharmony_ci                continue;
1057cb93a386Sopenharmony_ci            }
1058cb93a386Sopenharmony_ci        }
1059cb93a386Sopenharmony_ci
1060cb93a386Sopenharmony_ci        // Get the last run directions after clipping
1061cb93a386Sopenharmony_ci        fEllipsisIndex = cluster.runIndex();
1062cb93a386Sopenharmony_ci        fLastClipRunLtr = fOwner->run(fEllipsisIndex).leftToRight();
1063cb93a386Sopenharmony_ci
1064cb93a386Sopenharmony_ci        // We found enough room for the ellipsis
1065cb93a386Sopenharmony_ci        fAdvance.fX = width + ellipsisRun->advance().fX;
1066cb93a386Sopenharmony_ci        fEllipsis = std::move(ellipsisRun);
1067cb93a386Sopenharmony_ci        fEllipsis->setOwner(fOwner);
1068cb93a386Sopenharmony_ci        fTextRangeReplacedByEllipsis = TextRange(0, cluster.textRange().start);
1069cb93a386Sopenharmony_ci        fClusterRange.start = clusterIndex;
1070cb93a386Sopenharmony_ci        fGhostClusterRange.start = fClusterRange.start;
1071cb93a386Sopenharmony_ci        fEllipsis->fClusterStart = 0;
1072cb93a386Sopenharmony_ci        fText.start = cluster.textRange().start;
1073cb93a386Sopenharmony_ci        fTextIncludingNewlines.start = cluster.textRange().start;
1074cb93a386Sopenharmony_ci        fTextExcludingSpaces.start = cluster.textRange().start;
1075cb93a386Sopenharmony_ci        break;
1076cb93a386Sopenharmony_ci    }
1077cb93a386Sopenharmony_ci
1078cb93a386Sopenharmony_ci    fWidthWithSpaces = width;
1079cb93a386Sopenharmony_ci
1080cb93a386Sopenharmony_ci    ellipsisNotFitProcess(EllipsisModal::HEAD);
1081cb93a386Sopenharmony_ci}
1082cb93a386Sopenharmony_ci#endif
1083cb93a386Sopenharmony_ci
1084cb93a386Sopenharmony_cistatic inline SkUnichar nextUtf8Unit(const char** ptr, const char* end) {
1085cb93a386Sopenharmony_ci    SkUnichar val = SkUTF::NextUTF8(ptr, end);
1086cb93a386Sopenharmony_ci    return val < 0 ? 0xFFFD : val;
1087cb93a386Sopenharmony_ci}
1088cb93a386Sopenharmony_ci
1089cb93a386Sopenharmony_cistd::unique_ptr<Run> TextLine::shapeEllipsis(const SkString& ellipsis, const Cluster* cluster) {
1090cb93a386Sopenharmony_ci
1091cb93a386Sopenharmony_ci    class ShapeHandler final : public SkShaper::RunHandler {
1092cb93a386Sopenharmony_ci    public:
1093cb93a386Sopenharmony_ci        ShapeHandler(SkScalar lineHeight, bool useHalfLeading, SkScalar baselineShift, const SkString& ellipsis)
1094cb93a386Sopenharmony_ci            : fRun(nullptr), fLineHeight(lineHeight), fUseHalfLeading(useHalfLeading), fBaselineShift(baselineShift), fEllipsis(ellipsis) {}
1095cb93a386Sopenharmony_ci        std::unique_ptr<Run> run() & { return std::move(fRun); }
1096cb93a386Sopenharmony_ci
1097cb93a386Sopenharmony_ci    private:
1098cb93a386Sopenharmony_ci        void beginLine() override {}
1099cb93a386Sopenharmony_ci
1100cb93a386Sopenharmony_ci        void runInfo(const RunInfo&) override {}
1101cb93a386Sopenharmony_ci
1102cb93a386Sopenharmony_ci        void commitRunInfo() override {}
1103cb93a386Sopenharmony_ci
1104cb93a386Sopenharmony_ci        Buffer runBuffer(const RunInfo& info) override {
1105cb93a386Sopenharmony_ci            SkASSERT(!fRun);
1106cb93a386Sopenharmony_ci            fRun = std::make_unique<Run>(nullptr, info, 0, fLineHeight, fUseHalfLeading, fBaselineShift, 0, 0);
1107cb93a386Sopenharmony_ci            return fRun->newRunBuffer();
1108cb93a386Sopenharmony_ci        }
1109cb93a386Sopenharmony_ci
1110cb93a386Sopenharmony_ci        void commitRunBuffer(const RunInfo& info) override {
1111cb93a386Sopenharmony_ci            fRun->fAdvance.fX = info.fAdvance.fX;
1112cb93a386Sopenharmony_ci            fRun->fAdvance.fY = fRun->advance().fY;
1113cb93a386Sopenharmony_ci            fRun->fPlaceholderIndex = std::numeric_limits<size_t>::max();
1114cb93a386Sopenharmony_ci            fRun->fEllipsis = true;
1115cb93a386Sopenharmony_ci        }
1116cb93a386Sopenharmony_ci
1117cb93a386Sopenharmony_ci        void commitLine() override {}
1118cb93a386Sopenharmony_ci
1119cb93a386Sopenharmony_ci        std::unique_ptr<Run> fRun;
1120cb93a386Sopenharmony_ci        SkScalar fLineHeight;
1121cb93a386Sopenharmony_ci        bool fUseHalfLeading;
1122cb93a386Sopenharmony_ci        SkScalar fBaselineShift;
1123cb93a386Sopenharmony_ci        SkString fEllipsis;
1124cb93a386Sopenharmony_ci    };
1125cb93a386Sopenharmony_ci
1126cb93a386Sopenharmony_ci    const Run& run = cluster->run();
1127cb93a386Sopenharmony_ci    TextStyle textStyle = fOwner->paragraphStyle().getTextStyle();
1128cb93a386Sopenharmony_ci    for (auto i = fBlockRange.start; i < fBlockRange.end; ++i) {
1129cb93a386Sopenharmony_ci        auto& block = fOwner->block(i);
1130cb93a386Sopenharmony_ci        if (run.leftToRight() && cluster->textRange().end <= block.fRange.end) {
1131cb93a386Sopenharmony_ci            textStyle = block.fStyle;
1132cb93a386Sopenharmony_ci            break;
1133cb93a386Sopenharmony_ci        } else if (!run.leftToRight() && cluster->textRange().start <= block.fRange.end) {
1134cb93a386Sopenharmony_ci            textStyle = block.fStyle;
1135cb93a386Sopenharmony_ci            break;
1136cb93a386Sopenharmony_ci        }
1137cb93a386Sopenharmony_ci    }
1138cb93a386Sopenharmony_ci
1139cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
1140cb93a386Sopenharmony_ci    auto shaped = [&](sk_sp<SkTypeface> typeface, bool fallback) -> std::unique_ptr<Run> {
1141cb93a386Sopenharmony_ci#else
1142cb93a386Sopenharmony_ci    auto shaped = [&](std::shared_ptr<RSTypeface> typeface, bool fallback) -> std::unique_ptr<Run> {
1143cb93a386Sopenharmony_ci#endif
1144cb93a386Sopenharmony_ci        ShapeHandler handler(run.heightMultiplier(), run.useHalfLeading(), run.baselineShift(), ellipsis);
1145cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
1146cb93a386Sopenharmony_ci        SkFont font(typeface, textStyle.getFontSize());
1147cb93a386Sopenharmony_ci        font.setEdging(SkFont::Edging::kAntiAlias);
1148cb93a386Sopenharmony_ci        font.setHinting(SkFontHinting::kSlight);
1149cb93a386Sopenharmony_ci        font.setSubpixel(true);
1150cb93a386Sopenharmony_ci#else
1151cb93a386Sopenharmony_ci        RSFont font(typeface, textStyle.getFontSize(), 1, 0);
1152cb93a386Sopenharmony_ci        font.SetEdging(RSDrawing::FontEdging::ANTI_ALIAS);
1153cb93a386Sopenharmony_ci        font.SetHinting(RSDrawing::FontHinting::SLIGHT);
1154cb93a386Sopenharmony_ci        font.SetSubpixel(true);
1155cb93a386Sopenharmony_ci#endif
1156cb93a386Sopenharmony_ci
1157cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
1158cb93a386Sopenharmony_ci        std::unique_ptr<SkShaper> shaper = SkShaper::MakeShapeDontWrapOrReorder(
1159cb93a386Sopenharmony_ci                            fOwner->getUnicode()->copy(),
1160cb93a386Sopenharmony_ci                            fallback ? SkFontMgr::RefDefault() : SkFontMgr::RefEmpty());
1161cb93a386Sopenharmony_ci#else
1162cb93a386Sopenharmony_ci        std::unique_ptr<SkShaper> shaper = SkShaper::MakeShapeDontWrapOrReorder(
1163cb93a386Sopenharmony_ci                            fOwner->getUnicode()->copy(),
1164cb93a386Sopenharmony_ci                            fallback ? RSFontMgr::CreateDefaultFontMgr() : RSFontMgr::CreateDefaultFontMgr());
1165cb93a386Sopenharmony_ci#endif
1166cb93a386Sopenharmony_ci        shaper->shape(ellipsis.c_str(),
1167cb93a386Sopenharmony_ci                      ellipsis.size(),
1168cb93a386Sopenharmony_ci                      font,
1169cb93a386Sopenharmony_ci                      true,
1170cb93a386Sopenharmony_ci                      std::numeric_limits<SkScalar>::max(),
1171cb93a386Sopenharmony_ci                      &handler);
1172cb93a386Sopenharmony_ci        auto ellipsisRun = handler.run();
1173cb93a386Sopenharmony_ci        ellipsisRun->fTextRange = TextRange(0, ellipsis.size());
1174cb93a386Sopenharmony_ci        ellipsisRun->fOwner = fOwner;
1175cb93a386Sopenharmony_ci        return ellipsisRun;
1176cb93a386Sopenharmony_ci    };
1177cb93a386Sopenharmony_ci
1178cb93a386Sopenharmony_ci    // Check all allowed fonts
1179cb93a386Sopenharmony_ci    auto typefaces = fOwner->fontCollection()->findTypefaces(
1180cb93a386Sopenharmony_ci            textStyle.getFontFamilies(), textStyle.getFontStyle(), textStyle.getFontArguments());
1181cb93a386Sopenharmony_ci    for (const auto& typeface : typefaces) {
1182cb93a386Sopenharmony_ci        auto ellipsisRun = shaped(typeface, false);
1183cb93a386Sopenharmony_ci        if (ellipsisRun->isResolved()) {
1184cb93a386Sopenharmony_ci            return ellipsisRun;
1185cb93a386Sopenharmony_ci        }
1186cb93a386Sopenharmony_ci    }
1187cb93a386Sopenharmony_ci
1188cb93a386Sopenharmony_ci    // Try the fallback
1189cb93a386Sopenharmony_ci    if (fOwner->fontCollection()->fontFallbackEnabled()) {
1190cb93a386Sopenharmony_ci        const char* ch = ellipsis.c_str();
1191cb93a386Sopenharmony_ci        SkUnichar unicode = nextUtf8Unit(&ch, ellipsis.c_str() + ellipsis.size());
1192cb93a386Sopenharmony_ci
1193cb93a386Sopenharmony_ci        auto typeface = fOwner->fontCollection()->defaultFallback(
1194cb93a386Sopenharmony_ci            unicode, textStyle.getFontStyle(), textStyle.getLocale());
1195cb93a386Sopenharmony_ci        if (typeface) {
1196cb93a386Sopenharmony_ci            if (textStyle.getFontArguments()) {
1197cb93a386Sopenharmony_ci                typeface = fOwner->fontCollection()->CloneTypeface(typeface, textStyle.getFontArguments());
1198cb93a386Sopenharmony_ci            }
1199cb93a386Sopenharmony_ci            auto ellipsisRun = shaped(typeface, true);
1200cb93a386Sopenharmony_ci            if (ellipsisRun->isResolved()) {
1201cb93a386Sopenharmony_ci                return ellipsisRun;
1202cb93a386Sopenharmony_ci            }
1203cb93a386Sopenharmony_ci        }
1204cb93a386Sopenharmony_ci    }
1205cb93a386Sopenharmony_ci
1206cb93a386Sopenharmony_ci    // Check the current font
1207cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
1208cb93a386Sopenharmony_ci    auto ellipsisRun = shaped(run.fFont.refTypeface(), false);
1209cb93a386Sopenharmony_ci#else
1210cb93a386Sopenharmony_ci    auto ellipsisRun = shaped(const_cast<RSFont&>(run.fFont).GetTypeface(), false);
1211cb93a386Sopenharmony_ci#endif
1212cb93a386Sopenharmony_ci    if (ellipsisRun->isResolved()) {
1213cb93a386Sopenharmony_ci        return ellipsisRun;
1214cb93a386Sopenharmony_ci    }
1215cb93a386Sopenharmony_ci    return ellipsisRun;
1216cb93a386Sopenharmony_ci}
1217cb93a386Sopenharmony_ci
1218cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1219cb93a386Sopenharmony_civoid TextLine::measureTextWithSpacesAtTheEnd(ClipContext& context, bool includeGhostSpaces) const
1220cb93a386Sopenharmony_ci{
1221cb93a386Sopenharmony_ci    if (compareRound(context.clip.fRight, fAdvance.fX, fOwner->getApplyRoundingHack()) > 0 && !includeGhostSpaces &&
1222cb93a386Sopenharmony_ci        fAdvance.fX > 0) {
1223cb93a386Sopenharmony_ci        // There are few cases when we need it.
1224cb93a386Sopenharmony_ci        // The most important one: we measure the text with spaces at the end (or at the beginning in RTL)
1225cb93a386Sopenharmony_ci        // and we should ignore these spaces
1226cb93a386Sopenharmony_ci        if (fOwner->paragraphStyle().getTextDirection() == TextDirection::kLtr) {
1227cb93a386Sopenharmony_ci            // We only use this member for LTR
1228cb93a386Sopenharmony_ci            context.fExcludedTrailingSpaces = std::max(context.clip.fRight - fAdvance.fX, 0.0f);
1229cb93a386Sopenharmony_ci            context.clippingNeeded = true;
1230cb93a386Sopenharmony_ci            context.clip.fRight = fAdvance.fX;
1231cb93a386Sopenharmony_ci        }
1232cb93a386Sopenharmony_ci    }
1233cb93a386Sopenharmony_ci}
1234cb93a386Sopenharmony_ci#endif
1235cb93a386Sopenharmony_ci
1236cb93a386Sopenharmony_ciTextLine::ClipContext TextLine::measureTextInsideOneRun(TextRange textRange,
1237cb93a386Sopenharmony_ci                                                        const Run* run,
1238cb93a386Sopenharmony_ci                                                        SkScalar runOffsetInLine,
1239cb93a386Sopenharmony_ci                                                        SkScalar textOffsetInRunInLine,
1240cb93a386Sopenharmony_ci                                                        bool includeGhostSpaces,
1241cb93a386Sopenharmony_ci                                                        TextAdjustment textAdjustment) const {
1242cb93a386Sopenharmony_ci    ClipContext result = { run, 0, run->size(), 0, SkRect::MakeEmpty(), 0, false };
1243cb93a386Sopenharmony_ci
1244cb93a386Sopenharmony_ci    if (run->fEllipsis) {
1245cb93a386Sopenharmony_ci        // Both ellipsis and placeholders can only be measured as one glyph
1246cb93a386Sopenharmony_ci        result.fTextShift = runOffsetInLine;
1247cb93a386Sopenharmony_ci        result.clip = SkRect::MakeXYWH(runOffsetInLine,
1248cb93a386Sopenharmony_ci                                       sizes().runTop(run, this->fAscentStyle),
1249cb93a386Sopenharmony_ci                                       run->advance().fX,
1250cb93a386Sopenharmony_ci                                       run->calculateHeight(this->fAscentStyle,this->fDescentStyle));
1251cb93a386Sopenharmony_ci        return result;
1252cb93a386Sopenharmony_ci    } else if (run->isPlaceholder()) {
1253cb93a386Sopenharmony_ci        result.fTextShift = runOffsetInLine;
1254cb93a386Sopenharmony_ci        if (SkScalarIsFinite(run->fFontMetrics.fAscent)) {
1255cb93a386Sopenharmony_ci          result.clip = SkRect::MakeXYWH(runOffsetInLine,
1256cb93a386Sopenharmony_ci                                         sizes().runTop(run, this->fAscentStyle),
1257cb93a386Sopenharmony_ci                                         run->advance().fX,
1258cb93a386Sopenharmony_ci                                         run->calculateHeight(this->fAscentStyle,this->fDescentStyle));
1259cb93a386Sopenharmony_ci        } else {
1260cb93a386Sopenharmony_ci            result.clip = SkRect::MakeXYWH(runOffsetInLine, run->fFontMetrics.fAscent, run->advance().fX, 0);
1261cb93a386Sopenharmony_ci        }
1262cb93a386Sopenharmony_ci        return result;
1263cb93a386Sopenharmony_ci    } else if (textRange.empty()) {
1264cb93a386Sopenharmony_ci        return result;
1265cb93a386Sopenharmony_ci    }
1266cb93a386Sopenharmony_ci
1267cb93a386Sopenharmony_ci    TextRange originalTextRange(textRange); // We need it for proportional measurement
1268cb93a386Sopenharmony_ci    // Find [start:end] clusters for the text
1269cb93a386Sopenharmony_ci    while (true) {
1270cb93a386Sopenharmony_ci        // Update textRange by cluster edges (shift start up to the edge of the cluster)
1271cb93a386Sopenharmony_ci        // TODO: remove this limitation?
1272cb93a386Sopenharmony_ci        TextRange updatedTextRange;
1273cb93a386Sopenharmony_ci        bool found;
1274cb93a386Sopenharmony_ci        std::tie(found, updatedTextRange.start, updatedTextRange.end) =
1275cb93a386Sopenharmony_ci                                        run->findLimitingGlyphClusters(textRange);
1276cb93a386Sopenharmony_ci        if (!found) {
1277cb93a386Sopenharmony_ci            return result;
1278cb93a386Sopenharmony_ci        }
1279cb93a386Sopenharmony_ci
1280cb93a386Sopenharmony_ci        if ((textAdjustment & TextAdjustment::Grapheme) == 0) {
1281cb93a386Sopenharmony_ci            textRange = updatedTextRange;
1282cb93a386Sopenharmony_ci            break;
1283cb93a386Sopenharmony_ci        }
1284cb93a386Sopenharmony_ci
1285cb93a386Sopenharmony_ci        // Update text range by grapheme edges (shift start up to the edge of the grapheme)
1286cb93a386Sopenharmony_ci        std::tie(found, updatedTextRange.start, updatedTextRange.end) =
1287cb93a386Sopenharmony_ci                                    run->findLimitingGraphemes(updatedTextRange);
1288cb93a386Sopenharmony_ci        if (updatedTextRange == textRange) {
1289cb93a386Sopenharmony_ci            break;
1290cb93a386Sopenharmony_ci        }
1291cb93a386Sopenharmony_ci
1292cb93a386Sopenharmony_ci        // Some clusters are inside graphemes and we need to adjust them
1293cb93a386Sopenharmony_ci        //SkDebugf("Correct range: [%d:%d) -> [%d:%d)\n", textRange.start, textRange.end, startIndex, endIndex);
1294cb93a386Sopenharmony_ci        textRange = updatedTextRange;
1295cb93a386Sopenharmony_ci
1296cb93a386Sopenharmony_ci        // Move the start until it's on the grapheme edge (and glypheme, too)
1297cb93a386Sopenharmony_ci    }
1298cb93a386Sopenharmony_ci    Cluster* start = &fOwner->cluster(fOwner->clusterIndex(textRange.start));
1299cb93a386Sopenharmony_ci    Cluster* end = &fOwner->cluster(fOwner->clusterIndex(textRange.end - (textRange.width() == 0 ? 0 : 1)));
1300cb93a386Sopenharmony_ci
1301cb93a386Sopenharmony_ci    if (!run->leftToRight()) {
1302cb93a386Sopenharmony_ci        std::swap(start, end);
1303cb93a386Sopenharmony_ci    }
1304cb93a386Sopenharmony_ci    result.pos = start->startPos();
1305cb93a386Sopenharmony_ci    result.size = (end->isHardBreak() ? end->startPos() : end->endPos()) - start->startPos();
1306cb93a386Sopenharmony_ci    auto textStartInRun = run->positionX(start->startPos());
1307cb93a386Sopenharmony_ci    auto textStartInLine = runOffsetInLine + textOffsetInRunInLine;
1308cb93a386Sopenharmony_ci    if (!run->leftToRight()) {
1309cb93a386Sopenharmony_ci        std::swap(start, end);
1310cb93a386Sopenharmony_ci    }
1311cb93a386Sopenharmony_ci/*
1312cb93a386Sopenharmony_ci    if (!run->fJustificationShifts.empty()) {
1313cb93a386Sopenharmony_ci        SkDebugf("Justification for [%d:%d)\n", textRange.start, textRange.end);
1314cb93a386Sopenharmony_ci        for (auto i = result.pos; i < result.pos + result.size; ++i) {
1315cb93a386Sopenharmony_ci            auto j = run->fJustificationShifts[i];
1316cb93a386Sopenharmony_ci            SkDebugf("[%d] = %f %f\n", i, j.fX, j.fY);
1317cb93a386Sopenharmony_ci        }
1318cb93a386Sopenharmony_ci    }
1319cb93a386Sopenharmony_ci*/
1320cb93a386Sopenharmony_ci    // Calculate the clipping rectangle for the text with cluster edges
1321cb93a386Sopenharmony_ci    // There are 2 cases:
1322cb93a386Sopenharmony_ci    // EOL (when we expect the last cluster clipped without any spaces)
1323cb93a386Sopenharmony_ci    // Anything else (when we want the cluster width contain all the spaces -
1324cb93a386Sopenharmony_ci    // coming from letter spacing or word spacing or justification)
1325cb93a386Sopenharmony_ci    result.clip =
1326cb93a386Sopenharmony_ci            SkRect::MakeXYWH(0,
1327cb93a386Sopenharmony_ci                             sizes().runTop(run, this->fAscentStyle),
1328cb93a386Sopenharmony_ci                             run->calculateWidth(result.pos, result.pos + result.size, false),
1329cb93a386Sopenharmony_ci                             run->calculateHeight(this->fAscentStyle,this->fDescentStyle));
1330cb93a386Sopenharmony_ci
1331cb93a386Sopenharmony_ci    // Correct the width in case the text edges don't match clusters
1332cb93a386Sopenharmony_ci    // TODO: This is where we get smart about selecting a part of a cluster
1333cb93a386Sopenharmony_ci    //  by shaping each grapheme separately and then use the result sizes
1334cb93a386Sopenharmony_ci    //  to calculate the proportions
1335cb93a386Sopenharmony_ci    auto leftCorrection = start->sizeToChar(originalTextRange.start);
1336cb93a386Sopenharmony_ci    auto rightCorrection = end->sizeFromChar(originalTextRange.end - 1);
1337cb93a386Sopenharmony_ci    /*
1338cb93a386Sopenharmony_ci    SkDebugf("[%d: %d) => [%d: %d), @%d, %d: [%f:%f) + [%f:%f) = ", // جَآَهُ
1339cb93a386Sopenharmony_ci             originalTextRange.start, originalTextRange.end, textRange.start, textRange.end,
1340cb93a386Sopenharmony_ci             result.pos, result.size,
1341cb93a386Sopenharmony_ci             result.clip.fLeft, result.clip.fRight, leftCorrection, rightCorrection);
1342cb93a386Sopenharmony_ci     */
1343cb93a386Sopenharmony_ci    result.clippingNeeded = leftCorrection != 0 || rightCorrection != 0;
1344cb93a386Sopenharmony_ci    if (run->leftToRight()) {
1345cb93a386Sopenharmony_ci        result.clip.fLeft += leftCorrection;
1346cb93a386Sopenharmony_ci        result.clip.fRight -= rightCorrection;
1347cb93a386Sopenharmony_ci        textStartInLine -= leftCorrection;
1348cb93a386Sopenharmony_ci    } else {
1349cb93a386Sopenharmony_ci        result.clip.fRight -= leftCorrection;
1350cb93a386Sopenharmony_ci        result.clip.fLeft += rightCorrection;
1351cb93a386Sopenharmony_ci        textStartInLine -= rightCorrection;
1352cb93a386Sopenharmony_ci    }
1353cb93a386Sopenharmony_ci
1354cb93a386Sopenharmony_ci    result.clip.offset(textStartInLine, 0);
1355cb93a386Sopenharmony_ci    //SkDebugf("@%f[%f:%f)\n", textStartInLine, result.clip.fLeft, result.clip.fRight);
1356cb93a386Sopenharmony_ci
1357cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1358cb93a386Sopenharmony_ci    measureTextWithSpacesAtTheEnd(result, includeGhostSpaces);
1359cb93a386Sopenharmony_ci#else
1360cb93a386Sopenharmony_ci    if (compareRound(result.clip.fRight, fAdvance.fX, fOwner->getApplyRoundingHack()) > 0 && !includeGhostSpaces) {
1361cb93a386Sopenharmony_ci        // There are few cases when we need it.
1362cb93a386Sopenharmony_ci        // The most important one: we measure the text with spaces at the end (or at the beginning in RTL)
1363cb93a386Sopenharmony_ci        // and we should ignore these spaces
1364cb93a386Sopenharmony_ci        if (fOwner->paragraphStyle().getTextDirection() == TextDirection::kLtr) {
1365cb93a386Sopenharmony_ci            // We only use this member for LTR
1366cb93a386Sopenharmony_ci            result.fExcludedTrailingSpaces = std::max(result.clip.fRight - fAdvance.fX, 0.0f);
1367cb93a386Sopenharmony_ci            result.clippingNeeded = true;
1368cb93a386Sopenharmony_ci            result.clip.fRight = fAdvance.fX;
1369cb93a386Sopenharmony_ci        }
1370cb93a386Sopenharmony_ci    }
1371cb93a386Sopenharmony_ci
1372cb93a386Sopenharmony_ci    if (result.clip.width() < 0) {
1373cb93a386Sopenharmony_ci        // Weird situation when glyph offsets move the glyph to the left
1374cb93a386Sopenharmony_ci        // (happens with zalgo texts, for instance)
1375cb93a386Sopenharmony_ci        result.clip.fRight = result.clip.fLeft;
1376cb93a386Sopenharmony_ci    }
1377cb93a386Sopenharmony_ci#endif
1378cb93a386Sopenharmony_ci
1379cb93a386Sopenharmony_ci    // The text must be aligned with the lineOffset
1380cb93a386Sopenharmony_ci    result.fTextShift = textStartInLine - textStartInRun;
1381cb93a386Sopenharmony_ci
1382cb93a386Sopenharmony_ci    return result;
1383cb93a386Sopenharmony_ci}
1384cb93a386Sopenharmony_ci
1385cb93a386Sopenharmony_civoid TextLine::iterateThroughClustersInGlyphsOrder(bool reversed,
1386cb93a386Sopenharmony_ci                                                   bool includeGhosts,
1387cb93a386Sopenharmony_ci                                                   const ClustersVisitor& visitor) const {
1388cb93a386Sopenharmony_ci    // Walk through the clusters in the logical order (or reverse)
1389cb93a386Sopenharmony_ci    SkSpan<const size_t> runs(fRunsInVisualOrder.data(), fRunsInVisualOrder.size());
1390cb93a386Sopenharmony_ci    bool ignore = false;
1391cb93a386Sopenharmony_ci    ClusterIndex index = 0;
1392cb93a386Sopenharmony_ci    directional_for_each(runs, !reversed, [&](decltype(runs[0]) r) {
1393cb93a386Sopenharmony_ci        if (ignore) return;
1394cb93a386Sopenharmony_ci        auto run = this->fOwner->run(r);
1395cb93a386Sopenharmony_ci        auto trimmedRange = fClusterRange.intersection(run.clusterRange());
1396cb93a386Sopenharmony_ci        auto trailedRange = fGhostClusterRange.intersection(run.clusterRange());
1397cb93a386Sopenharmony_ci        SkASSERT(trimmedRange.start == trailedRange.start);
1398cb93a386Sopenharmony_ci
1399cb93a386Sopenharmony_ci        auto trailed = fOwner->clusters(trailedRange);
1400cb93a386Sopenharmony_ci        auto trimmed = fOwner->clusters(trimmedRange);
1401cb93a386Sopenharmony_ci        directional_for_each(trailed, reversed != run.leftToRight(), [&](Cluster& cluster) {
1402cb93a386Sopenharmony_ci            if (ignore) return;
1403cb93a386Sopenharmony_ci            bool ghost =  &cluster >= trimmed.end();
1404cb93a386Sopenharmony_ci            if (!includeGhosts && ghost) {
1405cb93a386Sopenharmony_ci                return;
1406cb93a386Sopenharmony_ci            }
1407cb93a386Sopenharmony_ci            if (!visitor(&cluster, index++, ghost)) {
1408cb93a386Sopenharmony_ci
1409cb93a386Sopenharmony_ci                ignore = true;
1410cb93a386Sopenharmony_ci                return;
1411cb93a386Sopenharmony_ci            }
1412cb93a386Sopenharmony_ci        });
1413cb93a386Sopenharmony_ci    });
1414cb93a386Sopenharmony_ci}
1415cb93a386Sopenharmony_ci
1416cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1417cb93a386Sopenharmony_civoid TextLine::computeNextPaintGlyphRange(ClipContext& context,
1418cb93a386Sopenharmony_ci    const TextRange& lastGlyphRange, StyleType styleType) const
1419cb93a386Sopenharmony_ci{
1420cb93a386Sopenharmony_ci    if (styleType != StyleType::kForeground) {
1421cb93a386Sopenharmony_ci        return;
1422cb93a386Sopenharmony_ci    }
1423cb93a386Sopenharmony_ci    TextRange curGlyphRange = TextRange(context.pos, context.pos + context.size);
1424cb93a386Sopenharmony_ci    auto intersect = intersected(lastGlyphRange, curGlyphRange);
1425cb93a386Sopenharmony_ci    if (intersect == EMPTY_TEXT || (intersect.start != curGlyphRange.start && intersect.end != curGlyphRange.end)) {
1426cb93a386Sopenharmony_ci        return;
1427cb93a386Sopenharmony_ci    }
1428cb93a386Sopenharmony_ci    if (intersect.start == curGlyphRange.start) {
1429cb93a386Sopenharmony_ci        curGlyphRange = TextRange(intersect.end, curGlyphRange.end);
1430cb93a386Sopenharmony_ci    } else if (intersect.end == curGlyphRange.end) {
1431cb93a386Sopenharmony_ci        curGlyphRange = TextRange(curGlyphRange.start, intersect.start);
1432cb93a386Sopenharmony_ci    }
1433cb93a386Sopenharmony_ci
1434cb93a386Sopenharmony_ci    context.pos = curGlyphRange.start;
1435cb93a386Sopenharmony_ci    context.size = curGlyphRange.width();
1436cb93a386Sopenharmony_ci}
1437cb93a386Sopenharmony_ci#endif
1438cb93a386Sopenharmony_ci
1439cb93a386Sopenharmony_ciSkScalar TextLine::iterateThroughSingleRunByStyles(TextAdjustment textAdjustment,
1440cb93a386Sopenharmony_ci                                                   const Run* run,
1441cb93a386Sopenharmony_ci                                                   SkScalar runOffset,
1442cb93a386Sopenharmony_ci                                                   TextRange textRange,
1443cb93a386Sopenharmony_ci                                                   StyleType styleType,
1444cb93a386Sopenharmony_ci                                                   const RunStyleVisitor& visitor) const {
1445cb93a386Sopenharmony_ci    auto includeGhostSpaces = (styleType == StyleType::kDecorations || styleType == StyleType::kBackground ||
1446cb93a386Sopenharmony_ci        styleType == StyleType::kNone);
1447cb93a386Sopenharmony_ci    auto correctContext = [&](TextRange textRange, SkScalar textOffsetInRun) -> ClipContext {
1448cb93a386Sopenharmony_ci        auto result = this->measureTextInsideOneRun(
1449cb93a386Sopenharmony_ci            textRange, run, runOffset, textOffsetInRun, includeGhostSpaces, textAdjustment);
1450cb93a386Sopenharmony_ci        if (styleType == StyleType::kDecorations) {
1451cb93a386Sopenharmony_ci            // Decorations are drawn based on the real font metrics (regardless of styles and strut)
1452cb93a386Sopenharmony_ci            result.clip.fTop = this->sizes().runTop(run, LineMetricStyle::CSS) - run->baselineShift();
1453cb93a386Sopenharmony_ci            result.clip.fBottom = result.clip.fTop +
1454cb93a386Sopenharmony_ci                                  run->calculateHeight(LineMetricStyle::CSS, LineMetricStyle::CSS);
1455cb93a386Sopenharmony_ci        }
1456cb93a386Sopenharmony_ci        return result;
1457cb93a386Sopenharmony_ci    };
1458cb93a386Sopenharmony_ci
1459cb93a386Sopenharmony_ci    if (run->fEllipsis) {
1460cb93a386Sopenharmony_ci        // Extra efforts to get the ellipsis text style
1461cb93a386Sopenharmony_ci        ClipContext clipContext = correctContext(run->textRange(), 0.0f);
1462cb93a386Sopenharmony_ci        for (BlockIndex index = fBlockRange.start; index < fBlockRange.end; ++index) {
1463cb93a386Sopenharmony_ci            auto block = fOwner->styles().begin() + index;
1464cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1465cb93a386Sopenharmony_ci            TextRange intersect = intersected(block->fRange,
1466cb93a386Sopenharmony_ci                TextRange(fEllipsis->textRange().start - 1, fEllipsis->textRange().end));
1467cb93a386Sopenharmony_ci            if (intersect.width() > 0) {
1468cb93a386Sopenharmony_ci                visitor(fTextRangeReplacedByEllipsis, block->fStyle, clipContext);
1469cb93a386Sopenharmony_ci                return run->advance().fX;
1470cb93a386Sopenharmony_ci            }
1471cb93a386Sopenharmony_ci#else
1472cb93a386Sopenharmony_ci           if (block->fRange.start >= run->fClusterStart && block->fRange.end < run->fClusterStart) {
1473cb93a386Sopenharmony_ci               visitor(fTextRangeReplacedByEllipsis, block->fStyle, clipContext);
1474cb93a386Sopenharmony_ci               return run->advance().fX;
1475cb93a386Sopenharmony_ci           }
1476cb93a386Sopenharmony_ci#endif
1477cb93a386Sopenharmony_ci        }
1478cb93a386Sopenharmony_ci        SkASSERT(false);
1479cb93a386Sopenharmony_ci    }
1480cb93a386Sopenharmony_ci
1481cb93a386Sopenharmony_ci    if (styleType == StyleType::kNone) {
1482cb93a386Sopenharmony_ci        ClipContext clipContext = correctContext(textRange, 0.0f);
1483cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1484cb93a386Sopenharmony_ci        if (clipContext.clip.height() > 0 ||
1485cb93a386Sopenharmony_ci            (run->isPlaceholder() && SkScalarNearlyZero(clipContext.clip.height()))) {
1486cb93a386Sopenharmony_ci#else
1487cb93a386Sopenharmony_ci        if (clipContext.clip.height() > 0) {
1488cb93a386Sopenharmony_ci#endif
1489cb93a386Sopenharmony_ci            visitor(textRange, TextStyle(), clipContext);
1490cb93a386Sopenharmony_ci            return clipContext.clip.width();
1491cb93a386Sopenharmony_ci        } else {
1492cb93a386Sopenharmony_ci            return 0;
1493cb93a386Sopenharmony_ci        }
1494cb93a386Sopenharmony_ci    }
1495cb93a386Sopenharmony_ci
1496cb93a386Sopenharmony_ci    TextIndex start = EMPTY_INDEX;
1497cb93a386Sopenharmony_ci    size_t size = 0;
1498cb93a386Sopenharmony_ci    const TextStyle* prevStyle = nullptr;
1499cb93a386Sopenharmony_ci    SkScalar textOffsetInRun = 0;
1500cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1501cb93a386Sopenharmony_ci    TextRange lastGlyphRange = EMPTY_TEXT;
1502cb93a386Sopenharmony_ci#endif
1503cb93a386Sopenharmony_ci    const BlockIndex blockRangeSize = fBlockRange.end - fBlockRange.start;
1504cb93a386Sopenharmony_ci    for (BlockIndex index = 0; index <= blockRangeSize; ++index) {
1505cb93a386Sopenharmony_ci
1506cb93a386Sopenharmony_ci        TextRange intersect;
1507cb93a386Sopenharmony_ci        TextStyle* style = nullptr;
1508cb93a386Sopenharmony_ci        if (index < blockRangeSize) {
1509cb93a386Sopenharmony_ci            auto block = fOwner->styles().begin() +
1510cb93a386Sopenharmony_ci                 (run->leftToRight() ? fBlockRange.start + index : fBlockRange.end - index - 1);
1511cb93a386Sopenharmony_ci
1512cb93a386Sopenharmony_ci            // Get the text
1513cb93a386Sopenharmony_ci            intersect = intersected(block->fRange, textRange);
1514cb93a386Sopenharmony_ci            if (intersect.width() == 0) {
1515cb93a386Sopenharmony_ci                if (start == EMPTY_INDEX) {
1516cb93a386Sopenharmony_ci                    // This style is not applicable to the text yet
1517cb93a386Sopenharmony_ci                    continue;
1518cb93a386Sopenharmony_ci                } else {
1519cb93a386Sopenharmony_ci                    // We have found all the good styles already
1520cb93a386Sopenharmony_ci                    // but we need to process the last one of them
1521cb93a386Sopenharmony_ci                    intersect = TextRange(start, start + size);
1522cb93a386Sopenharmony_ci                    index = fBlockRange.end;
1523cb93a386Sopenharmony_ci                }
1524cb93a386Sopenharmony_ci            } else {
1525cb93a386Sopenharmony_ci                // Get the style
1526cb93a386Sopenharmony_ci                style = &block->fStyle;
1527cb93a386Sopenharmony_ci                if (start != EMPTY_INDEX && style->matchOneAttribute(styleType, *prevStyle)) {
1528cb93a386Sopenharmony_ci                    size += intersect.width();
1529cb93a386Sopenharmony_ci                    // RTL text intervals move backward
1530cb93a386Sopenharmony_ci                    start = std::min(intersect.start, start);
1531cb93a386Sopenharmony_ci                    continue;
1532cb93a386Sopenharmony_ci                } else if (start == EMPTY_INDEX ) {
1533cb93a386Sopenharmony_ci                    // First time only
1534cb93a386Sopenharmony_ci                    prevStyle = style;
1535cb93a386Sopenharmony_ci                    size = intersect.width();
1536cb93a386Sopenharmony_ci                    start = intersect.start;
1537cb93a386Sopenharmony_ci                    continue;
1538cb93a386Sopenharmony_ci                }
1539cb93a386Sopenharmony_ci            }
1540cb93a386Sopenharmony_ci        } else if (prevStyle != nullptr) {
1541cb93a386Sopenharmony_ci            // This is the last style
1542cb93a386Sopenharmony_ci        } else {
1543cb93a386Sopenharmony_ci            break;
1544cb93a386Sopenharmony_ci        }
1545cb93a386Sopenharmony_ci
1546cb93a386Sopenharmony_ci        // We have the style and the text
1547cb93a386Sopenharmony_ci        auto runStyleTextRange = TextRange(start, start + size);
1548cb93a386Sopenharmony_ci        ClipContext clipContext = correctContext(runStyleTextRange, textOffsetInRun);
1549cb93a386Sopenharmony_ci        textOffsetInRun += clipContext.clip.width();
1550cb93a386Sopenharmony_ci        if (clipContext.clip.height() == 0) {
1551cb93a386Sopenharmony_ci            continue;
1552cb93a386Sopenharmony_ci        }
1553cb93a386Sopenharmony_ci
1554cb93a386Sopenharmony_ci        RectStyle temp;
1555cb93a386Sopenharmony_ci        if (styleType == StyleType::kBackground &&
1556cb93a386Sopenharmony_ci            prevStyle->getBackgroundRect() != temp &&
1557cb93a386Sopenharmony_ci            prevStyle->getHeight() != 0) {
1558cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1559cb93a386Sopenharmony_ci                clipContext.clip.fTop = run->fFontMetrics.fAscent + this->baseline();
1560cb93a386Sopenharmony_ci#else
1561cb93a386Sopenharmony_ci                clipContext.clip.fTop = run->fFontMetrics.fAscent - run->fCorrectAscent;
1562cb93a386Sopenharmony_ci#endif
1563cb93a386Sopenharmony_ci                clipContext.clip.fBottom = clipContext.clip.fTop + run->fFontMetrics.fDescent -
1564cb93a386Sopenharmony_ci                    run->fFontMetrics.fAscent;
1565cb93a386Sopenharmony_ci        }
1566cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1567cb93a386Sopenharmony_ci        computeNextPaintGlyphRange(clipContext, lastGlyphRange, styleType);
1568cb93a386Sopenharmony_ci        if (clipContext.size != 0) {
1569cb93a386Sopenharmony_ci            lastGlyphRange = TextRange(clipContext.pos, clipContext.pos + clipContext.size);
1570cb93a386Sopenharmony_ci        }
1571cb93a386Sopenharmony_ci#endif
1572cb93a386Sopenharmony_ci        visitor(runStyleTextRange, *prevStyle, clipContext);
1573cb93a386Sopenharmony_ci
1574cb93a386Sopenharmony_ci        // Start all over again
1575cb93a386Sopenharmony_ci        prevStyle = style;
1576cb93a386Sopenharmony_ci        start = intersect.start;
1577cb93a386Sopenharmony_ci        size = intersect.width();
1578cb93a386Sopenharmony_ci    }
1579cb93a386Sopenharmony_ci    return textOffsetInRun;
1580cb93a386Sopenharmony_ci}
1581cb93a386Sopenharmony_ci
1582cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1583cb93a386Sopenharmony_cibool TextLine::processEllipsisRun(bool& isAlreadyUseEllipsis,
1584cb93a386Sopenharmony_ci                                  SkScalar& runOffset,
1585cb93a386Sopenharmony_ci                                  EllipsisReadStrategy ellipsisReadStrategy,
1586cb93a386Sopenharmony_ci                                  const RunVisitor& visitor,
1587cb93a386Sopenharmony_ci                                  SkScalar& runWidthInLine) const {
1588cb93a386Sopenharmony_ci    isAlreadyUseEllipsis = true;
1589cb93a386Sopenharmony_ci    runOffset += this->ellipsis()->offset().fX;
1590cb93a386Sopenharmony_ci    if (ellipsisReadStrategy == EllipsisReadStrategy::READ_REPLACED_WORD) {
1591cb93a386Sopenharmony_ci        if (!visitor(ellipsis(), runOffset, fTextRangeReplacedByEllipsis, &runWidthInLine)) {
1592cb93a386Sopenharmony_ci            LOGE("Visitor process ellipsis replace word error!");
1593cb93a386Sopenharmony_ci            return false;
1594cb93a386Sopenharmony_ci        }
1595cb93a386Sopenharmony_ci    } else if (ellipsisReadStrategy == EllipsisReadStrategy::READ_ELLIPSIS_WORD) {
1596cb93a386Sopenharmony_ci        if (!visitor(ellipsis(), runOffset, ellipsis()->textRange(), &runWidthInLine)) {
1597cb93a386Sopenharmony_ci            LOGE("Visitor process ellipsis word error!");
1598cb93a386Sopenharmony_ci            return false;
1599cb93a386Sopenharmony_ci        }
1600cb93a386Sopenharmony_ci    } else {
1601cb93a386Sopenharmony_ci        runWidthInLine = this->ellipsis()->advance().fX;
1602cb93a386Sopenharmony_ci    }
1603cb93a386Sopenharmony_ci    return true;
1604cb93a386Sopenharmony_ci}
1605cb93a386Sopenharmony_ci#endif
1606cb93a386Sopenharmony_ci
1607cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1608cb93a386Sopenharmony_civoid TextLine::iterateThroughVisualRuns(EllipsisReadStrategy ellipsisReadStrategy,
1609cb93a386Sopenharmony_ci                                        bool includingGhostSpaces,
1610cb93a386Sopenharmony_ci                                        const RunVisitor& visitor) const {
1611cb93a386Sopenharmony_ci    // Walk through all the runs that intersect with the line in visual order
1612cb93a386Sopenharmony_ci    SkScalar width = 0;
1613cb93a386Sopenharmony_ci    SkScalar runOffset = 0;
1614cb93a386Sopenharmony_ci    SkScalar totalWidth = 0;
1615cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1616cb93a386Sopenharmony_ci    bool ellipsisModeIsHead = fIsTextLineEllipsisHeadModal ? true :
1617cb93a386Sopenharmony_ci            fOwner->paragraphStyle().getEllipsisMod() == EllipsisModal::HEAD;
1618cb93a386Sopenharmony_ci#else
1619cb93a386Sopenharmony_ci    bool ellipsisModeIsHead = fOwner->paragraphStyle().getEllipsisMod() == EllipsisModal::HEAD;
1620cb93a386Sopenharmony_ci#endif
1621cb93a386Sopenharmony_ci    bool isAlreadyUseEllipsis = false;
1622cb93a386Sopenharmony_ci    auto textRange = includingGhostSpaces ? this->textWithNewlines() : this->trimmedText();
1623cb93a386Sopenharmony_ci
1624cb93a386Sopenharmony_ci    if (fRunsInVisualOrder.size() == 0 && fEllipsis != nullptr) {
1625cb93a386Sopenharmony_ci        if (!processEllipsisRun(isAlreadyUseEllipsis, runOffset, ellipsisReadStrategy, visitor, width)) {
1626cb93a386Sopenharmony_ci            return;
1627cb93a386Sopenharmony_ci        }
1628cb93a386Sopenharmony_ci        totalWidth += width;
1629cb93a386Sopenharmony_ci    }
1630cb93a386Sopenharmony_ci
1631cb93a386Sopenharmony_ci    for (auto& runIndex : fRunsInVisualOrder) {
1632cb93a386Sopenharmony_ci        // add the lastClipRun's left ellipsis if necessary
1633cb93a386Sopenharmony_ci        if (!isAlreadyUseEllipsis && fEllipsisIndex == runIndex &&
1634cb93a386Sopenharmony_ci            ((!fLastClipRunLtr && !ellipsisModeIsHead) || (ellipsisModeIsHead && fLastClipRunLtr))) {
1635cb93a386Sopenharmony_ci            if (!processEllipsisRun(isAlreadyUseEllipsis, runOffset, ellipsisReadStrategy, visitor, width)) {
1636cb93a386Sopenharmony_ci                return;
1637cb93a386Sopenharmony_ci            }
1638cb93a386Sopenharmony_ci            runOffset += width;
1639cb93a386Sopenharmony_ci            totalWidth += width;
1640cb93a386Sopenharmony_ci        }
1641cb93a386Sopenharmony_ci
1642cb93a386Sopenharmony_ci        const auto run = &this->fOwner->run(runIndex);
1643cb93a386Sopenharmony_ci        auto lineIntersection = intersected(run->textRange(), textRange);
1644cb93a386Sopenharmony_ci        if (lineIntersection.width() == 0 && this->width() != 0) {
1645cb93a386Sopenharmony_ci            // TODO: deal with empty runs in a better way
1646cb93a386Sopenharmony_ci            continue;
1647cb93a386Sopenharmony_ci        }
1648cb93a386Sopenharmony_ci        if (!run->leftToRight() && runOffset == 0 && includingGhostSpaces) {
1649cb93a386Sopenharmony_ci            // runOffset does not take in account a possibility
1650cb93a386Sopenharmony_ci            // that RTL run could start before the line (trailing spaces)
1651cb93a386Sopenharmony_ci            // so we need to do runOffset -= "trailing whitespaces length"
1652cb93a386Sopenharmony_ci            TextRange whitespaces = intersected(
1653cb93a386Sopenharmony_ci                    TextRange(fTextExcludingSpaces.end, fTextIncludingNewlines.end), run->fTextRange);
1654cb93a386Sopenharmony_ci            if (whitespaces.width() > 0) {
1655cb93a386Sopenharmony_ci                auto whitespacesLen = measureTextInsideOneRun(whitespaces, run, runOffset, 0, true,
1656cb93a386Sopenharmony_ci                                                              TextAdjustment::GlyphCluster).clip.width();
1657cb93a386Sopenharmony_ci                runOffset -= whitespacesLen;
1658cb93a386Sopenharmony_ci            }
1659cb93a386Sopenharmony_ci        }
1660cb93a386Sopenharmony_ci
1661cb93a386Sopenharmony_ci        if (!visitor(run, runOffset, lineIntersection, &width)) {
1662cb93a386Sopenharmony_ci            return;
1663cb93a386Sopenharmony_ci        }
1664cb93a386Sopenharmony_ci
1665cb93a386Sopenharmony_ci        runOffset += width;
1666cb93a386Sopenharmony_ci        totalWidth += width;
1667cb93a386Sopenharmony_ci
1668cb93a386Sopenharmony_ci        // add the lastClipRun's right ellipsis if necessary
1669cb93a386Sopenharmony_ci        if (!isAlreadyUseEllipsis && fEllipsisIndex == runIndex) {
1670cb93a386Sopenharmony_ci            if (!processEllipsisRun(isAlreadyUseEllipsis, runOffset, ellipsisReadStrategy, visitor, width)) {
1671cb93a386Sopenharmony_ci                return;
1672cb93a386Sopenharmony_ci            }
1673cb93a386Sopenharmony_ci            runOffset += width;
1674cb93a386Sopenharmony_ci            totalWidth += width;
1675cb93a386Sopenharmony_ci        }
1676cb93a386Sopenharmony_ci    }
1677cb93a386Sopenharmony_ci
1678cb93a386Sopenharmony_ci    if (!includingGhostSpaces && compareRound(totalWidth, this->width(), fOwner->getApplyRoundingHack()) != 0) {
1679cb93a386Sopenharmony_ci    // This is a very important assert!
1680cb93a386Sopenharmony_ci    // It asserts that 2 different ways of calculation come with the same results
1681cb93a386Sopenharmony_ci        SkDebugf("ASSERT: %f != %f\n", totalWidth, this->width());
1682cb93a386Sopenharmony_ci        SkASSERT(false);
1683cb93a386Sopenharmony_ci    }
1684cb93a386Sopenharmony_ci}
1685cb93a386Sopenharmony_ci#else
1686cb93a386Sopenharmony_civoid TextLine::iterateThroughVisualRuns(bool includingGhostSpaces, const RunVisitor& visitor) const {
1687cb93a386Sopenharmony_ci
1688cb93a386Sopenharmony_ci    // Walk through all the runs that intersect with the line in visual order
1689cb93a386Sopenharmony_ci    SkScalar width = 0;
1690cb93a386Sopenharmony_ci    SkScalar runOffset = 0;
1691cb93a386Sopenharmony_ci    SkScalar totalWidth = 0;
1692cb93a386Sopenharmony_ci    auto textRange = includingGhostSpaces ? this->textWithNewlines() : this->trimmedText();
1693cb93a386Sopenharmony_ci    for (auto& runIndex : fRunsInVisualOrder) {
1694cb93a386Sopenharmony_ci
1695cb93a386Sopenharmony_ci        const auto run = &this->fOwner->run(runIndex);
1696cb93a386Sopenharmony_ci        auto lineIntersection = intersected(run->textRange(), textRange);
1697cb93a386Sopenharmony_ci        if (lineIntersection.width() == 0 && this->width() != 0) {
1698cb93a386Sopenharmony_ci            // TODO: deal with empty runs in a better way
1699cb93a386Sopenharmony_ci            continue;
1700cb93a386Sopenharmony_ci        }
1701cb93a386Sopenharmony_ci        if (!run->leftToRight() && runOffset == 0 && includingGhostSpaces) {
1702cb93a386Sopenharmony_ci            // runOffset does not take in account a possibility
1703cb93a386Sopenharmony_ci            // that RTL run could start before the line (trailing spaces)
1704cb93a386Sopenharmony_ci            // so we need to do runOffset -= "trailing whitespaces length"
1705cb93a386Sopenharmony_ci            TextRange whitespaces = intersected(
1706cb93a386Sopenharmony_ci                    TextRange(fTextExcludingSpaces.end, fTextIncludingNewlines.end), run->fTextRange);
1707cb93a386Sopenharmony_ci            if (whitespaces.width() > 0) {
1708cb93a386Sopenharmony_ci                auto whitespacesLen = measureTextInsideOneRun(whitespaces, run, runOffset, 0, true, false).clip.width();
1709cb93a386Sopenharmony_ci                runOffset -= whitespacesLen;
1710cb93a386Sopenharmony_ci            }
1711cb93a386Sopenharmony_ci        }
1712cb93a386Sopenharmony_ci        runOffset += width;
1713cb93a386Sopenharmony_ci        totalWidth += width;
1714cb93a386Sopenharmony_ci        if (!visitor(run, runOffset, lineIntersection, &width)) {
1715cb93a386Sopenharmony_ci            return;
1716cb93a386Sopenharmony_ci        }
1717cb93a386Sopenharmony_ci    }
1718cb93a386Sopenharmony_ci
1719cb93a386Sopenharmony_ci    runOffset += width;
1720cb93a386Sopenharmony_ci    totalWidth += width;
1721cb93a386Sopenharmony_ci
1722cb93a386Sopenharmony_ci    if (this->ellipsis() != nullptr) {
1723cb93a386Sopenharmony_ci        if (visitor(ellipsis(), runOffset, ellipsis()->textRange(), &width)) {
1724cb93a386Sopenharmony_ci            totalWidth += width;
1725cb93a386Sopenharmony_ci        }
1726cb93a386Sopenharmony_ci    }
1727cb93a386Sopenharmony_ci
1728cb93a386Sopenharmony_ci    // This is a very important assert!
1729cb93a386Sopenharmony_ci    // It asserts that 2 different ways of calculation come with the same results
1730cb93a386Sopenharmony_ci    if (!includingGhostSpaces && compareRound(totalWidth, this->width()) != 0) {
1731cb93a386Sopenharmony_ci        SkDebugf("ASSERT: %f != %f\n", totalWidth, this->width());
1732cb93a386Sopenharmony_ci        SkASSERT(false);
1733cb93a386Sopenharmony_ci    }
1734cb93a386Sopenharmony_ci}
1735cb93a386Sopenharmony_ci#endif
1736cb93a386Sopenharmony_ci
1737cb93a386Sopenharmony_ciSkVector TextLine::offset() const {
1738cb93a386Sopenharmony_ci    return fOffset + SkVector::Make(fShift, 0);
1739cb93a386Sopenharmony_ci}
1740cb93a386Sopenharmony_ci
1741cb93a386Sopenharmony_ciLineMetrics TextLine::getMetrics() const {
1742cb93a386Sopenharmony_ci    LineMetrics result;
1743cb93a386Sopenharmony_ci
1744cb93a386Sopenharmony_ci    // Fill out the metrics
1745cb93a386Sopenharmony_ci    fOwner->ensureUTF16Mapping();
1746cb93a386Sopenharmony_ci    result.fStartIndex = fOwner->getUTF16Index(fTextExcludingSpaces.start);
1747cb93a386Sopenharmony_ci    result.fEndExcludingWhitespaces = fOwner->getUTF16Index(fTextExcludingSpaces.end);
1748cb93a386Sopenharmony_ci    result.fEndIndex = fOwner->getUTF16Index(fText.end);
1749cb93a386Sopenharmony_ci    result.fEndIncludingNewline = fOwner->getUTF16Index(fTextIncludingNewlines.end);
1750cb93a386Sopenharmony_ci    result.fHardBreak = endsWithHardLineBreak();
1751cb93a386Sopenharmony_ci    result.fAscent = - fMaxRunMetrics.ascent();
1752cb93a386Sopenharmony_ci    result.fDescent = fMaxRunMetrics.descent();
1753cb93a386Sopenharmony_ci    result.fUnscaledAscent = - fMaxRunMetrics.ascent(); // TODO: implement
1754cb93a386Sopenharmony_ci    result.fHeight = fAdvance.fY;
1755cb93a386Sopenharmony_ci    result.fWidth = fAdvance.fX;
1756cb93a386Sopenharmony_ci    if (fOwner->getApplyRoundingHack()) {
1757cb93a386Sopenharmony_ci        result.fHeight = littleRound(result.fHeight);
1758cb93a386Sopenharmony_ci        result.fWidth = littleRound(result.fWidth);
1759cb93a386Sopenharmony_ci    }
1760cb93a386Sopenharmony_ci    result.fLeft = this->offset().fX;
1761cb93a386Sopenharmony_ci    // This is Flutter definition of a baseline
1762cb93a386Sopenharmony_ci    result.fBaseline = this->offset().fY + this->height() - this->sizes().descent();
1763cb93a386Sopenharmony_ci    result.fLineNumber = this - fOwner->lines().begin();
1764cb93a386Sopenharmony_ci    result.fWidthWithSpaces = fWidthWithSpaces;
1765cb93a386Sopenharmony_ci    result.fTopHeight = this->offset().fY;
1766cb93a386Sopenharmony_ci
1767cb93a386Sopenharmony_ci    // Fill out the style parts
1768cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1769cb93a386Sopenharmony_ci    this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, false,
1770cb93a386Sopenharmony_ci#else
1771cb93a386Sopenharmony_ci    this->iterateThroughVisualRuns(false,
1772cb93a386Sopenharmony_ci#endif
1773cb93a386Sopenharmony_ci        [this, &result]
1774cb93a386Sopenharmony_ci        (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) {
1775cb93a386Sopenharmony_ci        if (run->placeholderStyle() != nullptr) {
1776cb93a386Sopenharmony_ci            *runWidthInLine = run->advance().fX;
1777cb93a386Sopenharmony_ci            return true;
1778cb93a386Sopenharmony_ci        }
1779cb93a386Sopenharmony_ci        *runWidthInLine = this->iterateThroughSingleRunByStyles(
1780cb93a386Sopenharmony_ci        TextAdjustment::GlyphCluster, run, runOffsetInLine, textRange, StyleType::kForeground,
1781cb93a386Sopenharmony_ci        [&result, &run](TextRange textRange, const TextStyle& style, const ClipContext& context) {
1782cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
1783cb93a386Sopenharmony_ci            SkFontMetrics fontMetrics;
1784cb93a386Sopenharmony_ci            run->fFont.getMetrics(&fontMetrics);
1785cb93a386Sopenharmony_ci#else
1786cb93a386Sopenharmony_ci            RSFontMetrics fontMetrics;
1787cb93a386Sopenharmony_ci            run->fFont.GetMetrics(&fontMetrics);
1788cb93a386Sopenharmony_ci#endif
1789cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1790cb93a386Sopenharmony_ci            auto decompressFont = run->fFont;
1791cb93a386Sopenharmony_ci            scaleFontWithCompressionConfig(decompressFont, ScaleOP::DECOMPRESS);
1792cb93a386Sopenharmony_ci            metricsIncludeFontPadding(&fontMetrics, decompressFont);
1793cb93a386Sopenharmony_ci#endif
1794cb93a386Sopenharmony_ci            StyleMetrics styleMetrics(&style, fontMetrics);
1795cb93a386Sopenharmony_ci            result.fLineMetrics.emplace(textRange.start, styleMetrics);
1796cb93a386Sopenharmony_ci        });
1797cb93a386Sopenharmony_ci        return true;
1798cb93a386Sopenharmony_ci    });
1799cb93a386Sopenharmony_ci
1800cb93a386Sopenharmony_ci    return result;
1801cb93a386Sopenharmony_ci}
1802cb93a386Sopenharmony_ci
1803cb93a386Sopenharmony_cibool TextLine::isFirstLine() const {
1804cb93a386Sopenharmony_ci    return this == &fOwner->lines().front();
1805cb93a386Sopenharmony_ci}
1806cb93a386Sopenharmony_ci
1807cb93a386Sopenharmony_cibool TextLine::isLastLine() const {
1808cb93a386Sopenharmony_ci    return this == &fOwner->lines().back();
1809cb93a386Sopenharmony_ci}
1810cb93a386Sopenharmony_ci
1811cb93a386Sopenharmony_cibool TextLine::endsWithHardLineBreak() const {
1812cb93a386Sopenharmony_ci    // TODO: For some reason Flutter imagines a hard line break at the end of the last line.
1813cb93a386Sopenharmony_ci    //  To be removed...
1814cb93a386Sopenharmony_ci    return (fGhostClusterRange.width() > 0 && fOwner->cluster(fGhostClusterRange.end - 1).isHardBreak()) ||
1815cb93a386Sopenharmony_ci           fEllipsis != nullptr ||
1816cb93a386Sopenharmony_ci           fGhostClusterRange.end == fOwner->clusters().size() - 1;
1817cb93a386Sopenharmony_ci}
1818cb93a386Sopenharmony_ci
1819cb93a386Sopenharmony_civoid TextLine::getRectsForRange(TextRange textRange0,
1820cb93a386Sopenharmony_ci                                RectHeightStyle rectHeightStyle,
1821cb93a386Sopenharmony_ci                                RectWidthStyle rectWidthStyle,
1822cb93a386Sopenharmony_ci                                std::vector<TextBox>& boxes) const
1823cb93a386Sopenharmony_ci{
1824cb93a386Sopenharmony_ci    const Run* lastRun = nullptr;
1825cb93a386Sopenharmony_ci    auto startBox = boxes.size();
1826cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
1827cb93a386Sopenharmony_ci    this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, true,
1828cb93a386Sopenharmony_ci#else
1829cb93a386Sopenharmony_ci    this->iterateThroughVisualRuns(true,
1830cb93a386Sopenharmony_ci#endif
1831cb93a386Sopenharmony_ci        [textRange0, rectHeightStyle, rectWidthStyle, &boxes, &lastRun, startBox, this]
1832cb93a386Sopenharmony_ci        (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) {
1833cb93a386Sopenharmony_ci        *runWidthInLine = this->iterateThroughSingleRunByStyles(
1834cb93a386Sopenharmony_ci        TextAdjustment::GraphemeGluster, run, runOffsetInLine, textRange, StyleType::kNone,
1835cb93a386Sopenharmony_ci        [run, runOffsetInLine, textRange0, rectHeightStyle, rectWidthStyle, &boxes, &lastRun, startBox, this]
1836cb93a386Sopenharmony_ci        (TextRange textRange, const TextStyle& style, const TextLine::ClipContext& lineContext) {
1837cb93a386Sopenharmony_ci
1838cb93a386Sopenharmony_ci            auto intersect = textRange * textRange0;
1839cb93a386Sopenharmony_ci            if (intersect.empty()) {
1840cb93a386Sopenharmony_ci                return true;
1841cb93a386Sopenharmony_ci            }
1842cb93a386Sopenharmony_ci
1843cb93a386Sopenharmony_ci            auto paragraphStyle = fOwner->paragraphStyle();
1844cb93a386Sopenharmony_ci
1845cb93a386Sopenharmony_ci            // Found a run that intersects with the text
1846cb93a386Sopenharmony_ci            auto context = this->measureTextInsideOneRun(
1847cb93a386Sopenharmony_ci                    intersect, run, runOffsetInLine, 0, true, TextAdjustment::GraphemeGluster);
1848cb93a386Sopenharmony_ci            SkRect clip = context.clip;
1849cb93a386Sopenharmony_ci            clip.offset(lineContext.fTextShift - context.fTextShift, 0);
1850cb93a386Sopenharmony_ci
1851cb93a386Sopenharmony_ci            switch (rectHeightStyle) {
1852cb93a386Sopenharmony_ci                case RectHeightStyle::kMax:
1853cb93a386Sopenharmony_ci                    // TODO: Change it once flutter rolls into google3
1854cb93a386Sopenharmony_ci                    //  (probably will break things if changed before)
1855cb93a386Sopenharmony_ci                    clip.fBottom = this->height();
1856cb93a386Sopenharmony_ci                    clip.fTop = this->sizes().delta();
1857cb93a386Sopenharmony_ci                    break;
1858cb93a386Sopenharmony_ci                case RectHeightStyle::kIncludeLineSpacingTop: {
1859cb93a386Sopenharmony_ci                    clip.fBottom = this->height();
1860cb93a386Sopenharmony_ci                    clip.fTop = this->sizes().delta();
1861cb93a386Sopenharmony_ci                    auto verticalShift = this->sizes().rawAscent() - this->sizes().ascent();
1862cb93a386Sopenharmony_ci                    if (isFirstLine()) {
1863cb93a386Sopenharmony_ci                        clip.fTop += verticalShift;
1864cb93a386Sopenharmony_ci                    }
1865cb93a386Sopenharmony_ci                    break;
1866cb93a386Sopenharmony_ci                }
1867cb93a386Sopenharmony_ci                case RectHeightStyle::kIncludeLineSpacingMiddle: {
1868cb93a386Sopenharmony_ci                    clip.fBottom = this->height();
1869cb93a386Sopenharmony_ci                    clip.fTop = this->sizes().delta();
1870cb93a386Sopenharmony_ci                    auto verticalShift = this->sizes().rawAscent() - this->sizes().ascent();
1871cb93a386Sopenharmony_ci                    clip.offset(0, verticalShift / 2.0);
1872cb93a386Sopenharmony_ci                    if (isFirstLine()) {
1873cb93a386Sopenharmony_ci                        clip.fTop += verticalShift / 2.0;
1874cb93a386Sopenharmony_ci                    }
1875cb93a386Sopenharmony_ci                    if (isLastLine()) {
1876cb93a386Sopenharmony_ci                        clip.fBottom -= verticalShift / 2.0;
1877cb93a386Sopenharmony_ci                    }
1878cb93a386Sopenharmony_ci                    break;
1879cb93a386Sopenharmony_ci                 }
1880cb93a386Sopenharmony_ci                case RectHeightStyle::kIncludeLineSpacingBottom: {
1881cb93a386Sopenharmony_ci                    clip.fBottom = this->height();
1882cb93a386Sopenharmony_ci                    clip.fTop = this->sizes().delta();
1883cb93a386Sopenharmony_ci                    auto verticalShift = this->sizes().rawAscent() - this->sizes().ascent();
1884cb93a386Sopenharmony_ci                    clip.offset(0, verticalShift);
1885cb93a386Sopenharmony_ci                    if (isLastLine()) {
1886cb93a386Sopenharmony_ci                        clip.fBottom -= verticalShift;
1887cb93a386Sopenharmony_ci                    }
1888cb93a386Sopenharmony_ci                    break;
1889cb93a386Sopenharmony_ci                }
1890cb93a386Sopenharmony_ci                case RectHeightStyle::kStrut: {
1891cb93a386Sopenharmony_ci                    const auto& strutStyle = paragraphStyle.getStrutStyle();
1892cb93a386Sopenharmony_ci                    if (strutStyle.getStrutEnabled()
1893cb93a386Sopenharmony_ci                        && strutStyle.getFontSize() > 0) {
1894cb93a386Sopenharmony_ci                        auto strutMetrics = fOwner->strutMetrics();
1895cb93a386Sopenharmony_ci                        auto top = this->baseline();
1896cb93a386Sopenharmony_ci                        clip.fTop = top + strutMetrics.ascent();
1897cb93a386Sopenharmony_ci                        clip.fBottom = top + strutMetrics.descent();
1898cb93a386Sopenharmony_ci                    }
1899cb93a386Sopenharmony_ci                }
1900cb93a386Sopenharmony_ci                break;
1901cb93a386Sopenharmony_ci                case RectHeightStyle::kTight: {
1902cb93a386Sopenharmony_ci                    if (run->fHeightMultiplier <= 0) {
1903cb93a386Sopenharmony_ci                        break;
1904cb93a386Sopenharmony_ci                    }
1905cb93a386Sopenharmony_ci                    const auto effectiveBaseline = this->baseline() + this->sizes().delta();
1906cb93a386Sopenharmony_ci                    clip.fTop = effectiveBaseline + run->ascent();
1907cb93a386Sopenharmony_ci                    clip.fBottom = effectiveBaseline + run->descent();
1908cb93a386Sopenharmony_ci                }
1909cb93a386Sopenharmony_ci                break;
1910cb93a386Sopenharmony_ci                default:
1911cb93a386Sopenharmony_ci                    SkASSERT(false);
1912cb93a386Sopenharmony_ci                break;
1913cb93a386Sopenharmony_ci            }
1914cb93a386Sopenharmony_ci
1915cb93a386Sopenharmony_ci            // Separate trailing spaces and move them in the default order of the paragraph
1916cb93a386Sopenharmony_ci            // in case the run order and the paragraph order don't match
1917cb93a386Sopenharmony_ci            SkRect trailingSpaces = SkRect::MakeEmpty();
1918cb93a386Sopenharmony_ci            if (this->trimmedText().end <this->textWithNewlines().end && // Line has trailing space
1919cb93a386Sopenharmony_ci                this->textWithNewlines().end == intersect.end &&         // Range is at the end of the line
1920cb93a386Sopenharmony_ci                this->trimmedText().end > intersect.start)               // Range has more than just spaces
1921cb93a386Sopenharmony_ci            {
1922cb93a386Sopenharmony_ci                auto delta = this->spacesWidth();
1923cb93a386Sopenharmony_ci                trailingSpaces = SkRect::MakeXYWH(0, 0, 0, 0);
1924cb93a386Sopenharmony_ci                // There are trailing spaces in this run
1925cb93a386Sopenharmony_ci                if (paragraphStyle.getTextAlign() == TextAlign::kJustify && isLastLine())
1926cb93a386Sopenharmony_ci                {
1927cb93a386Sopenharmony_ci                    // TODO: this is just a patch. Make it right later (when it's clear what and how)
1928cb93a386Sopenharmony_ci                    trailingSpaces = clip;
1929cb93a386Sopenharmony_ci                    if(run->leftToRight()) {
1930cb93a386Sopenharmony_ci                        trailingSpaces.fLeft = this->width();
1931cb93a386Sopenharmony_ci                        clip.fRight = this->width();
1932cb93a386Sopenharmony_ci                    } else {
1933cb93a386Sopenharmony_ci                        trailingSpaces.fRight = 0;
1934cb93a386Sopenharmony_ci                        clip.fLeft = 0;
1935cb93a386Sopenharmony_ci                    }
1936cb93a386Sopenharmony_ci                } else if (paragraphStyle.getTextDirection() == TextDirection::kRtl &&
1937cb93a386Sopenharmony_ci                    !run->leftToRight())
1938cb93a386Sopenharmony_ci                {
1939cb93a386Sopenharmony_ci                    // Split
1940cb93a386Sopenharmony_ci                    trailingSpaces = clip;
1941cb93a386Sopenharmony_ci                    trailingSpaces.fLeft = - delta;
1942cb93a386Sopenharmony_ci                    trailingSpaces.fRight = 0;
1943cb93a386Sopenharmony_ci                    clip.fLeft += delta;
1944cb93a386Sopenharmony_ci                } else if (paragraphStyle.getTextDirection() == TextDirection::kLtr &&
1945cb93a386Sopenharmony_ci                    run->leftToRight())
1946cb93a386Sopenharmony_ci                {
1947cb93a386Sopenharmony_ci                    // Split
1948cb93a386Sopenharmony_ci                    trailingSpaces = clip;
1949cb93a386Sopenharmony_ci                    trailingSpaces.fLeft = this->width();
1950cb93a386Sopenharmony_ci                    trailingSpaces.fRight = trailingSpaces.fLeft + delta;
1951cb93a386Sopenharmony_ci                    clip.fRight -= delta;
1952cb93a386Sopenharmony_ci                }
1953cb93a386Sopenharmony_ci            }
1954cb93a386Sopenharmony_ci
1955cb93a386Sopenharmony_ci            clip.offset(this->offset());
1956cb93a386Sopenharmony_ci            if (trailingSpaces.width() > 0) {
1957cb93a386Sopenharmony_ci                trailingSpaces.offset(this->offset());
1958cb93a386Sopenharmony_ci            }
1959cb93a386Sopenharmony_ci
1960cb93a386Sopenharmony_ci            // Check if we can merge two boxes instead of adding a new one
1961cb93a386Sopenharmony_ci            auto merge = [&lastRun, &context, &boxes](SkRect clip) {
1962cb93a386Sopenharmony_ci                bool mergedBoxes = false;
1963cb93a386Sopenharmony_ci                if (!boxes.empty() &&
1964cb93a386Sopenharmony_ci                    lastRun != nullptr &&
1965cb93a386Sopenharmony_ci                    context.run->leftToRight() == lastRun->leftToRight() &&
1966cb93a386Sopenharmony_ci                    lastRun->placeholderStyle() == nullptr &&
1967cb93a386Sopenharmony_ci                    context.run->placeholderStyle() == nullptr &&
1968cb93a386Sopenharmony_ci                    nearlyEqual(lastRun->heightMultiplier(),
1969cb93a386Sopenharmony_ci                                context.run->heightMultiplier()) &&
1970cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
1971cb93a386Sopenharmony_ci                    lastRun->font() == context.run->font())
1972cb93a386Sopenharmony_ci#else
1973cb93a386Sopenharmony_ci                    IsRSFontEquals(lastRun->font(), context.run->font()))
1974cb93a386Sopenharmony_ci#endif
1975cb93a386Sopenharmony_ci                {
1976cb93a386Sopenharmony_ci                    auto& lastBox = boxes.back();
1977cb93a386Sopenharmony_ci                    if (nearlyEqual(lastBox.rect.fTop, clip.fTop) &&
1978cb93a386Sopenharmony_ci                        nearlyEqual(lastBox.rect.fBottom, clip.fBottom) &&
1979cb93a386Sopenharmony_ci                            (nearlyEqual(lastBox.rect.fLeft, clip.fRight) ||
1980cb93a386Sopenharmony_ci                             nearlyEqual(lastBox.rect.fRight, clip.fLeft)))
1981cb93a386Sopenharmony_ci                    {
1982cb93a386Sopenharmony_ci                        lastBox.rect.fLeft = std::min(lastBox.rect.fLeft, clip.fLeft);
1983cb93a386Sopenharmony_ci                        lastBox.rect.fRight = std::max(lastBox.rect.fRight, clip.fRight);
1984cb93a386Sopenharmony_ci                        mergedBoxes = true;
1985cb93a386Sopenharmony_ci                    }
1986cb93a386Sopenharmony_ci                }
1987cb93a386Sopenharmony_ci                lastRun = context.run;
1988cb93a386Sopenharmony_ci                return mergedBoxes;
1989cb93a386Sopenharmony_ci            };
1990cb93a386Sopenharmony_ci
1991cb93a386Sopenharmony_ci            if (!merge(clip)) {
1992cb93a386Sopenharmony_ci                boxes.emplace_back(clip, context.run->getTextDirection());
1993cb93a386Sopenharmony_ci            }
1994cb93a386Sopenharmony_ci            if (!nearlyZero(trailingSpaces.width()) && !merge(trailingSpaces)) {
1995cb93a386Sopenharmony_ci                boxes.emplace_back(trailingSpaces, paragraphStyle.getTextDirection());
1996cb93a386Sopenharmony_ci            }
1997cb93a386Sopenharmony_ci
1998cb93a386Sopenharmony_ci            if (rectWidthStyle == RectWidthStyle::kMax && !isLastLine()) {
1999cb93a386Sopenharmony_ci                // Align the very left/right box horizontally
2000cb93a386Sopenharmony_ci                auto lineStart = this->offset().fX;
2001cb93a386Sopenharmony_ci                auto lineEnd = this->offset().fX + this->width();
2002cb93a386Sopenharmony_ci                auto left = boxes[startBox];
2003cb93a386Sopenharmony_ci                auto right = boxes.back();
2004cb93a386Sopenharmony_ci                if (left.rect.fLeft > lineStart && left.direction == TextDirection::kRtl) {
2005cb93a386Sopenharmony_ci                    left.rect.fRight = left.rect.fLeft;
2006cb93a386Sopenharmony_ci                    left.rect.fLeft = 0;
2007cb93a386Sopenharmony_ci                    boxes.insert(boxes.begin() + startBox + 1, left);
2008cb93a386Sopenharmony_ci                }
2009cb93a386Sopenharmony_ci                if (right.direction == TextDirection::kLtr &&
2010cb93a386Sopenharmony_ci                    right.rect.fRight >= lineEnd &&
2011cb93a386Sopenharmony_ci                    right.rect.fRight < fOwner->widthWithTrailingSpaces()) {
2012cb93a386Sopenharmony_ci                    right.rect.fLeft = right.rect.fRight;
2013cb93a386Sopenharmony_ci                    right.rect.fRight = fOwner->widthWithTrailingSpaces();
2014cb93a386Sopenharmony_ci                    boxes.emplace_back(right);
2015cb93a386Sopenharmony_ci                }
2016cb93a386Sopenharmony_ci            }
2017cb93a386Sopenharmony_ci
2018cb93a386Sopenharmony_ci            return true;
2019cb93a386Sopenharmony_ci        });
2020cb93a386Sopenharmony_ci        return true;
2021cb93a386Sopenharmony_ci    });
2022cb93a386Sopenharmony_ci    if (fOwner->getApplyRoundingHack()) {
2023cb93a386Sopenharmony_ci        for (auto& r : boxes) {
2024cb93a386Sopenharmony_ci            r.rect.fLeft = littleRound(r.rect.fLeft);
2025cb93a386Sopenharmony_ci            r.rect.fRight = littleRound(r.rect.fRight);
2026cb93a386Sopenharmony_ci            r.rect.fTop = littleRound(r.rect.fTop);
2027cb93a386Sopenharmony_ci            r.rect.fBottom = littleRound(r.rect.fBottom);
2028cb93a386Sopenharmony_ci        }
2029cb93a386Sopenharmony_ci    }
2030cb93a386Sopenharmony_ci}
2031cb93a386Sopenharmony_ci
2032cb93a386Sopenharmony_ciPositionWithAffinity TextLine::getGlyphPositionAtCoordinate(SkScalar dx) {
2033cb93a386Sopenharmony_ci
2034cb93a386Sopenharmony_ci    if (SkScalarNearlyZero(this->width()) && SkScalarNearlyZero(this->spacesWidth())) {
2035cb93a386Sopenharmony_ci        // TODO: this is one of the flutter changes that have to go away eventually
2036cb93a386Sopenharmony_ci        //  Empty line is a special case in txtlib (but only when there are no spaces, too)
2037cb93a386Sopenharmony_ci        auto utf16Index = fOwner->getUTF16Index(this->fTextExcludingSpaces.end);
2038cb93a386Sopenharmony_ci        return { SkToS32(utf16Index) , kDownstream };
2039cb93a386Sopenharmony_ci    }
2040cb93a386Sopenharmony_ci
2041cb93a386Sopenharmony_ci    PositionWithAffinity result(0, Affinity::kDownstream);
2042cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
2043cb93a386Sopenharmony_ci    this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, true,
2044cb93a386Sopenharmony_ci#else
2045cb93a386Sopenharmony_ci    this->iterateThroughVisualRuns(true,
2046cb93a386Sopenharmony_ci#endif
2047cb93a386Sopenharmony_ci        [this, dx, &result]
2048cb93a386Sopenharmony_ci        (const Run* run, SkScalar runOffsetInLine, TextRange textRange, SkScalar* runWidthInLine) {
2049cb93a386Sopenharmony_ci            bool keepLooking = true;
2050cb93a386Sopenharmony_ci            *runWidthInLine = this->iterateThroughSingleRunByStyles(
2051cb93a386Sopenharmony_ci            TextAdjustment::GraphemeGluster, run, runOffsetInLine, textRange, StyleType::kNone,
2052cb93a386Sopenharmony_ci            [this, run, dx, &result, &keepLooking]
2053cb93a386Sopenharmony_ci            (TextRange textRange, const TextStyle& style, const TextLine::ClipContext& context0) {
2054cb93a386Sopenharmony_ci
2055cb93a386Sopenharmony_ci                SkScalar offsetX = this->offset().fX;
2056cb93a386Sopenharmony_ci                ClipContext context = context0;
2057cb93a386Sopenharmony_ci
2058cb93a386Sopenharmony_ci                // Correct the clip size because libtxt counts trailing spaces
2059cb93a386Sopenharmony_ci                if (run->leftToRight()) {
2060cb93a386Sopenharmony_ci                    context.clip.fRight += context.fExcludedTrailingSpaces; // extending clip to the right
2061cb93a386Sopenharmony_ci                } else {
2062cb93a386Sopenharmony_ci                    // Clip starts from 0; we cannot extend it to the left from that
2063cb93a386Sopenharmony_ci                }
2064cb93a386Sopenharmony_ci                // However, we need to offset the clip
2065cb93a386Sopenharmony_ci                context.clip.offset(offsetX, 0.0f);
2066cb93a386Sopenharmony_ci
2067cb93a386Sopenharmony_ci                // This patch will help us to avoid a floating point error
2068cb93a386Sopenharmony_ci                if (SkScalarNearlyEqual(context.clip.fRight, dx, 0.01f)) {
2069cb93a386Sopenharmony_ci                    context.clip.fRight = dx;
2070cb93a386Sopenharmony_ci                }
2071cb93a386Sopenharmony_ci
2072cb93a386Sopenharmony_ci                if (dx <= context.clip.fLeft) {
2073cb93a386Sopenharmony_ci                    // All the other runs are placed right of this one
2074cb93a386Sopenharmony_ci                    auto utf16Index = fOwner->getUTF16Index(context.run->globalClusterIndex(context.pos));
2075cb93a386Sopenharmony_ci                    if (run->leftToRight()) {
2076cb93a386Sopenharmony_ci                        result = { SkToS32(utf16Index), kDownstream};
2077cb93a386Sopenharmony_ci                        keepLooking = false;
2078cb93a386Sopenharmony_ci                    } else {
2079cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
2080cb93a386Sopenharmony_ci                        result = { SkToS32(utf16Index + 1), kUpstream};
2081cb93a386Sopenharmony_ci                        size_t glyphCnt = context.run->glyphs().size();
2082cb93a386Sopenharmony_ci                        if ((glyphCnt != 0) && (context.run->fUtf8Range.end() - context.run->fUtf8Range.begin()) /
2083cb93a386Sopenharmony_ci                            glyphCnt == EMOJI_WIDTH) {
2084cb93a386Sopenharmony_ci                            result = { SkToS32(utf16Index + 2), kUpstream};
2085cb93a386Sopenharmony_ci                        }
2086cb93a386Sopenharmony_ci#else
2087cb93a386Sopenharmony_ci                        result = { SkToS32(utf16Index + 1), kUpstream};
2088cb93a386Sopenharmony_ci#endif
2089cb93a386Sopenharmony_ci                        // If we haven't reached the end of the run we need to keep looking
2090cb93a386Sopenharmony_ci                        keepLooking = context.pos != 0;
2091cb93a386Sopenharmony_ci                    }
2092cb93a386Sopenharmony_ci                    // For RTL we go another way
2093cb93a386Sopenharmony_ci                    return !run->leftToRight();
2094cb93a386Sopenharmony_ci                }
2095cb93a386Sopenharmony_ci
2096cb93a386Sopenharmony_ci                if (dx >= context.clip.fRight) {
2097cb93a386Sopenharmony_ci                    // We have to keep looking ; just in case keep the last one as the closest
2098cb93a386Sopenharmony_ci                    auto utf16Index = fOwner->getUTF16Index(context.run->globalClusterIndex(context.pos + context.size));
2099cb93a386Sopenharmony_ci                    if (run->leftToRight()) {
2100cb93a386Sopenharmony_ci                        result = {SkToS32(utf16Index), kUpstream};
2101cb93a386Sopenharmony_ci                    } else {
2102cb93a386Sopenharmony_ci                        result = {SkToS32(utf16Index), kDownstream};
2103cb93a386Sopenharmony_ci                    }
2104cb93a386Sopenharmony_ci                    // For RTL we go another way
2105cb93a386Sopenharmony_ci                    return run->leftToRight();
2106cb93a386Sopenharmony_ci                }
2107cb93a386Sopenharmony_ci
2108cb93a386Sopenharmony_ci                // So we found the run that contains our coordinates
2109cb93a386Sopenharmony_ci                // Find the glyph position in the run that is the closest left of our point
2110cb93a386Sopenharmony_ci                // TODO: binary search
2111cb93a386Sopenharmony_ci                size_t found = context.pos;
2112cb93a386Sopenharmony_ci                for (size_t index = context.pos; index < context.pos + context.size; ++index) {
2113cb93a386Sopenharmony_ci                    // TODO: this rounding is done to match Flutter tests. Must be removed..
2114cb93a386Sopenharmony_ci                    auto end = context.run->positionX(index) + context.fTextShift + offsetX;
2115cb93a386Sopenharmony_ci                    if (fOwner->getApplyRoundingHack()) {
2116cb93a386Sopenharmony_ci                        end = littleRound(end);
2117cb93a386Sopenharmony_ci                    }
2118cb93a386Sopenharmony_ci                    if (end > dx) {
2119cb93a386Sopenharmony_ci                        break;
2120cb93a386Sopenharmony_ci                    } else if (end == dx && !context.run->leftToRight()) {
2121cb93a386Sopenharmony_ci                        // When we move RTL variable end points to the beginning of the code point which is included
2122cb93a386Sopenharmony_ci                        found = index;
2123cb93a386Sopenharmony_ci                        break;
2124cb93a386Sopenharmony_ci                    }
2125cb93a386Sopenharmony_ci                    found = index;
2126cb93a386Sopenharmony_ci                }
2127cb93a386Sopenharmony_ci
2128cb93a386Sopenharmony_ci                SkScalar glyphemePosLeft = context.run->positionX(found) + context.fTextShift + offsetX;
2129cb93a386Sopenharmony_ci                SkScalar glyphemesWidth = context.run->positionX(found + 1) - context.run->positionX(found);
2130cb93a386Sopenharmony_ci
2131cb93a386Sopenharmony_ci                // Find the grapheme range that contains the point
2132cb93a386Sopenharmony_ci                auto clusterIndex8 = context.run->globalClusterIndex(found);
2133cb93a386Sopenharmony_ci                auto clusterEnd8 = context.run->globalClusterIndex(found + 1);
2134cb93a386Sopenharmony_ci                auto graphemes = fOwner->countSurroundingGraphemes({clusterIndex8, clusterEnd8});
2135cb93a386Sopenharmony_ci
2136cb93a386Sopenharmony_ci                SkScalar center = (context.clip.right() + context.clip.left()) / 2;
2137cb93a386Sopenharmony_ci                if (graphemes.size() > 1) {
2138cb93a386Sopenharmony_ci                    // Calculate the position proportionally based on grapheme count
2139cb93a386Sopenharmony_ci                    SkScalar averageGraphemeWidth = glyphemesWidth / graphemes.size();
2140cb93a386Sopenharmony_ci                    SkScalar delta = dx - glyphemePosLeft;
2141cb93a386Sopenharmony_ci                    int graphemeIndex = SkScalarNearlyZero(averageGraphemeWidth)
2142cb93a386Sopenharmony_ci                                         ? 0
2143cb93a386Sopenharmony_ci                                         : SkScalarFloorToInt(delta / averageGraphemeWidth);
2144cb93a386Sopenharmony_ci                    auto graphemeCenter = glyphemePosLeft + graphemeIndex * averageGraphemeWidth +
2145cb93a386Sopenharmony_ci                                          averageGraphemeWidth * fOwner->getTextSplitRatio();
2146cb93a386Sopenharmony_ci                    auto graphemeUtf8Index = graphemes[graphemeIndex];
2147cb93a386Sopenharmony_ci                    if ((dx < graphemeCenter) == context.run->leftToRight()) {
2148cb93a386Sopenharmony_ci                        size_t utf16Index = fOwner->getUTF16Index(graphemeUtf8Index);
2149cb93a386Sopenharmony_ci                        result = { SkToS32(utf16Index), kDownstream };
2150cb93a386Sopenharmony_ci                    } else {
2151cb93a386Sopenharmony_ci                        size_t utf16Index = fOwner->getUTF16Index(graphemeUtf8Index + 1);
2152cb93a386Sopenharmony_ci                        result = { SkToS32(utf16Index), kUpstream };
2153cb93a386Sopenharmony_ci                    }
2154cb93a386Sopenharmony_ci                    // Keep UTF16 index as is
2155cb93a386Sopenharmony_ci                } else if ((dx < center) == context.run->leftToRight()) {
2156cb93a386Sopenharmony_ci                    size_t utf16Index = fOwner->getUTF16Index(clusterIndex8);
2157cb93a386Sopenharmony_ci                    result = { SkToS32(utf16Index), kDownstream };
2158cb93a386Sopenharmony_ci                } else {
2159cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
2160cb93a386Sopenharmony_ci                    size_t utf16Index = 0;
2161cb93a386Sopenharmony_ci                    size_t glyphCnt = context.run->glyphs().size();
2162cb93a386Sopenharmony_ci                    if ((glyphCnt != 0) && !context.run->leftToRight() && (context.run->fUtf8Range.end() -
2163cb93a386Sopenharmony_ci                        context.run->fUtf8Range.begin()) / glyphCnt == EMOJI_WIDTH) {
2164cb93a386Sopenharmony_ci                        utf16Index = fOwner->getUTF16Index(clusterIndex8) + 2;
2165cb93a386Sopenharmony_ci                    } else if (!context.run->leftToRight()) {
2166cb93a386Sopenharmony_ci                        utf16Index = fOwner->getUTF16Index(clusterIndex8) + 1;
2167cb93a386Sopenharmony_ci                    } else {
2168cb93a386Sopenharmony_ci                        utf16Index = fOwner->getUTF16Index(clusterEnd8);
2169cb93a386Sopenharmony_ci                    }
2170cb93a386Sopenharmony_ci#else
2171cb93a386Sopenharmony_ci                    size_t utf16Index = context.run->leftToRight()
2172cb93a386Sopenharmony_ci                                                ? fOwner->getUTF16Index(clusterEnd8)
2173cb93a386Sopenharmony_ci                                                : fOwner->getUTF16Index(clusterIndex8) + 1;
2174cb93a386Sopenharmony_ci#endif
2175cb93a386Sopenharmony_ci                    result = { SkToS32(utf16Index), kUpstream };
2176cb93a386Sopenharmony_ci                }
2177cb93a386Sopenharmony_ci
2178cb93a386Sopenharmony_ci                return keepLooking = false;
2179cb93a386Sopenharmony_ci
2180cb93a386Sopenharmony_ci            });
2181cb93a386Sopenharmony_ci            return keepLooking;
2182cb93a386Sopenharmony_ci        }
2183cb93a386Sopenharmony_ci    );
2184cb93a386Sopenharmony_ci    return result;
2185cb93a386Sopenharmony_ci}
2186cb93a386Sopenharmony_ci
2187cb93a386Sopenharmony_civoid TextLine::getRectsForPlaceholders(std::vector<TextBox>& boxes) {
2188cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
2189cb93a386Sopenharmony_ci    this->iterateThroughVisualRuns(EllipsisReadStrategy::READ_REPLACED_WORD, true,
2190cb93a386Sopenharmony_ci#else
2191cb93a386Sopenharmony_ci    this->iterateThroughVisualRuns( true,
2192cb93a386Sopenharmony_ci#endif
2193cb93a386Sopenharmony_ci        [&boxes, this](const Run* run, SkScalar runOffset, TextRange textRange,
2194cb93a386Sopenharmony_ci                        SkScalar* width) {
2195cb93a386Sopenharmony_ci                auto context = this->measureTextInsideOneRun(
2196cb93a386Sopenharmony_ci                        textRange, run, runOffset, 0, true, TextAdjustment::GraphemeGluster);
2197cb93a386Sopenharmony_ci                *width = context.clip.width();
2198cb93a386Sopenharmony_ci
2199cb93a386Sopenharmony_ci            if (textRange.width() == 0) {
2200cb93a386Sopenharmony_ci                return true;
2201cb93a386Sopenharmony_ci            }
2202cb93a386Sopenharmony_ci            if (!run->isPlaceholder()) {
2203cb93a386Sopenharmony_ci                return true;
2204cb93a386Sopenharmony_ci            }
2205cb93a386Sopenharmony_ci
2206cb93a386Sopenharmony_ci            SkRect clip = context.clip;
2207cb93a386Sopenharmony_ci            clip.offset(this->offset());
2208cb93a386Sopenharmony_ci
2209cb93a386Sopenharmony_ci            if (fOwner->getApplyRoundingHack()) {
2210cb93a386Sopenharmony_ci                clip.fLeft = littleRound(clip.fLeft);
2211cb93a386Sopenharmony_ci                clip.fRight = littleRound(clip.fRight);
2212cb93a386Sopenharmony_ci                clip.fTop = littleRound(clip.fTop);
2213cb93a386Sopenharmony_ci                clip.fBottom = littleRound(clip.fBottom);
2214cb93a386Sopenharmony_ci            }
2215cb93a386Sopenharmony_ci            boxes.emplace_back(clip, run->getTextDirection());
2216cb93a386Sopenharmony_ci            return true;
2217cb93a386Sopenharmony_ci        });
2218cb93a386Sopenharmony_ci}
2219cb93a386Sopenharmony_ci
2220cb93a386Sopenharmony_cisize_t TextLine::getGlyphCount() const
2221cb93a386Sopenharmony_ci{
2222cb93a386Sopenharmony_ci    size_t glyphCount = 0;
2223cb93a386Sopenharmony_ci    for (auto& blob: fTextBlobCache) {
2224cb93a386Sopenharmony_ci        glyphCount += blob.fVisitor_Size;
2225cb93a386Sopenharmony_ci    }
2226cb93a386Sopenharmony_ci    return glyphCount;
2227cb93a386Sopenharmony_ci}
2228cb93a386Sopenharmony_ci
2229cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
2230cb93a386Sopenharmony_cistd::vector<std::unique_ptr<RunBase>> TextLine::getGlyphRuns() const
2231cb93a386Sopenharmony_ci{
2232cb93a386Sopenharmony_ci    std::vector<std::unique_ptr<RunBase>> runBases;
2233cb93a386Sopenharmony_ci    size_t num = 0;
2234cb93a386Sopenharmony_ci    // Gets the offset position of the current line across the paragraph
2235cb93a386Sopenharmony_ci    size_t pos = fClusterRange.start;
2236cb93a386Sopenharmony_ci    size_t trailSpaces = 0;
2237cb93a386Sopenharmony_ci    for (auto& blob: fTextBlobCache) {
2238cb93a386Sopenharmony_ci        ++num;
2239cb93a386Sopenharmony_ci        if (blob.fVisitor_Size == 0) {
2240cb93a386Sopenharmony_ci            continue;
2241cb93a386Sopenharmony_ci        }
2242cb93a386Sopenharmony_ci        if (num == fTextBlobCache.size()) {
2243cb93a386Sopenharmony_ci            // Counts how many tabs have been removed from the end of the current line
2244cb93a386Sopenharmony_ci            trailSpaces = fGhostClusterRange.width() - fClusterRange.width();
2245cb93a386Sopenharmony_ci        }
2246cb93a386Sopenharmony_ci        std::unique_ptr<RunBaseImpl> runBaseImplPtr = std::make_unique<RunBaseImpl>(
2247cb93a386Sopenharmony_ci            blob.fBlob, blob.fOffset, blob.fPaint, blob.fClippingNeeded, blob.fClipRect,
2248cb93a386Sopenharmony_ci            blob.fVisitor_Run, blob.fVisitor_Pos, pos, trailSpaces, blob.fVisitor_Size);
2249cb93a386Sopenharmony_ci
2250cb93a386Sopenharmony_ci        // Calculate the position of each blob, relative to the entire paragraph
2251cb93a386Sopenharmony_ci        pos += blob.fVisitor_Size;
2252cb93a386Sopenharmony_ci        runBases.emplace_back(std::move(runBaseImplPtr));
2253cb93a386Sopenharmony_ci    }
2254cb93a386Sopenharmony_ci    return runBases;
2255cb93a386Sopenharmony_ci}
2256cb93a386Sopenharmony_ci#else
2257cb93a386Sopenharmony_cistd::vector<std::unique_ptr<RunBase>> TextLine::getGlyphRuns() const
2258cb93a386Sopenharmony_ci{
2259cb93a386Sopenharmony_ci    std::vector<std::unique_ptr<RunBase>> runBases;
2260cb93a386Sopenharmony_ci    for (auto& blob: fTextBlobCache) {
2261cb93a386Sopenharmony_ci        std::unique_ptr<RunBaseImpl> runBaseImplPtr = std::make_unique<RunBaseImpl>(
2262cb93a386Sopenharmony_ci            blob.fBlob, blob.fOffset, blob.fPaint, blob.fClippingNeeded, blob.fClipRect,
2263cb93a386Sopenharmony_ci            blob.fVisitor_Run, blob.fVisitor_Pos, blob.fVisitor_Size);
2264cb93a386Sopenharmony_ci        runBases.emplace_back(std::move(runBaseImplPtr));
2265cb93a386Sopenharmony_ci    }
2266cb93a386Sopenharmony_ci    return runBases;
2267cb93a386Sopenharmony_ci}
2268cb93a386Sopenharmony_ci#endif
2269cb93a386Sopenharmony_ci
2270cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
2271cb93a386Sopenharmony_ciint getEndWhitespaceCount(const ClusterRange& range, ParagraphImpl* owner)
2272cb93a386Sopenharmony_ci{
2273cb93a386Sopenharmony_ci    if (owner == nullptr) {
2274cb93a386Sopenharmony_ci        return 0;
2275cb93a386Sopenharmony_ci    }
2276cb93a386Sopenharmony_ci
2277cb93a386Sopenharmony_ci    int endWhitespaceCount = 0;
2278cb93a386Sopenharmony_ci    for (auto clusterIndex = range.end - 1; clusterIndex >= range.start; clusterIndex--) {
2279cb93a386Sopenharmony_ci        if (!owner->cluster(clusterIndex).isWhitespaceBreak()) {
2280cb93a386Sopenharmony_ci            break;
2281cb93a386Sopenharmony_ci        }
2282cb93a386Sopenharmony_ci
2283cb93a386Sopenharmony_ci        endWhitespaceCount++;
2284cb93a386Sopenharmony_ci        if (clusterIndex == range.start) {
2285cb93a386Sopenharmony_ci            break;
2286cb93a386Sopenharmony_ci        }
2287cb93a386Sopenharmony_ci    }
2288cb93a386Sopenharmony_ci
2289cb93a386Sopenharmony_ci    return endWhitespaceCount;
2290cb93a386Sopenharmony_ci}
2291cb93a386Sopenharmony_ci
2292cb93a386Sopenharmony_cistd::unique_ptr<TextLineBase> TextLine::createTruncatedLine(double width, EllipsisModal ellipsisMode,
2293cb93a386Sopenharmony_ci    const std::string& ellipsisStr)
2294cb93a386Sopenharmony_ci{
2295cb93a386Sopenharmony_ci    if (width > 0 && (ellipsisMode == EllipsisModal::HEAD || ellipsisMode == EllipsisModal::TAIL)) {
2296cb93a386Sopenharmony_ci        TextLine textLine = CloneSelf();
2297cb93a386Sopenharmony_ci        if (width < widthWithEllipsisSpaces() && !ellipsisStr.empty()) {
2298cb93a386Sopenharmony_ci            if (ellipsisMode == EllipsisModal::HEAD) {
2299cb93a386Sopenharmony_ci                textLine.fIsTextLineEllipsisHeadModal = true;
2300cb93a386Sopenharmony_ci                textLine.setTextBlobCachePopulated(false);
2301cb93a386Sopenharmony_ci                textLine.createHeadEllipsis(width, SkString(ellipsisStr), true);
2302cb93a386Sopenharmony_ci            } else if (ellipsisMode == EllipsisModal::TAIL) {
2303cb93a386Sopenharmony_ci                textLine.fIsTextLineEllipsisHeadModal = false;
2304cb93a386Sopenharmony_ci                textLine.setTextBlobCachePopulated(false);
2305cb93a386Sopenharmony_ci                int endWhitespaceCount = getEndWhitespaceCount(fGhostClusterRange, fOwner);
2306cb93a386Sopenharmony_ci                textLine.fGhostClusterRange.end -= endWhitespaceCount;
2307cb93a386Sopenharmony_ci                textLine.createTailEllipsis(width, SkString(ellipsisStr), true, fOwner->getWordBreakType());
2308cb93a386Sopenharmony_ci            }
2309cb93a386Sopenharmony_ci        }
2310cb93a386Sopenharmony_ci        return std::make_unique<TextLineBaseImpl>(std::make_unique<TextLine>(std::move(textLine)));
2311cb93a386Sopenharmony_ci    }
2312cb93a386Sopenharmony_ci
2313cb93a386Sopenharmony_ci    return nullptr;
2314cb93a386Sopenharmony_ci}
2315cb93a386Sopenharmony_ci
2316cb93a386Sopenharmony_cidouble TextLine::getTypographicBounds(double* ascent, double* descent, double* leading) const
2317cb93a386Sopenharmony_ci{
2318cb93a386Sopenharmony_ci    if (ascent == nullptr || descent == nullptr || leading == nullptr) {
2319cb93a386Sopenharmony_ci        return 0.0;
2320cb93a386Sopenharmony_ci    }
2321cb93a386Sopenharmony_ci
2322cb93a386Sopenharmony_ci    *ascent = std::abs(fMaxRunMetrics.ascent());
2323cb93a386Sopenharmony_ci    *descent = std::abs(fMaxRunMetrics.descent());
2324cb93a386Sopenharmony_ci    *leading = fMaxRunMetrics.leading();
2325cb93a386Sopenharmony_ci    return widthWithEllipsisSpaces();
2326cb93a386Sopenharmony_ci}
2327cb93a386Sopenharmony_ci
2328cb93a386Sopenharmony_cisize_t getPrevGlyphsIndex(const ClusterRange& range, ParagraphImpl* owner, RunIndex& prevRunIndex)
2329cb93a386Sopenharmony_ci{
2330cb93a386Sopenharmony_ci    if (owner == nullptr) {
2331cb93a386Sopenharmony_ci        return 0;
2332cb93a386Sopenharmony_ci    }
2333cb93a386Sopenharmony_ci
2334cb93a386Sopenharmony_ci    size_t glyphsIndex = 0;
2335cb93a386Sopenharmony_ci    auto clusterIndex = range.start - 1;
2336cb93a386Sopenharmony_ci    prevRunIndex = owner->cluster(clusterIndex).runIndex();
2337cb93a386Sopenharmony_ci    if (prevRunIndex != owner->cluster(range.start).runIndex()) {
2338cb93a386Sopenharmony_ci        // Belongs to a different run.
2339cb93a386Sopenharmony_ci        return 0;
2340cb93a386Sopenharmony_ci    }
2341cb93a386Sopenharmony_ci
2342cb93a386Sopenharmony_ci    for (; clusterIndex >= 0; clusterIndex--) {
2343cb93a386Sopenharmony_ci        RunIndex runIndex = owner->cluster(clusterIndex).runIndex();
2344cb93a386Sopenharmony_ci        if (prevRunIndex != runIndex) {
2345cb93a386Sopenharmony_ci            // Found a different run.
2346cb93a386Sopenharmony_ci            break;
2347cb93a386Sopenharmony_ci        }
2348cb93a386Sopenharmony_ci
2349cb93a386Sopenharmony_ci        glyphsIndex++;
2350cb93a386Sopenharmony_ci
2351cb93a386Sopenharmony_ci        if (clusterIndex == 0) {
2352cb93a386Sopenharmony_ci            // All belong to the first run.
2353cb93a386Sopenharmony_ci            break;
2354cb93a386Sopenharmony_ci        }
2355cb93a386Sopenharmony_ci    }
2356cb93a386Sopenharmony_ci
2357cb93a386Sopenharmony_ci    return glyphsIndex;
2358cb93a386Sopenharmony_ci}
2359cb93a386Sopenharmony_ci
2360cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
2361cb93a386Sopenharmony_cistd::vector<SkRect> getAllRectInfo(const ClusterRange& range, ParagraphImpl* owner)
2362cb93a386Sopenharmony_ci{
2363cb93a386Sopenharmony_ci    std::vector<SkRect> rectVec;
2364cb93a386Sopenharmony_ci#else
2365cb93a386Sopenharmony_cistd::vector<RSRect> getAllRectInfo(const ClusterRange& range, ParagraphImpl* owner)
2366cb93a386Sopenharmony_ci{
2367cb93a386Sopenharmony_ci    std::vector<RSRect> rectVec;
2368cb93a386Sopenharmony_ci#endif
2369cb93a386Sopenharmony_ci    if (owner == nullptr) {
2370cb93a386Sopenharmony_ci        return rectVec;
2371cb93a386Sopenharmony_ci    }
2372cb93a386Sopenharmony_ci
2373cb93a386Sopenharmony_ci    // If it is not the first line, you need to get the GlyphsIndex of the first character.
2374cb93a386Sopenharmony_ci    size_t glyphsIndex  = 0;
2375cb93a386Sopenharmony_ci    RunIndex prevRunIndex = 0;
2376cb93a386Sopenharmony_ci    if (range.start > 0) {
2377cb93a386Sopenharmony_ci        glyphsIndex = getPrevGlyphsIndex(range, owner, prevRunIndex);
2378cb93a386Sopenharmony_ci    }
2379cb93a386Sopenharmony_ci
2380cb93a386Sopenharmony_ci    for (auto clusterIndex = range.start; clusterIndex < range.end; clusterIndex++) {
2381cb93a386Sopenharmony_ci        RunIndex runIndex = owner->cluster(clusterIndex).runIndex();
2382cb93a386Sopenharmony_ci        if (prevRunIndex != runIndex) {
2383cb93a386Sopenharmony_ci            glyphsIndex = 0;
2384cb93a386Sopenharmony_ci        }
2385cb93a386Sopenharmony_ci
2386cb93a386Sopenharmony_ci        auto run = owner->cluster(clusterIndex).runOrNull();
2387cb93a386Sopenharmony_ci        if (run == nullptr) {
2388cb93a386Sopenharmony_ci            break;
2389cb93a386Sopenharmony_ci        }
2390cb93a386Sopenharmony_ci
2391cb93a386Sopenharmony_ci        SkGlyphID glyphId = run->glyphs()[glyphsIndex];
2392cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
2393cb93a386Sopenharmony_ci        SkRect glyphBounds;
2394cb93a386Sopenharmony_ci        run->font().getBounds(&glyphId, 1, &glyphBounds, nullptr);
2395cb93a386Sopenharmony_ci#else
2396cb93a386Sopenharmony_ci        RSRect glyphBounds;
2397cb93a386Sopenharmony_ci        run->font().GetWidths(&glyphId, 1, nullptr, &glyphBounds);
2398cb93a386Sopenharmony_ci#endif
2399cb93a386Sopenharmony_ci        rectVec.push_back(glyphBounds);
2400cb93a386Sopenharmony_ci        glyphsIndex++;
2401cb93a386Sopenharmony_ci        prevRunIndex = runIndex;
2402cb93a386Sopenharmony_ci    }
2403cb93a386Sopenharmony_ci
2404cb93a386Sopenharmony_ci    return rectVec;
2405cb93a386Sopenharmony_ci}
2406cb93a386Sopenharmony_ci
2407cb93a386Sopenharmony_ciRSRect TextLine::getImageBounds() const
2408cb93a386Sopenharmony_ci{
2409cb93a386Sopenharmony_ci    // Look for the first non-space character from the end and get its advance and index
2410cb93a386Sopenharmony_ci    // to calculate the final image bounds.
2411cb93a386Sopenharmony_ci    SkRect rect = {0.0, 0.0, 0.0, 0.0};
2412cb93a386Sopenharmony_ci    int endWhitespaceCount = getEndWhitespaceCount(fGhostClusterRange, fOwner);
2413cb93a386Sopenharmony_ci    if (endWhitespaceCount == (fGhostClusterRange.end - fGhostClusterRange.start)) {
2414cb93a386Sopenharmony_ci        // Full of Spaces.
2415cb93a386Sopenharmony_ci        return {};
2416cb93a386Sopenharmony_ci    }
2417cb93a386Sopenharmony_ci    SkScalar endAdvance = fOwner->cluster(fGhostClusterRange.end - endWhitespaceCount - 1).width();
2418cb93a386Sopenharmony_ci
2419cb93a386Sopenharmony_ci    // The first space width of the line needs to be added to the x value.
2420cb93a386Sopenharmony_ci    SkScalar startWhitespaceAdvance = 0.0;
2421cb93a386Sopenharmony_ci    int startWhitespaceCount = 0;
2422cb93a386Sopenharmony_ci    for (auto clusterIndex = fGhostClusterRange.start; clusterIndex < fGhostClusterRange.end; clusterIndex++) {
2423cb93a386Sopenharmony_ci        if (fOwner->cluster(clusterIndex).isWhitespaceBreak()) {
2424cb93a386Sopenharmony_ci            startWhitespaceAdvance += fOwner->cluster(clusterIndex).width();
2425cb93a386Sopenharmony_ci            startWhitespaceCount++;
2426cb93a386Sopenharmony_ci        } else {
2427cb93a386Sopenharmony_ci            break;
2428cb93a386Sopenharmony_ci        }
2429cb93a386Sopenharmony_ci    }
2430cb93a386Sopenharmony_ci
2431cb93a386Sopenharmony_ci    // Gets rect information for all characters in line.
2432cb93a386Sopenharmony_ci    auto rectVec = getAllRectInfo(fGhostClusterRange, fOwner);
2433cb93a386Sopenharmony_ci    // Calculate the final y and height.
2434cb93a386Sopenharmony_ci    auto joinRect = rectVec[startWhitespaceCount];
2435cb93a386Sopenharmony_ci    for (int i = startWhitespaceCount + 1; i < rectVec.size() - endWhitespaceCount; ++i) {
2436cb93a386Sopenharmony_ci        joinRect.Join(rectVec[i]);
2437cb93a386Sopenharmony_ci    }
2438cb93a386Sopenharmony_ci
2439cb93a386Sopenharmony_ci    SkScalar lineWidth = width();
2440cb93a386Sopenharmony_ci    auto endRect = rectVec[rectVec.size() - endWhitespaceCount - 1];
2441cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
2442cb93a386Sopenharmony_ci    SkScalar x = rectVec[startWhitespaceCount].x() + startWhitespaceAdvance;
2443cb93a386Sopenharmony_ci    SkScalar y = joinRect.bottom();
2444cb93a386Sopenharmony_ci    SkScalar width = lineWidth - (endAdvance - endRect.x() - endRect.width()) - x;
2445cb93a386Sopenharmony_ci    SkScalar height = joinRect.height();
2446cb93a386Sopenharmony_ci#else
2447cb93a386Sopenharmony_ci    SkScalar x = rectVec[startWhitespaceCount].GetLeft() + startWhitespaceAdvance;
2448cb93a386Sopenharmony_ci    SkScalar y = joinRect.GetBottom();
2449cb93a386Sopenharmony_ci    SkScalar width = lineWidth - (endAdvance - endRect.GetLeft() - endRect.GetWidth()) - x;
2450cb93a386Sopenharmony_ci    SkScalar height = joinRect.GetHeight();
2451cb93a386Sopenharmony_ci#endif
2452cb93a386Sopenharmony_ci
2453cb93a386Sopenharmony_ci    rect.setXYWH(x, y, width, height);
2454cb93a386Sopenharmony_ci    return {rect.fLeft, rect.fTop, rect.fRight, rect.fBottom};
2455cb93a386Sopenharmony_ci}
2456cb93a386Sopenharmony_ci
2457cb93a386Sopenharmony_cidouble TextLine::getTrailingSpaceWidth() const
2458cb93a386Sopenharmony_ci{
2459cb93a386Sopenharmony_ci    return spacesWidth();
2460cb93a386Sopenharmony_ci}
2461cb93a386Sopenharmony_ci
2462cb93a386Sopenharmony_ciint32_t TextLine::getStringIndexForPosition(SkPoint point) const
2463cb93a386Sopenharmony_ci{
2464cb93a386Sopenharmony_ci    int32_t index = fGhostClusterRange.start;
2465cb93a386Sopenharmony_ci    double offset = point.x();
2466cb93a386Sopenharmony_ci    if (offset >= widthWithEllipsisSpaces()) {
2467cb93a386Sopenharmony_ci        index = fGhostClusterRange.end;
2468cb93a386Sopenharmony_ci    } else if (offset > 0) {
2469cb93a386Sopenharmony_ci        double curOffset = 0.0;
2470cb93a386Sopenharmony_ci        for (auto clusterIndex = fGhostClusterRange.start; clusterIndex < fGhostClusterRange.end; ++clusterIndex) {
2471cb93a386Sopenharmony_ci            double characterWidth = fOwner->cluster(clusterIndex).width();
2472cb93a386Sopenharmony_ci            if (offset <= curOffset + characterWidth / 2) {
2473cb93a386Sopenharmony_ci                return index;
2474cb93a386Sopenharmony_ci            }
2475cb93a386Sopenharmony_ci            index++;
2476cb93a386Sopenharmony_ci            curOffset += characterWidth;
2477cb93a386Sopenharmony_ci        }
2478cb93a386Sopenharmony_ci    }
2479cb93a386Sopenharmony_ci
2480cb93a386Sopenharmony_ci    return index;
2481cb93a386Sopenharmony_ci}
2482cb93a386Sopenharmony_ci
2483cb93a386Sopenharmony_cidouble TextLine::getOffsetForStringIndex(int32_t index) const
2484cb93a386Sopenharmony_ci{
2485cb93a386Sopenharmony_ci    double offset = 0.0;
2486cb93a386Sopenharmony_ci    if (index <= 0) {
2487cb93a386Sopenharmony_ci        return offset;
2488cb93a386Sopenharmony_ci    }
2489cb93a386Sopenharmony_ci
2490cb93a386Sopenharmony_ci    if (index >= fGhostClusterRange.end) {
2491cb93a386Sopenharmony_ci        offset = widthWithEllipsisSpaces();
2492cb93a386Sopenharmony_ci    } else if (index > fGhostClusterRange.start) {
2493cb93a386Sopenharmony_ci        size_t clusterIndex = fGhostClusterRange.start;
2494cb93a386Sopenharmony_ci        while (clusterIndex < fGhostClusterRange.end) {
2495cb93a386Sopenharmony_ci            offset += fOwner->cluster(clusterIndex).width();
2496cb93a386Sopenharmony_ci            if (++clusterIndex == index) {
2497cb93a386Sopenharmony_ci                break;
2498cb93a386Sopenharmony_ci            }
2499cb93a386Sopenharmony_ci        }
2500cb93a386Sopenharmony_ci    }
2501cb93a386Sopenharmony_ci
2502cb93a386Sopenharmony_ci    return offset;
2503cb93a386Sopenharmony_ci}
2504cb93a386Sopenharmony_ci
2505cb93a386Sopenharmony_cistd::map<int32_t, double> TextLine::getIndexAndOffsets(bool& isHardBreak) const
2506cb93a386Sopenharmony_ci{
2507cb93a386Sopenharmony_ci    std::map<int32_t, double> offsetMap;
2508cb93a386Sopenharmony_ci    double offset = 0.0;
2509cb93a386Sopenharmony_ci    for (auto clusterIndex = fGhostClusterRange.start; clusterIndex < fGhostClusterRange.end; ++clusterIndex) {
2510cb93a386Sopenharmony_ci        auto& cluster = fOwner->cluster(clusterIndex);
2511cb93a386Sopenharmony_ci        offset += cluster.width();
2512cb93a386Sopenharmony_ci        isHardBreak = cluster.isHardBreak();
2513cb93a386Sopenharmony_ci        if (!isHardBreak) {
2514cb93a386Sopenharmony_ci            offsetMap[clusterIndex] = offset;
2515cb93a386Sopenharmony_ci        }
2516cb93a386Sopenharmony_ci    }
2517cb93a386Sopenharmony_ci    return offsetMap;
2518cb93a386Sopenharmony_ci}
2519cb93a386Sopenharmony_ci
2520cb93a386Sopenharmony_cidouble TextLine::getAlignmentOffset(double alignmentFactor, double alignmentWidth) const
2521cb93a386Sopenharmony_ci{
2522cb93a386Sopenharmony_ci    double lineWidth = width();
2523cb93a386Sopenharmony_ci    if (alignmentWidth <= lineWidth) {
2524cb93a386Sopenharmony_ci        return 0.0;
2525cb93a386Sopenharmony_ci    }
2526cb93a386Sopenharmony_ci
2527cb93a386Sopenharmony_ci    double offset = 0.0;
2528cb93a386Sopenharmony_ci    TextDirection textDirection = fOwner->paragraphStyle().getTextDirection();
2529cb93a386Sopenharmony_ci    if (alignmentFactor <= 0) {
2530cb93a386Sopenharmony_ci        // Flush left.
2531cb93a386Sopenharmony_ci        if (textDirection == TextDirection::kRtl) {
2532cb93a386Sopenharmony_ci            offset =  lineWidth - alignmentWidth;
2533cb93a386Sopenharmony_ci        }
2534cb93a386Sopenharmony_ci    } else if (alignmentFactor < 1) {
2535cb93a386Sopenharmony_ci        // Align according to the alignmentFactor.
2536cb93a386Sopenharmony_ci        if (textDirection == TextDirection::kLtr) {
2537cb93a386Sopenharmony_ci            offset = (alignmentWidth - lineWidth) * alignmentFactor;
2538cb93a386Sopenharmony_ci        } else {
2539cb93a386Sopenharmony_ci            offset = (lineWidth - alignmentWidth) * (1 - alignmentFactor);
2540cb93a386Sopenharmony_ci        }
2541cb93a386Sopenharmony_ci    } else {
2542cb93a386Sopenharmony_ci        // Flush right.
2543cb93a386Sopenharmony_ci        if (textDirection == TextDirection::kLtr) {
2544cb93a386Sopenharmony_ci            offset = alignmentWidth - lineWidth;
2545cb93a386Sopenharmony_ci        }
2546cb93a386Sopenharmony_ci    }
2547cb93a386Sopenharmony_ci
2548cb93a386Sopenharmony_ci    return offset;
2549cb93a386Sopenharmony_ci}
2550cb93a386Sopenharmony_ci#endif
2551cb93a386Sopenharmony_ci
2552cb93a386Sopenharmony_ciTextLine TextLine::CloneSelf()
2553cb93a386Sopenharmony_ci{
2554cb93a386Sopenharmony_ci    TextLine textLine;
2555cb93a386Sopenharmony_ci    textLine.fBlockRange = this->fBlockRange;
2556cb93a386Sopenharmony_ci    textLine.fTextExcludingSpaces = this->fTextExcludingSpaces;
2557cb93a386Sopenharmony_ci    textLine.fText = this->fText;
2558cb93a386Sopenharmony_ci    textLine.fTextIncludingNewlines = this->fTextIncludingNewlines;
2559cb93a386Sopenharmony_ci    textLine.fClusterRange = this->fClusterRange;
2560cb93a386Sopenharmony_ci
2561cb93a386Sopenharmony_ci    textLine.fGhostClusterRange = this->fGhostClusterRange;
2562cb93a386Sopenharmony_ci    textLine.fRunsInVisualOrder = this->fRunsInVisualOrder;
2563cb93a386Sopenharmony_ci    textLine.fAdvance = this->fAdvance;
2564cb93a386Sopenharmony_ci    textLine.fOffset = this->fOffset;
2565cb93a386Sopenharmony_ci    textLine.fShift = this->fShift;
2566cb93a386Sopenharmony_ci
2567cb93a386Sopenharmony_ci    textLine.fWidthWithSpaces = this->fWidthWithSpaces;
2568cb93a386Sopenharmony_ci    if (this->fEllipsis) {
2569cb93a386Sopenharmony_ci        textLine.fEllipsis = std::make_unique<Run>(*this->fEllipsis);
2570cb93a386Sopenharmony_ci    }
2571cb93a386Sopenharmony_ci
2572cb93a386Sopenharmony_ci    textLine.fSizes = this->fSizes;
2573cb93a386Sopenharmony_ci    textLine.fMaxRunMetrics = this->fMaxRunMetrics;
2574cb93a386Sopenharmony_ci    textLine.fHasBackground = this->fHasBackground;
2575cb93a386Sopenharmony_ci    textLine.fHasShadows = this->fHasShadows;
2576cb93a386Sopenharmony_ci    textLine.fHasDecorations = this->fHasDecorations;
2577cb93a386Sopenharmony_ci    textLine.fAscentStyle = this->fAscentStyle;
2578cb93a386Sopenharmony_ci    textLine.fDescentStyle = this->fDescentStyle;
2579cb93a386Sopenharmony_ci    textLine.fTextBlobCachePopulated = this->fTextBlobCachePopulated;
2580cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
2581cb93a386Sopenharmony_ci    textLine.fOwner = this->fOwner;
2582cb93a386Sopenharmony_ci    textLine.fIsTextLineEllipsisHeadModal = this->fIsTextLineEllipsisHeadModal;
2583cb93a386Sopenharmony_ci#endif
2584cb93a386Sopenharmony_ci
2585cb93a386Sopenharmony_ci    textLine.roundRectAttrs = this->roundRectAttrs;
2586cb93a386Sopenharmony_ci    textLine.fTextBlobCache = this->fTextBlobCache;
2587cb93a386Sopenharmony_ci    textLine.fTextRangeReplacedByEllipsis = this->fTextRangeReplacedByEllipsis;
2588cb93a386Sopenharmony_ci    textLine.fEllipsisIndex = this->fEllipsisIndex;
2589cb93a386Sopenharmony_ci    textLine.fLastClipRunLtr = this->fLastClipRunLtr;
2590cb93a386Sopenharmony_ci    return textLine;
2591cb93a386Sopenharmony_ci}
2592cb93a386Sopenharmony_ci}  // namespace textlayout
2593cb93a386Sopenharmony_ci}  // namespace skia
2594