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