From 81ecdbb7ff36afef9091c1b524baafe67381e70d Mon Sep 17 00:00:00 2001 From: Herb Derby Date: Fri, 20 Jul 2018 11:48:38 -0400 Subject: Clean up bitmap path Change-Id: If149194fd86f14bea289ad68262ea99cbbc398b6 Reviewed-on: https://skia-review.googlesource.com/142817 Reviewed-by: Ben Wagner Commit-Queue: Herb Derby --- src/core/SkBitmapDevice.cpp | 5 +- src/core/SkBitmapDevice.h | 1 - src/core/SkDraw.cpp | 134 ++++++++++++++++++++++++++++++++++++++++++++ src/core/SkDraw.h | 12 ++++ src/core/SkGlyphRun.cpp | 50 ++++++++++++----- src/core/SkGlyphRun.h | 26 +++++++-- 6 files changed, 207 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp index cb169dca87..94a4ddcd0d 100644 --- a/src/core/SkBitmapDevice.cpp +++ b/src/core/SkBitmapDevice.cpp @@ -572,7 +572,7 @@ void SkBitmapDevice::drawPosText(const void* text, size_t len, const SkScalar xp } void SkBitmapDevice::drawGlyphRunList(SkGlyphRunList* glyphRunList) { -#ifdef SK_SUPPORT_LEGACY_TEXT_BLOB +#if defined(SK_SUPPORT_LEGACY_TEXT_BLOB) auto blob = glyphRunList->blob(); if (blob == nullptr) { @@ -583,7 +583,8 @@ void SkBitmapDevice::drawGlyphRunList(SkGlyphRunList* glyphRunList) { this->drawTextBlob(blob, origin.x(), origin.y(), paint); } #else - glyphRunList->temporaryShuntToDrawPosText(this, glyphRunList->origin()); + SkBitmapDeviceFilteredSurfaceProps props(fBitmap, glyphRunList->paint(), fSurfaceProps); + LOOP_TILER( drawGlyphRunList(glyphRunList, &props()), nullptr ) #endif } diff --git a/src/core/SkBitmapDevice.h b/src/core/SkBitmapDevice.h index 890f7e1934..379d42ddd1 100644 --- a/src/core/SkBitmapDevice.h +++ b/src/core/SkBitmapDevice.h @@ -112,7 +112,6 @@ protected: */ void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override; - void drawGlyphRunList(SkGlyphRunList* glyphRunList) override; void drawVertices(const SkVertices*, const SkMatrix* bones, int boneCount, SkBlendMode, const SkPaint& paint) override; diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index ae1a873f2b..4c9dddf1f5 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -1598,6 +1598,140 @@ void SkDraw::drawPosText(const char text[], size_t byteLength, const SkScalar po offset, *fMatrix, pos, scalarsPerPosition, cache.get(), drawOneGlyph); } +void SkDraw::drawGlyphRunAsPaths( + SkGlyphRun* glyphRun, SkPoint origin, const SkSurfaceProps* props) const { + // setup our std paint, in hopes of getting hits in the cache + const SkPaint& origPaint = glyphRun->paint(); + SkPaint paint(glyphRun->paint()); + SkScalar matrixScale = paint.setupForAsPaths(); + + SkMatrix matrix; + matrix.setScale(matrixScale, matrixScale); + + // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. + paint.setStyle(SkPaint::kFill_Style); + paint.setPathEffect(nullptr); + + auto cache = SkStrikeCache::FindOrCreateStrikeExclusive( + paint, props, this->scalerContextFlags(), nullptr); + + // Now restore the original settings, so we "draw" with whatever style/stroking. + paint.setStyle(origPaint.getStyle()); + paint.setPathEffect(origPaint.refPathEffect()); + + auto eachGlyph = [this, origin, &cache, &matrix, &paint](SkGlyphID glyphID, SkPoint position) { + const SkGlyph& glyph = cache->getGlyphIDMetrics(glyphID); + if (glyph.fWidth > 0) { + const SkPath* path = cache->findPath(glyph); + if (path != nullptr) { + SkPoint loc = position + origin; + matrix[SkMatrix::kMTransX] = loc.fX; + matrix[SkMatrix::kMTransY] = loc.fY; + this->drawPath(*path, paint, &matrix, false); + } + } + }; + glyphRun->forEachGlyphAndPosition(eachGlyph); +} + +void SkDraw::drawGlyphRunAsSubpixelMask( + SkGlyphCache* cache, SkGlyphRun* glyphRun, SkPoint origin) const { + + SkMatrix matrix = *fMatrix; + // Add rounding and origin. + SkAxisAlignment axisAlignment = cache->getScalerContext()->computeAxisAlignmentForHText(); + SkPoint rounding = SkFindAndPlaceGlyph::SubpixelPositionRounding(axisAlignment); + matrix.preTranslate(origin.x(), origin.y()); + matrix.postTranslate(rounding.x(), rounding.y()); + + glyphRun->mapPositions(matrix); + + auto paint = glyphRun->paint(); + // The Blitter Choose needs to be live while using the blitter below. + SkAutoBlitterChoose blitterChooser(*this, nullptr, paint); + SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); + DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter()); + + auto eachGlyph = [cache, &drawOneGlyph, axisAlignment](SkGlyphID glyphID, SkPoint position) { + auto subpixelAlignment = [](SkAxisAlignment axisAlignment, SkPoint position) -> SkIPoint { + + if (!SkScalarsAreFinite(position.fX, position.fY)) { + return {0, 0}; + } + + // Only the fractional part of position.fX and position.fY matter, because the result of + // this function will just be passed to FixedToSub. + switch (axisAlignment) { + case kX_SkAxisAlignment: + return {SkScalarToFixed(SkScalarFraction(position.fX)), 0}; + case kY_SkAxisAlignment: + return {0, SkScalarToFixed(SkScalarFraction(position.fY))}; + case kNone_SkAxisAlignment: + return {SkScalarToFixed(SkScalarFraction(position.fX)), + SkScalarToFixed(SkScalarFraction(position.fY))}; + } + SK_ABORT("Should not get here."); + return {0, 0}; + }; + + SkIPoint lookupPosition = subpixelAlignment(axisAlignment, position); + const SkGlyph& glyph = cache->getGlyphIDMetrics( + glyphID, lookupPosition.x(), lookupPosition.y()); + if (glyph.fWidth > 0) { + drawOneGlyph(glyph, position, SkPoint::Make(0, 0)); + } + }; + glyphRun->forEachGlyphAndPosition(eachGlyph); +} + +void SkDraw::drawGlyphRunAsFullpixelMask( + SkGlyphCache* cache, SkGlyphRun* glyphRun, SkPoint origin) const { + SkMatrix matrix = *fMatrix; + // Add rounding and origin. + matrix.preTranslate(origin.x(), origin.y()); + matrix.postTranslate(SK_ScalarHalf, SK_ScalarHalf); + glyphRun->mapPositions(matrix); + + auto paint = glyphRun->paint(); + // The Blitter Choose needs to be live while using the blitter below. + SkAutoBlitterChoose blitterChooser(*this, nullptr, paint); + SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); + DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter()); + + auto eachGlyph = [cache, &drawOneGlyph](SkGlyphID glyphID, SkPoint position) { + const SkGlyph& glyph = cache->getGlyphIDMetrics(glyphID); + if (glyph.fWidth > 0) { + drawOneGlyph(glyph, position, SkPoint::Make(0, 0)); + } + }; + glyphRun->forEachGlyphAndPosition(eachGlyph); +} + +void SkDraw::drawGlyphRunList(SkGlyphRunList* glyphRunList, const SkSurfaceProps* props) const { + + SkDEBUGCODE(this->validate();) + + if (fRC->isEmpty()) { + return; + } + + SkPoint origin = glyphRunList->origin(); + for (auto& glyphRun : *glyphRunList) { + if (ShouldDrawTextAsPaths(glyphRun.paint(), *fMatrix)) { + this->drawGlyphRunAsPaths(&glyphRun, origin, props); + } else { + auto cache = SkStrikeCache::FindOrCreateStrikeExclusive( + glyphRun.paint(), props, this->scalerContextFlags(), fMatrix); + if (cache->isSubpixel()) { + this->drawGlyphRunAsSubpixelMask(cache.get(), &glyphRun, origin); + } else { + this->drawGlyphRunAsFullpixelMask(cache.get(), &glyphRun, origin); + } + } + } + +} + #if defined _WIN32 #pragma warning ( pop ) #endif diff --git a/src/core/SkDraw.h b/src/core/SkDraw.h index afd50ea229..deb7451b99 100644 --- a/src/core/SkDraw.h +++ b/src/core/SkDraw.h @@ -22,6 +22,8 @@ class SkBitmap; class SkClipStack; class SkBaseDevice; class SkBlitter; +class SkGlyphRun; +class SkGlyphRunList; class SkMatrix; class SkPath; class SkRegion; @@ -65,6 +67,16 @@ public: void drawPosText(const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkPaint&, const SkSurfaceProps*) const; + + void drawGlyphRunAsPaths( + SkGlyphRun* glyphRun, SkPoint origin, const SkSurfaceProps* props) const; + + void drawGlyphRunAsSubpixelMask( + SkGlyphCache* cache, SkGlyphRun* glyphRun, SkPoint origin) const; + + void drawGlyphRunAsFullpixelMask( + SkGlyphCache* cache, SkGlyphRun* glyphRun, SkPoint origin) const; + void drawGlyphRunList(SkGlyphRunList* glyphRunList, const SkSurfaceProps*) const; void drawVertices(SkVertices::VertexMode mode, int vertexCount, const SkPoint vertices[], const SkPoint textures[], const SkColor colors[], const SkVertices::BoneIndices boneIndices[], diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp index 82dae689f9..cfe63a87b1 100644 --- a/src/core/SkGlyphRun.cpp +++ b/src/core/SkGlyphRun.cpp @@ -16,6 +16,7 @@ #include "SkGlyphCache.h" #include "SkMSAN.h" #include "SkMakeUnique.h" +#include "SkMatrix.h" #include "SkPaint.h" #include "SkPaintPriv.h" #include "SkStrikeCache.h" @@ -38,7 +39,7 @@ static SkTypeface::Encoding convert_encoding(SkPaint::TextEncoding encoding) { // -- SkGlyphRun ----------------------------------------------------------------------------------- SkGlyphRun::SkGlyphRun(SkPaint&& runPaint, SkSpan denseIndices, - SkSpan positions, + SkSpan positions, SkSpan glyphIDs, SkSpan uniqueGlyphIDs, SkSpan text, @@ -59,7 +60,7 @@ void SkGlyphRun::eachGlyphToGlyphRun(SkGlyphRun::PerGlyph perGlyph) { SkGlyphRun run{ std::move(paint), SkSpan{}, // No dense indices for now. - SkSpan{&point, 1}, + SkSpan{&point, 1}, SkSpan{&glyphID, 1}, SkSpan{}, SkSpan{}, @@ -76,6 +77,11 @@ void SkGlyphRun::eachGlyphToGlyphRun(SkGlyphRun::PerGlyph perGlyph) { } +void SkGlyphRun::mapPositions(const SkMatrix& matrix) { + matrix.mapPoints(fPositions.data(), fPositions.data(), (int)fPositions.size()); +} + + void SkGlyphRun::temporaryShuntToDrawPosText(SkBaseDevice* device, SkPoint origin) { auto pos = (const SkScalar*) this->positions().data(); @@ -208,7 +214,7 @@ void SkGlyphRunBuilder::drawTextAtOrigin( this->initialize(glyphIDs.size()); } - auto positions = SkSpan{fPositions, glyphIDs.size()}; + auto positions = SkSpan{fPositions, glyphIDs.size()}; // Every glyph is at the origin. sk_bzero((void *)positions.data(), positions.size_bytes()); @@ -254,7 +260,8 @@ 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, fPositions); } this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0)); @@ -310,7 +317,7 @@ void SkGlyphRunBuilder::drawTextBlob(const SkPaint& paint, const SkTextBlob& blo case SkTextBlob::kFull_Positioning: uniqueGlyphIDsSize = this->simplifyDrawPosText( runPaint, glyphIDs, (const SkPoint*)it.pos(), - currentDenseIndices, currentUniqueGlyphIDs, + currentDenseIndices, currentUniqueGlyphIDs, currentPositions, text, clusters); break; default: @@ -384,7 +391,7 @@ SkSpan SkGlyphRunBuilder::addDenseAndUnique( void SkGlyphRunBuilder::makeGlyphRun( const SkPaint& runPaint, SkSpan glyphIDs, - SkSpan positions, + SkSpan positions, SkSpan uniqueGlyphIDIndices, SkSpan uniqueGlyphIDs, SkSpan text, @@ -454,7 +461,7 @@ size_t SkGlyphRunBuilder::simplifyDrawText( this->makeGlyphRun( paint, glyphIDs, - SkSpan{positions, runSize}, + SkSpan{positions, runSize}, SkSpan{uniqueGlyphIDIndicesBuffer, runSize}, unqiueGlyphIDs, text, @@ -469,21 +476,35 @@ size_t SkGlyphRunBuilder::simplifyDrawPosTextH( const SkScalar* xpos, SkScalar constY, uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer, SkPoint* positions, SkSpan text, SkSpan clusters) { + auto runSize = glyphIDs.size(); auto posCursor = positions; for (auto x : SkSpan{xpos, glyphIDs.size()}) { *posCursor++ = SkPoint::Make(x, constY); } - return this->simplifyDrawPosText( - paint, glyphIDs, positions, - uniqueGlyphIDIndicesBuffer, uniqueGlyphIDsBuffer, - text, clusters); + // The dense indices are not used by the rest of the stack yet. + SkSpan uniqueGlyphIDs; + #ifdef SK_DEBUG + uniqueGlyphIDs = this->addDenseAndUnique( + paint, glyphIDs, uniqueGlyphIDIndicesBuffer, uniqueGlyphIDsBuffer); + #endif + + this->makeGlyphRun( + paint, + glyphIDs, + SkSpan{positions, runSize}, + SkSpan{uniqueGlyphIDIndicesBuffer, runSize}, + uniqueGlyphIDs, + text, + clusters); + + return uniqueGlyphIDs.size(); } size_t SkGlyphRunBuilder::simplifyDrawPosText( const SkPaint& paint, SkSpan glyphIDs, const SkPoint* pos, - uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer, + uint16_t* uniqueGlyphIDIndicesBuffer, SkGlyphID* uniqueGlyphIDsBuffer, SkPoint* positions, SkSpan text, SkSpan clusters) { auto runSize = glyphIDs.size(); @@ -494,12 +515,15 @@ size_t SkGlyphRunBuilder::simplifyDrawPosText( paint, glyphIDs, uniqueGlyphIDIndicesBuffer, uniqueGlyphIDsBuffer); #endif + memcpy(positions, pos, runSize * sizeof(SkPoint)); + + // TODO: when using the unique glyph system have a guard that there are actually glyphs like // drawText above. this->makeGlyphRun( paint, glyphIDs, - SkSpan{pos, runSize}, + SkSpan{positions, runSize}, SkSpan{uniqueGlyphIDIndicesBuffer, runSize}, uniqueGlyphIDs, text, diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h index 0146b1d515..f3b4ff34e3 100644 --- a/src/core/SkGlyphRun.h +++ b/src/core/SkGlyphRun.h @@ -41,6 +41,7 @@ public: size_t size() const { return fSize; } bool empty() const { return fSize == 0; } size_t size_bytes() const { return fSize * sizeof(T); } + SkSpan toConst() const { return SkSpan{fPtr, fSize}; } private: T* fPtr; @@ -52,7 +53,7 @@ public: SkGlyphRun() = default; SkGlyphRun(SkPaint&& runPaint, SkSpan denseIndices, - SkSpan positions, + SkSpan positions, SkSpan glyphIDs, SkSpan uniqueGlyphIDs, SkSpan text, @@ -61,6 +62,13 @@ public: // A function that turns an SkGlyphRun into an SkGlyphRun for each glyph. using PerGlyph = std::function; void eachGlyphToGlyphRun(PerGlyph perGlyph); + void mapPositions(const SkMatrix& matrix); + + // The following made a ~5% speed improvement over not using a template. + //using PerGlyphPos = std::function; + template + void forEachGlyphAndPosition(PerGlyphPos perGlyph) const; + // The temporaryShunt calls are to allow inter-operating with existing code while glyph runs // are developed. @@ -70,7 +78,7 @@ public: void filloutGlyphsAndPositions(SkGlyphID* glyphIDs, SkPoint* positions); size_t runSize() const { return fGlyphIDs.size(); } - SkSpan positions() const { return fPositions; } + SkSpan positions() const { return fPositions.toConst(); } SkSpan shuntGlyphsIDs() const { return fGlyphIDs; } const SkPaint& paint() const { return fRunPaint; } SkPaint* mutablePaint() { return &fRunPaint; } @@ -81,7 +89,7 @@ private: // const SkSpan fUniqueGlyphIDIndices; // - const SkSpan fPositions; + const SkSpan fPositions; // This is temporary while converting from the old per glyph code to the bulk code. const SkSpan fGlyphIDs; // The unique glyphs from fGlyphIDs. @@ -94,6 +102,14 @@ private: SkPaint fRunPaint; }; +template +inline void SkGlyphRun::forEachGlyphAndPosition(PerGlyphPos perGlyph) const { + SkPoint* ptCursor = fPositions.data(); + for (auto glyphID : fGlyphIDs) { + perGlyph(glyphID, *ptCursor++); + } +} + class SkGlyphRunList { 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 @@ -207,7 +223,7 @@ private: void makeGlyphRun( const SkPaint& runPaint, SkSpan glyphIDs, - SkSpan positions, + SkSpan positions, SkSpan uniqueGlyphIDIndices, SkSpan uniqueGlyphIDs, SkSpan text, @@ -228,7 +244,7 @@ private: SkSpan clusters = SkSpan{}); size_t simplifyDrawPosText( const SkPaint& paint, SkSpan glyphIDs, const SkPoint* pos, - uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs, + uint16_t* uniqueGlyphIDIndices, SkGlyphID* uniqueGlyphIDs, SkPoint* positions, SkSpan text = SkSpan{}, SkSpan clusters = SkSpan{}); -- cgit v1.2.3