diff options
-rw-r--r-- | include/core/SkTextBlob.h | 2 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 12 | ||||
-rw-r--r-- | src/core/SkDevice.cpp | 11 | ||||
-rw-r--r-- | src/core/SkDevice.h | 4 | ||||
-rw-r--r-- | src/core/SkGlyphRun.cpp | 141 | ||||
-rw-r--r-- | src/core/SkGlyphRun.h | 76 | ||||
-rw-r--r-- | src/gpu/text/GrTextContext.cpp | 37 | ||||
-rw-r--r-- | tests/GlyphRunTest.cpp | 54 |
8 files changed, 276 insertions, 61 deletions
diff --git a/include/core/SkTextBlob.h b/include/core/SkTextBlob.h index 672cc20c5c..c68ad4147b 100644 --- a/include/core/SkTextBlob.h +++ b/include/core/SkTextBlob.h @@ -14,6 +14,7 @@ #include "SkString.h" #include "SkRefCnt.h" +class SkGlyphRunList; class SkReadBuffer; class SkWriteBuffer; @@ -107,6 +108,7 @@ private: fCacheID.store(cacheID); } + friend class SkGlyphRunList; friend class GrTextBlobCache; friend class SkTextBlobBuilder; friend class SkTextBlobRunIterator; diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 367105ddda..3c5ec347c7 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -2431,8 +2431,8 @@ void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkSca while (iter.next()) { fScratchGlyphRunBuilder->drawText( looper.paint(), text, byteLength, SkPoint::Make(x, y)); - auto glyphRun = fScratchGlyphRunBuilder->useGlyphRun(); - iter.fDevice->drawGlyphRun(looper.paint(), glyphRun); + auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList(); + iter.fDevice->drawGlyphRunList(looper.paint(), glyphRunList); } LOOPER_END @@ -2445,8 +2445,8 @@ void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint while (iter.next()) { fScratchGlyphRunBuilder->drawPosText(looper.paint(), text, byteLength, pos); - auto glyphRun = fScratchGlyphRunBuilder->useGlyphRun(); - iter.fDevice->drawGlyphRun(looper.paint(), glyphRun); + auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList(); + iter.fDevice->drawGlyphRunList(looper.paint(), glyphRunList); } LOOPER_END @@ -2460,8 +2460,8 @@ void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScala while (iter.next()) { fScratchGlyphRunBuilder->drawPosTextH( looper.paint(), text, byteLength, xpos, constY); - const auto& glyphRun = fScratchGlyphRunBuilder->useGlyphRun(); - iter.fDevice->drawGlyphRun(looper.paint(), glyphRun); + auto glyphRunList = fScratchGlyphRunBuilder->useGlyphRunList(); + iter.fDevice->drawGlyphRunList(looper.paint(), glyphRunList); } LOOPER_END diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 5ca8f5ec5e..a4482a19ec 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -157,8 +157,8 @@ void SkBaseDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, auto origin = SkPoint::Make(x + offset.x(), y + offset.y()); SkGlyphRunBuilder builder; builder.drawText(runPaint, (const char*) it.glyphs(), textLen, origin); - auto glyphRun = builder.useGlyphRun(); - glyphRun->temporaryShuntToDrawPosText(this); + auto glyphRunList = builder.useGlyphRunList(); + glyphRunList->temporaryShuntToDrawPosText(this); } break; case SkTextBlob::kHorizontal_Positioning: @@ -239,11 +239,8 @@ void SkBaseDevice::drawImageLattice(const SkImage* image, } } -void SkBaseDevice::drawGlyphRun(const SkPaint& paint, SkGlyphRun* glyphRun) { - SkPaint glyphPaint(paint); - glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - - glyphRun->temporaryShuntToDrawPosText(this); +void SkBaseDevice::drawGlyphRunList(const SkPaint& paint, SkGlyphRunList* glyphRunList) { + glyphRunList->temporaryShuntToDrawPosText(this); } void SkBaseDevice::drawBitmapLattice(const SkBitmap& bitmap, diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h index 2173d91023..2a33822b1e 100644 --- a/src/core/SkDevice.h +++ b/src/core/SkDevice.h @@ -16,7 +16,7 @@ class SkBitmap; struct SkDrawShadowRec; -class SkGlyphRun; +class SkGlyphRunList; class SkGlyphRunBuilder; class SkImageFilterCache; struct SkIRect; @@ -222,7 +222,7 @@ protected: * Does not handle text decoration. * Decorations (underline and stike-thru) will be handled by SkCanvas. */ - virtual void drawGlyphRun(const SkPaint& paint, SkGlyphRun* glyphRun); + virtual void drawGlyphRunList(const SkPaint& paint, SkGlyphRunList* glyphRunList); virtual void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode, const SkPaint&) = 0; virtual void drawShadow(const SkPath&, const SkDrawShadowRec&); diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp index 781263c103..6cb458544f 100644 --- a/src/core/SkGlyphRun.cpp +++ b/src/core/SkGlyphRun.cpp @@ -69,6 +69,36 @@ void SkGlyphRun::temporaryShuntToCallback(TemporaryShuntCallback callback) { callback(fTemporaryShuntGlyphIDs.size(), bytes, pos); } +// -- SkGlyphRunList ------------------------------------------------------------------------------- +SkGlyphRunList::SkGlyphRunList( + const SkPaint& paint, + const SkTextBlob* blob, + SkPoint origin, + SkSpan<SkGlyphRun> glyphRunList) + : fOriginalPaint{&paint} + , fOriginalTextBlob{blob} + , fOrigin{origin} + , fGlyphRuns{glyphRunList} { } + +uint64_t SkGlyphRunList::uniqueID() const { + return fOriginalTextBlob != nullptr ? fOriginalTextBlob->uniqueID() + : SK_InvalidUniqueID; +} + +bool SkGlyphRunList::anyRunsLCD() const { + for (const auto& r : fGlyphRuns) { + if (r.paint().isLCDRenderText()) { + return true; + } + } + return false; +} + +void SkGlyphRunList::temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const { + SkASSERT(fOriginalTextBlob != nullptr); + fOriginalTextBlob->notifyAddedToCache(cacheID); +} + // -- SkGlyphIDSet --------------------------------------------------------------------------------- // A faster set implementation that does not need any initialization, and reading the set items // is order the number of items, and not the size of the universe. @@ -140,6 +170,8 @@ void SkGlyphRunBuilder::drawText( this->simplifyDrawText( paint, glyphIDs, origin, fUniqueGlyphIDIndices, fUniqueGlyphIDs, fPositions); } + + this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0)); } void SkGlyphRunBuilder::drawPosTextH(const SkPaint& paint, const void* bytes, @@ -151,6 +183,8 @@ void SkGlyphRunBuilder::drawPosTextH(const SkPaint& paint, const void* bytes, this->simplifyDrawPosTextH( paint, glyphIDs, xpos, constY, fUniqueGlyphIDIndices, fUniqueGlyphIDs, fPositions); } + + this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0)); } void SkGlyphRunBuilder::drawPosText(const SkPaint& paint, const void* bytes, @@ -158,17 +192,82 @@ void SkGlyphRunBuilder::drawPosText(const SkPaint& paint, const void* bytes, auto glyphIDs = textToGlyphIDs(paint, bytes, byteLength); if (!glyphIDs.empty()) { this->initialize(glyphIDs.size()); - this->simplifyDrawPosText( - paint, glyphIDs, pos, fUniqueGlyphIDIndices, fUniqueGlyphIDs); + this->simplifyDrawPosText(paint, glyphIDs, pos, fUniqueGlyphIDIndices, fUniqueGlyphIDs); } + + this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0)); } -SkGlyphRun* SkGlyphRunBuilder::useGlyphRun() { - return &fScratchGlyphRun; +void SkGlyphRunBuilder::drawTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin) { + SkPaint runPaint = paint; + + // Figure out all the storage needed to pre-size everything below. + size_t totalGlyphs = 0; + for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) { + totalGlyphs += it.glyphCount(); + } + + // Pre-size all the buffers so they don't move during processing. + this->initialize(totalGlyphs); + + uint16_t* currentDenseIndices = fUniqueGlyphIDIndices; + SkPoint* currentPositions = fPositions; + SkGlyphID* currentUniqueGlyphIDs = fUniqueGlyphIDs; + + for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) { + // applyFontToPaint() always overwrites the exact same attributes, + // so it is safe to not re-seed the paint for this reason. + it.applyFontToPaint(&runPaint); + size_t runSize = it.glyphCount(); + + // These better be glyphs + SkASSERT(runPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); + + auto text = SkSpan<const char>(it.text(), it.textSize()); + auto clusters = SkSpan<const uint32_t>(it.clusters(), runSize); + const SkPoint& offset = it.offset(); + auto glyphIDs = SkSpan<const SkGlyphID>{it.glyphs(), runSize}; + + size_t uniqueGlyphIDsSize = 0; + switch (it.positioning()) { + case SkTextBlob::kDefault_Positioning: { + uniqueGlyphIDsSize = this->simplifyDrawText( + runPaint, glyphIDs, offset, + currentDenseIndices, currentUniqueGlyphIDs, currentPositions, + text, clusters); + } + break; + case SkTextBlob::kHorizontal_Positioning: { + auto constY = offset.y(); + uniqueGlyphIDsSize = this->simplifyDrawPosTextH( + runPaint, glyphIDs, it.pos(), constY, + currentDenseIndices, currentUniqueGlyphIDs, currentPositions, + text, clusters); + } + break; + case SkTextBlob::kFull_Positioning: + uniqueGlyphIDsSize = this->simplifyDrawPosText( + runPaint, glyphIDs, (const SkPoint*)it.pos(), + currentDenseIndices, currentUniqueGlyphIDs, + text, clusters); + break; + default: + SK_ABORT("unhandled positioning mode"); + } + + currentDenseIndices += runSize; + currentPositions += runSize; + currentUniqueGlyphIDs += uniqueGlyphIDsSize; + } + + this->makeGlyphRunList(paint, &blob, origin); +} + +SkGlyphRunList* SkGlyphRunBuilder::useGlyphRunList() { + return &fGlyphRunList; } void SkGlyphRunBuilder::initialize(size_t totalRunSize) { - fUniqueID = 0; if (totalRunSize > fMaxTotalRunSize) { fMaxTotalRunSize = totalRunSize; @@ -177,8 +276,7 @@ void SkGlyphRunBuilder::initialize(size_t totalRunSize) { fUniqueGlyphIDs.reset(fMaxTotalRunSize); } - // Be sure to clean up the last run before we reuse it. - fScratchGlyphRun.~SkGlyphRun(); + fGlyphRunListStorage.clear(); } SkSpan<const SkGlyphID> SkGlyphRunBuilder::textToGlyphIDs( @@ -236,25 +334,31 @@ void SkGlyphRunBuilder::makeGlyphRun( glyphRunPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); glyphRunPaint.setTextAlign(SkPaint::kLeft_Align); - new ((void*)&fScratchGlyphRun) SkGlyphRun{ + fGlyphRunListStorage.emplace_back( std::move(glyphRunPaint), uniqueGlyphIDIndices, positions, glyphIDs, uniqueGlyphIDs, text, - clusters - }; + clusters); } } -void SkGlyphRunBuilder::simplifyDrawText( +void SkGlyphRunBuilder::makeGlyphRunList( + const SkPaint& paint, const SkTextBlob* blob, SkPoint origin) { + + fGlyphRunList.~SkGlyphRunList(); + new (&fGlyphRunList) SkGlyphRunList{ + paint, blob, origin, SkSpan<SkGlyphRun>{fGlyphRunListStorage}}; +} + +size_t SkGlyphRunBuilder::simplifyDrawText( const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, SkPoint origin, uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer, SkPoint* positions, SkSpan<const char> text, SkSpan<const uint32_t> clusters) { SkASSERT(!glyphIDs.empty()); - auto runSize = glyphIDs.size(); auto unqiueGlyphIDs = this->addDenseAndUnique( @@ -271,7 +375,7 @@ void SkGlyphRunBuilder::simplifyDrawText( for (size_t i = 0; i < runSize; i++) { positions[i] = endOfLastGlyph; - endOfLastGlyph += fScratchAdvances[fUniqueGlyphIDIndices[i]]; + endOfLastGlyph += fScratchAdvances[uniqueGlyphIDIndicesBuffer[i]]; } if (paint.getTextAlign() != SkPaint::kLeft_Align) { @@ -289,14 +393,16 @@ void SkGlyphRunBuilder::simplifyDrawText( paint, glyphIDs, SkSpan<const SkPoint>{positions, runSize}, - SkSpan<const uint16_t>{fUniqueGlyphIDIndices, runSize}, + SkSpan<const uint16_t>{uniqueGlyphIDIndicesBuffer, runSize}, unqiueGlyphIDs, text, clusters); } + + return unqiueGlyphIDs.size(); } -void SkGlyphRunBuilder::simplifyDrawPosTextH( +size_t SkGlyphRunBuilder::simplifyDrawPosTextH( const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, const SkScalar* xpos, SkScalar constY, uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer, SkPoint* positions, @@ -307,13 +413,13 @@ void SkGlyphRunBuilder::simplifyDrawPosTextH( *posCursor++ = SkPoint::Make(x, constY); } - this->simplifyDrawPosText( + return this->simplifyDrawPosText( paint, glyphIDs, positions, uniqueGlyphIDIndicesBuffer, uniqueGlyphIDsBuffer, text, clusters); } -void SkGlyphRunBuilder::simplifyDrawPosText( +size_t SkGlyphRunBuilder::simplifyDrawPosText( const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, const SkPoint* pos, uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer, SkSpan<const char> text, SkSpan<const uint32_t> clusters) { @@ -336,6 +442,7 @@ void SkGlyphRunBuilder::simplifyDrawPosText( uniqueGlyphIDs, text, clusters); + return 0; } diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h index a1124fd58e..4b392fda0f 100644 --- a/src/core/SkGlyphRun.h +++ b/src/core/SkGlyphRun.h @@ -61,10 +61,8 @@ public: void temporaryShuntToCallback(TemporaryShuntCallback callback); size_t runSize() const { return fUniqueGlyphIDIndices.size(); } - uint16_t uniqueSize() const { return fUniqueGlyphIDs.size(); } SkSpan<const SkPoint> positions() const { return fPositions; } - SkSpan<const SkGlyphID> uniqueGlyphIDs() const { return fUniqueGlyphIDs; } - SkSpan<const SkGlyphID> shuntGlyphsIDs() const { return fTemporaryShuntGlyphIDs; } + const SkPaint& paint() const { return fRunPaint; } private: // @@ -83,6 +81,53 @@ private: const SkPaint fRunPaint; }; +class SkGlyphRunList { + const SkPaint* fOriginalPaint{nullptr}; + // The text blob is needed to hookup the call back that the SkTextBlob destructor calls. It + // should be used for nothing else + const SkTextBlob* fOriginalTextBlob{nullptr}; + SkPoint fOrigin = {0, 0}; + SkSpan<SkGlyphRun> fGlyphRuns; + +public: + SkGlyphRunList() = default; + // Blob maybe null. + SkGlyphRunList( + const SkPaint& paint, + const SkTextBlob* blob, + SkPoint origin, + SkSpan<SkGlyphRun> glyphRunList); + + uint64_t uniqueID() const; + bool anyRunsLCD() const; + void temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const; + + bool canCache() const { return fOriginalTextBlob != nullptr; } + size_t runCount() const { return fGlyphRuns.size(); } + size_t totalGlyphCount() const { + size_t glyphCount = 0; + for(const auto& run : fGlyphRuns) { + glyphCount += run.runSize(); + } + return glyphCount; + } + + SkPoint origin() const { return fOrigin; } + const SkPaint& paint() const { return *fOriginalPaint; } + + auto begin() -> decltype(fGlyphRuns.begin()) { return fGlyphRuns.begin(); } + auto end() -> decltype(fGlyphRuns.end()) { return fGlyphRuns.end(); } + auto size() -> decltype(fGlyphRuns.size()) { return fGlyphRuns.size(); } + auto empty() -> decltype(fGlyphRuns.empty()) { return fGlyphRuns.empty(); } + auto operator [] (size_t i) -> decltype(fGlyphRuns[i]) { return fGlyphRuns[i]; } + void temporaryShuntToDrawPosText(SkBaseDevice* device) { + for (auto& run : fGlyphRuns) { + run.temporaryShuntToDrawPosText(device); + } + } + +}; + class SkGlyphIDSet { public: SkSpan<const SkGlyphID> uniquifyGlyphIDs( @@ -96,16 +141,16 @@ private: class SkGlyphRunBuilder { public: void drawText( - const SkPaint& paint, const void* bytes, size_t byteLength, - SkPoint origin); + const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin); void drawPosTextH( const SkPaint& paint, const void* bytes, size_t byteLength, const SkScalar* xpos, SkScalar constY); void drawPosText( - const SkPaint& paint, const void* bytes, size_t byteLength, - const SkPoint* pos); + const SkPaint& paint, const void* bytes, size_t byteLength, const SkPoint* pos); + void drawTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin); SkGlyphRun* useGlyphRun(); + SkGlyphRunList* useGlyphRunList(); private: void initialize(size_t totalRunSize); @@ -128,30 +173,35 @@ private: SkSpan<const char> text, SkSpan<const uint32_t> clusters); - void simplifyDrawText( + void makeGlyphRunList(const SkPaint& paint, const SkTextBlob* blob, SkPoint origin); + + size_t simplifyDrawText( const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, SkPoint origin, uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs, SkPoint* positions, SkSpan<const char> text = SkSpan<const char>{}, SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{}); - void simplifyDrawPosTextH( + size_t simplifyDrawPosTextH( const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, const SkScalar* xpos, SkScalar constY, uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs, SkPoint* positions, SkSpan<const char> text = SkSpan<const char>{}, SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{}); - void simplifyDrawPosText( + size_t simplifyDrawPosText( const SkPaint& paint, SkSpan<const SkGlyphID> glyphIDs, const SkPoint* pos, uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs, SkSpan<const char> text = SkSpan<const char>{}, SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{}); - uint64_t fUniqueID{0}; size_t fMaxTotalRunSize{0}; SkAutoTMalloc<uint16_t> fUniqueGlyphIDIndices; SkAutoTMalloc<SkPoint> fPositions; SkAutoTMalloc<SkGlyphID> fUniqueGlyphIDs; + std::vector<SkGlyphRun> fGlyphRunListStorage; + SkGlyphRunList fGlyphRunList; + + // Used as a temporary for preparing using utfN text. This implies that only one run of // glyph ids will ever be needed because blobs are already glyph based. std::vector<SkGlyphID> fScratchGlyphIDs; @@ -159,10 +209,6 @@ private: // Used as temporary storage for calculating positions for drawText. std::vector<SkPoint> fScratchAdvances; - - // Used as temporary glyph run for the rest of the Text stack. - SkGlyphRun fScratchGlyphRun; - // Used for collecting the set of unique glyphs. SkGlyphIDSet fGlyphIDSet; }; diff --git a/src/gpu/text/GrTextContext.cpp b/src/gpu/text/GrTextContext.cpp index 04d92aef39..a2ef40f16d 100644 --- a/src/gpu/text/GrTextContext.cpp +++ b/src/gpu/text/GrTextContext.cpp @@ -214,15 +214,17 @@ void GrTextContext::regenerateTextBlob(GrTextBlob* cacheBlob, builder.drawText(runPaint.skPaint(), (const char*) it.glyphs(), textLen, origin); - auto glyphRun = builder.useGlyphRun(); - - glyphRun->temporaryShuntToCallback( + auto glyphRunList = builder.useGlyphRunList(); + if (!glyphRunList->empty()) { + auto glyphRun = (*glyphRunList)[0]; + glyphRun.temporaryShuntToCallback( [&](size_t runSize, const char* glyphIDs, const SkScalar* pos) { this->drawDFPosText( - cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, - viewMatrix, glyphIDs, 2 * runSize, pos, 2, - SkPoint::Make(0,0)); + cacheBlob, run, glyphCache, props, runPaint, + scalerContextFlags, viewMatrix, glyphIDs, 2 * runSize, + pos, 2, SkPoint::Make(0, 0)); }); + } break; } @@ -249,15 +251,18 @@ void GrTextContext::regenerateTextBlob(GrTextBlob* cacheBlob, builder.drawText(runPaint.skPaint(), (const char*) it.glyphs(), textLen, origin); - auto glyphRun = builder.useGlyphRun(); + auto glyphRunList = builder.useGlyphRunList(); + if (!glyphRunList->empty()) { + auto glyphRun = (*glyphRunList)[0]; - glyphRun->temporaryShuntToCallback( + glyphRun.temporaryShuntToCallback( [&](size_t runSize, const char* glyphIDs, const SkScalar* pos) { this->DrawBmpPosText( - cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, - viewMatrix, glyphIDs, 2 * runSize, + cacheBlob, run, glyphCache, props, runPaint, + scalerContextFlags, viewMatrix, glyphIDs, 2 * runSize, pos, 2, SkPoint::Make(0, 0)); }); + } break; } case SkTextBlob::kHorizontal_Positioning: @@ -783,16 +788,20 @@ std::unique_ptr<GrDrawOp> GrTextContext::createOp_TestingOnly(GrContext* context builder.drawText(skPaint, text, textLen, origin); sk_sp<GrTextBlob> blob; - auto glyphRun = builder.useGlyphRun(); - // Use the text and textLen below, because we don't want to mess with the paint. - glyphRun->temporaryShuntToCallback( + auto glyphRunList = builder.useGlyphRunList(); + if (!glyphRunList->empty()) { + auto glyphRun = (*glyphRunList)[0]; + // Use the text and textLen below, because we don't want to mess with the paint. + glyphRun.temporaryShuntToCallback( [&](size_t runSize, const char* glyphIDs, const SkScalar* pos) { blob = textContext->makeDrawPosTextBlob( context->contextPriv().getTextBlobCache(), glyphCache, *context->contextPriv().caps()->shaderCaps(), utilsPaint, - GrTextContext::kTextBlobOpScalerContextFlags, viewMatrix, surfaceProps, text, + GrTextContext::kTextBlobOpScalerContextFlags, viewMatrix, surfaceProps, + text, textLen, pos, 2, origin); }); + } return blob->test_makeOp(textLen, 0, 0, viewMatrix, x, y, utilsPaint, surfaceProps, textContext->dfAdjustTable(), rtc->textTarget()); diff --git a/tests/GlyphRunTest.cpp b/tests/GlyphRunTest.cpp index b87edc7731..49d7340aca 100644 --- a/tests/GlyphRunTest.cpp +++ b/tests/GlyphRunTest.cpp @@ -49,3 +49,57 @@ DEF_TEST(GlyphRunBasic, reporter) { SkGlyphRunBuilder builder; builder.drawText(paint, glyphs, count, SkPoint::Make(0, 0)); } + +DEF_TEST(GlyphRunBlob, reporter) { + constexpr uint16_t count = 5; + constexpr int runCount = 2; + + auto tf = SkTypeface::MakeFromName("monospace", SkFontStyle()); + + SkPaint font; + font.setTypeface(tf); + font.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + font.setTextAlign(SkPaint::kLeft_Align); + font.setStyle(SkPaint::kFill_Style); + font.setHinting(SkPaint::kNormal_Hinting); + font.setTextSize(1u); + + SkTextBlobBuilder blobBuilder; + for (int runNum = 0; runNum < runCount; runNum++) { + const auto& runBuffer = blobBuilder.allocRunPosH(font, count, runNum); + SkASSERT(runBuffer.utf8text == nullptr); + SkASSERT(runBuffer.clusters == nullptr); + + for (int i = 0; i < count; i++) { + runBuffer.glyphs[i] = static_cast<SkGlyphID>(i + runNum * count); + runBuffer.pos[i] = SkIntToScalar(i + runNum * count); + } + } + + auto blob = blobBuilder.make(); + + SkPaint paint; + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + + SkGlyphRunBuilder runBuilder; + runBuilder.drawTextBlob(font, *blob, SkPoint::Make(0, 0)); + + auto runList = runBuilder.useGlyphRunList(); + + REPORTER_ASSERT(reporter, runList->size() == runCount); + int runIndex = 0; + for (auto& run : *runList) { + REPORTER_ASSERT(reporter, run.runSize() == count); + + int index = 0; + for (auto p : run.positions()) { + if (p.x() != runIndex * count + index) { + ERRORF(reporter, "x: %g != k: %d", p.x(), runIndex * count + index); + break; + } + index += 1; + } + + runIndex += 1; + } +} |