Smarter use of glyph cache
Change-Id: Ic9bea7310b375575503042881d9d54ff13996729 Reviewed-on: https://skia-review.googlesource.com/131924 Reviewed-by: Mike Klein <mtklein@chromium.org>
This commit is contained in:
parent
975f8eeb44
commit
4ffa027cf6
@ -26,6 +26,7 @@ class SkDraw;
|
|||||||
class SkDrawable;
|
class SkDrawable;
|
||||||
class SkDrawFilter;
|
class SkDrawFilter;
|
||||||
struct SkDrawShadowRec;
|
struct SkDrawShadowRec;
|
||||||
|
class SkGlyphSet;
|
||||||
class SkImage;
|
class SkImage;
|
||||||
class SkImageFilter;
|
class SkImageFilter;
|
||||||
class SkMetaData;
|
class SkMetaData;
|
||||||
@ -2709,6 +2710,8 @@ private:
|
|||||||
void validateClip() const {}
|
void validateClip() const {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
std::unique_ptr<SkGlyphSet> fScratchGlyphSet;
|
||||||
|
|
||||||
typedef SkRefCnt INHERITED;
|
typedef SkRefCnt INHERITED;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -590,6 +590,8 @@ void SkCanvas::init(sk_sp<SkBaseDevice> device, InitFlags flags) {
|
|||||||
|
|
||||||
device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
|
device->androidFramework_setDeviceClipRestriction(&fClipRestrictionRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fScratchGlyphSet = skstd::make_unique<SkGlyphSet>();
|
||||||
}
|
}
|
||||||
|
|
||||||
SkCanvas::SkCanvas()
|
SkCanvas::SkCanvas()
|
||||||
@ -2448,7 +2450,7 @@ void SkCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkSca
|
|||||||
|
|
||||||
while (iter.next()) {
|
while (iter.next()) {
|
||||||
auto glyphRun = SkGlyphRun::MakeFromDrawText(
|
auto glyphRun = SkGlyphRun::MakeFromDrawText(
|
||||||
looper.paint(), text, byteLength, SkPoint::Make(x, y));
|
looper.paint(), text, byteLength, SkPoint::Make(x, y), fScratchGlyphSet.get());
|
||||||
iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
|
iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2461,7 +2463,8 @@ void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint
|
|||||||
LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
|
LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr)
|
||||||
|
|
||||||
while (iter.next()) {
|
while (iter.next()) {
|
||||||
auto glyphRun = SkGlyphRun::MakeFromDrawPosText(looper.paint(), text, byteLength, pos);
|
auto glyphRun = SkGlyphRun::MakeFromDrawPosText(
|
||||||
|
looper.paint(), text, byteLength, pos, fScratchGlyphSet.get());
|
||||||
iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
|
iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2475,7 +2478,8 @@ void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScala
|
|||||||
|
|
||||||
while (iter.next()) {
|
while (iter.next()) {
|
||||||
auto glyphRun =
|
auto glyphRun =
|
||||||
SkGlyphRun::MakeFromDrawPosTextH(looper.paint(), text, byteLength, xpos, constY);
|
SkGlyphRun::MakeFromDrawPosTextH(
|
||||||
|
looper.paint(), text, byteLength, xpos, constY, fScratchGlyphSet.get());
|
||||||
iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
|
iter.fDevice->drawGlyphRun(looper.paint(), &glyphRun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,10 +160,11 @@ void SkBaseDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
|
|||||||
|
|
||||||
switch (it.positioning()) {
|
switch (it.positioning()) {
|
||||||
case SkTextBlob::kDefault_Positioning: {
|
case SkTextBlob::kDefault_Positioning: {
|
||||||
|
SkGlyphSet glyphSet;
|
||||||
auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
|
auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
|
||||||
auto glyphRun =
|
auto glyphRun =
|
||||||
SkGlyphRun::MakeFromDrawText(runPaint,
|
SkGlyphRun::MakeFromDrawText(
|
||||||
(const char*) it.glyphs(), textLen, origin);
|
runPaint, (const char*) it.glyphs(), textLen, origin, &glyphSet);
|
||||||
this->drawPosText(
|
this->drawPosText(
|
||||||
it.glyphs(), textLen, glyphRun.getPositions(), 2,
|
it.glyphs(), textLen, glyphRun.getPositions(), 2,
|
||||||
SkPoint::Make(0, 0), runPaint);
|
SkPoint::Make(0, 0), runPaint);
|
||||||
|
@ -21,61 +21,7 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// A faster set implementation that does not need any initialization, and reading the set items
|
static SkTypeface::Encoding convert_encoding(SkPaint::TextEncoding encoding) {
|
||||||
// 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
|
|
||||||
// for Sparse Sets"
|
|
||||||
class GlyphSet {
|
|
||||||
public:
|
|
||||||
GlyphSet(uint32_t glyphUniverseSize)
|
|
||||||
: fUniverseSize{glyphUniverseSize}
|
|
||||||
, fIndexes{skstd::make_unique_default<uint16_t[]>(2 * glyphUniverseSize)}
|
|
||||||
, fUniqueGlyphIDs{&fIndexes[glyphUniverseSize]} {
|
|
||||||
SkASSERT(glyphUniverseSize <= (1 << 16));
|
|
||||||
sk_msan_mark_initialized(fIndexes.get(), &fIndexes[glyphUniverseSize], "works with uninited");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t add(SkGlyphID glyphID) {
|
|
||||||
if (glyphID >= fUniverseSize) {
|
|
||||||
glyphID = kUndefGlyph;
|
|
||||||
}
|
|
||||||
auto index = fIndexes[glyphID];
|
|
||||||
if (index < fUniqueCount && fUniqueGlyphIDs[index] == glyphID) {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
fUniqueGlyphIDs[fUniqueCount] = glyphID;
|
|
||||||
fIndexes[glyphID] = fUniqueCount;
|
|
||||||
fUniqueCount += 1;
|
|
||||||
return fUniqueCount - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<uint16_t, std::unique_ptr<SkGlyphID[]>> uniqueGlyphIDs() const {
|
|
||||||
auto uniqueGlyphs = skstd::make_unique_default<SkGlyphID[]>(fUniqueCount);
|
|
||||||
memcpy(uniqueGlyphs.get(), fUniqueGlyphIDs, fUniqueCount * sizeof(SkGlyphID));
|
|
||||||
return std::make_tuple(fUniqueCount, std::move(uniqueGlyphs));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr SkGlyphID kUndefGlyph{0};
|
|
||||||
const uint32_t fUniverseSize;
|
|
||||||
uint16_t fUniqueCount{0};
|
|
||||||
std::unique_ptr<uint16_t[]> fIndexes;
|
|
||||||
SkGlyphID* fUniqueGlyphIDs;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool is_aligned(const void* ptr) {
|
|
||||||
uintptr_t bits = reinterpret_cast<uintptr_t>(ptr);
|
|
||||||
return (bits & (alignof(T) - 1)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool is_aligned_size(size_t size) {
|
|
||||||
return size % sizeof(T) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SkTypeface::Encoding convert_encoding(SkPaint::TextEncoding encoding) {
|
|
||||||
switch (encoding) {
|
switch (encoding) {
|
||||||
case SkPaint::kUTF8_TextEncoding: return SkTypeface::kUTF8_Encoding;
|
case SkPaint::kUTF8_TextEncoding: return SkTypeface::kUTF8_Encoding;
|
||||||
case SkPaint::kUTF16_TextEncoding: return SkTypeface::kUTF16_Encoding;
|
case SkPaint::kUTF16_TextEncoding: return SkTypeface::kUTF16_Encoding;
|
||||||
@ -84,32 +30,28 @@ SkTypeface::Encoding convert_encoding(SkPaint::TextEncoding encoding) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using Core = std::tuple<size_t, std::unique_ptr<uint16_t[]>,
|
using Core = std::tuple<size_t, std::unique_ptr<uint16_t[]>, std::vector<SkGlyphID>>;
|
||||||
uint16_t, std::unique_ptr<SkGlyphID[]>>;
|
|
||||||
|
|
||||||
Core make_from_glyphids(size_t glyphCount, const SkGlyphID* glyphs, SkGlyphID maxGlyphID) {
|
Core make_from_glyphids(
|
||||||
if (glyphCount == 0) { return Core(0, nullptr, 0, nullptr); }
|
size_t glyphCount, const SkGlyphID* glyphs, SkGlyphID maxGlyphID, SkGlyphSet* glyphSet) {
|
||||||
|
if (glyphCount == 0) { return Core(0, nullptr, std::vector<SkGlyphID>()); }
|
||||||
|
|
||||||
GlyphSet glyphSet{maxGlyphID};
|
glyphSet->reuse(maxGlyphID);
|
||||||
|
|
||||||
auto denseIndex = skstd::make_unique_default<uint16_t[]>(glyphCount);
|
auto denseIndex = skstd::make_unique_default<uint16_t[]>(glyphCount);
|
||||||
for (size_t i = 0; i < glyphCount; i++) {
|
for (size_t i = 0; i < glyphCount; i++) {
|
||||||
denseIndex[i] = glyphSet.add(glyphs[i]);
|
denseIndex[i] = glyphSet->add(glyphs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SkGlyphID[]> uniqueGlyphIDs;
|
return Core(glyphCount, std::move(denseIndex), glyphSet->uniqueGlyphIDs());
|
||||||
uint16_t uniqueCount;
|
|
||||||
std::tie(uniqueCount, uniqueGlyphIDs) = glyphSet.uniqueGlyphIDs();
|
|
||||||
|
|
||||||
return Core(glyphCount, std::move(denseIndex), uniqueCount, std::move(uniqueGlyphIDs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Core make_from_utfn(size_t byteLength, const void* utfN, const SkTypeface& typeface,
|
Core make_from_utfn(size_t byteLength, const void* utfN, const SkTypeface& typeface,
|
||||||
SkTypeface::Encoding encoding) {
|
SkTypeface::Encoding encoding, SkGlyphSet* glyphSet) {
|
||||||
auto count = SkUTFN_CountUnichars(encoding, utfN, byteLength);
|
auto count = SkUTFN_CountUnichars(encoding, utfN, byteLength);
|
||||||
|
|
||||||
if (count <= 0) {
|
if (count <= 0) {
|
||||||
return Core(0, nullptr, 0, nullptr);
|
return Core(0, nullptr, std::vector<SkGlyphID>());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto glyphs = skstd::make_unique_default<SkGlyphID[]>(count);
|
auto glyphs = skstd::make_unique_default<SkGlyphID[]>(count);
|
||||||
@ -117,17 +59,18 @@ Core make_from_utfn(size_t byteLength, const void* utfN, const SkTypeface& typef
|
|||||||
// TODO: move to using cached version.
|
// TODO: move to using cached version.
|
||||||
typeface.charsToGlyphs(utfN, encoding, glyphs.get(), count);
|
typeface.charsToGlyphs(utfN, encoding, glyphs.get(), count);
|
||||||
|
|
||||||
return make_from_glyphids(count, glyphs.get(), typeface.countGlyphs());
|
return make_from_glyphids(count, glyphs.get(), typeface.countGlyphs(), glyphSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
Core make_core(const SkPaint& paint, const void* bytes, size_t byteLength) {
|
Core make_core(const SkPaint& paint, const void* bytes, size_t byteLength, SkGlyphSet* glyphSet) {
|
||||||
auto encoding = paint.getTextEncoding();
|
auto encoding = paint.getTextEncoding();
|
||||||
auto typeface = SkPaintPriv::GetTypefaceOrDefault(paint);
|
auto typeface = SkPaintPriv::GetTypefaceOrDefault(paint);
|
||||||
if (encoding == SkPaint::kGlyphID_TextEncoding) {
|
if (encoding == SkPaint::kGlyphID_TextEncoding) {
|
||||||
return make_from_glyphids(
|
return make_from_glyphids(
|
||||||
byteLength / 2, reinterpret_cast<const SkGlyphID*>(bytes), typeface->countGlyphs());
|
byteLength / 2, reinterpret_cast<const SkGlyphID*>(bytes),
|
||||||
|
typeface->countGlyphs(), glyphSet);
|
||||||
} else {
|
} else {
|
||||||
return make_from_utfn(byteLength, bytes, *typeface, convert_encoding(encoding));
|
return make_from_utfn(byteLength, bytes, *typeface, convert_encoding(encoding), glyphSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,20 +78,20 @@ Core make_core(const SkPaint& paint, const void* bytes, size_t byteLength) {
|
|||||||
|
|
||||||
SkGlyphRun SkGlyphRun::MakeFromDrawText(
|
SkGlyphRun SkGlyphRun::MakeFromDrawText(
|
||||||
const SkPaint& paint, const void* bytes, size_t byteLength,
|
const SkPaint& paint, const void* bytes, size_t byteLength,
|
||||||
const SkPoint origin) {
|
const SkPoint origin, SkGlyphSet* glyphSet) {
|
||||||
size_t runSize;
|
size_t runSize;
|
||||||
std::unique_ptr<uint16_t[]> denseIndex;
|
std::unique_ptr<uint16_t[]> denseIndex;
|
||||||
uint16_t uniqueSize;
|
std::vector<SkGlyphID> uniqueGlyphIDs;
|
||||||
std::unique_ptr<SkGlyphID[]> uniqueGlyphIDs;
|
std::tie(runSize, denseIndex, uniqueGlyphIDs) = make_core(paint, bytes, byteLength, glyphSet);
|
||||||
std::tie(runSize, denseIndex, uniqueSize, uniqueGlyphIDs) = make_core(paint, bytes, byteLength);
|
|
||||||
|
|
||||||
if (runSize == 0) { return SkGlyphRun{}; }
|
if (runSize == 0) { return SkGlyphRun{}; }
|
||||||
|
|
||||||
auto advances = skstd::make_unique_default<SkPoint[]>(uniqueSize);
|
auto advances = skstd::make_unique_default<SkPoint[]>(uniqueGlyphIDs.size());
|
||||||
|
|
||||||
{
|
{
|
||||||
auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(paint);
|
auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(paint);
|
||||||
cache->getAdvances(SkSpan<SkGlyphID>{uniqueGlyphIDs.get(), uniqueSize}, advances.get());
|
cache->getAdvances(SkSpan<SkGlyphID>{uniqueGlyphIDs.data(),
|
||||||
|
uniqueGlyphIDs.size()}, advances.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto positions = skstd::make_unique_default<SkPoint[]>(runSize);
|
auto positions = skstd::make_unique_default<SkPoint[]>(runSize);
|
||||||
@ -171,17 +114,16 @@ SkGlyphRun SkGlyphRun::MakeFromDrawText(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return SkGlyphRun{
|
return SkGlyphRun{
|
||||||
runSize, std::move(denseIndex), std::move(positions), uniqueSize, std::move(uniqueGlyphIDs)};
|
runSize, std::move(denseIndex), std::move(positions), std::move(uniqueGlyphIDs)};
|
||||||
}
|
}
|
||||||
|
|
||||||
SkGlyphRun SkGlyphRun::MakeFromDrawPosTextH(
|
SkGlyphRun SkGlyphRun::MakeFromDrawPosTextH(
|
||||||
const SkPaint& paint, const void* bytes, size_t byteLength,
|
const SkPaint& paint, const void* bytes, size_t byteLength,
|
||||||
const SkScalar xpos[], SkScalar constY) {
|
const SkScalar xpos[], SkScalar constY, SkGlyphSet* glyphSet) {
|
||||||
size_t runSize;
|
size_t runSize;
|
||||||
std::unique_ptr<uint16_t[]> denseIndex;
|
std::unique_ptr<uint16_t[]> denseIndex;
|
||||||
uint16_t uniqueSize;
|
std::vector<SkGlyphID> uniqueGlyphIDs;
|
||||||
std::unique_ptr<SkGlyphID[]> uniqueGlyphIDs;
|
std::tie(runSize, denseIndex, uniqueGlyphIDs) = make_core(paint, bytes, byteLength, glyphSet);
|
||||||
std::tie(runSize, denseIndex, uniqueSize, uniqueGlyphIDs) = make_core(paint, bytes, byteLength);
|
|
||||||
|
|
||||||
if (runSize == 0) { return SkGlyphRun{}; }
|
if (runSize == 0) { return SkGlyphRun{}; }
|
||||||
|
|
||||||
@ -192,17 +134,16 @@ SkGlyphRun SkGlyphRun::MakeFromDrawPosTextH(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return SkGlyphRun{
|
return SkGlyphRun{
|
||||||
runSize, std::move(denseIndex), std::move(positions), uniqueSize, std::move(uniqueGlyphIDs)};
|
runSize, std::move(denseIndex), std::move(positions), std::move(uniqueGlyphIDs)};
|
||||||
}
|
}
|
||||||
|
|
||||||
SkGlyphRun SkGlyphRun::MakeFromDrawPosText(
|
SkGlyphRun SkGlyphRun::MakeFromDrawPosText(
|
||||||
const SkPaint& paint, const void* bytes, size_t byteLength,
|
const SkPaint& paint, const void* bytes, size_t byteLength,
|
||||||
const SkPoint pos[]) {
|
const SkPoint pos[], SkGlyphSet* glyphSet) {
|
||||||
size_t runSize;
|
size_t runSize;
|
||||||
std::unique_ptr<uint16_t[]> denseIndex;
|
std::unique_ptr<uint16_t[]> denseIndex;
|
||||||
uint16_t uniqueSize;
|
std::vector<SkGlyphID> uniqueGlyphIDs;
|
||||||
std::unique_ptr<SkGlyphID[]> uniqueGlyphIDs;
|
std::tie(runSize, denseIndex, uniqueGlyphIDs) = make_core(paint, bytes, byteLength, glyphSet);
|
||||||
std::tie(runSize, denseIndex, uniqueSize, uniqueGlyphIDs) = make_core(paint, bytes, byteLength);
|
|
||||||
|
|
||||||
if (runSize == 0) { return SkGlyphRun{}; }
|
if (runSize == 0) { return SkGlyphRun{}; }
|
||||||
|
|
||||||
@ -211,7 +152,7 @@ SkGlyphRun SkGlyphRun::MakeFromDrawPosText(
|
|||||||
memcpy(positions.get(), pos, sizeof(SkPoint) * runSize);
|
memcpy(positions.get(), pos, sizeof(SkPoint) * runSize);
|
||||||
|
|
||||||
return SkGlyphRun{
|
return SkGlyphRun{
|
||||||
runSize, std::move(denseIndex), std::move(positions), uniqueSize, std::move(uniqueGlyphIDs)};
|
runSize, std::move(denseIndex), std::move(positions), std::move(uniqueGlyphIDs)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<SkGlyphID[]> SkGlyphRun::copyGlyphIDs() const {
|
std::unique_ptr<SkGlyphID[]> SkGlyphRun::copyGlyphIDs() const {
|
||||||
@ -227,10 +168,55 @@ std::unique_ptr<SkGlyphID[]> SkGlyphRun::copyGlyphIDs() const {
|
|||||||
SkGlyphRun::SkGlyphRun(size_t runSize,
|
SkGlyphRun::SkGlyphRun(size_t runSize,
|
||||||
std::unique_ptr<uint16_t[]>&& denseIndex,
|
std::unique_ptr<uint16_t[]>&& denseIndex,
|
||||||
std::unique_ptr<SkPoint[]>&& positions,
|
std::unique_ptr<SkPoint[]>&& positions,
|
||||||
uint16_t uniqueSize,
|
std::vector<SkGlyphID>&& uniqueGlyphIDs)
|
||||||
std::unique_ptr<SkGlyphID[]>&& uniqueGlyphIDs)
|
|
||||||
: fDenseIndex{std::move(denseIndex)}
|
: fDenseIndex{std::move(denseIndex)}
|
||||||
, fPositions{std::move(positions)}
|
, fPositions{std::move(positions)}
|
||||||
, fUniqueGlyphs{std::move(uniqueGlyphIDs)}
|
, fUniqueGlyphs{std::move(uniqueGlyphIDs)}
|
||||||
, fRunSize{runSize}
|
, fRunSize{runSize} { }
|
||||||
, fUniqueSize{uniqueSize} { }
|
|
||||||
|
uint16_t SkGlyphSet::add(SkGlyphID glyphID) {
|
||||||
|
static constexpr SkGlyphID kUndefGlyph{0};
|
||||||
|
|
||||||
|
if (glyphID >= fUniverseSize) {
|
||||||
|
glyphID = kUndefGlyph;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glyphID >= fIndices.size()) {
|
||||||
|
fIndices.resize(glyphID + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto index = fIndices[glyphID];
|
||||||
|
if (index < fUniqueGlyphIDs.size() && fUniqueGlyphIDs[index] == glyphID) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t newIndex = SkTo<uint16_t>(fUniqueGlyphIDs.size());
|
||||||
|
fUniqueGlyphIDs.push_back(glyphID);
|
||||||
|
fIndices[glyphID] = newIndex;
|
||||||
|
return newIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SkGlyphID> SkGlyphSet::uniqueGlyphIDs() {
|
||||||
|
return fUniqueGlyphIDs;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
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!
|
||||||
|
}
|
@ -17,22 +17,39 @@
|
|||||||
#include "SkPoint.h"
|
#include "SkPoint.h"
|
||||||
#include "SkTypes.h"
|
#include "SkTypes.h"
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// for Sparse Sets"
|
||||||
|
class SkGlyphSet {
|
||||||
|
public:
|
||||||
|
SkGlyphSet() = default;
|
||||||
|
uint16_t add(SkGlyphID glyphID);
|
||||||
|
std::vector<SkGlyphID> uniqueGlyphIDs();
|
||||||
|
void reuse(uint32_t glyphUniverseSize);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t fUniverseSize{0};
|
||||||
|
std::vector<uint16_t> fIndices;
|
||||||
|
std::vector<SkGlyphID> fUniqueGlyphIDs;
|
||||||
|
};
|
||||||
|
|
||||||
class SkGlyphRun {
|
class SkGlyphRun {
|
||||||
public:
|
public:
|
||||||
SkGlyphRun() = default;
|
SkGlyphRun() = default;
|
||||||
SkGlyphRun(SkGlyphRun&&) = default;
|
SkGlyphRun(SkGlyphRun&&) = default;
|
||||||
static SkGlyphRun MakeFromDrawText(
|
static SkGlyphRun MakeFromDrawText(
|
||||||
const SkPaint& paint, const void* bytes, size_t byteLength,
|
const SkPaint& paint, const void* bytes, size_t byteLength,
|
||||||
SkPoint origin);
|
SkPoint origin, SkGlyphSet* glyphSet);
|
||||||
static SkGlyphRun MakeFromDrawPosTextH(
|
static SkGlyphRun MakeFromDrawPosTextH(
|
||||||
const SkPaint& paint, const void* bytes, size_t byteLength,
|
const SkPaint& paint, const void* bytes, size_t byteLength,
|
||||||
const SkScalar xpos[], SkScalar constY);
|
const SkScalar xpos[], SkScalar constY, SkGlyphSet* glyphSet);
|
||||||
static SkGlyphRun MakeFromDrawPosText(
|
static SkGlyphRun MakeFromDrawPosText(
|
||||||
const SkPaint& paint, const void* bytes, size_t byteLength,
|
const SkPaint& paint, const void* bytes, size_t byteLength,
|
||||||
const SkPoint pos[]);
|
const SkPoint pos[], SkGlyphSet* glyphSet);
|
||||||
|
|
||||||
size_t runSize() const { return fRunSize; }
|
size_t runSize() const { return fRunSize; }
|
||||||
uint16_t uniqueSize() const { return fUniqueSize; }
|
uint16_t uniqueSize() const { return fUniqueGlyphs.size(); }
|
||||||
|
|
||||||
// copyGlyphIDs is temporary glue to work with the existing system. Don't use with new code.
|
// copyGlyphIDs is temporary glue to work with the existing system. Don't use with new code.
|
||||||
std::unique_ptr<SkGlyphID[]> copyGlyphIDs() const;
|
std::unique_ptr<SkGlyphID[]> copyGlyphIDs() const;
|
||||||
@ -44,14 +61,12 @@ private:
|
|||||||
SkGlyphRun(size_t runSize,
|
SkGlyphRun(size_t runSize,
|
||||||
std::unique_ptr<uint16_t[]>&& denseIndex,
|
std::unique_ptr<uint16_t[]>&& denseIndex,
|
||||||
std::unique_ptr<SkPoint[]>&& positions,
|
std::unique_ptr<SkPoint[]>&& positions,
|
||||||
uint16_t uniqueSize,
|
std::vector<SkGlyphID>&& uniqueGlyphIDs);
|
||||||
std::unique_ptr<SkGlyphID[]>&& uniqueGlyphIDs);
|
|
||||||
|
|
||||||
std::unique_ptr<uint16_t[]> fDenseIndex;
|
std::unique_ptr<uint16_t[]> fDenseIndex;
|
||||||
std::unique_ptr<SkPoint[]> fPositions;
|
std::unique_ptr<SkPoint[]> fPositions;
|
||||||
std::unique_ptr<SkGlyphID[]> fUniqueGlyphs;
|
std::vector<SkGlyphID> fUniqueGlyphs;
|
||||||
const size_t fRunSize{0};
|
const size_t fRunSize{0};
|
||||||
const uint16_t fUniqueSize{0};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -210,10 +210,11 @@ void GrTextContext::regenerateTextBlob(GrTextBlob* cacheBlob,
|
|||||||
shaderCaps.supportsDistanceFieldText(), fOptions)) {
|
shaderCaps.supportsDistanceFieldText(), fOptions)) {
|
||||||
switch (it.positioning()) {
|
switch (it.positioning()) {
|
||||||
case SkTextBlob::kDefault_Positioning: {
|
case SkTextBlob::kDefault_Positioning: {
|
||||||
|
SkGlyphSet glyphSet;
|
||||||
auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
|
auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
|
||||||
auto glyphRun =
|
auto glyphRun =
|
||||||
SkGlyphRun::MakeFromDrawText(runPaint.skPaint(),
|
SkGlyphRun::MakeFromDrawText(runPaint.skPaint(),
|
||||||
(const char*)it.glyphs(), textLen, origin);
|
(const char*)it.glyphs(), textLen, origin, &glyphSet);
|
||||||
|
|
||||||
this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint,
|
this->drawDFPosText(cacheBlob, run, glyphCache, props, runPaint,
|
||||||
scalerContextFlags, viewMatrix, (const char*)it.glyphs(),
|
scalerContextFlags, viewMatrix, (const char*)it.glyphs(),
|
||||||
@ -239,10 +240,12 @@ void GrTextContext::regenerateTextBlob(GrTextBlob* cacheBlob,
|
|||||||
} else {
|
} else {
|
||||||
switch (it.positioning()) {
|
switch (it.positioning()) {
|
||||||
case SkTextBlob::kDefault_Positioning: {
|
case SkTextBlob::kDefault_Positioning: {
|
||||||
|
SkGlyphSet glyphSet;
|
||||||
auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
|
auto origin = SkPoint::Make(x + offset.x(), y + offset.y());
|
||||||
auto glyphRun =
|
auto glyphRun =
|
||||||
SkGlyphRun::MakeFromDrawText(
|
SkGlyphRun::MakeFromDrawText(
|
||||||
runPaint.skPaint(), (const char*) it.glyphs(), textLen, origin);
|
runPaint.skPaint(), (const char*) it.glyphs(), textLen, origin,
|
||||||
|
&glyphSet);
|
||||||
|
|
||||||
this->DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint,
|
this->DrawBmpPosText(cacheBlob, run, glyphCache, props, runPaint,
|
||||||
scalerContextFlags, viewMatrix, (const char*) it.glyphs(),
|
scalerContextFlags, viewMatrix, (const char*) it.glyphs(),
|
||||||
@ -758,8 +761,9 @@ 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
|
// 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.
|
// test the text op with this unit test, that is okay.
|
||||||
|
|
||||||
|
SkGlyphSet glyphSet;
|
||||||
auto origin = SkPoint::Make(x, y);
|
auto origin = SkPoint::Make(x, y);
|
||||||
auto glyphRun = SkGlyphRun::MakeFromDrawText(skPaint, text, textLen, origin);
|
auto glyphRun = SkGlyphRun::MakeFromDrawText(skPaint, text, textLen, origin, &glyphSet);
|
||||||
|
|
||||||
sk_sp<GrTextBlob> blob(textContext->makeDrawPosTextBlob(
|
sk_sp<GrTextBlob> blob(textContext->makeDrawPosTextBlob(
|
||||||
context->contextPriv().getTextBlobCache(), glyphCache,
|
context->contextPriv().getTextBlobCache(), glyphCache,
|
||||||
|
@ -16,5 +16,7 @@ DEF_TEST(GlyphRunInfo, reporter) {
|
|||||||
SkPaint paint;
|
SkPaint paint;
|
||||||
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
||||||
|
|
||||||
SkGlyphRun::MakeFromDrawText(paint, glyphs, count, SkPoint::Make(0, 0));
|
SkGlyphSet glyphSet;
|
||||||
|
|
||||||
|
SkGlyphRun::MakeFromDrawText(paint, glyphs, count, SkPoint::Make(0, 0), &glyphSet);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user