1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.. All rights reserved.
3cb93a386Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4cb93a386Sopenharmony_ci * you may not use this file except in compliance with the License.
5cb93a386Sopenharmony_ci * You may obtain a copy of the License at
6cb93a386Sopenharmony_ci *
7cb93a386Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8cb93a386Sopenharmony_ci *
9cb93a386Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10cb93a386Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11cb93a386Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cb93a386Sopenharmony_ci * See the License for the specific language governing permissions and
13cb93a386Sopenharmony_ci * limitations under the License.
14cb93a386Sopenharmony_ci */
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
17cb93a386Sopenharmony_ci#include "ParagraphImpl.h"
18cb93a386Sopenharmony_ci#endif
19cb93a386Sopenharmony_ci#include "modules/skparagraph/src/RunBaseImpl.h"
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_cinamespace skia {
22cb93a386Sopenharmony_cinamespace textlayout {
23cb93a386Sopenharmony_ciRunBaseImpl::RunBaseImpl(
24cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
25cb93a386Sopenharmony_ci    sk_sp<SkTextBlob> blob,
26cb93a386Sopenharmony_ci#else
27cb93a386Sopenharmony_ci    std::shared_ptr<RSTextBlob> blob,
28cb93a386Sopenharmony_ci#endif
29cb93a386Sopenharmony_ci    SkPoint offset,
30cb93a386Sopenharmony_ci    ParagraphPainter::SkPaintOrID paint,
31cb93a386Sopenharmony_ci    bool clippingNeeded,
32cb93a386Sopenharmony_ci    SkRect clipRect,
33cb93a386Sopenharmony_ci    const Run* visitorRun,
34cb93a386Sopenharmony_ci    size_t visitorPos,
35cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
36cb93a386Sopenharmony_ci    size_t visitorGlobalPos,
37cb93a386Sopenharmony_ci    size_t trailSpaces,
38cb93a386Sopenharmony_ci#endif
39cb93a386Sopenharmony_ci    size_t visitorSize)
40cb93a386Sopenharmony_ci    : fBlob(blob),
41cb93a386Sopenharmony_ci    fOffset(offset),
42cb93a386Sopenharmony_ci    fClippingNeeded(clippingNeeded),
43cb93a386Sopenharmony_ci    fClipRect(clipRect),
44cb93a386Sopenharmony_ci    fVisitorRun(visitorRun),
45cb93a386Sopenharmony_ci    fVisitorPos(visitorPos),
46cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
47cb93a386Sopenharmony_ci    fVisitorGlobalPos(visitorGlobalPos),
48cb93a386Sopenharmony_ci    fTrailSpaces(trailSpaces),
49cb93a386Sopenharmony_ci#endif
50cb93a386Sopenharmony_ci    fVisitorSize(visitorSize)
51cb93a386Sopenharmony_ci{
52cb93a386Sopenharmony_ci    if (std::holds_alternative<SkPaint>(paint)) {
53cb93a386Sopenharmony_ci        fPaint = std::get<SkPaint>(paint);
54cb93a386Sopenharmony_ci    } else if (std::holds_alternative<ParagraphPainter::PaintID>(paint)) {
55cb93a386Sopenharmony_ci        fPaint = std::get<ParagraphPainter::PaintID>(paint);
56cb93a386Sopenharmony_ci    }
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ci}
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
61cb93a386Sopenharmony_ciconst SkFont& RunBaseImpl::font() const
62cb93a386Sopenharmony_ci#else
63cb93a386Sopenharmony_ciconst RSFont& RunBaseImpl::font() const
64cb93a386Sopenharmony_ci#endif
65cb93a386Sopenharmony_ci{
66cb93a386Sopenharmony_ci    if (!fVisitorRun) {
67cb93a386Sopenharmony_ci        return {};
68cb93a386Sopenharmony_ci    }
69cb93a386Sopenharmony_ci    return fVisitorRun->font();
70cb93a386Sopenharmony_ci}
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_cisize_t RunBaseImpl::size() const
73cb93a386Sopenharmony_ci{
74cb93a386Sopenharmony_ci    return fVisitorSize;
75cb93a386Sopenharmony_ci}
76cb93a386Sopenharmony_ci
77cb93a386Sopenharmony_cistd::vector<uint16_t> RunBaseImpl::getGlyphs() const
78cb93a386Sopenharmony_ci{
79cb93a386Sopenharmony_ci    if (!fVisitorRun) {
80cb93a386Sopenharmony_ci        return {};
81cb93a386Sopenharmony_ci    }
82cb93a386Sopenharmony_ci    SkSpan<const SkGlyphID> glyphIDSpan = fVisitorRun->glyphs();
83cb93a386Sopenharmony_ci    SkSpan<const SkGlyphID> runGlyphIDSpan = glyphIDSpan.subspan(fVisitorPos, fVisitorSize);
84cb93a386Sopenharmony_ci    return std::vector<uint16_t>(runGlyphIDSpan.begin(), runGlyphIDSpan.end());
85cb93a386Sopenharmony_ci}
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_cistd::vector<RSPoint> RunBaseImpl::getPositions() const
88cb93a386Sopenharmony_ci{
89cb93a386Sopenharmony_ci    if (!fVisitorRun) {
90cb93a386Sopenharmony_ci        return {};
91cb93a386Sopenharmony_ci    }
92cb93a386Sopenharmony_ci    SkSpan<const SkPoint> positionSpan = fVisitorRun->positions();
93cb93a386Sopenharmony_ci    SkSpan<const SkPoint> runPositionSpan = positionSpan.subspan(fVisitorPos, fVisitorSize);
94cb93a386Sopenharmony_ci    std::vector<RSPoint> positions;
95cb93a386Sopenharmony_ci    for (size_t i = 0; i < runPositionSpan.size(); i++) {
96cb93a386Sopenharmony_ci        RSPoint point(runPositionSpan[i].fX, runPositionSpan[i].fY);
97cb93a386Sopenharmony_ci        positions.emplace_back(point);
98cb93a386Sopenharmony_ci    }
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_ci    return positions;
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ci}
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_cistd::vector<RSPoint> RunBaseImpl::getOffsets() const
105cb93a386Sopenharmony_ci{
106cb93a386Sopenharmony_ci    if (!fVisitorRun) {
107cb93a386Sopenharmony_ci        return {};
108cb93a386Sopenharmony_ci    }
109cb93a386Sopenharmony_ci    SkSpan<const SkPoint> offsetSpan = fVisitorRun->offsets();
110cb93a386Sopenharmony_ci    SkSpan<const SkPoint> runOffsetSpan = offsetSpan.subspan(fVisitorPos, fVisitorSize);
111cb93a386Sopenharmony_ci    std::vector<RSPoint> offsets;
112cb93a386Sopenharmony_ci    for (size_t i = 0; i < runOffsetSpan.size(); i++) {
113cb93a386Sopenharmony_ci        RSPoint point(runOffsetSpan[i].fX, runOffsetSpan[i].fY);
114cb93a386Sopenharmony_ci        offsets.emplace_back(point);
115cb93a386Sopenharmony_ci    }
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci    return offsets;
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci}
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_civoid RunBaseImpl::paint(ParagraphPainter* painter, SkScalar x, SkScalar y)
122cb93a386Sopenharmony_ci{
123cb93a386Sopenharmony_ci    if (!painter) {
124cb93a386Sopenharmony_ci        return;
125cb93a386Sopenharmony_ci    }
126cb93a386Sopenharmony_ci    if (fClippingNeeded) {
127cb93a386Sopenharmony_ci        painter->save();
128cb93a386Sopenharmony_ci        painter->clipRect(fClipRect.makeOffset(x, y));
129cb93a386Sopenharmony_ci    }
130cb93a386Sopenharmony_ci    painter->drawTextBlob(fBlob, x + fOffset.x(), y + fOffset.y(), fPaint);
131cb93a386Sopenharmony_ci    if (fClippingNeeded) {
132cb93a386Sopenharmony_ci        painter->restore();
133cb93a386Sopenharmony_ci    }
134cb93a386Sopenharmony_ci}
135cb93a386Sopenharmony_ci
136cb93a386Sopenharmony_cisize_t RunBaseImpl::getVisitorPos() const
137cb93a386Sopenharmony_ci{
138cb93a386Sopenharmony_ci    return fVisitorPos;
139cb93a386Sopenharmony_ci}
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_cisize_t RunBaseImpl::getVisitorSize() const
142cb93a386Sopenharmony_ci{
143cb93a386Sopenharmony_ci    return fVisitorSize;
144cb93a386Sopenharmony_ci}
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci#ifdef OHOS_SUPPORT
147cb93a386Sopenharmony_cistd::vector<uint16_t> RunBaseImpl::getGlyphs(int64_t start, int64_t length) const
148cb93a386Sopenharmony_ci{
149cb93a386Sopenharmony_ci    if (!fVisitorRun) {
150cb93a386Sopenharmony_ci        return {};
151cb93a386Sopenharmony_ci    }
152cb93a386Sopenharmony_ci    uint64_t actualLength = calculateActualLength(start, length);
153cb93a386Sopenharmony_ci    if (actualLength == 0) {
154cb93a386Sopenharmony_ci        return {};
155cb93a386Sopenharmony_ci    }
156cb93a386Sopenharmony_ci    SkSpan<const SkGlyphID> glyphIdSpan = fVisitorRun->glyphs();
157cb93a386Sopenharmony_ci    SkSpan<const SkGlyphID> runGlyphIdSpan = glyphIdSpan.subspan(fVisitorPos + start, actualLength);
158cb93a386Sopenharmony_ci    std::vector<uint16_t> glyphs;
159cb93a386Sopenharmony_ci    for (size_t i = 0; i < runGlyphIdSpan.size(); i++) {
160cb93a386Sopenharmony_ci        glyphs.emplace_back(runGlyphIdSpan[i]);
161cb93a386Sopenharmony_ci    }
162cb93a386Sopenharmony_ci
163cb93a386Sopenharmony_ci    return glyphs;
164cb93a386Sopenharmony_ci}
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
167cb93a386Sopenharmony_cistd::vector<SkPoint> RunBaseImpl::getPositions(int64_t start, int64_t length) const
168cb93a386Sopenharmony_ci#else
169cb93a386Sopenharmony_cistd::vector<RSPoint> RunBaseImpl::getPositions(int64_t start, int64_t length) const
170cb93a386Sopenharmony_ci#endif
171cb93a386Sopenharmony_ci{
172cb93a386Sopenharmony_ci    if (!fVisitorRun) {
173cb93a386Sopenharmony_ci        return {};
174cb93a386Sopenharmony_ci    }
175cb93a386Sopenharmony_ci    uint64_t actualLength = calculateActualLength(start, length);
176cb93a386Sopenharmony_ci    if (actualLength == 0) {
177cb93a386Sopenharmony_ci        return {};
178cb93a386Sopenharmony_ci    }
179cb93a386Sopenharmony_ci    SkSpan<const SkPoint> positionSpan = fVisitorRun->positions();
180cb93a386Sopenharmony_ci    SkSpan<const SkPoint> runPositionSpan = positionSpan.subspan(fVisitorPos + start, actualLength);
181cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
182cb93a386Sopenharmony_ci    std::vector<SkPoint> positions;
183cb93a386Sopenharmony_ci#else
184cb93a386Sopenharmony_ci    std::vector<RSPoint> positions;
185cb93a386Sopenharmony_ci#endif
186cb93a386Sopenharmony_ci    for (size_t i = 0; i < runPositionSpan.size(); i++) {
187cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
188cb93a386Sopenharmony_ci        positions.emplace_back(SkPoint::Make(runPositionSpan[i].fX, runPositionSpan[i].fY));
189cb93a386Sopenharmony_ci#else
190cb93a386Sopenharmony_ci        positions.emplace_back(runPositionSpan[i].fX, runPositionSpan[i].fY);
191cb93a386Sopenharmony_ci#endif
192cb93a386Sopenharmony_ci    }
193cb93a386Sopenharmony_ci
194cb93a386Sopenharmony_ci    return positions;
195cb93a386Sopenharmony_ci}
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_civoid RunBaseImpl::getStringRange(uint64_t* location, uint64_t* length) const
198cb93a386Sopenharmony_ci{
199cb93a386Sopenharmony_ci    if (location == nullptr || length == nullptr) {
200cb93a386Sopenharmony_ci        return;
201cb93a386Sopenharmony_ci    } else if (!fVisitorRun) {
202cb93a386Sopenharmony_ci        *location = 0;
203cb93a386Sopenharmony_ci        *length = 0;
204cb93a386Sopenharmony_ci        return;
205cb93a386Sopenharmony_ci    }
206cb93a386Sopenharmony_ci    *location = fVisitorGlobalPos;
207cb93a386Sopenharmony_ci    *length = fVisitorSize;
208cb93a386Sopenharmony_ci}
209cb93a386Sopenharmony_ci
210cb93a386Sopenharmony_cistd::vector<uint64_t> RunBaseImpl::getStringIndices(int64_t start, int64_t length) const
211cb93a386Sopenharmony_ci{
212cb93a386Sopenharmony_ci    if (!fVisitorRun) {
213cb93a386Sopenharmony_ci        return {};
214cb93a386Sopenharmony_ci    }
215cb93a386Sopenharmony_ci    uint64_t actualLength = calculateActualLength(start, length);
216cb93a386Sopenharmony_ci    if (actualLength == 0) {
217cb93a386Sopenharmony_ci        return {};
218cb93a386Sopenharmony_ci    }
219cb93a386Sopenharmony_ci    std::vector<uint64_t> indices;
220cb93a386Sopenharmony_ci    for (size_t i = 0; i < actualLength; i++) {
221cb93a386Sopenharmony_ci        indices.emplace_back(fVisitorGlobalPos + start + i);
222cb93a386Sopenharmony_ci    }
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_ci    return indices;
225cb93a386Sopenharmony_ci}
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ciSkRect RunBaseImpl::getAllGlyphRectInfo(SkSpan<const SkGlyphID>& runGlyphIdSpan, size_t startNotWhiteSpaceIndex,
228cb93a386Sopenharmony_ci    SkScalar startWhiteSpaceWidth, size_t endWhiteSpaceNum, SkScalar endAdvance) const
229cb93a386Sopenharmony_ci{
230cb93a386Sopenharmony_ci    SkRect rect = {0.0, 0.0, 0.0, 0.0};
231cb93a386Sopenharmony_ci    SkScalar runNotWhiteSpaceWidth = 0.0;
232cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
233cb93a386Sopenharmony_ci    SkRect joinRect{0.0, 0.0, 0.0, 0.0};
234cb93a386Sopenharmony_ci    SkRect endRect {0.0, 0.0, 0.0, 0.0};
235cb93a386Sopenharmony_ci    SkRect startRect {0.0, 0.0, 0.0, 0.0};
236cb93a386Sopenharmony_ci#else
237cb93a386Sopenharmony_ci    RSRect joinRect{0.0, 0.0, 0.0, 0.0};
238cb93a386Sopenharmony_ci    RSRect endRect {0.0, 0.0, 0.0, 0.0};
239cb93a386Sopenharmony_ci    RSRect startRect {0.0, 0.0, 0.0, 0.0};
240cb93a386Sopenharmony_ci#endif
241cb93a386Sopenharmony_ci    size_t end = runGlyphIdSpan.size() - endWhiteSpaceNum;
242cb93a386Sopenharmony_ci    for (size_t i = startNotWhiteSpaceIndex; i < end; i++) {
243cb93a386Sopenharmony_ci    // Get the bounds of each glyph
244cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
245cb93a386Sopenharmony_ci        SkRect glyphBounds;
246cb93a386Sopenharmony_ci        fVisitorRun->font().getBounds(&runGlyphIdSpan[i], 1, &glyphBounds, nullptr);
247cb93a386Sopenharmony_ci#else
248cb93a386Sopenharmony_ci        RSRect glyphBounds;
249cb93a386Sopenharmony_ci        fVisitorRun->font().GetWidths(&runGlyphIdSpan[i], 1, nullptr, &glyphBounds);
250cb93a386Sopenharmony_ci#endif
251cb93a386Sopenharmony_ci        // Record the first non-blank glyph boundary
252cb93a386Sopenharmony_ci        if (i == startNotWhiteSpaceIndex) {
253cb93a386Sopenharmony_ci            startRect = glyphBounds;
254cb93a386Sopenharmony_ci        }
255cb93a386Sopenharmony_ci        if (i == end - 1) {
256cb93a386Sopenharmony_ci            endRect = glyphBounds;
257cb93a386Sopenharmony_ci        }
258cb93a386Sopenharmony_ci        // Stitching removes glyph boundaries at the beginning and end of lines
259cb93a386Sopenharmony_ci        joinRect.Join(glyphBounds);
260cb93a386Sopenharmony_ci        auto& cluster = fVisitorRun->owner()->cluster(fVisitorGlobalPos + i);
261cb93a386Sopenharmony_ci        // Calculates the width of the glyph with the beginning and end of the line removed
262cb93a386Sopenharmony_ci        runNotWhiteSpaceWidth += cluster.width();
263cb93a386Sopenharmony_ci    }
264cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
265cb93a386Sopenharmony_ci    // If the first glyph of run is a blank glyph, you need to add startWhitespaceWidth
266cb93a386Sopenharmony_ci    SkScalar x = fClipRect.fLeft + startRect.x() + startWhiteSpaceWidth;
267cb93a386Sopenharmony_ci    SkScalar y = joinRect.bottom();
268cb93a386Sopenharmony_ci    SkScalar width = runNotWhiteSpaceWidth - (endAdvance - endRect.x() - endRect.width()) - startRect.x();
269cb93a386Sopenharmony_ci    SkScalar height = joinRect.height();
270cb93a386Sopenharmony_ci#else
271cb93a386Sopenharmony_ci    SkScalar x = fClipRect.fLeft + startRect.GetLeft() + startWhiteSpaceWidth;
272cb93a386Sopenharmony_ci    SkScalar y = joinRect.GetBottom();
273cb93a386Sopenharmony_ci    SkScalar width = runNotWhiteSpaceWidth - (endAdvance - endRect.GetLeft() - endRect.GetWidth()) - startRect.GetLeft();
274cb93a386Sopenharmony_ci    SkScalar height = joinRect.GetHeight();
275cb93a386Sopenharmony_ci#endif
276cb93a386Sopenharmony_ci     rect.setXYWH(x, y, width, height);
277cb93a386Sopenharmony_ci     return rect;
278cb93a386Sopenharmony_ci}
279cb93a386Sopenharmony_ci
280cb93a386Sopenharmony_ci#ifndef USE_SKIA_TXT
281cb93a386Sopenharmony_ciSkRect RunBaseImpl::getImageBounds() const
282cb93a386Sopenharmony_ci#else
283cb93a386Sopenharmony_ciRSRect RunBaseImpl::getImageBounds() const
284cb93a386Sopenharmony_ci#endif
285cb93a386Sopenharmony_ci{
286cb93a386Sopenharmony_ci    if (!fVisitorRun) {
287cb93a386Sopenharmony_ci        return {};
288cb93a386Sopenharmony_ci    }
289cb93a386Sopenharmony_ci    SkSpan<const SkGlyphID> glyphIdSpan = fVisitorRun->glyphs();
290cb93a386Sopenharmony_ci    SkSpan<const SkGlyphID> runGlyphIdSpan = glyphIdSpan.subspan(fVisitorPos, fVisitorSize);
291cb93a386Sopenharmony_ci    if (runGlyphIdSpan.size() == 0) {
292cb93a386Sopenharmony_ci        return {};
293cb93a386Sopenharmony_ci    }
294cb93a386Sopenharmony_ci    SkScalar endAdvance = 0.0;
295cb93a386Sopenharmony_ci    SkScalar startWhiteSpaceWidth = 0.0;
296cb93a386Sopenharmony_ci    size_t endWhiteSpaceNum = 0;
297cb93a386Sopenharmony_ci    size_t startNotWhiteSpaceIndex = 0;
298cb93a386Sopenharmony_ci    // Gets the width of the first non-blank glyph at the end
299cb93a386Sopenharmony_ci    for (size_t i = runGlyphIdSpan.size() - 1; i >= 0; --i) {
300cb93a386Sopenharmony_ci        auto& cluster = fVisitorRun->owner()->cluster(fVisitorGlobalPos + i);
301cb93a386Sopenharmony_ci        if (!cluster.isWhitespaceBreak()) {
302cb93a386Sopenharmony_ci            endAdvance = cluster.width();
303cb93a386Sopenharmony_ci            break;
304cb93a386Sopenharmony_ci        }
305cb93a386Sopenharmony_ci        ++endWhiteSpaceNum;
306cb93a386Sopenharmony_ci        if (i == 0) {
307cb93a386Sopenharmony_ci            break;
308cb93a386Sopenharmony_ci        }
309cb93a386Sopenharmony_ci    }
310cb93a386Sopenharmony_ci    // Gets the width of the first non-blank glyph at the end
311cb93a386Sopenharmony_ci    for (size_t i = 0; i < runGlyphIdSpan.size(); ++i) {
312cb93a386Sopenharmony_ci        auto& cluster = fVisitorRun->owner()->cluster(fVisitorGlobalPos + i);
313cb93a386Sopenharmony_ci        if (!cluster.isWhitespaceBreak()) {
314cb93a386Sopenharmony_ci            break;
315cb93a386Sopenharmony_ci        }
316cb93a386Sopenharmony_ci        startWhiteSpaceWidth += cluster.width();
317cb93a386Sopenharmony_ci        ++startNotWhiteSpaceIndex;
318cb93a386Sopenharmony_ci    }
319cb93a386Sopenharmony_ci    SkRect rect = getAllGlyphRectInfo(runGlyphIdSpan, startNotWhiteSpaceIndex, startWhiteSpaceWidth, endWhiteSpaceNum, endAdvance);
320cb93a386Sopenharmony_ci    return {rect.fLeft, rect.fTop, rect.fRight, rect.fBottom};
321cb93a386Sopenharmony_ci}
322cb93a386Sopenharmony_ci
323cb93a386Sopenharmony_cifloat RunBaseImpl::getTypographicBounds(float* ascent, float* descent, float* leading) const
324cb93a386Sopenharmony_ci{
325cb93a386Sopenharmony_ci    if (ascent == nullptr || descent == nullptr || leading == nullptr) {
326cb93a386Sopenharmony_ci        return 0.0;
327cb93a386Sopenharmony_ci    }
328cb93a386Sopenharmony_ci    if (!fVisitorRun) {
329cb93a386Sopenharmony_ci        *ascent = 0.0;
330cb93a386Sopenharmony_ci        *descent = 0.0;
331cb93a386Sopenharmony_ci        *leading = 0.0;
332cb93a386Sopenharmony_ci        return 0.0;
333cb93a386Sopenharmony_ci    }
334cb93a386Sopenharmony_ci    *ascent = std::abs(fVisitorRun->ascent());
335cb93a386Sopenharmony_ci    *descent = fVisitorRun->descent();
336cb93a386Sopenharmony_ci    *leading = fVisitorRun->leading();
337cb93a386Sopenharmony_ci    return fClipRect.width() + calculateTrailSpacesWidth();
338cb93a386Sopenharmony_ci}
339cb93a386Sopenharmony_ci
340cb93a386Sopenharmony_cifloat RunBaseImpl::calculateTrailSpacesWidth() const
341cb93a386Sopenharmony_ci{
342cb93a386Sopenharmony_ci    // Calculates the width of the whitespace character at the end of the line
343cb93a386Sopenharmony_ci    if (!fVisitorRun || fTrailSpaces == 0) {
344cb93a386Sopenharmony_ci        return 0.0;
345cb93a386Sopenharmony_ci    }
346cb93a386Sopenharmony_ci    SkScalar spaceWidth = 0;
347cb93a386Sopenharmony_ci    for (size_t i = 0; i < fTrailSpaces; i++) {
348cb93a386Sopenharmony_ci        auto& cluster = fVisitorRun->owner()->cluster(fVisitorGlobalPos + fVisitorSize + i);
349cb93a386Sopenharmony_ci        // doesn't calculate the width of a hard line wrap at the end of a line
350cb93a386Sopenharmony_ci        if (cluster.isHardBreak()) {
351cb93a386Sopenharmony_ci            break;
352cb93a386Sopenharmony_ci        }
353cb93a386Sopenharmony_ci        spaceWidth += cluster.width();
354cb93a386Sopenharmony_ci    }
355cb93a386Sopenharmony_ci
356cb93a386Sopenharmony_ci    return spaceWidth;
357cb93a386Sopenharmony_ci}
358cb93a386Sopenharmony_ci
359cb93a386Sopenharmony_ciuint64_t RunBaseImpl::calculateActualLength(int64_t start, int64_t length) const
360cb93a386Sopenharmony_ci{
361cb93a386Sopenharmony_ci    // Calculate the actual size of the run,
362cb93a386Sopenharmony_ci    // start and length equal to 0 means that the data is obtained from start to end, so no filtering is required
363cb93a386Sopenharmony_ci    if (start >= fVisitorSize || start < 0 || length < 0) {
364cb93a386Sopenharmony_ci        return 0;
365cb93a386Sopenharmony_ci    }
366cb93a386Sopenharmony_ci    uint64_t actualLength = fVisitorSize - start;
367cb93a386Sopenharmony_ci    actualLength = actualLength > length ? length: actualLength;
368cb93a386Sopenharmony_ci    // If length is equal to 0, the end of the line is obtained
369cb93a386Sopenharmony_ci    if (start >= 0 && length == 0) {
370cb93a386Sopenharmony_ci        return fVisitorSize - start;
371cb93a386Sopenharmony_ci    }
372cb93a386Sopenharmony_ci
373cb93a386Sopenharmony_ci    return actualLength;
374cb93a386Sopenharmony_ci}
375cb93a386Sopenharmony_ci#endif
376cb93a386Sopenharmony_ci}  // namespace textlayout
377cb93a386Sopenharmony_ci}  // namespace skia