aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Khushal <khushalsagar@chromium.org>2018-06-12 11:26:17 -0700
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-06-12 20:42:34 +0000
commit8523b6bd0d22083266d990191764a0460885fd6e (patch)
tree15e9d39366e769bd79c9d243d01f8c2d2db983c1
parent047fb122b94d5a569a5b64f4e65ecc8bf68cf09c (diff)
fonts: Fix memory allocation for fallback glyphs.
When allocating the mask for a fallback glyph, we allocate it on the arena on the SkScalerContext while the image belongs to a glyph on a different cache. This can lead to use-after-free bugs if accessing the image after the context owning that memory is destroyed. Fix this by allocating on the arena from the owning cache. R=herb@google.com, mtklein@google.com Bug: 829622 Change-Id: Ife53e24f5bc868f36c43f2adcd7a2629ab5577fe Reviewed-on: https://skia-review.googlesource.com/134182 Commit-Queue: Mike Klein <mtklein@google.com> Reviewed-by: Mike Klein <mtklein@google.com>
-rw-r--r--src/core/SkGlyph.h9
-rw-r--r--src/core/SkGlyphCache.cpp33
-rw-r--r--src/core/SkGlyphCache.h10
-rw-r--r--src/core/SkRemoteGlyphCache.cpp1
-rw-r--r--src/core/SkRemoteGlyphCache.h18
-rw-r--r--src/core/SkStrikeCache.cpp51
-rw-r--r--src/core/SkStrikeCache.h9
-rw-r--r--src/core/SkTypeface_remote.cpp47
-rw-r--r--src/core/SkTypeface_remote.h10
-rw-r--r--tests/SkRemoteGlyphCacheTest.cpp97
10 files changed, 167 insertions, 118 deletions
diff --git a/src/core/SkGlyph.h b/src/core/SkGlyph.h
index 748b87fab3..2b3adafd74 100644
--- a/src/core/SkGlyph.h
+++ b/src/core/SkGlyph.h
@@ -196,7 +196,9 @@ public:
void toMask(SkMask* mask) const;
- void copyImageData(const SkGlyph& from, SkArenaAlloc* alloc) {
+ /** Returns the size allocated on the arena.
+ */
+ size_t copyImageData(const SkGlyph& from, SkArenaAlloc* alloc) {
fMaskFormat = from.fMaskFormat;
fWidth = from.fWidth;
fHeight = from.fHeight;
@@ -206,8 +208,13 @@ public:
if (from.fImage != nullptr) {
auto imageSize = this->allocImage(alloc);
+ SkASSERT(imageSize == from.computeImageSize());
+
memcpy(fImage, from.fImage, imageSize);
+ return imageSize;
}
+
+ return 0u;
}
class HashTraits {
diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp
index 79e714758c..6b8bd7098a 100644
--- a/src/core/SkGlyphCache.cpp
+++ b/src/core/SkGlyphCache.cpp
@@ -154,13 +154,7 @@ SkGlyph* SkGlyphCache::lookupByPackedGlyphID(SkPackedGlyphID packedGlyphID, Metr
glyph = this->allocateNewGlyph(packedGlyphID, type);
} else {
if (type == kFull_MetricsType && glyph->isJustAdvance()) {
- fScalerContext->getMetrics(glyph);
-
- // Just in case someone allocated an image in the getMetrics call, be sure to account
- // for the memory used.
- if (glyph->fImage != nullptr) {
- fMemoryUsed += glyph->computeImageSize();
- }
+ fScalerContext->getMetrics(glyph);
}
}
return glyph;
@@ -215,7 +209,7 @@ bool SkGlyphCache::initializeImage(const volatile void* data, size_t size, SkGly
// check that alloc() actually succeeded
if (glyph->fImage) {
SkAssertResult(size == allocSize);
- memcpy(glyph->fImage, const_cast<const void*>(data), size);
+ memcpy(glyph->fImage, const_cast<const void*>(data), allocSize);
fMemoryUsed += size;
}
}
@@ -261,6 +255,29 @@ bool SkGlyphCache::initializePath(SkGlyph* glyph, const volatile void* data, siz
return true;
}
+bool SkGlyphCache::belongsToCache(const SkGlyph* glyph) const {
+ return glyph && fGlyphMap.find(glyph->getPackedID()) == glyph;
+}
+
+const SkGlyph* SkGlyphCache::getCachedGlyphAnySubPix(SkGlyphID glyphID,
+ SkPackedGlyphID vetoID) const {
+ for (SkFixed subY = 0; subY < SK_Fixed1; subY += SK_FixedQuarter) {
+ for (SkFixed subX = 0; subX < SK_Fixed1; subX += SK_FixedQuarter) {
+ SkPackedGlyphID packedGlyphID{glyphID, subX, subY};
+ if (packedGlyphID == vetoID) continue;
+ if (const auto* glyph = fGlyphMap.find(packedGlyphID)) {
+ return glyph;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+void SkGlyphCache::initializeGlyphFromFallback(SkGlyph* glyph, const SkGlyph& fallback) {
+ fMemoryUsed += glyph->copyImageData(fallback, &fAlloc);
+}
+
#include "../pathops/SkPathOpsCubic.h"
#include "../pathops/SkPathOpsQuad.h"
diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h
index e904c6e5c7..47a1d3d4d2 100644
--- a/src/core/SkGlyphCache.h
+++ b/src/core/SkGlyphCache.h
@@ -112,6 +112,16 @@ public:
*/
bool initializePath(SkGlyph*, const volatile void* data, size_t size);
+ /** Fallback glyphs used during font remoting if the original glyph can't be found.
+ */
+ bool belongsToCache(const SkGlyph* glyph) const;
+ /** Find any glyph in this cache with the given ID, regardless of subpixel positioning.
+ * If set and present, skip over the glyph with vetoID.
+ */
+ const SkGlyph* getCachedGlyphAnySubPix(SkGlyphID,
+ SkPackedGlyphID vetoID = SkPackedGlyphID()) const;
+ void initializeGlyphFromFallback(SkGlyph* glyph, const SkGlyph&);
+
/** Return the vertical metrics for this strike.
*/
const SkPaint::FontMetrics& getFontMetrics() const {
diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp
index 49688886c1..0ccbf2f15e 100644
--- a/src/core/SkRemoteGlyphCache.cpp
+++ b/src/core/SkRemoteGlyphCache.cpp
@@ -801,6 +801,7 @@ bool SkStrikeClient::readStrikeData(const volatile void* memory, size_t memorySi
*client_desc, std::move(scaler), &fontMetrics,
skstd::make_unique<DiscardableStrikePinner>(spec.discardableHandleId,
fDiscardableHandleManager));
+ static_cast<SkScalerContextProxy*>(strike->getScalerContext())->initCache(strike.get());
}
size_t glyphImagesCount = 0u;
diff --git a/src/core/SkRemoteGlyphCache.h b/src/core/SkRemoteGlyphCache.h
index ce318489e4..ac13920772 100644
--- a/src/core/SkRemoteGlyphCache.h
+++ b/src/core/SkRemoteGlyphCache.h
@@ -184,12 +184,20 @@ private:
class SK_API SkStrikeClient {
public:
+ // This enum is used in histogram reporting in chromium. Please don't re-order the list of
+ // entries, and consider it to be append-only.
enum CacheMissType : uint32_t {
- kFontMetrics,
- kGlyphMetrics,
- kGlyphImage,
- kGlyphPath,
- kLast = kGlyphPath
+ // Hard failures where no fallback could be found.
+ kFontMetrics = 0,
+ kGlyphMetrics = 1,
+ kGlyphImage = 2,
+ kGlyphPath = 3,
+
+ // The original glyph could not be found and a fallback was used.
+ kGlyphMetricsFallback = 4,
+ kGlyphPathFallback = 5,
+
+ kLast = kGlyphPathFallback
};
// An interface to delete handles that may be pinned by the remote server.
diff --git a/src/core/SkStrikeCache.cpp b/src/core/SkStrikeCache.cpp
index 20ed6e772c..fef46fd36d 100644
--- a/src/core/SkStrikeCache.cpp
+++ b/src/core/SkStrikeCache.cpp
@@ -101,9 +101,9 @@ SkExclusiveStrikePtr SkStrikeCache::FindStrikeExclusive(const SkDescriptor& desc
return get_globals().findStrikeExclusive(desc);
}
-bool SkStrikeCache::DesperationSearchForImage(
- const SkDescriptor& desc, SkGlyph* glyph, SkArenaAlloc* arena) {
- return get_globals().desperationSearchForImage(desc, glyph, arena);
+bool SkStrikeCache::DesperationSearchForImage(const SkDescriptor& desc, SkGlyph* glyph,
+ SkGlyphCache* targetCache) {
+ return get_globals().desperationSearchForImage(desc, glyph, targetCache);
}
bool SkStrikeCache::DesperationSearchForPath(
@@ -265,7 +265,7 @@ SkExclusiveStrikePtr SkStrikeCache::findStrikeExclusive(const SkDescriptor& desc
return SkExclusiveStrikePtr(nullptr);
}
-static bool loose_compare (const SkDescriptor& lhs, const SkDescriptor& rhs) {
+static bool loose_compare(const SkDescriptor& lhs, const SkDescriptor& rhs) {
uint32_t size;
auto ptr = lhs.findEntry(kRec_SkDescriptorTag, &size);
SkScalerContextRec lhsRec;
@@ -276,7 +276,10 @@ static bool loose_compare (const SkDescriptor& lhs, const SkDescriptor& rhs) {
std::memcpy(&rhsRec, ptr, size);
// If these don't match, there's no way we can use these strikes interchangeably.
- // TODO: make sure we don't search other renderer's caches.
+ // Note that a typeface from each renderer maps to a unique proxy typeface on the GPU,
+ // keyed in the glyph cache using fontID in the SkDescriptor. By limiting this search
+ // to descriptors with the same fontID, we ensure that a renderer never uses glyphs
+ // generated by a different renderer.
return
lhsRec.fFontID == rhsRec.fFontID &&
lhsRec.fTextSize == rhsRec.fTextSize &&
@@ -288,46 +291,34 @@ static bool loose_compare (const SkDescriptor& lhs, const SkDescriptor& rhs) {
lhsRec.fPost2x2[1][1] == rhsRec.fPost2x2[1][1];
}
-bool SkStrikeCache::desperationSearchForImage(
- const SkDescriptor& desc, SkGlyph* glyph, SkArenaAlloc* alloc) {
+bool SkStrikeCache::desperationSearchForImage(const SkDescriptor& desc, SkGlyph* glyph,
+ SkGlyphCache* targetCache) {
SkAutoExclusive ac(fLock);
SkGlyphID glyphID = glyph->getGlyphID();
SkFixed targetSubX = glyph->getSubXFixed(),
targetSubY = glyph->getSubYFixed();
- // We don't have this glyph with the exact subpixel positioning,
- // but we might have this glyph with another subpixel position... search them all.
for (Node* node = internalGetHead(); node != nullptr; node = node->fNext) {
if (loose_compare(node->fCache.getDescriptor(), desc)) {
auto targetGlyphID = SkPackedGlyphID(glyphID, targetSubX, targetSubY);
if (node->fCache.isGlyphCached(glyphID, targetSubX, targetSubY)) {
- SkGlyph* from = node->fCache.getRawGlyphByID(targetGlyphID);
- if (from->fImage != nullptr) {
- // This desperate-match node may disappear as soon as we drop fLock, so we
- // need to copy the glyph from node into this strike, including a
- // deep copy of the mask.
- glyph->copyImageData(*from, alloc);
- return true;
- }
+ SkGlyph* fallback = node->fCache.getRawGlyphByID(targetGlyphID);
+ // This desperate-match node may disappear as soon as we drop fLock, so we
+ // need to copy the glyph from node into this strike, including a
+ // deep copy of the mask.
+ targetCache->initializeGlyphFromFallback(glyph, *fallback);
+ return true;
}
- // We don't have this glyph with the exact subpixel positioning,
- // but we might have this glyph with another subpixel position... search them all.
- for (SkFixed subY = 0; subY < SK_Fixed1; subY += SK_FixedQuarter) {
- for (SkFixed subX = 0; subX < SK_Fixed1; subX += SK_FixedQuarter) {
- if (node->fCache.isGlyphCached(glyphID, subX, subY)) {
- SkGlyph* from =
- node->fCache.getRawGlyphByID(SkPackedGlyphID(glyphID, subX, subY));
- if (from->fImage != nullptr) {
- glyph->copyImageData(*from, alloc);
- return true;
- }
- }
- }
+ // Look for any sub-pixel pos for this glyph, in case there is a pos mismatch.
+ if (const auto* fallback = node->fCache.getCachedGlyphAnySubPix(glyphID)) {
+ targetCache->initializeGlyphFromFallback(glyph, *fallback);
+ return true;
}
}
}
+
return false;
}
diff --git a/src/core/SkStrikeCache.h b/src/core/SkStrikeCache.h
index da984cce13..05e3aa4025 100644
--- a/src/core/SkStrikeCache.h
+++ b/src/core/SkStrikeCache.h
@@ -70,8 +70,9 @@ public:
static ExclusiveStrikePtr FindStrikeExclusive(const SkDescriptor&);
- static bool DesperationSearchForImage(
- const SkDescriptor& desc, SkGlyph* glyph, SkArenaAlloc* arena);
+ static bool DesperationSearchForImage(const SkDescriptor& desc,
+ SkGlyph* glyph,
+ SkGlyphCache* targetCache);
static bool DesperationSearchForPath(
const SkDescriptor& desc, SkGlyphID glyphID, SkPath* path);
@@ -112,7 +113,9 @@ public:
// Routines to find suitable data when working in a remote cache situation. These are
// suitable as substitutes for similar calls in SkScalerContext.
- bool desperationSearchForImage(const SkDescriptor& desc, SkGlyph* glyph, SkArenaAlloc* alloc);
+ bool desperationSearchForImage(const SkDescriptor& desc,
+ SkGlyph* glyph,
+ SkGlyphCache* targetCache);
bool desperationSearchForPath(const SkDescriptor& desc, SkGlyphID glyphID, SkPath* path);
void purgeAll(); // does not change budget
diff --git a/src/core/SkTypeface_remote.cpp b/src/core/SkTypeface_remote.cpp
index 9388b16ef4..4b10f1e96f 100644
--- a/src/core/SkTypeface_remote.cpp
+++ b/src/core/SkTypeface_remote.cpp
@@ -6,6 +6,7 @@
*/
#include "SkTypeface_remote.h"
+#include "SkGlyphCache.h"
#include "SkPaint.h"
#include "SkRemoteGlyphCache.h"
#include "SkStrikeCache.h"
@@ -18,6 +19,13 @@ SkScalerContextProxy::SkScalerContextProxy(sk_sp<SkTypeface> tf,
: SkScalerContext{std::move(tf), effects, desc}
, fDiscardableManager{std::move(manager)} {}
+void SkScalerContextProxy::initCache(SkGlyphCache* cache) {
+ SkASSERT(fCache == nullptr);
+ SkASSERT(cache != nullptr);
+
+ fCache = cache;
+}
+
unsigned SkScalerContextProxy::generateGlyphCount() {
SK_ABORT("Should never be called.");
return 0;
@@ -28,9 +36,7 @@ uint16_t SkScalerContextProxy::generateCharToGlyph(SkUnichar) {
return 0;
}
-void SkScalerContextProxy::generateAdvance(SkGlyph* glyph) {
- this->generateMetrics(glyph);
-}
+void SkScalerContextProxy::generateAdvance(SkGlyph* glyph) { this->generateMetrics(glyph); }
void SkScalerContextProxy::generateMetrics(SkGlyph* glyph) {
TRACE_EVENT1("skia", "generateMetrics", "rec", TRACE_STR_COPY(this->getRec().dump().c_str()));
@@ -38,14 +44,27 @@ void SkScalerContextProxy::generateMetrics(SkGlyph* glyph) {
SkDebugf("GlyphCacheMiss generateMetrics: %s\n", this->getRec().dump().c_str());
}
- // Since the scaler context is being called, we don't have the needed data. Go look through
- // looking for a suitable substitute before failing.
- auto desc = SkScalerContext::DescriptorGivenRecAndEffects(this->getRec(), this->getEffects());
- SkStrikeCache::DesperationSearchForImage(*desc, glyph, &fAlloc);
+ // Since the scaler context is being called, we don't have the needed data. Try to find a
+ // fallback before failing.
+ if (fCache && fCache->belongsToCache(glyph)) {
+ // First check the original cache, in case there is a sub-pixel pos mismatch.
+ if (const auto* fallback =
+ fCache->getCachedGlyphAnySubPix(glyph->getGlyphID(), glyph->getPackedID())) {
+ fCache->initializeGlyphFromFallback(glyph, *fallback);
+ fDiscardableManager->notifyCacheMiss(
+ SkStrikeClient::CacheMissType::kGlyphMetricsFallback);
+ return;
+ }
- if (glyph->fMaskFormat == MASK_FORMAT_UNKNOWN) {
- glyph->zeroMetrics();
+ // Now check other caches for a desc mismatch.
+ if (SkStrikeCache::DesperationSearchForImage(fCache->getDescriptor(), glyph, fCache)) {
+ fDiscardableManager->notifyCacheMiss(
+ SkStrikeClient::CacheMissType::kGlyphMetricsFallback);
+ return;
+ }
}
+
+ glyph->zeroMetrics();
fDiscardableManager->notifyCacheMiss(SkStrikeClient::CacheMissType::kGlyphMetrics);
}
@@ -65,12 +84,14 @@ bool SkScalerContextProxy::generatePath(SkGlyphID glyphID, SkPath* path) {
if (this->getProxyTypeface()->isLogging()) {
SkDebugf("GlyphCacheMiss generatePath: %s\n", this->getRec().dump().c_str());
}
- // Since the scaler context is being called, we don't have the needed data. Go look through
- // looking for a suitable substitute before failing.
+
+ // Since the scaler context is being called, we don't have the needed data. Try to find a
+ // fallback before failing.
auto desc = SkScalerContext::DescriptorGivenRecAndEffects(this->getRec(), this->getEffects());
bool foundPath = SkStrikeCache::DesperationSearchForPath(*desc, glyphID, path);
-
- fDiscardableManager->notifyCacheMiss(SkStrikeClient::CacheMissType::kGlyphPath);
+ fDiscardableManager->notifyCacheMiss(foundPath
+ ? SkStrikeClient::CacheMissType::kGlyphPathFallback
+ : SkStrikeClient::CacheMissType::kGlyphPath);
return foundPath;
}
diff --git a/src/core/SkTypeface_remote.h b/src/core/SkTypeface_remote.h
index 1e079eff49..88628d13b4 100644
--- a/src/core/SkTypeface_remote.h
+++ b/src/core/SkTypeface_remote.h
@@ -26,6 +26,8 @@ public:
const SkDescriptor* desc,
sk_sp<SkStrikeClient::DiscardableHandleManager> manager);
+ void initCache(SkGlyphCache*);
+
protected:
unsigned generateGlyphCount() override;
uint16_t generateCharToGlyph(SkUnichar) override;
@@ -37,14 +39,8 @@ protected:
SkTypefaceProxy* getProxyTypeface() const;
private:
- // Copied from SkGlyphCache
- // so we don't grow our arrays a lot
- static constexpr size_t kMinGlyphCount = 8;
- static constexpr size_t kMinGlyphImageSize = 16 /* height */ * 8 /* width */;
- static constexpr size_t kMinAllocAmount = kMinGlyphImageSize * kMinGlyphCount;
-
- SkArenaAlloc fAlloc{kMinAllocAmount};
sk_sp<SkStrikeClient::DiscardableHandleManager> fDiscardableManager;
+ SkGlyphCache* fCache = nullptr;
typedef SkScalerContext INHERITED;
};
diff --git a/tests/SkRemoteGlyphCacheTest.cpp b/tests/SkRemoteGlyphCacheTest.cpp
index 359c506950..62036d2285 100644
--- a/tests/SkRemoteGlyphCacheTest.cpp
+++ b/tests/SkRemoteGlyphCacheTest.cpp
@@ -46,7 +46,7 @@ public:
}
const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const { return fLockedHandles; }
SkDiscardableHandleId handleCount() { return fNextHandleId; }
- int cacheMissCount(SkStrikeClient::CacheMissType type) { return fCacheMissCount[type]; }
+ int cacheMissCount(uint32_t type) { return fCacheMissCount[type]; }
bool hasCacheMiss() const {
for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
if (fCacheMissCount[i] > 0) return true;
@@ -410,14 +410,22 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, report
}
DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
+ // Build proxy typeface on the client for initializing the cache.
+ sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
+ SkStrikeServer server(discardableManager.get());
+ SkStrikeClient client(discardableManager, false);
+
+ auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
+ auto tfData = server.serializeTypeface(serverTf.get());
+ auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
+ REPORTER_ASSERT(reporter, clientTf);
+
SkPaint paint;
paint.setAntiAlias(true);
- auto typeface = SkTypeface::MakeFromName("monospace", SkFontStyle());
- paint.setTypeface(typeface);
+ paint.setTypeface(clientTf);
paint.setColor(SK_ColorRED);
auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
-
const uint8_t glyphImage[] = {0xFF, 0xFF};
// Build a fallback cache.
@@ -429,7 +437,7 @@ DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
- auto fallbackCache = SkStrikeCache::FindOrCreateStrikeExclusive(*desc, effects, *typeface);
+ auto fallbackCache = SkStrikeCache::FindOrCreateStrikeExclusive(*desc, effects, *clientTf);
auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
glyph->fMaskFormat = SkMask::kA8_Format;
glyph->fHeight = 1;
@@ -450,67 +458,54 @@ DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
REPORTER_ASSERT(reporter, !(testCache == nullptr));
}
- // Make sure we can't find the target cache.
+ // Create the target cache.
+ SkExclusiveStrikePtr testCache;
+ SkAutoDescriptor ad;
+ SkScalerContextRec rec;
+ SkScalerContextEffects effects;
+ SkScalerContextFlags flags = SkScalerContextFlags::kNone;
+ SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
+ auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
+ testCache = SkStrikeCache::FindStrikeExclusive(*desc);
+ REPORTER_ASSERT(reporter, testCache == nullptr);
+ testCache = SkStrikeCache::CreateStrikeExclusive(*desc,
+ clientTf->createScalerContext(effects, desc));
+ static_cast<SkScalerContextProxy*>(testCache->getScalerContext())->initCache(testCache.get());
+
+ // Look for the lost glyph.
{
- SkAutoDescriptor ad;
- SkScalerContextRec rec;
- SkScalerContextEffects effects;
- SkScalerContextFlags flags = SkScalerContextFlags::kNone;
- SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
- auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
- auto testCache = SkStrikeCache::FindStrikeExclusive(*desc);
- REPORTER_ASSERT(reporter, testCache == nullptr);
- }
+ const auto& lostGlyph = testCache->getGlyphIDMetrics(
+ lostGlyphID.code(), lostGlyphID.getSubXFixed(), lostGlyphID.getSubYFixed());
+ testCache->findImage(lostGlyph);
- {
- SkGlyph lostGlyph;
- lostGlyph.initWithGlyphID(lostGlyphID);
-
- SkAutoDescriptor ad;
- SkScalerContextRec rec;
- SkScalerContextEffects effects;
- SkScalerContextFlags flags = SkScalerContextFlags::kNone;
- SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
- auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
- SkArenaAlloc alloc{100};
- auto found = SkStrikeCache::DesperationSearchForImage(*desc, &lostGlyph, &alloc);
- REPORTER_ASSERT(reporter, found);
REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
+ REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
}
+ // Look for the lost glyph with a different sub-pix position.
{
- SkGlyph lostGlyph;
- auto reallyLostGlyphID = SkPackedGlyphID(1, SK_FixedQuarter, SK_FixedQuarter);
- lostGlyph.initWithGlyphID(reallyLostGlyphID);
+ const auto& lostGlyph =
+ testCache->getGlyphIDMetrics(lostGlyphID.code(), SK_FixedQuarter, SK_FixedQuarter);
+ testCache->findImage(lostGlyph);
- SkAutoDescriptor ad;
- SkScalerContextRec rec;
- SkScalerContextEffects effects;
- SkScalerContextFlags flags = SkScalerContextFlags::kNone;
- SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
- auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
- SkArenaAlloc alloc{100};
- auto found = SkStrikeCache::DesperationSearchForImage(*desc, &lostGlyph, &alloc);
- REPORTER_ASSERT(reporter, found);
REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
+ REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
}
- // Make sure we can't find the target cache again.
- {
- SkAutoDescriptor ad;
- SkScalerContextRec rec;
- SkScalerContextEffects effects;
- SkScalerContextFlags flags = SkScalerContextFlags::kNone;
- SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
- auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
- auto testCache = SkStrikeCache::FindStrikeExclusive(*desc);
- REPORTER_ASSERT(reporter, testCache == nullptr);
+ for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
+ if (i == SkStrikeClient::CacheMissType::kGlyphMetricsFallback ||
+ i == SkStrikeClient::CacheMissType::kFontMetrics) {
+ REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 2);
+ } else {
+ REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 0);
+ }
}
-
SkStrikeCache::Validate();
+ // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
+ discardableManager->unlockAndDeleteAll();
}