1 /* 2 * Copyright 2015 Google Inc. 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 #ifndef GrAtlasTextBlob_DEFINED 9 #define GrAtlasTextBlob_DEFINED 10 11 #include "GrColor.h" 12 #include "GrDrawOpAtlas.h" 13 #include "GrGlyphCache.h" 14 #include "GrMemoryPool.h" 15 #include "GrTextUtils.h" 16 #include "SkDescriptor.h" 17 #include "SkMaskFilterBase.h" 18 #include "SkOpts.h" 19 #include "SkPathEffect.h" 20 #include "SkPoint3.h" 21 #include "SkRectPriv.h" 22 #include "SkSurfaceProps.h" 23 #include "SkTInternalLList.h" 24 25 class GrAtlasManager; 26 struct GrDistanceFieldAdjustTable; 27 struct GrGlyph; 28 class GrGlyphCache; 29 class GrMemoryPool; 30 class GrRestrictedAtlasManager; 31 32 class SkDrawFilter; 33 class SkTextBlob; 34 class SkTextBlobRunIterator; 35 36 // With this flag enabled, the GrAtlasTextContext will, as a sanity check, regenerate every blob 37 // that comes in to verify the integrity of its cache 38 #define CACHE_SANITY_CHECK 0 39 40 /* 41 * A GrAtlasTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing 42 * on the GPU. These are initially created with valid positions and colors, but invalid 43 * texture coordinates. The GrAtlasTextBlob itself has a few Blob-wide properties, and also 44 * consists of a number of runs. Runs inside a blob are flushed individually so they can be 45 * reordered. 46 * 47 * The only thing(aside from a memcopy) required to flush a GrAtlasTextBlob is to ensure that 48 * the GrAtlas will not evict anything the Blob needs. 49 * 50 * Note: This struct should really be named GrCachedAtasTextBlob, but that is too verbose. 51 * 52 * *WARNING* If you add new fields to this struct, then you may need to to update AssertEqual 53 */ 54 class GrAtlasTextBlob : public SkNVRefCnt<GrAtlasTextBlob> { 55 public: 56 SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrAtlasTextBlob); 57 58 class VertexRegenerator; 59 60 static sk_sp<GrAtlasTextBlob> Make(GrMemoryPool*, int glyphCount, int runCount); 61 62 /** 63 * We currently force regeneration of a blob if old or new matrix differ in having perspective. 64 * If we ever change that then the key must contain the perspectiveness when there are distance 65 * fields as perspective distance field use 3 component vertex positions and non-perspective 66 * uses 2. 67 */ 68 struct Key { KeyKey69 Key() { 70 sk_bzero(this, sizeof(Key)); 71 } 72 uint32_t fUniqueID; 73 // Color may affect the gamma of the mask we generate, but in a fairly limited way. 74 // Each color is assigned to on of a fixed number of buckets based on its 75 // luminance. For each luminance bucket there is a "canonical color" that 76 // represents the bucket. This functionality is currently only supported for A8 77 SkColor fCanonicalColor; 78 SkPaint::Style fStyle; 79 SkPixelGeometry fPixelGeometry; 80 bool fHasBlur; 81 uint32_t fScalerContextFlags; 82 83 bool operator==(const Key& other) const { 84 return 0 == memcmp(this, &other, sizeof(Key)); 85 } 86 }; 87 setupKey(const GrAtlasTextBlob::Key & key,const SkMaskFilterBase::BlurRec & blurRec,const SkPaint & paint)88 void setupKey(const GrAtlasTextBlob::Key& key, 89 const SkMaskFilterBase::BlurRec& blurRec, 90 const SkPaint& paint) { 91 fKey = key; 92 if (key.fHasBlur) { 93 fBlurRec = blurRec; 94 } 95 if (key.fStyle != SkPaint::kFill_Style) { 96 fStrokeInfo.fFrameWidth = paint.getStrokeWidth(); 97 fStrokeInfo.fMiterLimit = paint.getStrokeMiter(); 98 fStrokeInfo.fJoin = paint.getStrokeJoin(); 99 } 100 } 101 GetKey(const GrAtlasTextBlob & blob)102 static const Key& GetKey(const GrAtlasTextBlob& blob) { 103 return blob.fKey; 104 } 105 Hash(const Key & key)106 static uint32_t Hash(const Key& key) { 107 return SkOpts::hash(&key, sizeof(Key)); 108 } 109 delete(void * p)110 void operator delete(void* p) { 111 GrAtlasTextBlob* blob = reinterpret_cast<GrAtlasTextBlob*>(p); 112 if (blob->fPool) { 113 blob->fPool->release(p); 114 } else { 115 ::operator delete(p); 116 } 117 } new(size_t)118 void* operator new(size_t) { 119 SK_ABORT("All blobs are created by placement new."); 120 return sk_malloc_throw(0); 121 } 122 new(size_t,void * p)123 void* operator new(size_t, void* p) { return p; } delete(void * target,void * placement)124 void operator delete(void* target, void* placement) { 125 ::operator delete(target, placement); 126 } 127 hasDistanceField()128 bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); } hasBitmap()129 bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); } setHasDistanceField()130 void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; } setHasBitmap()131 void setHasBitmap() { fTextType |= kHasBitmap_TextType; } 132 runCount()133 int runCount() const { return fRunCount; } 134 push_back_run(int currRun)135 void push_back_run(int currRun) { 136 SkASSERT(currRun < fRunCount); 137 if (currRun > 0) { 138 Run::SubRunInfo& newRun = fRuns[currRun].fSubRunInfo.back(); 139 Run::SubRunInfo& lastRun = fRuns[currRun - 1].fSubRunInfo.back(); 140 newRun.setAsSuccessor(lastRun); 141 } 142 } 143 144 // sets the last subrun of runIndex to use distance field text setSubRunHasDistanceFields(int runIndex,bool hasLCD,bool isAntiAlias,bool hasWCoord)145 void setSubRunHasDistanceFields(int runIndex, bool hasLCD, bool isAntiAlias, bool hasWCoord) { 146 Run& run = fRuns[runIndex]; 147 Run::SubRunInfo& subRun = run.fSubRunInfo.back(); 148 subRun.setUseLCDText(hasLCD); 149 subRun.setAntiAliased(isAntiAlias); 150 subRun.setDrawAsDistanceFields(); 151 subRun.setHasWCoord(hasWCoord); 152 } 153 setRunPaintFlags(int runIndex,uint16_t paintFlags)154 void setRunPaintFlags(int runIndex, uint16_t paintFlags) { 155 fRuns[runIndex].fPaintFlags = paintFlags & Run::kPaintFlagsMask; 156 } 157 setMinAndMaxScale(SkScalar scaledMax,SkScalar scaledMin)158 void setMinAndMaxScale(SkScalar scaledMax, SkScalar scaledMin) { 159 // we init fMaxMinScale and fMinMaxScale in the constructor 160 fMaxMinScale = SkMaxScalar(scaledMax, fMaxMinScale); 161 fMinMaxScale = SkMinScalar(scaledMin, fMinMaxScale); 162 } 163 164 // inits the override descriptor on the current run. All following subruns must use this 165 // descriptor initOverride(int runIndex)166 void initOverride(int runIndex) { 167 Run& run = fRuns[runIndex]; 168 // Push back a new subrun to fill and set the override descriptor 169 run.push_back(); 170 run.fOverrideDescriptor.reset(new SkAutoDescriptor); 171 } 172 173 SkGlyphCache* setupCache(int runIndex, 174 const SkSurfaceProps& props, 175 SkScalerContextFlags scalerContextFlags, 176 const SkPaint& skPaint, 177 const SkMatrix* viewMatrix); 178 179 // Appends a glyph to the blob. If the glyph is too large, the glyph will be appended 180 // as a path. 181 void appendGlyph(int runIndex, 182 const SkRect& positions, 183 GrColor color, 184 sk_sp<GrTextStrike> strike, 185 GrGlyph* glyph, 186 SkGlyphCache*, const SkGlyph& skGlyph, 187 SkScalar x, SkScalar y, SkScalar scale, bool preTransformed); 188 189 // Appends a glyph to the blob as a path only. 190 void appendPathGlyph(int runIndex, const SkPath& path, 191 SkScalar x, SkScalar y, SkScalar scale, bool preTransformed); 192 GetVertexStride(GrMaskFormat maskFormat,bool isDistanceFieldWithWCoord)193 static size_t GetVertexStride(GrMaskFormat maskFormat, bool isDistanceFieldWithWCoord) { 194 switch (maskFormat) { 195 case kA8_GrMaskFormat: 196 return isDistanceFieldWithWCoord ? kGrayTextDFPerspectiveVASize : kGrayTextVASize; 197 case kARGB_GrMaskFormat: 198 SkASSERT(!isDistanceFieldWithWCoord); 199 return kColorTextVASize; 200 default: 201 SkASSERT(!isDistanceFieldWithWCoord); 202 return kLCDTextVASize; 203 } 204 } 205 206 bool mustRegenerate(const GrTextUtils::Paint&, const SkMaskFilterBase::BlurRec& blurRec, 207 const SkMatrix& viewMatrix, SkScalar x, SkScalar y); 208 209 void flush(GrRestrictedAtlasManager*, GrTextUtils::Target*, const SkSurfaceProps& props, 210 const GrDistanceFieldAdjustTable* distanceAdjustTable, 211 const GrTextUtils::Paint& paint, const GrClip& clip, 212 const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, 213 SkScalar y); 214 computeSubRunBounds(SkRect * outBounds,int runIndex,int subRunIndex,const SkMatrix & viewMatrix,SkScalar x,SkScalar y)215 void computeSubRunBounds(SkRect* outBounds, int runIndex, int subRunIndex, 216 const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { 217 // We don't yet position distance field text on the cpu, so we have to map the vertex bounds 218 // into device space. 219 // We handle vertex bounds differently for distance field text and bitmap text because 220 // the vertex bounds of bitmap text are in device space. If we are flushing multiple runs 221 // from one blob then we are going to pay the price here of mapping the rect for each run. 222 const Run& run = fRuns[runIndex]; 223 const Run::SubRunInfo& subRun = run.fSubRunInfo[subRunIndex]; 224 *outBounds = subRun.vertexBounds(); 225 if (subRun.drawAsDistanceFields()) { 226 // Distance field text is positioned with the (X,Y) as part of the glyph position, 227 // and currently the view matrix is applied on the GPU 228 outBounds->offset(x - fInitialX, y - fInitialY); 229 viewMatrix.mapRect(outBounds); 230 } else { 231 // Bitmap text is fully positioned on the CPU, and offset by an (X,Y) translate in 232 // device space. 233 SkMatrix boundsMatrix = fInitialViewMatrixInverse; 234 235 boundsMatrix.postTranslate(-fInitialX, -fInitialY); 236 237 boundsMatrix.postTranslate(x, y); 238 239 boundsMatrix.postConcat(viewMatrix); 240 boundsMatrix.mapRect(outBounds); 241 242 // Due to floating point numerical inaccuracies, we have to round out here 243 outBounds->roundOut(outBounds); 244 } 245 } 246 247 // position + local coord 248 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); 249 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16); 250 static const size_t kGrayTextDFPerspectiveVASize = 251 sizeof(SkPoint3) + sizeof(GrColor) + sizeof(SkIPoint16); 252 static const size_t kLCDTextVASize = kGrayTextVASize; 253 static const size_t kMaxVASize = kGrayTextDFPerspectiveVASize; 254 static const int kVerticesPerGlyph = 4; 255 256 static void AssertEqual(const GrAtlasTextBlob&, const GrAtlasTextBlob&); 257 258 // The color here is the GrPaint color, and it is used to determine whether we 259 // have to regenerate LCD text blobs. 260 // We use this color vs the SkPaint color because it has the colorfilter applied. initReusableBlob(SkColor luminanceColor,const SkMatrix & viewMatrix,SkScalar x,SkScalar y)261 void initReusableBlob(SkColor luminanceColor, const SkMatrix& viewMatrix, 262 SkScalar x, SkScalar y) { 263 fLuminanceColor = luminanceColor; 264 this->setupViewMatrix(viewMatrix, x, y); 265 } 266 initThrowawayBlob(const SkMatrix & viewMatrix,SkScalar x,SkScalar y)267 void initThrowawayBlob(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { 268 this->setupViewMatrix(viewMatrix, x, y); 269 } 270 key()271 const Key& key() const { return fKey; } 272 ~GrAtlasTextBlob()273 ~GrAtlasTextBlob() { 274 for (int i = 0; i < fRunCount; i++) { 275 fRuns[i].~Run(); 276 } 277 } 278 279 //////////////////////////////////////////////////////////////////////////////////////////////// 280 // Internal test methods 281 std::unique_ptr<GrDrawOp> test_makeOp(int glyphCount, uint16_t run, uint16_t subRun, 282 const SkMatrix& viewMatrix, SkScalar x, SkScalar y, 283 const GrTextUtils::Paint&, const SkSurfaceProps&, 284 const GrDistanceFieldAdjustTable*, 285 GrRestrictedAtlasManager*, GrTextUtils::Target*); 286 287 private: GrAtlasTextBlob()288 GrAtlasTextBlob() 289 : fMaxMinScale(-SK_ScalarMax) 290 , fMinMaxScale(SK_ScalarMax) 291 , fTextType(0) {} 292 293 294 // This function will only be called when we are generating a blob from scratch. We record the 295 // initial view matrix and initial offsets(x,y), because we record vertex bounds relative to 296 // these numbers. When blobs are reused with new matrices, we need to return to model space so 297 // we can update the vertex bounds appropriately. setupViewMatrix(const SkMatrix & viewMatrix,SkScalar x,SkScalar y)298 void setupViewMatrix(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { 299 fInitialViewMatrix = viewMatrix; 300 if (!viewMatrix.invert(&fInitialViewMatrixInverse)) { 301 fInitialViewMatrixInverse = SkMatrix::I(); 302 SkDebugf("Could not invert viewmatrix\n"); 303 } 304 fInitialX = x; 305 fInitialY = y; 306 307 // make sure all initial subruns have the correct VM and X/Y applied 308 for (int i = 0; i < fRunCount; i++) { 309 fRuns[i].fSubRunInfo[0].init(fInitialViewMatrix, x, y); 310 } 311 } 312 313 /* 314 * Each Run inside of the blob can have its texture coordinates regenerated if required. 315 * To determine if regeneration is necessary, fAtlasGeneration is used. If there have been 316 * any evictions inside of the atlas, then we will simply regenerate Runs. We could track 317 * this at a more fine grained level, but its not clear if this is worth it, as evictions 318 * should be fairly rare. 319 * 320 * One additional point, each run can contain glyphs with any of the three mask formats. 321 * We call these SubRuns. Because a subrun must be a contiguous range, we have to create 322 * a new subrun each time the mask format changes in a run. In theory, a run can have as 323 * many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8. In 324 * practice, the vast majority of runs have only a single subrun. 325 * 326 * Finally, for runs where the entire thing is too large for the GrAtlasTextContext to 327 * handle, we have a bit to mark the run as flushable via rendering as paths or as scaled 328 * glyphs. It would be a bit expensive to figure out ahead of time whether or not a run 329 * can flush in this manner, so we always allocate vertices for the run, regardless of 330 * whether or not it is too large. The benefit of this strategy is that we can always reuse 331 * a blob allocation regardless of viewmatrix changes. We could store positions for these 332 * glyphs, however, it's not clear if this is a win because we'd still have to either go to the 333 * glyph cache to get the path at flush time, or hold onto the path in the cache, which 334 * would greatly increase the memory of these cached items. 335 */ 336 struct Run { RunRun337 Run() : fPaintFlags(0) 338 , fInitialized(false) { 339 // To ensure we always have one subrun, we push back a fresh run here 340 fSubRunInfo.push_back(); 341 } 342 struct SubRunInfo { SubRunInfoRun::SubRunInfo343 SubRunInfo() 344 : fAtlasGeneration(GrDrawOpAtlas::kInvalidAtlasGeneration) 345 , fVertexStartIndex(0) 346 , fVertexEndIndex(0) 347 , fGlyphStartIndex(0) 348 , fGlyphEndIndex(0) 349 , fColor(GrColor_ILLEGAL) 350 , fMaskFormat(kA8_GrMaskFormat) 351 , fFlags(0) { 352 fVertexBounds = SkRectPriv::MakeLargestInverted(); 353 } SubRunInfoRun::SubRunInfo354 SubRunInfo(const SubRunInfo& that) 355 : fBulkUseToken(that.fBulkUseToken) 356 , fStrike(SkSafeRef(that.fStrike.get())) 357 , fCurrentViewMatrix(that.fCurrentViewMatrix) 358 , fVertexBounds(that.fVertexBounds) 359 , fAtlasGeneration(that.fAtlasGeneration) 360 , fVertexStartIndex(that.fVertexStartIndex) 361 , fVertexEndIndex(that.fVertexEndIndex) 362 , fGlyphStartIndex(that.fGlyphStartIndex) 363 , fGlyphEndIndex(that.fGlyphEndIndex) 364 , fX(that.fX) 365 , fY(that.fY) 366 , fColor(that.fColor) 367 , fMaskFormat(that.fMaskFormat) 368 , fFlags(that.fFlags) { 369 } 370 371 // TODO when this object is more internal, drop the privacy resetBulkUseTokenRun::SubRunInfo372 void resetBulkUseToken() { fBulkUseToken.reset(); } bulkUseTokenRun::SubRunInfo373 GrDrawOpAtlas::BulkUseTokenUpdater* bulkUseToken() { return &fBulkUseToken; } setStrikeRun::SubRunInfo374 void setStrike(sk_sp<GrTextStrike> strike) { fStrike = std::move(strike); } strikeRun::SubRunInfo375 GrTextStrike* strike() const { return fStrike.get(); } refStrikeRun::SubRunInfo376 sk_sp<GrTextStrike> refStrike() const { return fStrike; } 377 setAtlasGenerationRun::SubRunInfo378 void setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;} atlasGenerationRun::SubRunInfo379 uint64_t atlasGeneration() const { return fAtlasGeneration; } 380 byteCountRun::SubRunInfo381 size_t byteCount() const { return fVertexEndIndex - fVertexStartIndex; } vertexStartIndexRun::SubRunInfo382 size_t vertexStartIndex() const { return fVertexStartIndex; } vertexEndIndexRun::SubRunInfo383 size_t vertexEndIndex() const { return fVertexEndIndex; } appendVerticesRun::SubRunInfo384 void appendVertices(size_t vertexStride) { 385 fVertexEndIndex += vertexStride * kVerticesPerGlyph; 386 } 387 glyphCountRun::SubRunInfo388 uint32_t glyphCount() const { return fGlyphEndIndex - fGlyphStartIndex; } glyphStartIndexRun::SubRunInfo389 uint32_t glyphStartIndex() const { return fGlyphStartIndex; } glyphEndIndexRun::SubRunInfo390 uint32_t glyphEndIndex() const { return fGlyphEndIndex; } glyphAppendedRun::SubRunInfo391 void glyphAppended() { fGlyphEndIndex++; } setColorRun::SubRunInfo392 void setColor(GrColor color) { fColor = color; } colorRun::SubRunInfo393 GrColor color() const { return fColor; } setMaskFormatRun::SubRunInfo394 void setMaskFormat(GrMaskFormat format) { fMaskFormat = format; } maskFormatRun::SubRunInfo395 GrMaskFormat maskFormat() const { return fMaskFormat; } 396 setAsSuccessorRun::SubRunInfo397 void setAsSuccessor(const SubRunInfo& prev) { 398 fGlyphStartIndex = prev.glyphEndIndex(); 399 fGlyphEndIndex = prev.glyphEndIndex(); 400 401 fVertexStartIndex = prev.vertexEndIndex(); 402 fVertexEndIndex = prev.vertexEndIndex(); 403 404 // copy over viewmatrix settings 405 this->init(prev.fCurrentViewMatrix, prev.fX, prev.fY); 406 } 407 vertexBoundsRun::SubRunInfo408 const SkRect& vertexBounds() const { return fVertexBounds; } joinGlyphBoundsRun::SubRunInfo409 void joinGlyphBounds(const SkRect& glyphBounds) { 410 fVertexBounds.joinNonEmptyArg(glyphBounds); 411 } 412 initRun::SubRunInfo413 void init(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { 414 fCurrentViewMatrix = viewMatrix; 415 fX = x; 416 fY = y; 417 } 418 419 // This function assumes the translation will be applied before it is called again 420 void computeTranslation(const SkMatrix& viewMatrix, SkScalar x, SkScalar y, 421 SkScalar* transX, SkScalar* transY); 422 423 // df properties setDrawAsDistanceFieldsRun::SubRunInfo424 void setDrawAsDistanceFields() { fFlags |= kDrawAsSDF_Flag; } drawAsDistanceFieldsRun::SubRunInfo425 bool drawAsDistanceFields() const { return SkToBool(fFlags & kDrawAsSDF_Flag); } setUseLCDTextRun::SubRunInfo426 void setUseLCDText(bool useLCDText) { 427 fFlags = useLCDText ? fFlags | kUseLCDText_Flag : fFlags & ~kUseLCDText_Flag; 428 } hasUseLCDTextRun::SubRunInfo429 bool hasUseLCDText() const { return SkToBool(fFlags & kUseLCDText_Flag); } setAntiAliasedRun::SubRunInfo430 void setAntiAliased(bool antiAliased) { 431 fFlags = antiAliased ? fFlags | kAntiAliased_Flag : fFlags & ~kAntiAliased_Flag; 432 } isAntiAliasedRun::SubRunInfo433 bool isAntiAliased() const { return SkToBool(fFlags & kAntiAliased_Flag); } setHasWCoordRun::SubRunInfo434 void setHasWCoord(bool hasW) { 435 fFlags = hasW ? (fFlags | kHasWCoord_Flag) : fFlags & ~kHasWCoord_Flag; 436 } hasWCoordRun::SubRunInfo437 bool hasWCoord() const { return SkToBool(fFlags & kHasWCoord_Flag); } 438 439 private: 440 enum Flag { 441 kDrawAsSDF_Flag = 0x1, 442 kUseLCDText_Flag = 0x2, 443 kAntiAliased_Flag = 0x4, 444 kHasWCoord_Flag = 0x8 445 }; 446 447 GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken; 448 sk_sp<GrTextStrike> fStrike; 449 SkMatrix fCurrentViewMatrix; 450 SkRect fVertexBounds; 451 uint64_t fAtlasGeneration; 452 size_t fVertexStartIndex; 453 size_t fVertexEndIndex; 454 uint32_t fGlyphStartIndex; 455 uint32_t fGlyphEndIndex; 456 SkScalar fX; 457 SkScalar fY; 458 GrColor fColor; 459 GrMaskFormat fMaskFormat; 460 uint32_t fFlags; 461 }; // SubRunInfo 462 push_backRun463 SubRunInfo& push_back() { 464 // Forward glyph / vertex information to seed the new sub run 465 SubRunInfo& newSubRun = fSubRunInfo.push_back(); 466 const SubRunInfo& prevSubRun = fSubRunInfo.fromBack(1); 467 468 newSubRun.setAsSuccessor(prevSubRun); 469 return newSubRun; 470 } 471 static const int kMinSubRuns = 1; 472 sk_sp<SkTypeface> fTypeface; 473 SkSTArray<kMinSubRuns, SubRunInfo> fSubRunInfo; 474 SkAutoDescriptor fDescriptor; 475 476 // Effects from the paint that are used to build a SkScalerContext. 477 sk_sp<SkPathEffect> fPathEffect; 478 sk_sp<SkMaskFilter> fMaskFilter; 479 480 // Distance field text cannot draw coloremoji, and so has to fall back. However, 481 // though the distance field text and the coloremoji may share the same run, they 482 // will have different descriptors. If fOverrideDescriptor is non-nullptr, then it 483 // will be used in place of the run's descriptor to regen texture coords 484 std::unique_ptr<SkAutoDescriptor> fOverrideDescriptor; // df properties 485 486 // Any glyphs that can't be rendered with the base or override descriptor 487 // are rendered as paths 488 struct PathGlyph { PathGlyphRun::PathGlyph489 PathGlyph(const SkPath& path, SkScalar x, SkScalar y, SkScalar scale, bool preXformed) 490 : fPath(path) 491 , fX(x) 492 , fY(y) 493 , fScale(scale) 494 , fPreTransformed(preXformed) {} 495 SkPath fPath; 496 SkScalar fX; 497 SkScalar fY; 498 SkScalar fScale; 499 bool fPreTransformed; 500 }; 501 502 SkTArray<PathGlyph> fPathGlyphs; 503 504 struct { 505 unsigned fPaintFlags : 16; // needed mainly for rendering paths 506 bool fInitialized : 1; 507 }; 508 // the only flags we need to set 509 static constexpr auto kPaintFlagsMask = SkPaint::kAntiAlias_Flag; 510 }; // Run 511 512 inline std::unique_ptr<GrAtlasTextOp> makeOp( 513 const Run::SubRunInfo& info, int glyphCount, uint16_t run, uint16_t subRun, 514 const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipRect, 515 const GrTextUtils::Paint&, const SkSurfaceProps&, 516 const GrDistanceFieldAdjustTable*, GrRestrictedAtlasManager* , GrTextUtils::Target*); 517 518 struct StrokeInfo { 519 SkScalar fFrameWidth; 520 SkScalar fMiterLimit; 521 SkPaint::Join fJoin; 522 }; 523 524 enum TextType { 525 kHasDistanceField_TextType = 0x1, 526 kHasBitmap_TextType = 0x2, 527 }; 528 529 // all glyph / vertex offsets are into these pools. 530 char* fVertices; 531 GrGlyph** fGlyphs; 532 Run* fRuns; 533 GrMemoryPool* fPool; // this will be null when DDLs are being recorded 534 SkMaskFilterBase::BlurRec fBlurRec; 535 StrokeInfo fStrokeInfo; 536 Key fKey; 537 SkMatrix fInitialViewMatrix; 538 SkMatrix fInitialViewMatrixInverse; 539 size_t fSize; 540 SkColor fLuminanceColor; 541 SkScalar fInitialX; 542 SkScalar fInitialY; 543 544 // We can reuse distance field text, but only if the new viewmatrix would not result in 545 // a mip change. Because there can be multiple runs in a blob, we track the overall 546 // maximum minimum scale, and minimum maximum scale, we can support before we need to regen 547 SkScalar fMaxMinScale; 548 SkScalar fMinMaxScale; 549 int fRunCount; 550 uint8_t fTextType; 551 }; 552 553 /** 554 * Used to produce vertices for a subrun of a blob. The vertices are cached in the blob itself. 555 * This is invoked each time a sub run is drawn. It regenerates the vertex data as required either 556 * because of changes to the atlas or because of different draw parameters (e.g. color change). In 557 * rare cases the draw may have to interrupted and flushed in the middle of the sub run in order to 558 * free up atlas space. Thus, this generator is stateful and should be invoked in a loop until the 559 * entire sub run has been completed. 560 */ 561 class GrAtlasTextBlob::VertexRegenerator { 562 public: 563 /** 564 * Consecutive VertexRegenerators often use the same SkGlyphCache. If the same instance of 565 * SkAutoGlyphCache is reused then it can save the cost of multiple detach/attach operations of 566 * SkGlyphCache. 567 */ 568 VertexRegenerator(GrResourceProvider*, GrAtlasTextBlob*, int runIdx, int subRunIdx, 569 const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color, 570 GrDeferredUploadTarget*, GrGlyphCache*, GrAtlasManager*, 571 SkAutoGlyphCache*); 572 573 struct Result { 574 /** 575 * Was regenerate() able to draw all the glyphs from the sub run? If not flush all glyph 576 * draws and call regenerate() again. 577 */ 578 bool fFinished = true; 579 580 /** 581 * How many glyphs were regenerated. Will be equal to the sub run's glyph count if 582 * fType is kFinished. 583 */ 584 int fGlyphsRegenerated = 0; 585 586 /** 587 * Pointer where the caller finds the first regenerated vertex. 588 */ 589 const char* fFirstVertex; 590 }; 591 592 Result regenerate(); 593 594 private: 595 template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs> 596 Result doRegen(); 597 598 GrResourceProvider* fResourceProvider; 599 const SkMatrix& fViewMatrix; 600 GrAtlasTextBlob* fBlob; 601 GrDeferredUploadTarget* fUploadTarget; 602 GrGlyphCache* fGlyphCache; 603 GrAtlasManager* fFullAtlasManager; 604 SkAutoGlyphCache* fLazyCache; 605 Run* fRun; 606 Run::SubRunInfo* fSubRun; 607 GrColor fColor; 608 SkScalar fTransX; 609 SkScalar fTransY; 610 611 uint32_t fRegenFlags = 0; 612 int fCurrGlyph = 0; 613 bool fBrokenRun = false; 614 }; 615 616 #endif 617