From 2eacff02f1436e282468670373f5867ab2b27916 Mon Sep 17 00:00:00 2001 From: Herb Derby Date: Wed, 18 Jul 2018 13:41:15 -0400 Subject: Redo drawTextRSXForm for glyph runs Change-Id: Iec9ad6a2c91b16c4e25150902b433fc7aae68a33 Reviewed-on: https://skia-review.googlesource.com/142171 Reviewed-by: Mike Reed Commit-Queue: Herb Derby --- src/core/SkCanvas.cpp | 9 ++++++-- src/core/SkDevice.cpp | 59 ++++++++++++++++--------------------------------- src/core/SkDevice.h | 5 ++--- src/core/SkGlyphRun.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++ src/core/SkGlyphRun.h | 16 ++++++++++---- 5 files changed, 95 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index cb98b09b37..8fc431864d 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -2478,7 +2478,7 @@ void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPat LOOPER_END } -void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], +void SkCanvas::onDrawTextRSXform(const void* text, size_t len, const SkRSXform xform[], const SkRect* cullRect, const SkPaint& paint) { if (cullRect && this->quickReject(*cullRect)) { return; @@ -2487,7 +2487,12 @@ void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRS LOOPER_BEGIN(paint, nullptr) while (iter.next()) { - iter.fDevice->drawTextRSXform(text, byteLength, xform, looper.paint()); + fScratchGlyphRunBuilder->drawTextAtOrigin(paint, text, len); + auto list = fScratchGlyphRunBuilder->useGlyphRunList(); + if (!list->empty()) { + auto glyphRun = (*list)[0]; + iter.fDevice->drawGlyphRunRSXform(&glyphRun, xform); + } } LOOPER_END diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 2296d359da..60f8cd861f 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -476,55 +476,34 @@ void SkBaseDevice::drawTextOnPath(const void* text, size_t byteLength, #include "SkUtils.h" -void SkBaseDevice::drawTextRSXform(const void* text, size_t len, - const SkRSXform xform[], const SkPaint& paint) { - SkPaint::TextEncoding textEncoding = paint.getTextEncoding(); - const char* end = (const char*)text + len; - SkPaint localPaint(paint); - SkShader* shader = paint.getShader(); - SkScalar pos[2] = {0.0f, 0.0f}; - SkPoint origin = SkPoint::Make(0, 0); - - SkMatrix localM, currM; - const void* stopText = (const char*)text + len; - while ((const char*)text < (const char*)stopText) { - localM.setRSXform(*xform++); - currM.setConcat(this->ctm(), localM); - SkAutoDeviceCTMRestore adc(this, currM); +void SkBaseDevice::drawGlyphRunRSXform(SkGlyphRun* run, const SkRSXform* xform) { + const SkMatrix originalCTM = this->ctm(); + sk_sp shader = sk_ref_sp(run->mutablePaint()->getShader()); + auto perGlyph = [this, &xform, &originalCTM, shader] ( + SkGlyphRun* glyphRun, SkPaint* runPaint) { + SkMatrix ctm; + ctm.setRSXform(*xform++); // We want to rotate each glyph by the rsxform, but we don't want to rotate "space" // (i.e. the shader that cares about the ctm) so we have to undo our little ctm trick // with a localmatrixshader so that the shader draws as if there was no change to the ctm. if (shader) { SkMatrix inverse; - if (localM.invert(&inverse)) { - localPaint.setShader(shader->makeWithLocalMatrix(inverse)); + if (ctm.invert(&inverse)) { + runPaint->setShader(shader->makeWithLocalMatrix(inverse)); } else { - localPaint.setShader(nullptr); // can't handle this xform + runPaint->setShader(nullptr); // can't handle this xform } } - int subLen = 0; - switch (textEncoding) { - case SkPaint::kUTF8_TextEncoding: - subLen = SkUTF8_CountUTF8Bytes((const char*)text); - break; - case SkPaint::kUTF16_TextEncoding: - { - const uint16_t* ptr = (const uint16_t*)text; - (void)SkUTF16_NextUnichar(&ptr, (const uint16_t*)end); - subLen = SkToInt((const char*)ptr - (const char*)text); - }; - break; - case SkPaint::kUTF32_TextEncoding: - subLen = 4; - break; - case SkPaint::kGlyphID_TextEncoding: - subLen = 2; - break; - } - this->drawPosText(text, subLen, pos, 2, origin, localPaint); - text = (const char*)text + subLen; - } + + ctm.setConcat(originalCTM, ctm); + this->setCTM(ctm); + SkGlyphRunList glyphRunList{glyphRun}; + this->drawGlyphRunList(&glyphRunList); + }; + run->eachGlyphToGlyphRun(perGlyph); + run->mutablePaint()->setShader(shader); + this->setCTM(originalCTM); } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h index 345b90548b..bd327a65c3 100644 --- a/src/core/SkDevice.h +++ b/src/core/SkDevice.h @@ -16,8 +16,8 @@ class SkBitmap; struct SkDrawShadowRec; +class SkGlyphRun; class SkGlyphRunList; -class SkGlyphRunBuilder; class SkImageFilterCache; struct SkIRect; class SkMatrix; @@ -242,8 +242,7 @@ protected: virtual void drawTextOnPath(const void* text, size_t len, const SkPath&, const SkMatrix*, const SkPaint&); - virtual void drawTextRSXform(const void* text, size_t len, const SkRSXform[], - const SkPaint&); + void drawGlyphRunRSXform(SkGlyphRun* run, const SkRSXform* xform); virtual void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&, SkImage* clipImage, const SkMatrix& clipMatrix); diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp index 3548dfa203..e587dc55c6 100644 --- a/src/core/SkGlyphRun.cpp +++ b/src/core/SkGlyphRun.cpp @@ -51,6 +51,31 @@ SkGlyphRun::SkGlyphRun(SkPaint&& runPaint, , fClusters{clusters} , fRunPaint{std::move(runPaint)} {} + +void SkGlyphRun::eachGlyphToGlyphRun(SkGlyphRun::PerGlyph perGlyph) { + SkPaint paint{fRunPaint}; + SkPoint point; + SkGlyphID glyphID; + SkGlyphRun run{ + std::move(paint), + SkSpan{}, // No dense indices for now. + SkSpan{&point, 1}, + SkSpan{&glyphID, 1}, + SkSpan{}, + SkSpan{}, + SkSpan{} + }; + + auto runSize = fTemporaryShuntGlyphIDs.size(); + auto runPaint = run.mutablePaint(); + for (size_t i = 0; i < runSize; i++) { + glyphID = fTemporaryShuntGlyphIDs[i]; + point = fPositions[i]; + perGlyph(&run, runPaint); + } + +} + void SkGlyphRun::temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin) { auto pos = (const SkScalar*) this->positions().data(); @@ -74,6 +99,7 @@ void SkGlyphRun::filloutGlyphsAndPositions(SkGlyphID* glyphIDs, SkPoint* positio } // -- SkGlyphRunList ------------------------------------------------------------------------------- +SkGlyphRunList::SkGlyphRunList() = default; SkGlyphRunList::SkGlyphRunList( const SkPaint& paint, const SkTextBlob* blob, @@ -84,6 +110,12 @@ SkGlyphRunList::SkGlyphRunList( , fOrigin{origin} , fGlyphRuns{glyphRunList} { } +SkGlyphRunList::SkGlyphRunList(SkGlyphRun* glyphRun) + : fOriginalPaint{nullptr} + , fOriginalTextBlob{nullptr} + , fOrigin{SkPoint::Make(0, 0)} + , fGlyphRuns{SkSpan{glyphRun, 1}} {} + uint64_t SkGlyphRunList::uniqueID() const { return fOriginalTextBlob != nullptr ? fOriginalTextBlob->uniqueID() : SK_InvalidUniqueID; @@ -166,6 +198,29 @@ SkSpan SkGlyphIDSet::uniquifyGlyphIDs( } // -- SkGlyphRunBuilder ---------------------------------------------------------------------------- +void SkGlyphRunBuilder::drawTextAtOrigin( + const SkPaint& paint, const void* bytes, size_t byteLength) { + auto glyphIDs = textToGlyphIDs(paint, bytes, byteLength); + if (!glyphIDs.empty()) { + this->initialize(glyphIDs.size()); + } + + auto positions = SkSpan{fPositions, glyphIDs.size()}; + + // Every glyph is at the origin. + sk_bzero((void *)positions.data(), positions.size_bytes()); + + this->makeGlyphRun( + paint, + glyphIDs, + positions, + SkSpan{}, // no dense indices for now., + SkSpan{}, + SkSpan{}, + SkSpan{}); + this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0)); +} + void SkGlyphRunBuilder::drawText( const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin) { auto glyphIDs = textToGlyphIDs(paint, bytes, byteLength); diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h index 001c3c4548..6de4cdc40f 100644 --- a/src/core/SkGlyphRun.h +++ b/src/core/SkGlyphRun.h @@ -19,6 +19,7 @@ #include "SkTypes.h" class SkBaseDevice; +class SkGlyphRunList; template class SkSpan { @@ -55,6 +56,10 @@ public: SkSpan text, SkSpan clusters); + // A function that turns an SkGlyphRun into an SkGlyphRun for each glyph. + using PerGlyph = std::function; + void eachGlyphToGlyphRun(PerGlyph perGlyph); + // The temporaryShunt calls are to allow inter-operating with existing code while glyph runs // are developed. void temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin); @@ -65,6 +70,7 @@ public: size_t runSize() const { return fTemporaryShuntGlyphIDs.size(); } SkSpan positions() const { return fPositions; } const SkPaint& paint() const { return fRunPaint; } + SkPaint* mutablePaint() { return &fRunPaint; } private: // @@ -80,11 +86,11 @@ private: // Original clusters from SkTextBlob if present. Will be empty if not present. const SkSpan fClusters; // Paint for this run modified to have glyph encoding and left alignment. - const SkPaint fRunPaint; + SkPaint fRunPaint; }; class SkGlyphRunList { - const SkPaint* fOriginalPaint{nullptr}; + const SkPaint* fOriginalPaint{nullptr}; // This should be deleted soon. // 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}; @@ -92,7 +98,7 @@ class SkGlyphRunList { SkSpan fGlyphRuns; public: - SkGlyphRunList() = default; + SkGlyphRunList(); // Blob maybe null. SkGlyphRunList( const SkPaint& paint, @@ -100,6 +106,8 @@ public: SkPoint origin, SkSpan glyphRunList); + SkGlyphRunList(SkGlyphRun* glyphRun); + uint64_t uniqueID() const; bool anyRunsLCD() const; void temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const; @@ -143,6 +151,7 @@ private: class SkGlyphRunBuilder { public: + void drawTextAtOrigin(const SkPaint& paint, const void* bytes, size_t byteLength); void drawText( const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin); void drawPosTextH( @@ -152,7 +161,6 @@ public: 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: -- cgit v1.2.3