diff options
-rw-r--r-- | include/core/SkCanvas.h | 4 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 18 | ||||
-rw-r--r-- | src/core/SkDevice.cpp | 18 | ||||
-rw-r--r-- | src/core/SkDevice.h | 5 | ||||
-rw-r--r-- | src/core/SkGlyphRun.cpp | 239 | ||||
-rw-r--r-- | src/core/SkGlyphRun.h | 124 | ||||
-rw-r--r-- | src/gpu/text/GrTextContext.cpp | 60 | ||||
-rw-r--r-- | tests/GlyphRunTest.cpp | 4 |
8 files changed, 237 insertions, 235 deletions
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index a57d00c0b9..d3b2e5890e 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -36,7 +36,7 @@ class SkDraw; class SkDrawable; class SkDrawFilter; struct SkDrawShadowRec; -class SkGlyphSet; +class SkGlyphRunBuilder; class SkImage; class SkImageFilter; class SkMetaData; @@ -2720,7 +2720,7 @@ private: void validateClip() const {} #endif - std::unique_ptr<SkGlyphSet> fScratchGlyphSet; + std::unique_ptr<SkGlyphRunBuilder> fScratchGlyphRunBuilder; typedef SkRefCnt INHERITED; }; diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 4a6251f110..8494bdb753 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -591,7 +591,7 @@ void SkCanvas::init(sk_sp<SkBaseDevice> device, InitFlags flags) { device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect); } - fScratchGlyphSet = skstd::make_unique<SkGlyphSet>(); + fScratchGlyphRunBuilder = skstd::make_unique<SkGlyphRunBuilder>(); } SkCanvas::SkCanvas() @@ -2449,9 +2449,8 @@ void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkSca LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) while (iter.next()) { - auto glyphRun = SkGlyphRun::MakeFromDrawText( - looper.paint(), text, byteLength, SkPoint::Make(x, y), fScratchGlyphSet.get()); - iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun); + fScratchGlyphRunBuilder->prepareDrawText(paint, text, byteLength, SkPoint::Make(x, y)); + iter.fDevice->drawGlyphRun(looper.paint(), fScratchGlyphRunBuilder.get()); } LOOPER_END @@ -2463,9 +2462,8 @@ void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) while (iter.next()) { - auto glyphRun = SkGlyphRun::MakeFromDrawPosText( - looper.paint(), text, byteLength, pos, fScratchGlyphSet.get()); - iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun); + fScratchGlyphRunBuilder->prepareDrawPosText(paint, text, byteLength, pos); + iter.fDevice->drawGlyphRun(looper.paint(), fScratchGlyphRunBuilder.get()); } LOOPER_END @@ -2477,10 +2475,8 @@ void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScala LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) while (iter.next()) { - auto glyphRun = - SkGlyphRun::MakeFromDrawPosTextH( - looper.paint(), text, byteLength, xpos, constY, fScratchGlyphSet.get()); - iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun); + fScratchGlyphRunBuilder->prepareDrawPosTextH(paint, text, byteLength, xpos, constY); + iter.fDevice->drawGlyphRun(looper.paint(), fScratchGlyphRunBuilder.get()); } LOOPER_END diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 8321718bab..aa9b1e2c34 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -160,14 +160,10 @@ void SkBaseDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: { - SkGlyphSet glyphSet; auto origin = SkPoint::Make(x + offset.x(), y + offset.y()); - auto glyphRun = - SkGlyphRun::MakeFromDrawText( - runPaint, (const char*) it.glyphs(), textLen, origin, &glyphSet); - this->drawPosText( - it.glyphs(), textLen, glyphRun.getPositions(), 2, - SkPoint::Make(0, 0), runPaint); + SkGlyphRunBuilder builder; + builder.prepareDrawText(runPaint, (const char*) it.glyphs(), textLen, origin); + builder.temporaryShuntToDrawPosText(runPaint, this); } break; case SkTextBlob::kHorizontal_Positioning: @@ -253,15 +249,11 @@ void SkBaseDevice::drawImageLattice(const SkImage* image, } } -void SkBaseDevice::drawGlyphRun(const SkPaint& paint, SkGlyphRun* info) { +void SkBaseDevice::drawGlyphRun(const SkPaint& paint, SkGlyphRunBuilder* runBuilder) { SkPaint glyphPaint(paint); glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - auto glyphs = info->copyGlyphIDs(); - - this->drawPosText( - glyphs.get(), info->runSize() * 2, - info->getPositions(), 2, SkPoint::Make(0, 0), glyphPaint); + runBuilder->temporaryShuntToDrawPosText(glyphPaint, this); } void SkBaseDevice::drawBitmapLattice(const SkBitmap& bitmap, diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h index d36dc4d6ab..25008336c6 100644 --- a/src/core/SkDevice.h +++ b/src/core/SkDevice.h @@ -18,6 +18,7 @@ class SkBitmap; class SkDrawFilter; struct SkDrawShadowRec; class SkGlyphRun; +class SkGlyphRunBuilder; class SkImageFilterCache; struct SkIRect; class SkMatrix; @@ -223,7 +224,7 @@ protected: * Does not handle text decoration. * Decorations (underline and stike-thru) will be handled by SkCanvas. */ - virtual void drawGlyphRun(const SkPaint& paint, SkGlyphRun* info); + virtual void drawGlyphRun(const SkPaint& paint, SkGlyphRunBuilder* info); virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) = 0; virtual void drawShadow(const SkPath&, const SkDrawShadowRec&); @@ -346,6 +347,8 @@ private: friend class SkSurface_Raster; friend class DeviceTestingAccess; + // Temporarily friend the SkGlyphRunBuilder until drawPosText is gone. + friend class SkGlyphRunBuilder; virtual void drawPosText(const void* text, size_t len, const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) = 0; diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp index 41f50134e9..ce4c907b5b 100644 --- a/src/core/SkGlyphRun.cpp +++ b/src/core/SkGlyphRun.cpp @@ -10,6 +10,7 @@ #include <algorithm> #include <tuple> +#include "SkDevice.h" #include "SkDraw.h" #include "SkGlyphCache.h" #include "SkMakeUnique.h" @@ -19,8 +20,6 @@ #include "SkStrikeCache.h" #include "SkUtils.h" -namespace { - static SkTypeface::Encoding convert_encoding(SkPaint::TextEncoding encoding) { switch (encoding) { case SkPaint::kUTF8_TextEncoding: return SkTypeface::kUTF8_Encoding; @@ -30,77 +29,68 @@ static SkTypeface::Encoding convert_encoding(SkPaint::TextEncoding encoding) { } } -using Core = std::tuple<size_t, std::unique_ptr<uint16_t[]>, std::vector<SkGlyphID>>; - -Core make_from_glyphids( - size_t glyphCount, const SkGlyphID* glyphs, SkGlyphID maxGlyphID, SkGlyphSet* glyphSet) { - if (glyphCount == 0) { return Core(0, nullptr, std::vector<SkGlyphID>()); } - - glyphSet->reuse(maxGlyphID); +// -- SkGlyphSet ---------------------------------------------------------------------------------- +uint16_t SkGlyphSet::add(SkGlyphID glyphID) { + static constexpr SkGlyphID kUndefGlyph{0}; - auto denseIndex = skstd::make_unique_default<uint16_t[]>(glyphCount); - for (size_t i = 0; i < glyphCount; i++) { - denseIndex[i] = glyphSet->add(glyphs[i]); + if (glyphID >= fUniverseSize) { + glyphID = kUndefGlyph; } - return Core(glyphCount, std::move(denseIndex), glyphSet->uniqueGlyphIDs()); -} - -Core make_from_utfn(size_t byteLength, const void* utfN, const SkTypeface& typeface, - SkTypeface::Encoding encoding, SkGlyphSet* glyphSet) { - auto count = SkUTFN_CountUnichars(encoding, utfN, byteLength); - - if (count <= 0) { - return Core(0, nullptr, std::vector<SkGlyphID>()); + if (glyphID >= fIndices.size()) { + fIndices.resize(glyphID + 1); } - auto glyphs = skstd::make_unique_default<SkGlyphID[]>(count); - - // TODO: move to using cached version. - typeface.charsToGlyphs(utfN, encoding, glyphs.get(), count); + auto index = fIndices[glyphID]; + if (index < fUniqueGlyphIDs->size() && (*fUniqueGlyphIDs)[index] == glyphID) { + return index; + } - return make_from_glyphids(count, glyphs.get(), typeface.countGlyphs(), glyphSet); + uint16_t newIndex = SkTo<uint16_t>(fUniqueGlyphIDs->size()); + fUniqueGlyphIDs->push_back(glyphID); + fIndices[glyphID] = newIndex; + return newIndex; } -Core make_core(const SkPaint& paint, const void* bytes, size_t byteLength, SkGlyphSet* glyphSet) { - auto encoding = paint.getTextEncoding(); - auto typeface = SkPaintPriv::GetTypefaceOrDefault(paint); - if (encoding == SkPaint::kGlyphID_TextEncoding) { - return make_from_glyphids( - byteLength / 2, reinterpret_cast<const SkGlyphID*>(bytes), - typeface->countGlyphs(), glyphSet); - } else { - return make_from_utfn(byteLength, bytes, *typeface, convert_encoding(encoding), glyphSet); +void SkGlyphSet::reuse(uint32_t glyphUniverseSize, std::vector<SkGlyphID>* uniqueGlyphIDs) { + SkASSERT(glyphUniverseSize <= (1 << 16)); + fUniverseSize = glyphUniverseSize; + fUniqueGlyphIDs = uniqueGlyphIDs; + // If we're hanging onto these arrays for a long time, we don't want their size to drift + // endlessly upwards. It's unusual to see more than 256 unique glyphs used in a run, + // or a typeface with more than 4096 possible glyphs. + if (fUniqueGlyphIDs->size() > 256) { + fUniqueGlyphIDs->resize(256); + fUniqueGlyphIDs->shrink_to_fit(); } -} + fUniqueGlyphIDs->clear(); -} // namespace + if (glyphUniverseSize < 4096 && fIndices.size() > 4096) { + fIndices.resize(4096); + fIndices.shrink_to_fit(); + } -SkGlyphRun SkGlyphRun::MakeFromDrawText( - const SkPaint& paint, const void* bytes, size_t byteLength, - const SkPoint origin, SkGlyphSet* glyphSet) { - size_t runSize; - std::unique_ptr<uint16_t[]> denseIndex; - std::vector<SkGlyphID> uniqueGlyphIDs; - std::tie(runSize, denseIndex, uniqueGlyphIDs) = make_core(paint, bytes, byteLength, glyphSet); + // No need to clear fIndices here... SkGlyphSet's set insertion algorithm is designed to work + // correctly even when the fIndexes buffer is uninitialized! +} - if (runSize == 0) { return SkGlyphRun{}; } +// -- SkGlyphRunBuilder ---------------------------------------------------------------------------- +void SkGlyphRunBuilder::prepareDrawText( + const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin) { - auto advances = skstd::make_unique_default<SkPoint[]>(uniqueGlyphIDs.size()); + this->initializeDenseAndUnique(paint, bytes, byteLength); + fScratchAdvances.resize(this->uniqueSize()); { auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(paint); - cache->getAdvances(SkSpan<SkGlyphID>{uniqueGlyphIDs.data(), - uniqueGlyphIDs.size()}, advances.get()); + cache->getAdvances(SkSpan<SkGlyphID>{fUniqueGlyphs}, fScratchAdvances.data()); } - auto positions = skstd::make_unique_default<SkPoint[]>(runSize); - SkPoint endOfLastGlyph = origin; - for (size_t i = 0; i < runSize; i++) { - positions[i] = endOfLastGlyph; - endOfLastGlyph += advances[denseIndex[i]]; + for (size_t i = 0; i < this->runSize(); i++) { + fPositions.push_back(endOfLastGlyph); + endOfLastGlyph += fScratchAdvances[fDenseIndex[i]]; } if (paint.getTextAlign() != SkPaint::kLeft_Align) { @@ -108,115 +98,88 @@ SkGlyphRun SkGlyphRun::MakeFromDrawText( if (paint.getTextAlign() == SkPaint::kCenter_Align) { len.scale(SK_ScalarHalf); } - for (size_t i = 0; i < runSize; i++) { - positions[i] -= len; + for (size_t i = 0; i < this->runSize(); i++) { + fPositions[i] -= len; } } - return SkGlyphRun{ - runSize, std::move(denseIndex), std::move(positions), std::move(uniqueGlyphIDs)}; } -SkGlyphRun SkGlyphRun::MakeFromDrawPosTextH( - const SkPaint& paint, const void* bytes, size_t byteLength, - const SkScalar xpos[], SkScalar constY, SkGlyphSet* glyphSet) { - size_t runSize; - std::unique_ptr<uint16_t[]> denseIndex; - std::vector<SkGlyphID> uniqueGlyphIDs; - std::tie(runSize, denseIndex, uniqueGlyphIDs) = make_core(paint, bytes, byteLength, glyphSet); - - if (runSize == 0) { return SkGlyphRun{}; } +void SkGlyphRunBuilder::prepareDrawPosTextH(const SkPaint& paint, const void* bytes, + size_t byteLength, const SkScalar* xpos, + SkScalar constY) { - auto positions = skstd::make_unique_default<SkPoint[]>(runSize); + this->initializeDenseAndUnique(paint, bytes, byteLength); - for (size_t i = 0; i < runSize; i++) { - positions[i] = SkPoint::Make(xpos[i], constY); + for (size_t i = 0; i < runSize(); i++) { + fPositions.push_back(SkPoint::Make(xpos[i], constY)); } - - return SkGlyphRun{ - runSize, std::move(denseIndex), std::move(positions), std::move(uniqueGlyphIDs)}; } -SkGlyphRun SkGlyphRun::MakeFromDrawPosText( - const SkPaint& paint, const void* bytes, size_t byteLength, - const SkPoint pos[], SkGlyphSet* glyphSet) { - size_t runSize; - std::unique_ptr<uint16_t[]> denseIndex; - std::vector<SkGlyphID> uniqueGlyphIDs; - std::tie(runSize, denseIndex, uniqueGlyphIDs) = make_core(paint, bytes, byteLength, glyphSet); +void SkGlyphRunBuilder::prepareDrawPosText(const SkPaint& paint, const void* bytes, + size_t byteLength, const SkPoint* pos) { + this->initializeDenseAndUnique(paint, bytes, byteLength); - if (runSize == 0) { return SkGlyphRun{}; } - - auto positions = skstd::make_unique_default<SkPoint[]>(runSize); - - memcpy(positions.get(), pos, sizeof(SkPoint) * runSize); + for (size_t i = 0; i < runSize(); i++) { + fPositions.push_back(pos[i]); + } +} - return SkGlyphRun{ - runSize, std::move(denseIndex), std::move(positions), std::move(uniqueGlyphIDs)}; +const SkGlyphRun& SkGlyphRunBuilder::useGlyphRun() const { + new ((void*)&fScratchGlyphRun) SkGlyphRun{SkSpan<uint16_t>(fDenseIndex), + SkSpan<SkPoint>(fPositions), + SkSpan<SkGlyphID>(fUniqueGlyphs)}; + return fScratchGlyphRun; } -std::unique_ptr<SkGlyphID[]> SkGlyphRun::copyGlyphIDs() const { - auto glyphs = skstd::make_unique_default<SkGlyphID[]>(fRunSize); +void SkGlyphRunBuilder::temporaryShuntToDrawPosText(const SkPaint& paint, SkBaseDevice* device) { - for (size_t i = 0; i < fRunSize; i++) { - glyphs[i] = fUniqueGlyphs[fDenseIndex[i]]; - } + auto pos = (const SkScalar*) fPositions.data(); - return glyphs; + device->drawPosText( + fTemporaryShuntGlyphIDs, fDenseIndex.size() * 2, + pos, 2, SkPoint::Make(0, 0), paint); } -SkGlyphRun::SkGlyphRun(size_t runSize, - std::unique_ptr<uint16_t[]>&& denseIndex, - std::unique_ptr<SkPoint[]>&& positions, - std::vector<SkGlyphID>&& uniqueGlyphIDs) - : fDenseIndex{std::move(denseIndex)} - , fPositions{std::move(positions)} - , fUniqueGlyphs{std::move(uniqueGlyphIDs)} - , fRunSize{runSize} { } - -uint16_t SkGlyphSet::add(SkGlyphID glyphID) { - static constexpr SkGlyphID kUndefGlyph{0}; +void SkGlyphRunBuilder::temporaryShuntToCallback(TemporaryShuntCallback callback) { + auto bytes = (const char *)fTemporaryShuntGlyphIDs; + auto pos = (const SkScalar*)fPositions.data(); + callback(this->runSize(), bytes, pos); +} - if (glyphID >= fUniverseSize) { - glyphID = kUndefGlyph; - } +void SkGlyphRunBuilder::initializeDenseAndUnique( + const SkPaint& paint, const void* bytes, size_t byteLength) { - if (glyphID >= fIndices.size()) { - fIndices.resize(glyphID + 1); - } + fDenseIndex.clear(); + fPositions.clear(); + fUniqueGlyphs.clear(); + fTemporaryShuntGlyphIDs = nullptr; - auto index = fIndices[glyphID]; - if (index < fUniqueGlyphIDs.size() && fUniqueGlyphIDs[index] == glyphID) { - return index; + size_t runSize = 0; + const SkGlyphID* glyphIDs = nullptr; + auto encoding = paint.getTextEncoding(); + auto typeface = SkPaintPriv::GetTypefaceOrDefault(paint); + if (encoding != SkPaint::kGlyphID_TextEncoding) { + auto tfEncoding = convert_encoding(encoding); + int utfSize = SkUTFN_CountUnichars(tfEncoding, bytes, byteLength); + if (utfSize > 0) { + runSize = SkTo<size_t>(utfSize); + fScratchGlyphIDs.resize(runSize); + typeface->charsToGlyphs(bytes, tfEncoding, fScratchGlyphIDs.data(), runSize); + glyphIDs = fScratchGlyphIDs.data(); + } + } else { + runSize = byteLength / 2; + glyphIDs = (const SkGlyphID*)bytes; } - uint16_t newIndex = SkTo<uint16_t>(fUniqueGlyphIDs.size()); - fUniqueGlyphIDs.push_back(glyphID); - fIndices[glyphID] = newIndex; - return newIndex; -} - -std::vector<SkGlyphID> SkGlyphSet::uniqueGlyphIDs() { - return fUniqueGlyphIDs; -} + if (runSize == 0) { return; } + fTemporaryShuntGlyphIDs = glyphIDs; -void SkGlyphSet::reuse(uint32_t glyphUniverseSize) { - SkASSERT(glyphUniverseSize <= (1 << 16)); - fUniverseSize = glyphUniverseSize; - // If we're hanging onto these arrays for a long time, we don't want their size to drift - // endlessly upwards. It's unusual to see more than 256 unique glyphs used in a run, - // or a typeface with more than 4096 possible glyphs. - if (fUniqueGlyphIDs.size() > 256) { - fUniqueGlyphIDs.resize(256); - fUniqueGlyphIDs.shrink_to_fit(); + fGlyphSet.reuse(typeface->countGlyphs(), &fUniqueGlyphs); + for (size_t i = 0; i < runSize; i++) { + fDenseIndex.push_back(fGlyphSet.add(glyphIDs[i])); } - fUniqueGlyphIDs.clear(); +} - if (glyphUniverseSize < 4096 && fIndices.size() > 4096) { - fIndices.resize(4096); - fIndices.shrink_to_fit(); - } - // No need to clear fIndices here... SkGlyphSet's set insertion algorithm is designed to work - // correctly even when the fIndexes buffer is uninitialized! -}
\ No newline at end of file diff --git a/src/core/SkGlyphRun.h b/src/core/SkGlyphRun.h index 53d57af8c4..eeb9c2924e 100644 --- a/src/core/SkGlyphRun.h +++ b/src/core/SkGlyphRun.h @@ -8,6 +8,7 @@ #ifndef SkGlyphRunInfo_DEFINED #define SkGlyphRunInfo_DEFINED +#include <functional> #include <memory> #include <vector> @@ -17,6 +18,43 @@ #include "SkPoint.h" #include "SkTypes.h" +class SkBaseDevice; + +template <typename T> +class SkSpan { +public: + SkSpan() = default; + SkSpan(const T* ptr, size_t size) : fPtr{ptr}, fSize{size} {} + explicit SkSpan(const std::vector<T>& v) : fPtr{v.data()}, fSize{v.size()} {} + const T& operator [] (ptrdiff_t i) const { return fPtr[i]; } + const T* begin() const { return fPtr; } + const T* end() const { return fPtr + fSize; } + ptrdiff_t size() const { return fSize; } + +private: + const T* fPtr; + size_t fSize; +}; + +class SkGlyphRun { +public: + SkGlyphRun() = default; + SkGlyphRun(SkSpan<uint16_t> denseIndex, SkSpan<SkPoint> positions, + SkSpan<SkGlyphID> uniqueGlyphIDs) + : fDenseIndex{denseIndex} + , fPositions{positions} + , fUniqueGlyphIDs{uniqueGlyphIDs} {} + + size_t runSize() const { return fDenseIndex.size(); } + uint16_t uniqueSize() const { return fUniqueGlyphIDs.size(); } + SkSpan<SkPoint> positions() const { return SkSpan<SkPoint>(fPositions); } + +private: + SkSpan<uint16_t> fDenseIndex; + SkSpan<SkPoint> fPositions; + SkSpan<SkGlyphID> fUniqueGlyphIDs; +}; + // 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. // This implementation is based on the paper by Briggs and Torczon, "An Efficient Representation @@ -25,63 +63,63 @@ class SkGlyphSet { public: SkGlyphSet() = default; uint16_t add(SkGlyphID glyphID); - std::vector<SkGlyphID> uniqueGlyphIDs(); - void reuse(uint32_t glyphUniverseSize); + void reuse(uint32_t glyphUniverseSize, std::vector<SkGlyphID>* uniqueGlyphIDs); private: uint32_t fUniverseSize{0}; std::vector<uint16_t> fIndices; - std::vector<SkGlyphID> fUniqueGlyphIDs; + std::vector<SkGlyphID>* fUniqueGlyphIDs{nullptr}; }; -class SkGlyphRun { +// Currently the old code is passing around SkGlyphRunBuilder because it facilitates working in the +// old single glyph lookup style with the cache. When the lower level code is transitioned over to +// the bulk glyph cache style, then the builder will only be used in the canvas, and only runs will +// be passed around. +class SkGlyphRunBuilder { public: - SkGlyphRun() = default; - SkGlyphRun(SkGlyphRun&&) = default; - static SkGlyphRun MakeFromDrawText( + SkGlyphRunBuilder() = default; + void prepareDrawText( + const SkPaint& paint, const void* bytes, size_t byteLength, SkPoint origin); + void prepareDrawPosTextH( const SkPaint& paint, const void* bytes, size_t byteLength, - SkPoint origin, SkGlyphSet* glyphSet); - static SkGlyphRun MakeFromDrawPosTextH( - const SkPaint& paint, const void* bytes, size_t byteLength, - const SkScalar xpos[], SkScalar constY, SkGlyphSet* glyphSet); - static SkGlyphRun MakeFromDrawPosText( - const SkPaint& paint, const void* bytes, size_t byteLength, - const SkPoint pos[], SkGlyphSet* glyphSet); + const SkScalar xpos[], SkScalar constY); + void prepareDrawPosText( + const SkPaint& paint, const void* bytes, size_t byteLength, const SkPoint pos[]); + + size_t runSize() const {return fDenseIndex.size();} + size_t uniqueSize() const {return fUniqueGlyphs.size();} - size_t runSize() const { return fRunSize; } - uint16_t uniqueSize() const { return fUniqueGlyphs.size(); } + const SkGlyphRun& useGlyphRun() const; - // copyGlyphIDs is temporary glue to work with the existing system. Don't use with new code. - std::unique_ptr<SkGlyphID[]> copyGlyphIDs() const; - const SkScalar* getPositions() const { - return reinterpret_cast<const SkScalar*>(fPositions.get()); - } + // The temporaryShunt calls are to allow inter-operating with existing code while glyph runs + // are developed. + void temporaryShuntToDrawPosText(const SkPaint& paint, SkBaseDevice* device); + using TemporaryShuntCallback = std::function<void(size_t, const char*, const SkScalar*)>; + void temporaryShuntToCallback(TemporaryShuntCallback callback); private: - SkGlyphRun(size_t runSize, - std::unique_ptr<uint16_t[]>&& denseIndex, - std::unique_ptr<SkPoint[]>&& positions, - std::vector<SkGlyphID>&& uniqueGlyphIDs); - - std::unique_ptr<uint16_t[]> fDenseIndex; - std::unique_ptr<SkPoint[]> fPositions; - std::vector<SkGlyphID> fUniqueGlyphs; - const size_t fRunSize{0}; -}; + void initializeDenseAndUnique(const SkPaint& paint, const void* bytes, size_t byteLength); -template <typename T> -class SkSpan { -public: - SkSpan(const T* ptr, size_t size) : fPtr{ptr}, fSize{size} {} - SkSpan(const std::vector<T>& v) : fPtr{v.data()}, fSize{v.size()} {} - const T& operator [] (ptrdiff_t i) const { return fPtr[i]; } - const T* begin() const { return fPtr; } - const T* end() const { return fPtr + fSize; } - ptrdiff_t size() const { return fSize; } + std::vector<uint16_t> fDenseIndex; + std::vector<SkPoint> fPositions; + std::vector<SkGlyphID> fUniqueGlyphs; -private: - const T* fPtr; - size_t fSize; + // Used as a temporary for preparing using utfN text. + std::vector<SkGlyphID> fScratchGlyphIDs; + + // Used as temporary storage for calculating positions for drawText. + std::vector<SkPoint> fScratchAdvances; + + // Used to temporarily use of a glyph run for bulk cache API calls (just an experiment at + // this point). + SkGlyphRun fScratchGlyphRun; + + // Used as an aid to shunt from glyph runs to drawPosText. It will either be fScratchIDs or + // the bytes passed in. + const SkGlyphID* fTemporaryShuntGlyphIDs{nullptr}; + + // Used for collecting the set of unique glyphs. + SkGlyphSet fGlyphSet; }; #endif // SkGlyphRunInfo_DEFINED diff --git a/src/gpu/text/GrTextContext.cpp b/src/gpu/text/GrTextContext.cpp index 9864d027de..b8fe456b79 100644 --- a/src/gpu/text/GrTextContext.cpp +++ b/src/gpu/text/GrTextContext.cpp @@ -210,15 +210,18 @@ void GrTextContext::regenerateTextBlob(GrTextBlob* cacheBlob, shaderCaps.supportsDistanceFieldText(), fOptions)) { switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: { - SkGlyphSet glyphSet; auto origin = SkPoint::Make(x + offset.x(), y + offset.y()); - auto glyphRun = - SkGlyphRun::MakeFromDrawText(runPaint.skPaint(), - (const char*)it.glyphs(), textLen, origin, &glyphSet); - - this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint, - scalerContextFlags, viewMatrix, (const char*)it.glyphs(), - textLen, glyphRun.getPositions(), 2, SkPoint::Make(0,0)); + SkGlyphRunBuilder builder; + builder.prepareDrawText(runPaint.skPaint(), + (const char*)it.glyphs(), textLen, origin); + + builder.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)); + }); break; } @@ -240,16 +243,18 @@ void GrTextContext::regenerateTextBlob(GrTextBlob* cacheBlob, } else { switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: { - SkGlyphSet glyphSet; auto origin = SkPoint::Make(x + offset.x(), y + offset.y()); - auto glyphRun = - SkGlyphRun::MakeFromDrawText( - runPaint.skPaint(), (const char*) it.glyphs(), textLen, origin, - &glyphSet); - - this->DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint, - scalerContextFlags, viewMatrix, (const char*) it.glyphs(), - textLen, glyphRun.getPositions(), 2, SkPoint::Make(0, 0)); + SkGlyphRunBuilder builder; + builder.prepareDrawText(runPaint.skPaint(), + (const char*)it.glyphs(), textLen, origin); + + builder.temporaryShuntToCallback( + [&](size_t runSize, const char* glyphIDs, const SkScalar* pos) { + this->DrawBmpPosText( + cacheBlob, run, glyphCache, props, runPaint, scalerContextFlags, + viewMatrix, glyphIDs, 2 * runSize, + pos, 2, SkPoint::Make(0, 0)); + }); break; } case SkTextBlob::kHorizontal_Positioning: @@ -768,15 +773,20 @@ std::unique_ptr<GrDrawOp> GrTextContext::createOp_TestingOnly(GrContext* context // right now we don't handle textblobs, nor do we handle drawPosText. Since we only intend to // test the text op with this unit test, that is okay. - SkGlyphSet glyphSet; auto origin = SkPoint::Make(x, y); - auto glyphRun = SkGlyphRun::MakeFromDrawText(skPaint, text, textLen, origin, &glyphSet); - - sk_sp<GrTextBlob> blob(textContext->makeDrawPosTextBlob( - context->contextPriv().getTextBlobCache(), glyphCache, - *context->contextPriv().caps()->shaderCaps(), utilsPaint, - GrTextContext::kTextBlobOpScalerContextFlags, viewMatrix, surfaceProps, text, - static_cast<size_t>(textLen), glyphRun.getPositions(), 2, origin)); + SkGlyphRunBuilder builder; + builder.prepareDrawText(skPaint, text, textLen, origin); + sk_sp<GrTextBlob> blob; + + // Use the text and textLen below, because we don't want to mess with the paint. + builder.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, + 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 7a80b7be93..3b25625a7a 100644 --- a/tests/GlyphRunTest.cpp +++ b/tests/GlyphRunTest.cpp @@ -16,7 +16,7 @@ DEF_TEST(GlyphRunInfo, reporter) { SkPaint paint; paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - SkGlyphSet glyphSet; + SkGlyphRunBuilder builder; + builder.prepareDrawText(paint, glyphs, count, SkPoint::Make(0, 0)); - SkGlyphRun::MakeFromDrawText(paint, glyphs, count, SkPoint::Make(0, 0), &glyphSet); }
\ No newline at end of file |