aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkCanvas.h4
-rw-r--r--src/core/SkCanvas.cpp18
-rw-r--r--src/core/SkDevice.cpp18
-rw-r--r--src/core/SkDevice.h5
-rw-r--r--src/core/SkGlyphRun.cpp239
-rw-r--r--src/core/SkGlyphRun.h124
-rw-r--r--src/gpu/text/GrTextContext.cpp60
-rw-r--r--tests/GlyphRunTest.cpp4
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