1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2018 The Android Open Source Project
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/core/SkGlyphRun.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkFont.h"
11cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
12cb93a386Sopenharmony_ci#include "include/core/SkRSXform.h"
13cb93a386Sopenharmony_ci#include "include/core/SkTextBlob.h"
14cb93a386Sopenharmony_ci#include "include/private/SkTo.h"
15cb93a386Sopenharmony_ci#include "src/core/SkDevice.h"
16cb93a386Sopenharmony_ci#include "src/core/SkFontPriv.h"
17cb93a386Sopenharmony_ci#include "src/core/SkScalerCache.h"
18cb93a386Sopenharmony_ci#include "src/core/SkStrikeCache.h"
19cb93a386Sopenharmony_ci#include "src/core/SkStrikeSpec.h"
20cb93a386Sopenharmony_ci#include "src/core/SkTextBlobPriv.h"
21cb93a386Sopenharmony_ci#include "src/core/SkUtils.h"
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ci// -- SkGlyphRun -----------------------------------------------------------------------------------
24cb93a386Sopenharmony_ciSkGlyphRun::SkGlyphRun(const SkFont& font,
25cb93a386Sopenharmony_ci                       SkSpan<const SkPoint> positions,
26cb93a386Sopenharmony_ci                       SkSpan<const SkGlyphID> glyphIDs,
27cb93a386Sopenharmony_ci                       SkSpan<const char> text,
28cb93a386Sopenharmony_ci                       SkSpan<const uint32_t> clusters,
29cb93a386Sopenharmony_ci                       SkSpan<const SkVector> scaledRotations)
30cb93a386Sopenharmony_ci        : fSource{SkMakeZip(glyphIDs, positions)}
31cb93a386Sopenharmony_ci        , fText{text}
32cb93a386Sopenharmony_ci        , fClusters{clusters}
33cb93a386Sopenharmony_ci        , fScaledRotations{scaledRotations}
34cb93a386Sopenharmony_ci        , fFont{font} {}
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ciSkGlyphRun::SkGlyphRun(const SkGlyphRun& that, const SkFont& font)
37cb93a386Sopenharmony_ci    : fSource{that.fSource}
38cb93a386Sopenharmony_ci    , fText{that.fText}
39cb93a386Sopenharmony_ci    , fClusters{that.fClusters}
40cb93a386Sopenharmony_ci    , fFont{font} {}
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_ciSkRect SkGlyphRun::sourceBounds(const SkPaint& paint) const {
43cb93a386Sopenharmony_ci    SkASSERT(this->runSize() > 0);
44cb93a386Sopenharmony_ci    const SkRect fontBounds = SkFontPriv::GetFontBounds(fFont);
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ci    if (fontBounds.isEmpty()) {
47cb93a386Sopenharmony_ci        // Empty font bounds are likely a font bug.  TightBounds has a better chance of
48cb93a386Sopenharmony_ci        // producing useful results in this case.
49cb93a386Sopenharmony_ci        auto [strikeSpec, strikeToSourceScale] = SkStrikeSpec::MakeCanonicalized(fFont, &paint);
50cb93a386Sopenharmony_ci        SkBulkGlyphMetrics metrics{strikeSpec};
51cb93a386Sopenharmony_ci        SkSpan<const SkGlyph*> glyphs = metrics.glyphs(this->glyphsIDs());
52cb93a386Sopenharmony_ci        if (fScaledRotations.empty()) {
53cb93a386Sopenharmony_ci            // No RSXForm data - glyphs x/y aligned.
54cb93a386Sopenharmony_ci            auto scaleAndTranslateRect =
55cb93a386Sopenharmony_ci                [scale = strikeToSourceScale](const SkRect& in, const SkPoint& pos) {
56cb93a386Sopenharmony_ci                    return SkRect::MakeLTRB(in.left()   * scale + pos.x(),
57cb93a386Sopenharmony_ci                                            in.top()    * scale + pos.y(),
58cb93a386Sopenharmony_ci                                            in.right()  * scale + pos.x(),
59cb93a386Sopenharmony_ci                                            in.bottom() * scale + pos.y());
60cb93a386Sopenharmony_ci                };
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci            SkRect bounds = SkRect::MakeEmpty();
63cb93a386Sopenharmony_ci            for (auto [pos, glyph] : SkMakeZip(this->positions(), glyphs)) {
64cb93a386Sopenharmony_ci                if (SkRect r = glyph->rect(); !r.isEmpty()) {
65cb93a386Sopenharmony_ci                    bounds.join(scaleAndTranslateRect(r, pos));
66cb93a386Sopenharmony_ci                }
67cb93a386Sopenharmony_ci            }
68cb93a386Sopenharmony_ci            return bounds;
69cb93a386Sopenharmony_ci        } else {
70cb93a386Sopenharmony_ci            // RSXForm - glyphs can be any scale or rotation.
71cb93a386Sopenharmony_ci            SkRect bounds = SkRect::MakeEmpty();
72cb93a386Sopenharmony_ci            for (auto [pos, scaleRotate, glyph] :
73cb93a386Sopenharmony_ci                    SkMakeZip(this->positions(), fScaledRotations, glyphs)) {
74cb93a386Sopenharmony_ci                if (!glyph->rect().isEmpty()) {
75cb93a386Sopenharmony_ci                    SkMatrix xform = SkMatrix().setRSXform(
76cb93a386Sopenharmony_ci                            SkRSXform{pos.x(), pos.y(), scaleRotate.x(), scaleRotate.y()});
77cb93a386Sopenharmony_ci                    xform.preScale(strikeToSourceScale, strikeToSourceScale);
78cb93a386Sopenharmony_ci                    bounds.join(xform.mapRect(glyph->rect()));
79cb93a386Sopenharmony_ci                }
80cb93a386Sopenharmony_ci            }
81cb93a386Sopenharmony_ci            return bounds;
82cb93a386Sopenharmony_ci        }
83cb93a386Sopenharmony_ci    }
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_ci    // Use conservative bounds. All glyph have a box of fontBounds size.
86cb93a386Sopenharmony_ci    if (fScaledRotations.empty()) {
87cb93a386Sopenharmony_ci        SkRect bounds;
88cb93a386Sopenharmony_ci        bounds.setBounds(this->positions().data(), SkCount(this->positions()));
89cb93a386Sopenharmony_ci        bounds.fLeft   += fontBounds.left();
90cb93a386Sopenharmony_ci        bounds.fTop    += fontBounds.top();
91cb93a386Sopenharmony_ci        bounds.fRight  += fontBounds.right();
92cb93a386Sopenharmony_ci        bounds.fBottom += fontBounds.bottom();
93cb93a386Sopenharmony_ci        return bounds;
94cb93a386Sopenharmony_ci    } else {
95cb93a386Sopenharmony_ci        // RSXForm case glyphs can be any scale or rotation.
96cb93a386Sopenharmony_ci        SkRect bounds;
97cb93a386Sopenharmony_ci        bounds.setEmpty();
98cb93a386Sopenharmony_ci        for (auto [pos, scaleRotate] : SkMakeZip(this->positions(), fScaledRotations)) {
99cb93a386Sopenharmony_ci            const SkRSXform xform{pos.x(), pos.y(), scaleRotate.x(), scaleRotate.y()};
100cb93a386Sopenharmony_ci            bounds.join(SkMatrix().setRSXform(xform).mapRect(fontBounds));
101cb93a386Sopenharmony_ci        }
102cb93a386Sopenharmony_ci        return bounds;
103cb93a386Sopenharmony_ci    }
104cb93a386Sopenharmony_ci}
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci// -- SkGlyphRunList -------------------------------------------------------------------------------
107cb93a386Sopenharmony_ciSkGlyphRunList::SkGlyphRunList() = default;
108cb93a386Sopenharmony_ciSkGlyphRunList::SkGlyphRunList(
109cb93a386Sopenharmony_ci        const SkTextBlob* blob,
110cb93a386Sopenharmony_ci        SkRect bounds,
111cb93a386Sopenharmony_ci        SkPoint origin,
112cb93a386Sopenharmony_ci        SkSpan<const SkGlyphRun> glyphRunList)
113cb93a386Sopenharmony_ci        : fGlyphRuns{glyphRunList}
114cb93a386Sopenharmony_ci        , fOriginalTextBlob{blob}
115cb93a386Sopenharmony_ci        , fSourceBounds{bounds}
116cb93a386Sopenharmony_ci        , fOrigin{origin} { }
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ciSkGlyphRunList::SkGlyphRunList(const SkGlyphRun& glyphRun, const SkRect& bounds, SkPoint origin)
119cb93a386Sopenharmony_ci        : fGlyphRuns{SkSpan<const SkGlyphRun>{&glyphRun, 1}}
120cb93a386Sopenharmony_ci        , fOriginalTextBlob{nullptr}
121cb93a386Sopenharmony_ci        , fSourceBounds{bounds}
122cb93a386Sopenharmony_ci        , fOrigin{origin} {}
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_ciuint64_t SkGlyphRunList::uniqueID() const {
125cb93a386Sopenharmony_ci    return fOriginalTextBlob != nullptr ? fOriginalTextBlob->uniqueID()
126cb93a386Sopenharmony_ci                                        : SK_InvalidUniqueID;
127cb93a386Sopenharmony_ci}
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_cibool SkGlyphRunList::anyRunsLCD() const {
130cb93a386Sopenharmony_ci    for (const auto& r : fGlyphRuns) {
131cb93a386Sopenharmony_ci        if (r.font().getEdging() == SkFont::Edging::kSubpixelAntiAlias) {
132cb93a386Sopenharmony_ci            return true;
133cb93a386Sopenharmony_ci        }
134cb93a386Sopenharmony_ci    }
135cb93a386Sopenharmony_ci    return false;
136cb93a386Sopenharmony_ci}
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_civoid SkGlyphRunList::temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const {
139cb93a386Sopenharmony_ci    SkASSERT(fOriginalTextBlob != nullptr);
140cb93a386Sopenharmony_ci    fOriginalTextBlob->notifyAddedToCache(cacheID);
141cb93a386Sopenharmony_ci}
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_cisk_sp<SkTextBlob> SkGlyphRunList::makeBlob() const {
144cb93a386Sopenharmony_ci    SkTextBlobBuilder builder;
145cb93a386Sopenharmony_ci    for (auto& run : *this) {
146cb93a386Sopenharmony_ci        SkTextBlobBuilder::RunBuffer buffer;
147cb93a386Sopenharmony_ci        if (run.scaledRotations().empty()) {
148cb93a386Sopenharmony_ci            if (run.text().empty()) {
149cb93a386Sopenharmony_ci                buffer = builder.allocRunPos(run.font(), run.runSize(), nullptr);
150cb93a386Sopenharmony_ci            } else {
151cb93a386Sopenharmony_ci                buffer = builder.allocRunTextPos(run.font(), run.runSize(), run.text().size(), nullptr);
152cb93a386Sopenharmony_ci                auto text = run.text();
153cb93a386Sopenharmony_ci                memcpy(buffer.utf8text, text.data(), text.size_bytes());
154cb93a386Sopenharmony_ci                auto clusters = run.clusters();
155cb93a386Sopenharmony_ci                memcpy(buffer.clusters, clusters.data(), clusters.size_bytes());
156cb93a386Sopenharmony_ci            }
157cb93a386Sopenharmony_ci            auto positions = run.positions();
158cb93a386Sopenharmony_ci            memcpy(buffer.points(), positions.data(), positions.size_bytes());
159cb93a386Sopenharmony_ci        } else {
160cb93a386Sopenharmony_ci            buffer = builder.allocRunRSXform(run.font(), run.runSize());
161cb93a386Sopenharmony_ci            for (auto [xform, pos, sr] : SkMakeZip(buffer.xforms(),
162cb93a386Sopenharmony_ci                                                   run.positions(),
163cb93a386Sopenharmony_ci                                                   run.scaledRotations())) {
164cb93a386Sopenharmony_ci                xform = SkRSXform::Make(sr.x(), sr.y(), pos.x(), pos.y());
165cb93a386Sopenharmony_ci            }
166cb93a386Sopenharmony_ci        }
167cb93a386Sopenharmony_ci        auto glyphIDs = run.glyphsIDs();
168cb93a386Sopenharmony_ci        memcpy(buffer.glyphs, glyphIDs.data(), glyphIDs.size_bytes());
169cb93a386Sopenharmony_ci    }
170cb93a386Sopenharmony_ci    return builder.make();
171cb93a386Sopenharmony_ci}
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci// -- SkGlyphRunBuilder ----------------------------------------------------------------------------
174cb93a386Sopenharmony_cistatic SkSpan<const SkPoint> draw_text_positions(
175cb93a386Sopenharmony_ci        const SkFont& font, SkSpan<const SkGlyphID> glyphIDs, SkPoint origin, SkPoint* buffer) {
176cb93a386Sopenharmony_ci    SkStrikeSpec strikeSpec = SkStrikeSpec::MakeWithNoDevice(font);
177cb93a386Sopenharmony_ci    SkBulkGlyphMetrics storage{strikeSpec};
178cb93a386Sopenharmony_ci    auto glyphs = storage.glyphs(glyphIDs);
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_ci    SkPoint* positionCursor = buffer;
181cb93a386Sopenharmony_ci    SkPoint endOfLastGlyph = origin;
182cb93a386Sopenharmony_ci    for (auto glyph : glyphs) {
183cb93a386Sopenharmony_ci        *positionCursor++ = endOfLastGlyph;
184cb93a386Sopenharmony_ci        endOfLastGlyph += glyph->advanceVector();
185cb93a386Sopenharmony_ci    }
186cb93a386Sopenharmony_ci    return SkMakeSpan(buffer, glyphIDs.size());
187cb93a386Sopenharmony_ci}
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_ciconst SkGlyphRunList& SkGlyphRunBuilder::textToGlyphRunList(
190cb93a386Sopenharmony_ci        const SkFont& font, const SkPaint& paint,
191cb93a386Sopenharmony_ci        const void* bytes, size_t byteLength, SkPoint origin,
192cb93a386Sopenharmony_ci        SkTextEncoding encoding) {
193cb93a386Sopenharmony_ci    auto glyphIDs = textToGlyphIDs(font, bytes, byteLength, encoding);
194cb93a386Sopenharmony_ci    SkRect bounds = SkRect::MakeEmpty();
195cb93a386Sopenharmony_ci    this->prepareBuffers(glyphIDs.size(), 0);
196cb93a386Sopenharmony_ci    if (!glyphIDs.empty()) {
197cb93a386Sopenharmony_ci        SkSpan<const SkPoint> positions = draw_text_positions(font, glyphIDs, {0, 0}, fPositions);
198cb93a386Sopenharmony_ci        this->makeGlyphRun(font,
199cb93a386Sopenharmony_ci                           glyphIDs,
200cb93a386Sopenharmony_ci                           positions,
201cb93a386Sopenharmony_ci                           SkSpan<const char>{},
202cb93a386Sopenharmony_ci                           SkSpan<const uint32_t>{},
203cb93a386Sopenharmony_ci                           SkSpan<const SkVector>{});
204cb93a386Sopenharmony_ci        bounds = fGlyphRunListStorage.front().sourceBounds(paint);
205cb93a386Sopenharmony_ci    }
206cb93a386Sopenharmony_ci
207cb93a386Sopenharmony_ci    return this->makeGlyphRunList(nullptr, bounds.makeOffset(origin), origin);
208cb93a386Sopenharmony_ci}
209cb93a386Sopenharmony_ci
210cb93a386Sopenharmony_ciconst SkGlyphRunList& SkGlyphRunBuilder::blobToGlyphRunList(
211cb93a386Sopenharmony_ci        const SkTextBlob& blob, SkPoint origin) {
212cb93a386Sopenharmony_ci    // Pre-size all the buffers so they don't move during processing.
213cb93a386Sopenharmony_ci    this->initialize(blob);
214cb93a386Sopenharmony_ci
215cb93a386Sopenharmony_ci    SkPoint* positionCursor = fPositions;
216cb93a386Sopenharmony_ci    SkVector* scaledRotationsCursor = fScaledRotations;
217cb93a386Sopenharmony_ci    for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
218cb93a386Sopenharmony_ci        size_t runSize = it.glyphCount();
219cb93a386Sopenharmony_ci        if (runSize == 0 || !SkFontPriv::IsFinite(it.font())) {
220cb93a386Sopenharmony_ci            // If no glyphs or the font is not finite, don't add the run.
221cb93a386Sopenharmony_ci            continue;
222cb93a386Sopenharmony_ci        }
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_ci        const SkFont& font = it.font();
225cb93a386Sopenharmony_ci        auto glyphIDs = SkSpan<const SkGlyphID>{it.glyphs(), runSize};
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci        SkSpan<const SkPoint> positions;
228cb93a386Sopenharmony_ci        SkSpan<const SkVector> scaledRotations;
229cb93a386Sopenharmony_ci        switch (it.positioning()) {
230cb93a386Sopenharmony_ci            case SkTextBlobRunIterator::kDefault_Positioning: {
231cb93a386Sopenharmony_ci                positions = draw_text_positions(font, glyphIDs, it.offset(), positionCursor);
232cb93a386Sopenharmony_ci                positionCursor += positions.size();
233cb93a386Sopenharmony_ci                break;
234cb93a386Sopenharmony_ci            }
235cb93a386Sopenharmony_ci            case SkTextBlobRunIterator::kHorizontal_Positioning: {
236cb93a386Sopenharmony_ci                positions = SkMakeSpan(positionCursor, runSize);
237cb93a386Sopenharmony_ci                for (auto x : SkSpan<const SkScalar>{it.pos(), glyphIDs.size()}) {
238cb93a386Sopenharmony_ci                    *positionCursor++ = SkPoint::Make(x, it.offset().y());
239cb93a386Sopenharmony_ci                }
240cb93a386Sopenharmony_ci                break;
241cb93a386Sopenharmony_ci            }
242cb93a386Sopenharmony_ci            case SkTextBlobRunIterator::kFull_Positioning: {
243cb93a386Sopenharmony_ci                positions = SkMakeSpan(it.points(), runSize);
244cb93a386Sopenharmony_ci                break;
245cb93a386Sopenharmony_ci            }
246cb93a386Sopenharmony_ci            case SkTextBlobRunIterator::kRSXform_Positioning: {
247cb93a386Sopenharmony_ci                positions = SkMakeSpan(positionCursor, runSize);
248cb93a386Sopenharmony_ci                scaledRotations = SkMakeSpan(scaledRotationsCursor, runSize);
249cb93a386Sopenharmony_ci                for (const SkRSXform& xform : SkMakeSpan(it.xforms(), runSize)) {
250cb93a386Sopenharmony_ci                    *positionCursor++ = {xform.fTx, xform.fTy};
251cb93a386Sopenharmony_ci                    *scaledRotationsCursor++ = {xform.fSCos, xform.fSSin};
252cb93a386Sopenharmony_ci                }
253cb93a386Sopenharmony_ci                break;
254cb93a386Sopenharmony_ci            }
255cb93a386Sopenharmony_ci        }
256cb93a386Sopenharmony_ci
257cb93a386Sopenharmony_ci        this->makeGlyphRun(
258cb93a386Sopenharmony_ci                font,
259cb93a386Sopenharmony_ci                glyphIDs,
260cb93a386Sopenharmony_ci                positions,
261cb93a386Sopenharmony_ci                SkSpan<const char>(it.text(), it.textSize()),
262cb93a386Sopenharmony_ci                SkSpan<const uint32_t>(it.clusters(), runSize),
263cb93a386Sopenharmony_ci                scaledRotations);
264cb93a386Sopenharmony_ci    }
265cb93a386Sopenharmony_ci
266cb93a386Sopenharmony_ci    return this->makeGlyphRunList(&blob, blob.bounds().makeOffset(origin), origin);
267cb93a386Sopenharmony_ci}
268cb93a386Sopenharmony_ci
269cb93a386Sopenharmony_cistd::tuple<SkSpan<const SkPoint>, SkSpan<const SkVector>>
270cb93a386Sopenharmony_ciSkGlyphRunBuilder::convertRSXForm(SkSpan<const SkRSXform> xforms) {
271cb93a386Sopenharmony_ci    const int count = SkCount(xforms);
272cb93a386Sopenharmony_ci    this->prepareBuffers(count, count);
273cb93a386Sopenharmony_ci    auto positions = SkMakeSpan(fPositions.get(), count);
274cb93a386Sopenharmony_ci    auto scaledRotations = SkMakeSpan(fScaledRotations.get(), count);
275cb93a386Sopenharmony_ci    for (auto [pos, sr, xform] : SkMakeZip(positions, scaledRotations, xforms)) {
276cb93a386Sopenharmony_ci        auto [scos, ssin, tx, ty] = xform;
277cb93a386Sopenharmony_ci        pos = {tx, ty};
278cb93a386Sopenharmony_ci        sr = {scos, ssin};
279cb93a386Sopenharmony_ci    }
280cb93a386Sopenharmony_ci    return {positions, scaledRotations};
281cb93a386Sopenharmony_ci}
282cb93a386Sopenharmony_ci
283cb93a386Sopenharmony_civoid SkGlyphRunBuilder::initialize(const SkTextBlob& blob) {
284cb93a386Sopenharmony_ci    int positionCount = 0;
285cb93a386Sopenharmony_ci    int rsxFormCount = 0;
286cb93a386Sopenharmony_ci    for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
287cb93a386Sopenharmony_ci        if (it.positioning() != SkTextBlobRunIterator::kFull_Positioning) {
288cb93a386Sopenharmony_ci            positionCount += it.glyphCount();
289cb93a386Sopenharmony_ci        }
290cb93a386Sopenharmony_ci        if (it.positioning() == SkTextBlobRunIterator::kRSXform_Positioning) {
291cb93a386Sopenharmony_ci            rsxFormCount += it.glyphCount();
292cb93a386Sopenharmony_ci        }
293cb93a386Sopenharmony_ci    }
294cb93a386Sopenharmony_ci
295cb93a386Sopenharmony_ci    prepareBuffers(positionCount, rsxFormCount);
296cb93a386Sopenharmony_ci}
297cb93a386Sopenharmony_ci
298cb93a386Sopenharmony_civoid SkGlyphRunBuilder::prepareBuffers(int positionCount, int RSXFormCount) {
299cb93a386Sopenharmony_ci    if (positionCount > fMaxTotalRunSize) {
300cb93a386Sopenharmony_ci        fMaxTotalRunSize = positionCount;
301cb93a386Sopenharmony_ci        fPositions.reset(fMaxTotalRunSize);
302cb93a386Sopenharmony_ci    }
303cb93a386Sopenharmony_ci
304cb93a386Sopenharmony_ci    if (RSXFormCount > fMaxScaledRotations) {
305cb93a386Sopenharmony_ci        fMaxScaledRotations = RSXFormCount;
306cb93a386Sopenharmony_ci        fScaledRotations.reset(RSXFormCount);
307cb93a386Sopenharmony_ci    }
308cb93a386Sopenharmony_ci
309cb93a386Sopenharmony_ci    fGlyphRunListStorage.clear();
310cb93a386Sopenharmony_ci}
311cb93a386Sopenharmony_ci
312cb93a386Sopenharmony_ciSkSpan<const SkGlyphID> SkGlyphRunBuilder::textToGlyphIDs(
313cb93a386Sopenharmony_ci        const SkFont& font, const void* bytes, size_t byteLength, SkTextEncoding encoding) {
314cb93a386Sopenharmony_ci    if (encoding != SkTextEncoding::kGlyphID) {
315cb93a386Sopenharmony_ci        int count = font.countText(bytes, byteLength, encoding);
316cb93a386Sopenharmony_ci        if (count > 0) {
317cb93a386Sopenharmony_ci            fScratchGlyphIDs.resize(count);
318cb93a386Sopenharmony_ci            font.textToGlyphs(bytes, byteLength, encoding, fScratchGlyphIDs.data(), count);
319cb93a386Sopenharmony_ci            return SkMakeSpan(fScratchGlyphIDs);
320cb93a386Sopenharmony_ci        } else {
321cb93a386Sopenharmony_ci            return SkSpan<const SkGlyphID>();
322cb93a386Sopenharmony_ci        }
323cb93a386Sopenharmony_ci    } else {
324cb93a386Sopenharmony_ci        return SkSpan<const SkGlyphID>((const SkGlyphID*)bytes, byteLength / 2);
325cb93a386Sopenharmony_ci    }
326cb93a386Sopenharmony_ci}
327cb93a386Sopenharmony_ci
328cb93a386Sopenharmony_civoid SkGlyphRunBuilder::makeGlyphRun(
329cb93a386Sopenharmony_ci        const SkFont& font,
330cb93a386Sopenharmony_ci        SkSpan<const SkGlyphID> glyphIDs,
331cb93a386Sopenharmony_ci        SkSpan<const SkPoint> positions,
332cb93a386Sopenharmony_ci        SkSpan<const char> text,
333cb93a386Sopenharmony_ci        SkSpan<const uint32_t> clusters,
334cb93a386Sopenharmony_ci        SkSpan<const SkVector> scaledRotations) {
335cb93a386Sopenharmony_ci
336cb93a386Sopenharmony_ci    // Ignore empty runs.
337cb93a386Sopenharmony_ci    if (!glyphIDs.empty()) {
338cb93a386Sopenharmony_ci        fGlyphRunListStorage.emplace_back(
339cb93a386Sopenharmony_ci                font,
340cb93a386Sopenharmony_ci                positions,
341cb93a386Sopenharmony_ci                glyphIDs,
342cb93a386Sopenharmony_ci                text,
343cb93a386Sopenharmony_ci                clusters,
344cb93a386Sopenharmony_ci                scaledRotations);
345cb93a386Sopenharmony_ci    }
346cb93a386Sopenharmony_ci}
347cb93a386Sopenharmony_ci
348cb93a386Sopenharmony_ciconst SkGlyphRunList& SkGlyphRunBuilder::makeGlyphRunList(
349cb93a386Sopenharmony_ci        const SkTextBlob* blob, const SkRect& bounds, SkPoint origin) {
350cb93a386Sopenharmony_ci    fGlyphRunList.~SkGlyphRunList();
351cb93a386Sopenharmony_ci    return *new (&fGlyphRunList)
352cb93a386Sopenharmony_ci            SkGlyphRunList{blob, bounds, origin, SkMakeSpan(fGlyphRunListStorage)};
353cb93a386Sopenharmony_ci}
354