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