1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc.
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 "include/core/SkRSXform.h"
9cb93a386Sopenharmony_ci#include "include/core/SkTextBlob.h"
10cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h"
11cb93a386Sopenharmony_ci#include "src/core/SkFontPriv.h"
12cb93a386Sopenharmony_ci#include "src/core/SkGlyphRun.h"
13cb93a386Sopenharmony_ci#include "src/core/SkPaintPriv.h"
14cb93a386Sopenharmony_ci#include "src/core/SkReadBuffer.h"
15cb93a386Sopenharmony_ci#include "src/core/SkSafeMath.h"
16cb93a386Sopenharmony_ci#include "src/core/SkStrikeCache.h"
17cb93a386Sopenharmony_ci#include "src/core/SkStrikeSpec.h"
18cb93a386Sopenharmony_ci#include "src/core/SkTextBlobPriv.h"
19cb93a386Sopenharmony_ci#include "src/core/SkWriteBuffer.h"
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci#include <atomic>
22cb93a386Sopenharmony_ci#include <limits>
23cb93a386Sopenharmony_ci#include <new>
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_ci#if SK_SUPPORT_GPU
26cb93a386Sopenharmony_ci#include "src/gpu/text/GrTextBlobCache.h"
27cb93a386Sopenharmony_ci#endif
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_cinamespace {
30cb93a386Sopenharmony_cistruct RunFontStorageEquivalent {
31cb93a386Sopenharmony_ci    SkScalar fSize, fScaleX;
32cb93a386Sopenharmony_ci    void*    fTypeface;
33cb93a386Sopenharmony_ci    SkScalar fSkewX;
34cb93a386Sopenharmony_ci    uint32_t fFlags;
35cb93a386Sopenharmony_ci};
36cb93a386Sopenharmony_cistatic_assert(sizeof(SkFont) == sizeof(RunFontStorageEquivalent), "runfont_should_stay_packed");
37cb93a386Sopenharmony_ci}  // namespace
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_cisize_t SkTextBlob::RunRecord::StorageSize(uint32_t glyphCount, uint32_t textSize,
40cb93a386Sopenharmony_ci                                          SkTextBlob::GlyphPositioning positioning,
41cb93a386Sopenharmony_ci                                          SkSafeMath* safe) {
42cb93a386Sopenharmony_ci    static_assert(SkIsAlign4(sizeof(SkScalar)), "SkScalar size alignment");
43cb93a386Sopenharmony_ci
44cb93a386Sopenharmony_ci    auto glyphSize = safe->mul(glyphCount, sizeof(uint16_t)),
45cb93a386Sopenharmony_ci            posSize = safe->mul(PosCount(glyphCount, positioning, safe), sizeof(SkScalar));
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci    // RunRecord object + (aligned) glyph buffer + position buffer
48cb93a386Sopenharmony_ci    auto size = sizeof(SkTextBlob::RunRecord);
49cb93a386Sopenharmony_ci    size = safe->add(size, safe->alignUp(glyphSize, 4));
50cb93a386Sopenharmony_ci    size = safe->add(size, posSize);
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci    if (textSize) {  // Extended run.
53cb93a386Sopenharmony_ci        size = safe->add(size, sizeof(uint32_t));
54cb93a386Sopenharmony_ci        size = safe->add(size, safe->mul(glyphCount, sizeof(uint32_t)));
55cb93a386Sopenharmony_ci        size = safe->add(size, textSize);
56cb93a386Sopenharmony_ci    }
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ci    return safe->alignUp(size, sizeof(void*));
59cb93a386Sopenharmony_ci}
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ciconst SkTextBlob::RunRecord* SkTextBlob::RunRecord::First(const SkTextBlob* blob) {
62cb93a386Sopenharmony_ci    // The first record (if present) is stored following the blob object.
63cb93a386Sopenharmony_ci    // (aligned up to make the RunRecord aligned too)
64cb93a386Sopenharmony_ci    return reinterpret_cast<const RunRecord*>(SkAlignPtr((uintptr_t)(blob + 1)));
65cb93a386Sopenharmony_ci}
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ciconst SkTextBlob::RunRecord* SkTextBlob::RunRecord::Next(const RunRecord* run) {
68cb93a386Sopenharmony_ci    return SkToBool(run->fFlags & kLast_Flag) ? nullptr : NextUnchecked(run);
69cb93a386Sopenharmony_ci}
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_cinamespace {
72cb93a386Sopenharmony_cistruct RunRecordStorageEquivalent {
73cb93a386Sopenharmony_ci    SkFont   fFont;
74cb93a386Sopenharmony_ci    SkPoint  fOffset;
75cb93a386Sopenharmony_ci    uint32_t fCount;
76cb93a386Sopenharmony_ci    uint32_t fFlags;
77cb93a386Sopenharmony_ci    SkDEBUGCODE(unsigned fMagic;)
78cb93a386Sopenharmony_ci};
79cb93a386Sopenharmony_ci}  // namespace
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_civoid SkTextBlob::RunRecord::validate(const uint8_t* storageTop) const {
82cb93a386Sopenharmony_ci    SkASSERT(kRunRecordMagic == fMagic);
83cb93a386Sopenharmony_ci    SkASSERT((uint8_t*)NextUnchecked(this) <= storageTop);
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_ci    SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer());
86cb93a386Sopenharmony_ci    SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(positioning())
87cb93a386Sopenharmony_ci             <= (SkScalar*)NextUnchecked(this));
88cb93a386Sopenharmony_ci    if (isExtended()) {
89cb93a386Sopenharmony_ci        SkASSERT(textSize() > 0);
90cb93a386Sopenharmony_ci        SkASSERT(textSizePtr() < (uint32_t*)NextUnchecked(this));
91cb93a386Sopenharmony_ci        SkASSERT(clusterBuffer() < (uint32_t*)NextUnchecked(this));
92cb93a386Sopenharmony_ci        SkASSERT(textBuffer() + textSize() <= (char*)NextUnchecked(this));
93cb93a386Sopenharmony_ci    }
94cb93a386Sopenharmony_ci    static_assert(sizeof(SkTextBlob::RunRecord) == sizeof(RunRecordStorageEquivalent),
95cb93a386Sopenharmony_ci                  "runrecord_should_stay_packed");
96cb93a386Sopenharmony_ci}
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ciconst SkTextBlob::RunRecord* SkTextBlob::RunRecord::NextUnchecked(const RunRecord* run) {
99cb93a386Sopenharmony_ci    SkSafeMath safe;
100cb93a386Sopenharmony_ci    auto res = reinterpret_cast<const RunRecord*>(
101cb93a386Sopenharmony_ci            reinterpret_cast<const uint8_t*>(run)
102cb93a386Sopenharmony_ci            + StorageSize(run->glyphCount(), run->textSize(), run->positioning(), &safe));
103cb93a386Sopenharmony_ci    SkASSERT(safe);
104cb93a386Sopenharmony_ci    return res;
105cb93a386Sopenharmony_ci}
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_cisize_t SkTextBlob::RunRecord::PosCount(uint32_t glyphCount,
108cb93a386Sopenharmony_ci                                       SkTextBlob::GlyphPositioning positioning,
109cb93a386Sopenharmony_ci                                       SkSafeMath* safe) {
110cb93a386Sopenharmony_ci    return safe->mul(glyphCount, ScalarsPerGlyph(positioning));
111cb93a386Sopenharmony_ci}
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ciuint32_t* SkTextBlob::RunRecord::textSizePtr() const {
114cb93a386Sopenharmony_ci    // textSize follows the position buffer.
115cb93a386Sopenharmony_ci    SkASSERT(isExtended());
116cb93a386Sopenharmony_ci    SkSafeMath safe;
117cb93a386Sopenharmony_ci    auto res = (uint32_t*)(&this->posBuffer()[PosCount(fCount, positioning(), &safe)]);
118cb93a386Sopenharmony_ci    SkASSERT(safe);
119cb93a386Sopenharmony_ci    return res;
120cb93a386Sopenharmony_ci}
121cb93a386Sopenharmony_ci
122cb93a386Sopenharmony_civoid SkTextBlob::RunRecord::grow(uint32_t count) {
123cb93a386Sopenharmony_ci    SkScalar* initialPosBuffer = posBuffer();
124cb93a386Sopenharmony_ci    uint32_t initialCount = fCount;
125cb93a386Sopenharmony_ci    fCount += count;
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ci    // Move the initial pos scalars to their new location.
128cb93a386Sopenharmony_ci    size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(positioning());
129cb93a386Sopenharmony_ci    SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)NextUnchecked(this));
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_ci    // memmove, as the buffers may overlap
132cb93a386Sopenharmony_ci    memmove(posBuffer(), initialPosBuffer, copySize);
133cb93a386Sopenharmony_ci}
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_cistatic int32_t next_id() {
136cb93a386Sopenharmony_ci    static std::atomic<int32_t> nextID{1};
137cb93a386Sopenharmony_ci    int32_t id;
138cb93a386Sopenharmony_ci    do {
139cb93a386Sopenharmony_ci        id = nextID.fetch_add(1, std::memory_order_relaxed);
140cb93a386Sopenharmony_ci    } while (id == SK_InvalidGenID);
141cb93a386Sopenharmony_ci    return id;
142cb93a386Sopenharmony_ci}
143cb93a386Sopenharmony_ci
144cb93a386Sopenharmony_ciSkTextBlob::SkTextBlob(const SkRect& bounds)
145cb93a386Sopenharmony_ci    : fBounds(bounds)
146cb93a386Sopenharmony_ci    , fUniqueID(next_id())
147cb93a386Sopenharmony_ci    , fCacheID(SK_InvalidUniqueID) {}
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_ciSkTextBlob::~SkTextBlob() {
150cb93a386Sopenharmony_ci#if SK_SUPPORT_GPU
151cb93a386Sopenharmony_ci    if (SK_InvalidUniqueID != fCacheID.load()) {
152cb93a386Sopenharmony_ci        GrTextBlobCache::PostPurgeBlobMessage(fUniqueID, fCacheID);
153cb93a386Sopenharmony_ci    }
154cb93a386Sopenharmony_ci#endif
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci    const auto* run = RunRecord::First(this);
157cb93a386Sopenharmony_ci    do {
158cb93a386Sopenharmony_ci        const auto* nextRun = RunRecord::Next(run);
159cb93a386Sopenharmony_ci        SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);)
160cb93a386Sopenharmony_ci        run->~RunRecord();
161cb93a386Sopenharmony_ci        run = nextRun;
162cb93a386Sopenharmony_ci    } while (run);
163cb93a386Sopenharmony_ci}
164cb93a386Sopenharmony_ci
165cb93a386Sopenharmony_cinamespace {
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ciunion PositioningAndExtended {
168cb93a386Sopenharmony_ci    int32_t intValue;
169cb93a386Sopenharmony_ci    struct {
170cb93a386Sopenharmony_ci        uint8_t  positioning;
171cb93a386Sopenharmony_ci        uint8_t  extended;
172cb93a386Sopenharmony_ci        uint16_t padding;
173cb93a386Sopenharmony_ci    };
174cb93a386Sopenharmony_ci};
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_cistatic_assert(sizeof(PositioningAndExtended) == sizeof(int32_t), "");
177cb93a386Sopenharmony_ci
178cb93a386Sopenharmony_ci} // namespace
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_cienum SkTextBlob::GlyphPositioning : uint8_t {
181cb93a386Sopenharmony_ci    kDefault_Positioning      = 0, // Default glyph advances -- zero scalars per glyph.
182cb93a386Sopenharmony_ci    kHorizontal_Positioning   = 1, // Horizontal positioning -- one scalar per glyph.
183cb93a386Sopenharmony_ci    kFull_Positioning         = 2, // Point positioning -- two scalars per glyph.
184cb93a386Sopenharmony_ci    kRSXform_Positioning      = 3, // RSXform positioning -- four scalars per glyph.
185cb93a386Sopenharmony_ci};
186cb93a386Sopenharmony_ci
187cb93a386Sopenharmony_ciunsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) {
188cb93a386Sopenharmony_ci    const uint8_t gScalarsPerPositioning[] = {
189cb93a386Sopenharmony_ci        0,  // kDefault_Positioning
190cb93a386Sopenharmony_ci        1,  // kHorizontal_Positioning
191cb93a386Sopenharmony_ci        2,  // kFull_Positioning
192cb93a386Sopenharmony_ci        4,  // kRSXform_Positioning
193cb93a386Sopenharmony_ci    };
194cb93a386Sopenharmony_ci    SkASSERT((unsigned)pos <= 3);
195cb93a386Sopenharmony_ci    return gScalarsPerPositioning[pos];
196cb93a386Sopenharmony_ci}
197cb93a386Sopenharmony_ci
198cb93a386Sopenharmony_civoid SkTextBlob::operator delete(void* p) {
199cb93a386Sopenharmony_ci    sk_free(p);
200cb93a386Sopenharmony_ci}
201cb93a386Sopenharmony_ci
202cb93a386Sopenharmony_civoid* SkTextBlob::operator new(size_t) {
203cb93a386Sopenharmony_ci    SK_ABORT("All blobs are created by placement new.");
204cb93a386Sopenharmony_ci}
205cb93a386Sopenharmony_ci
206cb93a386Sopenharmony_civoid* SkTextBlob::operator new(size_t, void* p) {
207cb93a386Sopenharmony_ci    return p;
208cb93a386Sopenharmony_ci}
209cb93a386Sopenharmony_ci
210cb93a386Sopenharmony_ciSkTextBlobRunIterator::SkTextBlobRunIterator(const SkTextBlob* blob)
211cb93a386Sopenharmony_ci    : fCurrentRun(SkTextBlob::RunRecord::First(blob)) {
212cb93a386Sopenharmony_ci    SkDEBUGCODE(fStorageTop = (uint8_t*)blob + blob->fStorageSize;)
213cb93a386Sopenharmony_ci}
214cb93a386Sopenharmony_ci
215cb93a386Sopenharmony_civoid SkTextBlobRunIterator::next() {
216cb93a386Sopenharmony_ci    SkASSERT(!this->done());
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci    if (!this->done()) {
219cb93a386Sopenharmony_ci        SkDEBUGCODE(fCurrentRun->validate(fStorageTop);)
220cb93a386Sopenharmony_ci        fCurrentRun = SkTextBlob::RunRecord::Next(fCurrentRun);
221cb93a386Sopenharmony_ci    }
222cb93a386Sopenharmony_ci}
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_ciSkTextBlobRunIterator::GlyphPositioning SkTextBlobRunIterator::positioning() const {
225cb93a386Sopenharmony_ci    SkASSERT(!this->done());
226cb93a386Sopenharmony_ci    static_assert(static_cast<GlyphPositioning>(SkTextBlob::kDefault_Positioning) ==
227cb93a386Sopenharmony_ci                  kDefault_Positioning, "");
228cb93a386Sopenharmony_ci    static_assert(static_cast<GlyphPositioning>(SkTextBlob::kHorizontal_Positioning) ==
229cb93a386Sopenharmony_ci                  kHorizontal_Positioning, "");
230cb93a386Sopenharmony_ci    static_assert(static_cast<GlyphPositioning>(SkTextBlob::kFull_Positioning) ==
231cb93a386Sopenharmony_ci                  kFull_Positioning, "");
232cb93a386Sopenharmony_ci    static_assert(static_cast<GlyphPositioning>(SkTextBlob::kRSXform_Positioning) ==
233cb93a386Sopenharmony_ci                  kRSXform_Positioning, "");
234cb93a386Sopenharmony_ci
235cb93a386Sopenharmony_ci    return SkTo<GlyphPositioning>(fCurrentRun->positioning());
236cb93a386Sopenharmony_ci}
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_ciunsigned SkTextBlobRunIterator::scalarsPerGlyph() const {
239cb93a386Sopenharmony_ci    return SkTextBlob::ScalarsPerGlyph(fCurrentRun->positioning());
240cb93a386Sopenharmony_ci}
241cb93a386Sopenharmony_ci
242cb93a386Sopenharmony_cibool SkTextBlobRunIterator::isLCD() const {
243cb93a386Sopenharmony_ci    return fCurrentRun->font().getEdging() == SkFont::Edging::kSubpixelAntiAlias;
244cb93a386Sopenharmony_ci}
245cb93a386Sopenharmony_ci
246cb93a386Sopenharmony_ciSkTextBlobBuilder::SkTextBlobBuilder()
247cb93a386Sopenharmony_ci    : fStorageSize(0)
248cb93a386Sopenharmony_ci    , fStorageUsed(0)
249cb93a386Sopenharmony_ci    , fRunCount(0)
250cb93a386Sopenharmony_ci    , fDeferredBounds(false)
251cb93a386Sopenharmony_ci    , fLastRun(0) {
252cb93a386Sopenharmony_ci    fBounds.setEmpty();
253cb93a386Sopenharmony_ci}
254cb93a386Sopenharmony_ci
255cb93a386Sopenharmony_ciSkTextBlobBuilder::~SkTextBlobBuilder() {
256cb93a386Sopenharmony_ci    if (nullptr != fStorage.get()) {
257cb93a386Sopenharmony_ci        // We are abandoning runs and must destruct the associated font data.
258cb93a386Sopenharmony_ci        // The easiest way to accomplish that is to use the blob destructor.
259cb93a386Sopenharmony_ci        this->make();
260cb93a386Sopenharmony_ci    }
261cb93a386Sopenharmony_ci}
262cb93a386Sopenharmony_ci
263cb93a386Sopenharmony_cistatic SkRect map_quad_to_rect(const SkRSXform& xform, const SkRect& rect) {
264cb93a386Sopenharmony_ci    return SkMatrix().setRSXform(xform).mapRect(rect);
265cb93a386Sopenharmony_ci}
266cb93a386Sopenharmony_ci
267cb93a386Sopenharmony_ciSkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) {
268cb93a386Sopenharmony_ci    const SkFont& font = run.font();
269cb93a386Sopenharmony_ci    SkRect bounds;
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ci    if (SkTextBlob::kDefault_Positioning == run.positioning()) {
272cb93a386Sopenharmony_ci        font.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t),
273cb93a386Sopenharmony_ci                         SkTextEncoding::kGlyphID, &bounds);
274cb93a386Sopenharmony_ci        return bounds.makeOffset(run.offset().x(), run.offset().y());
275cb93a386Sopenharmony_ci    }
276cb93a386Sopenharmony_ci
277cb93a386Sopenharmony_ci    SkAutoSTArray<16, SkRect> glyphBounds(run.glyphCount());
278cb93a386Sopenharmony_ci    font.getBounds(run.glyphBuffer(), run.glyphCount(), glyphBounds.get(), nullptr);
279cb93a386Sopenharmony_ci
280cb93a386Sopenharmony_ci    if (SkTextBlob::kRSXform_Positioning == run.positioning()) {
281cb93a386Sopenharmony_ci        bounds.setEmpty();
282cb93a386Sopenharmony_ci        const SkRSXform* xform = run.xformBuffer();
283cb93a386Sopenharmony_ci        SkASSERT((void*)(xform + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
284cb93a386Sopenharmony_ci        for (unsigned i = 0; i < run.glyphCount(); ++i) {
285cb93a386Sopenharmony_ci            bounds.join(map_quad_to_rect(xform[i], glyphBounds[i]));
286cb93a386Sopenharmony_ci        }
287cb93a386Sopenharmony_ci    } else {
288cb93a386Sopenharmony_ci        SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() ||
289cb93a386Sopenharmony_ci                 SkTextBlob::kHorizontal_Positioning == run.positioning());
290cb93a386Sopenharmony_ci        // kFull_Positioning       => [ x, y, x, y... ]
291cb93a386Sopenharmony_ci        // kHorizontal_Positioning => [ x, x, x... ]
292cb93a386Sopenharmony_ci        //                            (const y applied by runBounds.offset(run->offset()) later)
293cb93a386Sopenharmony_ci        const SkScalar horizontalConstY = 0;
294cb93a386Sopenharmony_ci        const SkScalar* glyphPosX = run.posBuffer();
295cb93a386Sopenharmony_ci        const SkScalar* glyphPosY = (run.positioning() == SkTextBlob::kFull_Positioning) ?
296cb93a386Sopenharmony_ci                                                        glyphPosX + 1 : &horizontalConstY;
297cb93a386Sopenharmony_ci        const unsigned posXInc = SkTextBlob::ScalarsPerGlyph(run.positioning());
298cb93a386Sopenharmony_ci        const unsigned posYInc = (run.positioning() == SkTextBlob::kFull_Positioning) ?
299cb93a386Sopenharmony_ci                                                    posXInc : 0;
300cb93a386Sopenharmony_ci
301cb93a386Sopenharmony_ci        bounds.setEmpty();
302cb93a386Sopenharmony_ci        for (unsigned i = 0; i < run.glyphCount(); ++i) {
303cb93a386Sopenharmony_ci            bounds.join(glyphBounds[i].makeOffset(*glyphPosX, *glyphPosY));
304cb93a386Sopenharmony_ci            glyphPosX += posXInc;
305cb93a386Sopenharmony_ci            glyphPosY += posYInc;
306cb93a386Sopenharmony_ci        }
307cb93a386Sopenharmony_ci
308cb93a386Sopenharmony_ci        SkASSERT((void*)glyphPosX <= SkTextBlob::RunRecord::Next(&run));
309cb93a386Sopenharmony_ci    }
310cb93a386Sopenharmony_ci    return bounds.makeOffset(run.offset().x(), run.offset().y());
311cb93a386Sopenharmony_ci}
312cb93a386Sopenharmony_ci
313cb93a386Sopenharmony_ciSkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run) {
314cb93a386Sopenharmony_ci    SkASSERT(run.glyphCount() > 0);
315cb93a386Sopenharmony_ci    SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() ||
316cb93a386Sopenharmony_ci             SkTextBlob::kHorizontal_Positioning == run.positioning() ||
317cb93a386Sopenharmony_ci             SkTextBlob::kRSXform_Positioning == run.positioning());
318cb93a386Sopenharmony_ci
319cb93a386Sopenharmony_ci    const SkRect fontBounds = SkFontPriv::GetFontBounds(run.font());
320cb93a386Sopenharmony_ci    if (fontBounds.isEmpty()) {
321cb93a386Sopenharmony_ci        // Empty font bounds are likely a font bug.  TightBounds has a better chance of
322cb93a386Sopenharmony_ci        // producing useful results in this case.
323cb93a386Sopenharmony_ci        return TightRunBounds(run);
324cb93a386Sopenharmony_ci    }
325cb93a386Sopenharmony_ci
326cb93a386Sopenharmony_ci    // Compute the glyph position bbox.
327cb93a386Sopenharmony_ci    SkRect bounds;
328cb93a386Sopenharmony_ci    switch (run.positioning()) {
329cb93a386Sopenharmony_ci    case SkTextBlob::kHorizontal_Positioning: {
330cb93a386Sopenharmony_ci        const SkScalar* glyphPos = run.posBuffer();
331cb93a386Sopenharmony_ci        SkASSERT((void*)(glyphPos + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
332cb93a386Sopenharmony_ci
333cb93a386Sopenharmony_ci        SkScalar minX = *glyphPos;
334cb93a386Sopenharmony_ci        SkScalar maxX = *glyphPos;
335cb93a386Sopenharmony_ci        for (unsigned i = 1; i < run.glyphCount(); ++i) {
336cb93a386Sopenharmony_ci            SkScalar x = glyphPos[i];
337cb93a386Sopenharmony_ci            minX = std::min(x, minX);
338cb93a386Sopenharmony_ci            maxX = std::max(x, maxX);
339cb93a386Sopenharmony_ci        }
340cb93a386Sopenharmony_ci
341cb93a386Sopenharmony_ci        bounds.setLTRB(minX, 0, maxX, 0);
342cb93a386Sopenharmony_ci    } break;
343cb93a386Sopenharmony_ci    case SkTextBlob::kFull_Positioning: {
344cb93a386Sopenharmony_ci        const SkPoint* glyphPosPts = run.pointBuffer();
345cb93a386Sopenharmony_ci        SkASSERT((void*)(glyphPosPts + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_ci        bounds.setBounds(glyphPosPts, run.glyphCount());
348cb93a386Sopenharmony_ci    } break;
349cb93a386Sopenharmony_ci    case SkTextBlob::kRSXform_Positioning: {
350cb93a386Sopenharmony_ci        const SkRSXform* xform = run.xformBuffer();
351cb93a386Sopenharmony_ci        SkASSERT((void*)(xform + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run));
352cb93a386Sopenharmony_ci        bounds.setEmpty();
353cb93a386Sopenharmony_ci        for (unsigned i = 0; i < run.glyphCount(); ++i) {
354cb93a386Sopenharmony_ci            bounds.join(map_quad_to_rect(xform[i], fontBounds));
355cb93a386Sopenharmony_ci        }
356cb93a386Sopenharmony_ci    } break;
357cb93a386Sopenharmony_ci    default:
358cb93a386Sopenharmony_ci        SK_ABORT("unsupported positioning mode");
359cb93a386Sopenharmony_ci    }
360cb93a386Sopenharmony_ci
361cb93a386Sopenharmony_ci    if (run.positioning() != SkTextBlob::kRSXform_Positioning) {
362cb93a386Sopenharmony_ci        // Expand by typeface glyph bounds.
363cb93a386Sopenharmony_ci        bounds.fLeft   += fontBounds.left();
364cb93a386Sopenharmony_ci        bounds.fTop    += fontBounds.top();
365cb93a386Sopenharmony_ci        bounds.fRight  += fontBounds.right();
366cb93a386Sopenharmony_ci        bounds.fBottom += fontBounds.bottom();
367cb93a386Sopenharmony_ci    }
368cb93a386Sopenharmony_ci
369cb93a386Sopenharmony_ci    // Offset by run position.
370cb93a386Sopenharmony_ci    return bounds.makeOffset(run.offset().x(), run.offset().y());
371cb93a386Sopenharmony_ci}
372cb93a386Sopenharmony_ci
373cb93a386Sopenharmony_civoid SkTextBlobBuilder::updateDeferredBounds() {
374cb93a386Sopenharmony_ci    SkASSERT(!fDeferredBounds || fRunCount > 0);
375cb93a386Sopenharmony_ci
376cb93a386Sopenharmony_ci    if (!fDeferredBounds) {
377cb93a386Sopenharmony_ci        return;
378cb93a386Sopenharmony_ci    }
379cb93a386Sopenharmony_ci
380cb93a386Sopenharmony_ci    SkASSERT(fLastRun >= SkAlignPtr(sizeof(SkTextBlob)));
381cb93a386Sopenharmony_ci    SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() +
382cb93a386Sopenharmony_ci                                                                          fLastRun);
383cb93a386Sopenharmony_ci
384cb93a386Sopenharmony_ci    // FIXME: we should also use conservative bounds for kDefault_Positioning.
385cb93a386Sopenharmony_ci    SkRect runBounds = SkTextBlob::kDefault_Positioning == run->positioning() ?
386cb93a386Sopenharmony_ci                       TightRunBounds(*run) : ConservativeRunBounds(*run);
387cb93a386Sopenharmony_ci    fBounds.join(runBounds);
388cb93a386Sopenharmony_ci    fDeferredBounds = false;
389cb93a386Sopenharmony_ci}
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_civoid SkTextBlobBuilder::reserve(size_t size) {
392cb93a386Sopenharmony_ci    SkSafeMath safe;
393cb93a386Sopenharmony_ci
394cb93a386Sopenharmony_ci    // We don't currently pre-allocate, but maybe someday...
395cb93a386Sopenharmony_ci    if (safe.add(fStorageUsed, size) <= fStorageSize && safe) {
396cb93a386Sopenharmony_ci        return;
397cb93a386Sopenharmony_ci    }
398cb93a386Sopenharmony_ci
399cb93a386Sopenharmony_ci    if (0 == fRunCount) {
400cb93a386Sopenharmony_ci        SkASSERT(nullptr == fStorage.get());
401cb93a386Sopenharmony_ci        SkASSERT(0 == fStorageSize);
402cb93a386Sopenharmony_ci        SkASSERT(0 == fStorageUsed);
403cb93a386Sopenharmony_ci
404cb93a386Sopenharmony_ci        // the first allocation also includes blob storage
405cb93a386Sopenharmony_ci        // aligned up to a pointer alignment so SkTextBlob::RunRecords after it stay aligned.
406cb93a386Sopenharmony_ci        fStorageUsed = SkAlignPtr(sizeof(SkTextBlob));
407cb93a386Sopenharmony_ci    }
408cb93a386Sopenharmony_ci
409cb93a386Sopenharmony_ci    fStorageSize = safe.add(fStorageUsed, size);
410cb93a386Sopenharmony_ci
411cb93a386Sopenharmony_ci    // FYI: This relies on everything we store being relocatable, particularly SkPaint.
412cb93a386Sopenharmony_ci    //      Also, this is counting on the underlying realloc to throw when passed max().
413cb93a386Sopenharmony_ci    fStorage.realloc(safe ? fStorageSize : std::numeric_limits<size_t>::max());
414cb93a386Sopenharmony_ci}
415cb93a386Sopenharmony_ci
416cb93a386Sopenharmony_cibool SkTextBlobBuilder::mergeRun(const SkFont& font, SkTextBlob::GlyphPositioning positioning,
417cb93a386Sopenharmony_ci                                 uint32_t count, SkPoint offset) {
418cb93a386Sopenharmony_ci    if (0 == fLastRun) {
419cb93a386Sopenharmony_ci        SkASSERT(0 == fRunCount);
420cb93a386Sopenharmony_ci        return false;
421cb93a386Sopenharmony_ci    }
422cb93a386Sopenharmony_ci
423cb93a386Sopenharmony_ci    SkASSERT(fLastRun >= SkAlignPtr(sizeof(SkTextBlob)));
424cb93a386Sopenharmony_ci    SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() +
425cb93a386Sopenharmony_ci                                                                          fLastRun);
426cb93a386Sopenharmony_ci    SkASSERT(run->glyphCount() > 0);
427cb93a386Sopenharmony_ci
428cb93a386Sopenharmony_ci    if (run->textSize() != 0) {
429cb93a386Sopenharmony_ci        return false;
430cb93a386Sopenharmony_ci    }
431cb93a386Sopenharmony_ci
432cb93a386Sopenharmony_ci    if (run->positioning() != positioning
433cb93a386Sopenharmony_ci        || run->font() != font
434cb93a386Sopenharmony_ci        || (run->glyphCount() + count < run->glyphCount())) {
435cb93a386Sopenharmony_ci        return false;
436cb93a386Sopenharmony_ci    }
437cb93a386Sopenharmony_ci
438cb93a386Sopenharmony_ci    // we can merge same-font/same-positioning runs in the following cases:
439cb93a386Sopenharmony_ci    //   * fully positioned run following another fully positioned run
440cb93a386Sopenharmony_ci    //   * horizontally postioned run following another horizontally positioned run with the same
441cb93a386Sopenharmony_ci    //     y-offset
442cb93a386Sopenharmony_ci    if (SkTextBlob::kFull_Positioning != positioning
443cb93a386Sopenharmony_ci        && (SkTextBlob::kHorizontal_Positioning != positioning
444cb93a386Sopenharmony_ci            || run->offset().y() != offset.y())) {
445cb93a386Sopenharmony_ci        return false;
446cb93a386Sopenharmony_ci    }
447cb93a386Sopenharmony_ci
448cb93a386Sopenharmony_ci    SkSafeMath safe;
449cb93a386Sopenharmony_ci    size_t sizeDelta =
450cb93a386Sopenharmony_ci        SkTextBlob::RunRecord::StorageSize(run->glyphCount() + count, 0, positioning, &safe) -
451cb93a386Sopenharmony_ci        SkTextBlob::RunRecord::StorageSize(run->glyphCount()        , 0, positioning, &safe);
452cb93a386Sopenharmony_ci    if (!safe) {
453cb93a386Sopenharmony_ci        return false;
454cb93a386Sopenharmony_ci    }
455cb93a386Sopenharmony_ci
456cb93a386Sopenharmony_ci    this->reserve(sizeDelta);
457cb93a386Sopenharmony_ci
458cb93a386Sopenharmony_ci    // reserve may have realloced
459cb93a386Sopenharmony_ci    run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun);
460cb93a386Sopenharmony_ci    uint32_t preMergeCount = run->glyphCount();
461cb93a386Sopenharmony_ci    run->grow(count);
462cb93a386Sopenharmony_ci
463cb93a386Sopenharmony_ci    // Callers expect the buffers to point at the newly added slice, ant not at the beginning.
464cb93a386Sopenharmony_ci    fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount;
465cb93a386Sopenharmony_ci    fCurrentRunBuffer.pos = run->posBuffer()
466cb93a386Sopenharmony_ci                          + preMergeCount * SkTextBlob::ScalarsPerGlyph(positioning);
467cb93a386Sopenharmony_ci
468cb93a386Sopenharmony_ci    fStorageUsed += sizeDelta;
469cb93a386Sopenharmony_ci
470cb93a386Sopenharmony_ci    SkASSERT(fStorageUsed <= fStorageSize);
471cb93a386Sopenharmony_ci    run->validate(fStorage.get() + fStorageUsed);
472cb93a386Sopenharmony_ci
473cb93a386Sopenharmony_ci    return true;
474cb93a386Sopenharmony_ci}
475cb93a386Sopenharmony_ci
476cb93a386Sopenharmony_civoid SkTextBlobBuilder::allocInternal(const SkFont& font,
477cb93a386Sopenharmony_ci                                      SkTextBlob::GlyphPositioning positioning,
478cb93a386Sopenharmony_ci                                      int count, int textSize, SkPoint offset,
479cb93a386Sopenharmony_ci                                      const SkRect* bounds) {
480cb93a386Sopenharmony_ci    if (count <= 0 || textSize < 0) {
481cb93a386Sopenharmony_ci        fCurrentRunBuffer = { nullptr, nullptr, nullptr, nullptr };
482cb93a386Sopenharmony_ci        return;
483cb93a386Sopenharmony_ci    }
484cb93a386Sopenharmony_ci
485cb93a386Sopenharmony_ci    if (textSize != 0 || !this->mergeRun(font, positioning, count, offset)) {
486cb93a386Sopenharmony_ci        this->updateDeferredBounds();
487cb93a386Sopenharmony_ci
488cb93a386Sopenharmony_ci        SkSafeMath safe;
489cb93a386Sopenharmony_ci        size_t runSize = SkTextBlob::RunRecord::StorageSize(count, textSize, positioning, &safe);
490cb93a386Sopenharmony_ci        if (!safe) {
491cb93a386Sopenharmony_ci            fCurrentRunBuffer = { nullptr, nullptr, nullptr, nullptr };
492cb93a386Sopenharmony_ci            return;
493cb93a386Sopenharmony_ci        }
494cb93a386Sopenharmony_ci
495cb93a386Sopenharmony_ci        this->reserve(runSize);
496cb93a386Sopenharmony_ci
497cb93a386Sopenharmony_ci        SkASSERT(fStorageUsed >= SkAlignPtr(sizeof(SkTextBlob)));
498cb93a386Sopenharmony_ci        SkASSERT(fStorageUsed + runSize <= fStorageSize);
499cb93a386Sopenharmony_ci
500cb93a386Sopenharmony_ci        SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed)
501cb93a386Sopenharmony_ci            SkTextBlob::RunRecord(count, textSize, offset, font, positioning);
502cb93a386Sopenharmony_ci        fCurrentRunBuffer.glyphs = run->glyphBuffer();
503cb93a386Sopenharmony_ci        fCurrentRunBuffer.pos = run->posBuffer();
504cb93a386Sopenharmony_ci        fCurrentRunBuffer.utf8text = run->textBuffer();
505cb93a386Sopenharmony_ci        fCurrentRunBuffer.clusters = run->clusterBuffer();
506cb93a386Sopenharmony_ci
507cb93a386Sopenharmony_ci        fLastRun = fStorageUsed;
508cb93a386Sopenharmony_ci        fStorageUsed += runSize;
509cb93a386Sopenharmony_ci        fRunCount++;
510cb93a386Sopenharmony_ci
511cb93a386Sopenharmony_ci        SkASSERT(fStorageUsed <= fStorageSize);
512cb93a386Sopenharmony_ci        run->validate(fStorage.get() + fStorageUsed);
513cb93a386Sopenharmony_ci    }
514cb93a386Sopenharmony_ci    SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.utf8text);
515cb93a386Sopenharmony_ci    SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.clusters);
516cb93a386Sopenharmony_ci    if (!fDeferredBounds) {
517cb93a386Sopenharmony_ci        if (bounds) {
518cb93a386Sopenharmony_ci            fBounds.join(*bounds);
519cb93a386Sopenharmony_ci        } else {
520cb93a386Sopenharmony_ci            fDeferredBounds = true;
521cb93a386Sopenharmony_ci        }
522cb93a386Sopenharmony_ci    }
523cb93a386Sopenharmony_ci}
524cb93a386Sopenharmony_ci
525cb93a386Sopenharmony_ci// SkFont versions
526cb93a386Sopenharmony_ci
527cb93a386Sopenharmony_ciconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRun(const SkFont& font, int count,
528cb93a386Sopenharmony_ci                                                                SkScalar x, SkScalar y,
529cb93a386Sopenharmony_ci                                                                const SkRect* bounds) {
530cb93a386Sopenharmony_ci    this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, 0, {x, y}, bounds);
531cb93a386Sopenharmony_ci    return fCurrentRunBuffer;
532cb93a386Sopenharmony_ci}
533cb93a386Sopenharmony_ci
534cb93a386Sopenharmony_ciconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPosH(const SkFont& font, int count,
535cb93a386Sopenharmony_ci                                                                    SkScalar y,
536cb93a386Sopenharmony_ci                                                                    const SkRect* bounds) {
537cb93a386Sopenharmony_ci    this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, 0, {0, y}, bounds);
538cb93a386Sopenharmony_ci    return fCurrentRunBuffer;
539cb93a386Sopenharmony_ci}
540cb93a386Sopenharmony_ci
541cb93a386Sopenharmony_ciconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPos(const SkFont& font, int count,
542cb93a386Sopenharmony_ci                                                                   const SkRect* bounds) {
543cb93a386Sopenharmony_ci    this->allocInternal(font, SkTextBlob::kFull_Positioning, count, 0, {0, 0}, bounds);
544cb93a386Sopenharmony_ci    return fCurrentRunBuffer;
545cb93a386Sopenharmony_ci}
546cb93a386Sopenharmony_ci
547cb93a386Sopenharmony_ciconst SkTextBlobBuilder::RunBuffer&
548cb93a386Sopenharmony_ciSkTextBlobBuilder::allocRunRSXform(const SkFont& font, int count) {
549cb93a386Sopenharmony_ci    this->allocInternal(font, SkTextBlob::kRSXform_Positioning, count, 0, {0, 0}, nullptr);
550cb93a386Sopenharmony_ci    return fCurrentRunBuffer;
551cb93a386Sopenharmony_ci}
552cb93a386Sopenharmony_ci
553cb93a386Sopenharmony_ciconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunText(const SkFont& font, int count,
554cb93a386Sopenharmony_ci                                                                    SkScalar x, SkScalar y,
555cb93a386Sopenharmony_ci                                                                    int textByteCount,
556cb93a386Sopenharmony_ci                                                                    const SkRect* bounds) {
557cb93a386Sopenharmony_ci    this->allocInternal(font,
558cb93a386Sopenharmony_ci                        SkTextBlob::kDefault_Positioning,
559cb93a386Sopenharmony_ci                        count,
560cb93a386Sopenharmony_ci                        textByteCount,
561cb93a386Sopenharmony_ci                        SkPoint::Make(x, y),
562cb93a386Sopenharmony_ci                        bounds);
563cb93a386Sopenharmony_ci    return fCurrentRunBuffer;
564cb93a386Sopenharmony_ci}
565cb93a386Sopenharmony_ci
566cb93a386Sopenharmony_ciconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPosH(const SkFont& font,
567cb93a386Sopenharmony_ci                                                                        int count,
568cb93a386Sopenharmony_ci                                                                        SkScalar y,
569cb93a386Sopenharmony_ci                                                                        int textByteCount,
570cb93a386Sopenharmony_ci                                                                        const SkRect* bounds) {
571cb93a386Sopenharmony_ci    this->allocInternal(font,
572cb93a386Sopenharmony_ci                        SkTextBlob::kHorizontal_Positioning,
573cb93a386Sopenharmony_ci                        count,
574cb93a386Sopenharmony_ci                        textByteCount,
575cb93a386Sopenharmony_ci                        SkPoint::Make(0, y),
576cb93a386Sopenharmony_ci                        bounds);
577cb93a386Sopenharmony_ci    return fCurrentRunBuffer;
578cb93a386Sopenharmony_ci}
579cb93a386Sopenharmony_ci
580cb93a386Sopenharmony_ciconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPos(const SkFont& font,
581cb93a386Sopenharmony_ci                                                                       int count,
582cb93a386Sopenharmony_ci                                                                       int textByteCount,
583cb93a386Sopenharmony_ci                                                                       const SkRect *bounds) {
584cb93a386Sopenharmony_ci    this->allocInternal(font,
585cb93a386Sopenharmony_ci                        SkTextBlob::kFull_Positioning,
586cb93a386Sopenharmony_ci                        count, textByteCount,
587cb93a386Sopenharmony_ci                        SkPoint::Make(0, 0),
588cb93a386Sopenharmony_ci                        bounds);
589cb93a386Sopenharmony_ci    return fCurrentRunBuffer;
590cb93a386Sopenharmony_ci}
591cb93a386Sopenharmony_ci
592cb93a386Sopenharmony_ciconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextRSXform(const SkFont& font,
593cb93a386Sopenharmony_ci                                                                           int count,
594cb93a386Sopenharmony_ci                                                                           int textByteCount,
595cb93a386Sopenharmony_ci                                                                           const SkRect *bounds) {
596cb93a386Sopenharmony_ci    this->allocInternal(font,
597cb93a386Sopenharmony_ci                        SkTextBlob::kRSXform_Positioning,
598cb93a386Sopenharmony_ci                        count,
599cb93a386Sopenharmony_ci                        textByteCount,
600cb93a386Sopenharmony_ci                        {0, 0},
601cb93a386Sopenharmony_ci                        bounds);
602cb93a386Sopenharmony_ci    return fCurrentRunBuffer;
603cb93a386Sopenharmony_ci}
604cb93a386Sopenharmony_ci
605cb93a386Sopenharmony_cisk_sp<SkTextBlob> SkTextBlobBuilder::make() {
606cb93a386Sopenharmony_ci    if (!fRunCount) {
607cb93a386Sopenharmony_ci        // We don't instantiate empty blobs.
608cb93a386Sopenharmony_ci        SkASSERT(!fStorage.get());
609cb93a386Sopenharmony_ci        SkASSERT(fStorageUsed == 0);
610cb93a386Sopenharmony_ci        SkASSERT(fStorageSize == 0);
611cb93a386Sopenharmony_ci        SkASSERT(fLastRun == 0);
612cb93a386Sopenharmony_ci        SkASSERT(fBounds.isEmpty());
613cb93a386Sopenharmony_ci        return nullptr;
614cb93a386Sopenharmony_ci    }
615cb93a386Sopenharmony_ci
616cb93a386Sopenharmony_ci    this->updateDeferredBounds();
617cb93a386Sopenharmony_ci
618cb93a386Sopenharmony_ci    // Tag the last run as such.
619cb93a386Sopenharmony_ci    auto* lastRun = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun);
620cb93a386Sopenharmony_ci    lastRun->fFlags |= SkTextBlob::RunRecord::kLast_Flag;
621cb93a386Sopenharmony_ci
622cb93a386Sopenharmony_ci    SkTextBlob* blob = new (fStorage.release()) SkTextBlob(fBounds);
623cb93a386Sopenharmony_ci    SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;)
624cb93a386Sopenharmony_ci
625cb93a386Sopenharmony_ci    SkDEBUGCODE(
626cb93a386Sopenharmony_ci        SkSafeMath safe;
627cb93a386Sopenharmony_ci        size_t validateSize = SkAlignPtr(sizeof(SkTextBlob));
628cb93a386Sopenharmony_ci        for (const auto* run = SkTextBlob::RunRecord::First(blob); run;
629cb93a386Sopenharmony_ci             run = SkTextBlob::RunRecord::Next(run)) {
630cb93a386Sopenharmony_ci            validateSize += SkTextBlob::RunRecord::StorageSize(
631cb93a386Sopenharmony_ci                    run->fCount, run->textSize(), run->positioning(), &safe);
632cb93a386Sopenharmony_ci            run->validate(reinterpret_cast<const uint8_t*>(blob) + fStorageUsed);
633cb93a386Sopenharmony_ci            fRunCount--;
634cb93a386Sopenharmony_ci        }
635cb93a386Sopenharmony_ci        SkASSERT(validateSize == fStorageUsed);
636cb93a386Sopenharmony_ci        SkASSERT(fRunCount == 0);
637cb93a386Sopenharmony_ci        SkASSERT(safe);
638cb93a386Sopenharmony_ci    )
639cb93a386Sopenharmony_ci
640cb93a386Sopenharmony_ci    fStorageUsed = 0;
641cb93a386Sopenharmony_ci    fStorageSize = 0;
642cb93a386Sopenharmony_ci    fRunCount = 0;
643cb93a386Sopenharmony_ci    fLastRun = 0;
644cb93a386Sopenharmony_ci    fBounds.setEmpty();
645cb93a386Sopenharmony_ci
646cb93a386Sopenharmony_ci    return sk_sp<SkTextBlob>(blob);
647cb93a386Sopenharmony_ci}
648cb93a386Sopenharmony_ci
649cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
650cb93a386Sopenharmony_ci
651cb93a386Sopenharmony_civoid SkTextBlobPriv::Flatten(const SkTextBlob& blob, SkWriteBuffer& buffer) {
652cb93a386Sopenharmony_ci    // seems like we could skip this, and just recompute bounds in unflatten, but
653cb93a386Sopenharmony_ci    // some cc_unittests fail if we remove this...
654cb93a386Sopenharmony_ci    buffer.writeRect(blob.bounds());
655cb93a386Sopenharmony_ci
656cb93a386Sopenharmony_ci    SkTextBlobRunIterator it(&blob);
657cb93a386Sopenharmony_ci    while (!it.done()) {
658cb93a386Sopenharmony_ci        SkASSERT(it.glyphCount() > 0);
659cb93a386Sopenharmony_ci
660cb93a386Sopenharmony_ci        buffer.write32(it.glyphCount());
661cb93a386Sopenharmony_ci        PositioningAndExtended pe;
662cb93a386Sopenharmony_ci        pe.intValue = 0;
663cb93a386Sopenharmony_ci        pe.positioning = it.positioning();
664cb93a386Sopenharmony_ci        SkASSERT((int32_t)it.positioning() == pe.intValue);  // backwards compat.
665cb93a386Sopenharmony_ci
666cb93a386Sopenharmony_ci        uint32_t textSize = it.textSize();
667cb93a386Sopenharmony_ci        pe.extended = textSize > 0;
668cb93a386Sopenharmony_ci        buffer.write32(pe.intValue);
669cb93a386Sopenharmony_ci        if (pe.extended) {
670cb93a386Sopenharmony_ci            buffer.write32(textSize);
671cb93a386Sopenharmony_ci        }
672cb93a386Sopenharmony_ci        buffer.writePoint(it.offset());
673cb93a386Sopenharmony_ci
674cb93a386Sopenharmony_ci        SkFontPriv::Flatten(it.font(), buffer);
675cb93a386Sopenharmony_ci
676cb93a386Sopenharmony_ci        buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t));
677cb93a386Sopenharmony_ci        buffer.writeByteArray(it.pos(),
678cb93a386Sopenharmony_ci                              it.glyphCount() * sizeof(SkScalar) *
679cb93a386Sopenharmony_ci                              SkTextBlob::ScalarsPerGlyph(
680cb93a386Sopenharmony_ci                                  SkTo<SkTextBlob::GlyphPositioning>(it.positioning())));
681cb93a386Sopenharmony_ci        if (pe.extended) {
682cb93a386Sopenharmony_ci            buffer.writeByteArray(it.clusters(), sizeof(uint32_t) * it.glyphCount());
683cb93a386Sopenharmony_ci            buffer.writeByteArray(it.text(), it.textSize());
684cb93a386Sopenharmony_ci        }
685cb93a386Sopenharmony_ci
686cb93a386Sopenharmony_ci        it.next();
687cb93a386Sopenharmony_ci    }
688cb93a386Sopenharmony_ci
689cb93a386Sopenharmony_ci    // Marker for the last run (0 is not a valid glyph count).
690cb93a386Sopenharmony_ci    buffer.write32(0);
691cb93a386Sopenharmony_ci}
692cb93a386Sopenharmony_ci
693cb93a386Sopenharmony_cisk_sp<SkTextBlob> SkTextBlobPriv::MakeFromBuffer(SkReadBuffer& reader) {
694cb93a386Sopenharmony_ci    SkRect bounds;
695cb93a386Sopenharmony_ci    reader.readRect(&bounds);
696cb93a386Sopenharmony_ci
697cb93a386Sopenharmony_ci    SkTextBlobBuilder blobBuilder;
698cb93a386Sopenharmony_ci    SkSafeMath safe;
699cb93a386Sopenharmony_ci    for (;;) {
700cb93a386Sopenharmony_ci        int glyphCount = reader.read32();
701cb93a386Sopenharmony_ci        if (glyphCount == 0) {
702cb93a386Sopenharmony_ci            // End-of-runs marker.
703cb93a386Sopenharmony_ci            break;
704cb93a386Sopenharmony_ci        }
705cb93a386Sopenharmony_ci
706cb93a386Sopenharmony_ci        PositioningAndExtended pe;
707cb93a386Sopenharmony_ci        pe.intValue = reader.read32();
708cb93a386Sopenharmony_ci        const auto pos = SkTo<SkTextBlob::GlyphPositioning>(pe.positioning);
709cb93a386Sopenharmony_ci        if (glyphCount <= 0 || pos > SkTextBlob::kRSXform_Positioning) {
710cb93a386Sopenharmony_ci            return nullptr;
711cb93a386Sopenharmony_ci        }
712cb93a386Sopenharmony_ci        int textSize = pe.extended ? reader.read32() : 0;
713cb93a386Sopenharmony_ci        if (textSize < 0) {
714cb93a386Sopenharmony_ci            return nullptr;
715cb93a386Sopenharmony_ci        }
716cb93a386Sopenharmony_ci
717cb93a386Sopenharmony_ci        SkPoint offset;
718cb93a386Sopenharmony_ci        reader.readPoint(&offset);
719cb93a386Sopenharmony_ci        SkFont font;
720cb93a386Sopenharmony_ci        SkFontPriv::Unflatten(&font, reader);
721cb93a386Sopenharmony_ci
722cb93a386Sopenharmony_ci        // Compute the expected size of the buffer and ensure we have enough to deserialize
723cb93a386Sopenharmony_ci        // a run before allocating it.
724cb93a386Sopenharmony_ci        const size_t glyphSize = safe.mul(glyphCount, sizeof(uint16_t)),
725cb93a386Sopenharmony_ci                     posSize =
726cb93a386Sopenharmony_ci                             safe.mul(glyphCount, safe.mul(sizeof(SkScalar),
727cb93a386Sopenharmony_ci                             SkTextBlob::ScalarsPerGlyph(pos))),
728cb93a386Sopenharmony_ci                     clusterSize = pe.extended ? safe.mul(glyphCount, sizeof(uint32_t)) : 0;
729cb93a386Sopenharmony_ci        const size_t totalSize =
730cb93a386Sopenharmony_ci                safe.add(safe.add(glyphSize, posSize), safe.add(clusterSize, textSize));
731cb93a386Sopenharmony_ci
732cb93a386Sopenharmony_ci        if (!reader.isValid() || !safe || totalSize > reader.available()) {
733cb93a386Sopenharmony_ci            return nullptr;
734cb93a386Sopenharmony_ci        }
735cb93a386Sopenharmony_ci
736cb93a386Sopenharmony_ci        const SkTextBlobBuilder::RunBuffer* buf = nullptr;
737cb93a386Sopenharmony_ci        switch (pos) {
738cb93a386Sopenharmony_ci            case SkTextBlob::kDefault_Positioning:
739cb93a386Sopenharmony_ci                buf = &blobBuilder.allocRunText(font, glyphCount, offset.x(), offset.y(),
740cb93a386Sopenharmony_ci                                                textSize, &bounds);
741cb93a386Sopenharmony_ci                break;
742cb93a386Sopenharmony_ci            case SkTextBlob::kHorizontal_Positioning:
743cb93a386Sopenharmony_ci                buf = &blobBuilder.allocRunTextPosH(font, glyphCount, offset.y(),
744cb93a386Sopenharmony_ci                                                    textSize, &bounds);
745cb93a386Sopenharmony_ci                break;
746cb93a386Sopenharmony_ci            case SkTextBlob::kFull_Positioning:
747cb93a386Sopenharmony_ci                buf = &blobBuilder.allocRunTextPos(font, glyphCount, textSize, &bounds);
748cb93a386Sopenharmony_ci                break;
749cb93a386Sopenharmony_ci            case SkTextBlob::kRSXform_Positioning:
750cb93a386Sopenharmony_ci                buf = &blobBuilder.allocRunTextRSXform(font, glyphCount, textSize, &bounds);
751cb93a386Sopenharmony_ci                break;
752cb93a386Sopenharmony_ci        }
753cb93a386Sopenharmony_ci
754cb93a386Sopenharmony_ci        if (!buf->glyphs ||
755cb93a386Sopenharmony_ci            !buf->pos ||
756cb93a386Sopenharmony_ci            (pe.extended && (!buf->clusters || !buf->utf8text))) {
757cb93a386Sopenharmony_ci            return nullptr;
758cb93a386Sopenharmony_ci        }
759cb93a386Sopenharmony_ci
760cb93a386Sopenharmony_ci        if (!reader.readByteArray(buf->glyphs, glyphSize) ||
761cb93a386Sopenharmony_ci            !reader.readByteArray(buf->pos, posSize)) {
762cb93a386Sopenharmony_ci            return nullptr;
763cb93a386Sopenharmony_ci            }
764cb93a386Sopenharmony_ci
765cb93a386Sopenharmony_ci        if (pe.extended) {
766cb93a386Sopenharmony_ci            if (!reader.readByteArray(buf->clusters, clusterSize) ||
767cb93a386Sopenharmony_ci                !reader.readByteArray(buf->utf8text, textSize)) {
768cb93a386Sopenharmony_ci                return nullptr;
769cb93a386Sopenharmony_ci            }
770cb93a386Sopenharmony_ci        }
771cb93a386Sopenharmony_ci    }
772cb93a386Sopenharmony_ci
773cb93a386Sopenharmony_ci    return blobBuilder.make();
774cb93a386Sopenharmony_ci}
775cb93a386Sopenharmony_ci
776cb93a386Sopenharmony_cisk_sp<SkTextBlob> SkTextBlob::MakeFromText(const void* text, size_t byteLength, const SkFont& font,
777cb93a386Sopenharmony_ci                                           SkTextEncoding encoding) {
778cb93a386Sopenharmony_ci    // Note: we deliberately promote this to fully positioned blobs, since we'd have to pay the
779cb93a386Sopenharmony_ci    // same cost down stream (i.e. computing bounds), so its cheaper to pay the cost once now.
780cb93a386Sopenharmony_ci    const int count = font.countText(text, byteLength, encoding);
781cb93a386Sopenharmony_ci    if (count < 1) {
782cb93a386Sopenharmony_ci        return nullptr;
783cb93a386Sopenharmony_ci    }
784cb93a386Sopenharmony_ci    SkTextBlobBuilder builder;
785cb93a386Sopenharmony_ci    auto buffer = builder.allocRunPos(font, count);
786cb93a386Sopenharmony_ci    font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
787cb93a386Sopenharmony_ci    font.getPos(buffer.glyphs, count, buffer.points(), {0, 0});
788cb93a386Sopenharmony_ci    return builder.make();
789cb93a386Sopenharmony_ci}
790cb93a386Sopenharmony_ci
791cb93a386Sopenharmony_cisk_sp<SkTextBlob> SkTextBlob::MakeFromPosText(const void* text, size_t byteLength,
792cb93a386Sopenharmony_ci                                              const SkPoint pos[], const SkFont& font,
793cb93a386Sopenharmony_ci                                              SkTextEncoding encoding) {
794cb93a386Sopenharmony_ci    const int count = font.countText(text, byteLength, encoding);
795cb93a386Sopenharmony_ci    if (count < 1) {
796cb93a386Sopenharmony_ci        return nullptr;
797cb93a386Sopenharmony_ci    }
798cb93a386Sopenharmony_ci    SkTextBlobBuilder builder;
799cb93a386Sopenharmony_ci    auto buffer = builder.allocRunPos(font, count);
800cb93a386Sopenharmony_ci    font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
801cb93a386Sopenharmony_ci    memcpy(buffer.points(), pos, count * sizeof(SkPoint));
802cb93a386Sopenharmony_ci    return builder.make();
803cb93a386Sopenharmony_ci}
804cb93a386Sopenharmony_ci
805cb93a386Sopenharmony_cisk_sp<SkTextBlob> SkTextBlob::MakeFromPosTextH(const void* text, size_t byteLength,
806cb93a386Sopenharmony_ci                                               const SkScalar xpos[], SkScalar constY,
807cb93a386Sopenharmony_ci                                               const SkFont& font, SkTextEncoding encoding) {
808cb93a386Sopenharmony_ci    const int count = font.countText(text, byteLength, encoding);
809cb93a386Sopenharmony_ci    if (count < 1) {
810cb93a386Sopenharmony_ci        return nullptr;
811cb93a386Sopenharmony_ci    }
812cb93a386Sopenharmony_ci    SkTextBlobBuilder builder;
813cb93a386Sopenharmony_ci    auto buffer = builder.allocRunPosH(font, count, constY);
814cb93a386Sopenharmony_ci    font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
815cb93a386Sopenharmony_ci    memcpy(buffer.pos, xpos, count * sizeof(SkScalar));
816cb93a386Sopenharmony_ci    return builder.make();
817cb93a386Sopenharmony_ci}
818cb93a386Sopenharmony_ci
819cb93a386Sopenharmony_cisk_sp<SkTextBlob> SkTextBlob::MakeFromRSXform(const void* text, size_t byteLength,
820cb93a386Sopenharmony_ci                                              const SkRSXform xform[], const SkFont& font,
821cb93a386Sopenharmony_ci                                              SkTextEncoding encoding) {
822cb93a386Sopenharmony_ci    const int count = font.countText(text, byteLength, encoding);
823cb93a386Sopenharmony_ci    if (count < 1) {
824cb93a386Sopenharmony_ci        return nullptr;
825cb93a386Sopenharmony_ci    }
826cb93a386Sopenharmony_ci    SkTextBlobBuilder builder;
827cb93a386Sopenharmony_ci    auto buffer = builder.allocRunRSXform(font, count);
828cb93a386Sopenharmony_ci    font.textToGlyphs(text, byteLength, encoding, buffer.glyphs, count);
829cb93a386Sopenharmony_ci    memcpy(buffer.xforms(), xform, count * sizeof(SkRSXform));
830cb93a386Sopenharmony_ci    return builder.make();
831cb93a386Sopenharmony_ci}
832cb93a386Sopenharmony_ci
833cb93a386Sopenharmony_cisk_sp<SkData> SkTextBlob::serialize(const SkSerialProcs& procs) const {
834cb93a386Sopenharmony_ci    SkBinaryWriteBuffer buffer;
835cb93a386Sopenharmony_ci    buffer.setSerialProcs(procs);
836cb93a386Sopenharmony_ci    SkTextBlobPriv::Flatten(*this, buffer);
837cb93a386Sopenharmony_ci
838cb93a386Sopenharmony_ci    size_t total = buffer.bytesWritten();
839cb93a386Sopenharmony_ci    sk_sp<SkData> data = SkData::MakeUninitialized(total);
840cb93a386Sopenharmony_ci    buffer.writeToMemory(data->writable_data());
841cb93a386Sopenharmony_ci    return data;
842cb93a386Sopenharmony_ci}
843cb93a386Sopenharmony_ci
844cb93a386Sopenharmony_cisk_sp<SkTextBlob> SkTextBlob::Deserialize(const void* data, size_t length,
845cb93a386Sopenharmony_ci                                          const SkDeserialProcs& procs) {
846cb93a386Sopenharmony_ci    SkReadBuffer buffer(data, length);
847cb93a386Sopenharmony_ci    buffer.setDeserialProcs(procs);
848cb93a386Sopenharmony_ci    return SkTextBlobPriv::MakeFromBuffer(buffer);
849cb93a386Sopenharmony_ci}
850cb93a386Sopenharmony_ci
851cb93a386Sopenharmony_civoid SkTextBlob::dump(std::string& desc, int depth) const {
852cb93a386Sopenharmony_ci    std::string split(depth, '\t');
853cb93a386Sopenharmony_ci    desc += split + "\n SkTextBlob:{ \n";
854cb93a386Sopenharmony_ci    fBounds.dump(desc, depth + 1);
855cb93a386Sopenharmony_ci    desc += split + "\t fUniqueID:" + std::to_string(fUniqueID) + "\n";
856cb93a386Sopenharmony_ci    desc += split + "}\n";
857cb93a386Sopenharmony_ci}
858cb93a386Sopenharmony_ci
859cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
860cb93a386Sopenharmony_ci
861cb93a386Sopenharmony_cisize_t SkTextBlob::serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const {
862cb93a386Sopenharmony_ci    SkBinaryWriteBuffer buffer(memory, memory_size);
863cb93a386Sopenharmony_ci    buffer.setSerialProcs(procs);
864cb93a386Sopenharmony_ci    SkTextBlobPriv::Flatten(*this, buffer);
865cb93a386Sopenharmony_ci    return buffer.usingInitialStorage() ? buffer.bytesWritten() : 0u;
866cb93a386Sopenharmony_ci}
867cb93a386Sopenharmony_ci
868cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
869cb93a386Sopenharmony_ci
870cb93a386Sopenharmony_cinamespace {
871cb93a386Sopenharmony_ciint get_glyph_run_intercepts(const SkGlyphRun& glyphRun,
872cb93a386Sopenharmony_ci                             const SkPaint& paint,
873cb93a386Sopenharmony_ci                             const SkScalar bounds[2],
874cb93a386Sopenharmony_ci                             SkScalar intervals[],
875cb93a386Sopenharmony_ci                             int* intervalCount) {
876cb93a386Sopenharmony_ci    SkScalar scale = SK_Scalar1;
877cb93a386Sopenharmony_ci    SkPaint interceptPaint{paint};
878cb93a386Sopenharmony_ci    SkFont interceptFont{glyphRun.font()};
879cb93a386Sopenharmony_ci
880cb93a386Sopenharmony_ci    interceptPaint.setMaskFilter(nullptr);   // don't want this affecting our path-cache lookup
881cb93a386Sopenharmony_ci
882cb93a386Sopenharmony_ci    // can't use our canonical size if we need to apply path effects
883cb93a386Sopenharmony_ci    if (interceptPaint.getPathEffect() == nullptr) {
884cb93a386Sopenharmony_ci        // If the wrong size is going to be used, don't hint anything.
885cb93a386Sopenharmony_ci        interceptFont.setHinting(SkFontHinting::kNone);
886cb93a386Sopenharmony_ci        interceptFont.setSubpixel(true);
887cb93a386Sopenharmony_ci        scale = interceptFont.getSize() / SkFontPriv::kCanonicalTextSizeForPaths;
888cb93a386Sopenharmony_ci        interceptFont.setSize(SkIntToScalar(SkFontPriv::kCanonicalTextSizeForPaths));
889cb93a386Sopenharmony_ci        // Note: fScale can be zero here (even if it wasn't before the divide). It can also
890cb93a386Sopenharmony_ci        // be very very small. We call sk_ieee_float_divide below to ensure IEEE divide behavior,
891cb93a386Sopenharmony_ci        // since downstream we will check for the resulting coordinates being non-finite anyway.
892cb93a386Sopenharmony_ci        // Thus we don't need to check for zero here.
893cb93a386Sopenharmony_ci        if (interceptPaint.getStrokeWidth() > 0
894cb93a386Sopenharmony_ci            && interceptPaint.getStyle() != SkPaint::kFill_Style) {
895cb93a386Sopenharmony_ci            interceptPaint.setStrokeWidth(
896cb93a386Sopenharmony_ci                    sk_ieee_float_divide(interceptPaint.getStrokeWidth(), scale));
897cb93a386Sopenharmony_ci        }
898cb93a386Sopenharmony_ci    }
899cb93a386Sopenharmony_ci
900cb93a386Sopenharmony_ci    interceptPaint.setStyle(SkPaint::kFill_Style);
901cb93a386Sopenharmony_ci    interceptPaint.setPathEffect(nullptr);
902cb93a386Sopenharmony_ci
903cb93a386Sopenharmony_ci    SkStrikeSpec strikeSpec = SkStrikeSpec::MakeWithNoDevice(interceptFont, &interceptPaint);
904cb93a386Sopenharmony_ci    SkBulkGlyphMetricsAndPaths metricsAndPaths{strikeSpec};
905cb93a386Sopenharmony_ci
906cb93a386Sopenharmony_ci    const SkPoint* posCursor = glyphRun.positions().begin();
907cb93a386Sopenharmony_ci    for (const SkGlyph* glyph : metricsAndPaths.glyphs(glyphRun.glyphsIDs())) {
908cb93a386Sopenharmony_ci        SkPoint pos = *posCursor++;
909cb93a386Sopenharmony_ci
910cb93a386Sopenharmony_ci        if (glyph->path() != nullptr) {
911cb93a386Sopenharmony_ci            // The typeface is scaled, so un-scale the bounds to be in the space of the typeface.
912cb93a386Sopenharmony_ci            // Also ensure the bounds are properly offset by the vertical positioning of the glyph.
913cb93a386Sopenharmony_ci            SkScalar scaledBounds[2] = {
914cb93a386Sopenharmony_ci                (bounds[0] - pos.y()) / scale,
915cb93a386Sopenharmony_ci                (bounds[1] - pos.y()) / scale
916cb93a386Sopenharmony_ci            };
917cb93a386Sopenharmony_ci            metricsAndPaths.findIntercepts(
918cb93a386Sopenharmony_ci                    scaledBounds, scale, pos.x(), glyph, intervals, intervalCount);
919cb93a386Sopenharmony_ci        }
920cb93a386Sopenharmony_ci    }
921cb93a386Sopenharmony_ci    return *intervalCount;
922cb93a386Sopenharmony_ci}
923cb93a386Sopenharmony_ci}  // namespace
924cb93a386Sopenharmony_ci
925cb93a386Sopenharmony_ciint SkTextBlob::getIntercepts(const SkScalar bounds[2], SkScalar intervals[],
926cb93a386Sopenharmony_ci                              const SkPaint* paint) const {
927cb93a386Sopenharmony_ci    SkTLazy<SkPaint> defaultPaint;
928cb93a386Sopenharmony_ci    if (paint == nullptr) {
929cb93a386Sopenharmony_ci        defaultPaint.init();
930cb93a386Sopenharmony_ci        paint = defaultPaint.get();
931cb93a386Sopenharmony_ci    }
932cb93a386Sopenharmony_ci
933cb93a386Sopenharmony_ci    SkGlyphRunBuilder builder;
934cb93a386Sopenharmony_ci    auto glyphRunList = builder.blobToGlyphRunList(*this, {0, 0});
935cb93a386Sopenharmony_ci
936cb93a386Sopenharmony_ci    int intervalCount = 0;
937cb93a386Sopenharmony_ci    for (const SkGlyphRun& glyphRun : glyphRunList) {
938cb93a386Sopenharmony_ci        // Ignore RSXForm runs.
939cb93a386Sopenharmony_ci        if (glyphRun.scaledRotations().empty()) {
940cb93a386Sopenharmony_ci            intervalCount = get_glyph_run_intercepts(
941cb93a386Sopenharmony_ci                glyphRun, *paint, bounds, intervals, &intervalCount);
942cb93a386Sopenharmony_ci        }
943cb93a386Sopenharmony_ci    }
944cb93a386Sopenharmony_ci
945cb93a386Sopenharmony_ci    return intervalCount;
946cb93a386Sopenharmony_ci}
947cb93a386Sopenharmony_ci
948cb93a386Sopenharmony_cistd::vector<SkScalar> SkFont::getIntercepts(const SkGlyphID glyphs[], int count,
949cb93a386Sopenharmony_ci                                            const SkPoint positions[],
950cb93a386Sopenharmony_ci                                            SkScalar top, SkScalar bottom,
951cb93a386Sopenharmony_ci                                            const SkPaint* paintPtr) const {
952cb93a386Sopenharmony_ci    if (count <= 0) {
953cb93a386Sopenharmony_ci        return std::vector<SkScalar>();
954cb93a386Sopenharmony_ci    }
955cb93a386Sopenharmony_ci
956cb93a386Sopenharmony_ci    const SkPaint paint(paintPtr ? *paintPtr : SkPaint());
957cb93a386Sopenharmony_ci    const SkScalar bounds[] = {top, bottom};
958cb93a386Sopenharmony_ci    const SkGlyphRun run(*this,
959cb93a386Sopenharmony_ci                         {positions, size_t(count)}, {glyphs, size_t(count)},
960cb93a386Sopenharmony_ci                         {nullptr, 0}, {nullptr, 0}, {nullptr, 0});
961cb93a386Sopenharmony_ci
962cb93a386Sopenharmony_ci    std::vector<SkScalar> result;
963cb93a386Sopenharmony_ci    result.resize(count * 2);   // worst case allocation
964cb93a386Sopenharmony_ci    int intervalCount = 0;
965cb93a386Sopenharmony_ci    intervalCount = get_glyph_run_intercepts(run, paint, bounds, result.data(), &intervalCount);
966cb93a386Sopenharmony_ci    result.resize(intervalCount);
967cb93a386Sopenharmony_ci    return result;
968cb93a386Sopenharmony_ci}
969cb93a386Sopenharmony_ci
970cb93a386Sopenharmony_ci////////
971cb93a386Sopenharmony_ci
972cb93a386Sopenharmony_ciSkTextBlob::Iter::Iter(const SkTextBlob& blob) {
973cb93a386Sopenharmony_ci    fRunRecord = RunRecord::First(&blob);
974cb93a386Sopenharmony_ci}
975cb93a386Sopenharmony_ci
976cb93a386Sopenharmony_cibool SkTextBlob::Iter::next(Run* rec) {
977cb93a386Sopenharmony_ci    if (fRunRecord) {
978cb93a386Sopenharmony_ci        if (rec) {
979cb93a386Sopenharmony_ci            rec->fTypeface = fRunRecord->font().getTypeface();
980cb93a386Sopenharmony_ci            rec->fGlyphCount = fRunRecord->glyphCount();
981cb93a386Sopenharmony_ci            rec->fGlyphIndices = fRunRecord->glyphBuffer();
982cb93a386Sopenharmony_ci#ifdef SK_UNTIL_CRBUG_1187654_IS_FIXED
983cb93a386Sopenharmony_ci            rec->fClusterIndex_forTest = fRunRecord->clusterBuffer();
984cb93a386Sopenharmony_ci            rec->fUtf8Size_forTest = fRunRecord->textSize();
985cb93a386Sopenharmony_ci            rec->fUtf8_forTest = fRunRecord->textBuffer();
986cb93a386Sopenharmony_ci#endif
987cb93a386Sopenharmony_ci        }
988cb93a386Sopenharmony_ci        if (fRunRecord->isLastRun()) {
989cb93a386Sopenharmony_ci            fRunRecord = nullptr;
990cb93a386Sopenharmony_ci        } else {
991cb93a386Sopenharmony_ci            fRunRecord = RunRecord::Next(fRunRecord);
992cb93a386Sopenharmony_ci        }
993cb93a386Sopenharmony_ci        return true;
994cb93a386Sopenharmony_ci    }
995cb93a386Sopenharmony_ci    return false;
996cb93a386Sopenharmony_ci}
997cb93a386Sopenharmony_ci
998cb93a386Sopenharmony_cibool SkTextBlob::Iter::experimentalNext(ExperimentalRun* rec) {
999cb93a386Sopenharmony_ci    if (fRunRecord) {
1000cb93a386Sopenharmony_ci        if (rec) {
1001cb93a386Sopenharmony_ci            rec->font = fRunRecord->font();
1002cb93a386Sopenharmony_ci            rec->count = fRunRecord->glyphCount();
1003cb93a386Sopenharmony_ci            rec->glyphs = fRunRecord->glyphBuffer();
1004cb93a386Sopenharmony_ci            rec->positions = fRunRecord->pointBuffer();
1005cb93a386Sopenharmony_ci        }
1006cb93a386Sopenharmony_ci        if (fRunRecord->isLastRun()) {
1007cb93a386Sopenharmony_ci            fRunRecord = nullptr;
1008cb93a386Sopenharmony_ci        } else {
1009cb93a386Sopenharmony_ci            fRunRecord = RunRecord::Next(fRunRecord);
1010cb93a386Sopenharmony_ci        }
1011cb93a386Sopenharmony_ci        return true;
1012cb93a386Sopenharmony_ci    }
1013cb93a386Sopenharmony_ci    return false;
1014cb93a386Sopenharmony_ci}
1015cb93a386Sopenharmony_ci
1016cb93a386Sopenharmony_civoid GetGlyphIDforTextBlob(const SkTextBlob* blob, std::vector<SkGlyphID>& glyphIds)
1017cb93a386Sopenharmony_ci{
1018cb93a386Sopenharmony_ci    if (blob == nullptr) {
1019cb93a386Sopenharmony_ci        return;
1020cb93a386Sopenharmony_ci    }
1021cb93a386Sopenharmony_ci    SkTextBlobRunIterator it(blob);
1022cb93a386Sopenharmony_ci    if (!it.done()) {
1023cb93a386Sopenharmony_ci        size_t runSize = it.glyphCount();
1024cb93a386Sopenharmony_ci        auto glyphIDs = it.glyphs();
1025cb93a386Sopenharmony_ci        for (size_t i = 0; i < runSize; ++i) {
1026cb93a386Sopenharmony_ci            glyphIds.push_back(glyphIDs[i]);
1027cb93a386Sopenharmony_ci        }
1028cb93a386Sopenharmony_ci    }
1029cb93a386Sopenharmony_ci}
1030cb93a386Sopenharmony_ci
1031cb93a386Sopenharmony_ciSkPath GetPathforTextBlob(const SkGlyphID& glyphId, const SkTextBlob* blob)
1032cb93a386Sopenharmony_ci{
1033cb93a386Sopenharmony_ci    SkPath path;
1034cb93a386Sopenharmony_ci    if (blob == nullptr) {
1035cb93a386Sopenharmony_ci        return path;
1036cb93a386Sopenharmony_ci    }
1037cb93a386Sopenharmony_ci    SkTextBlobRunIterator it(blob);
1038cb93a386Sopenharmony_ci    if (!it.done()) {
1039cb93a386Sopenharmony_ci        SkFont font = it.font();
1040cb93a386Sopenharmony_ci        font.getPath(glyphId, &path);
1041cb93a386Sopenharmony_ci    }
1042cb93a386Sopenharmony_ci    return path;
1043cb93a386Sopenharmony_ci}
1044cb93a386Sopenharmony_ci
1045cb93a386Sopenharmony_civoid GetPointsForTextBlob(const SkTextBlob* blob, std::vector<SkPoint>& points)
1046cb93a386Sopenharmony_ci{
1047cb93a386Sopenharmony_ci    if (blob == nullptr) {
1048cb93a386Sopenharmony_ci        return;
1049cb93a386Sopenharmony_ci    }
1050cb93a386Sopenharmony_ci    SkTextBlobRunIterator run(blob);
1051cb93a386Sopenharmony_ci    if (!run.done()) {
1052cb93a386Sopenharmony_ci        const auto glyphCount = run.glyphCount();
1053cb93a386Sopenharmony_ci        switch (run.positioning()) {
1054cb93a386Sopenharmony_ci            case SkTextBlobRunIterator::kFull_Positioning: {
1055cb93a386Sopenharmony_ci                for (auto i = 0; i < glyphCount; i++) {
1056cb93a386Sopenharmony_ci                    const SkPoint* glyphPoints = run.points();
1057cb93a386Sopenharmony_ci                    const auto* point = glyphPoints + i;
1058cb93a386Sopenharmony_ci                    points.push_back(*point);
1059cb93a386Sopenharmony_ci                }
1060cb93a386Sopenharmony_ci                break;
1061cb93a386Sopenharmony_ci            }
1062cb93a386Sopenharmony_ci            default:
1063cb93a386Sopenharmony_ci                break;
1064cb93a386Sopenharmony_ci        }
1065cb93a386Sopenharmony_ci        run.next();
1066cb93a386Sopenharmony_ci    }
1067cb93a386Sopenharmony_ci}
1068