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