const GrStencilAndCoverTextContext::TextBlob&
GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob,
                                                   const SkPaint& skPaint) {
    // The font-related parameters are baked into the text blob and will override this skPaint, so
    // the only remaining properties that can affect a TextBlob are the ones related to stroke.
    if (SkPaint::kFill_Style == skPaint.getStyle()) { // Fast path.
        if (TextBlob** found = fBlobIdCache.find(skBlob->uniqueID())) {
            fLRUList.remove(*found);
            fLRUList.addToTail(*found);
            return **found;
        }
        TextBlob* blob = new TextBlob(skBlob->uniqueID(), skBlob, skPaint, fContext,
                                      &fSurfaceProps);
        this->purgeToFit(*blob);
        fBlobIdCache.set(skBlob->uniqueID(), blob);
        fLRUList.addToTail(blob);
        fCacheSize += blob->cpuMemorySize();
        return *blob;
    } else {
        GrStrokeInfo stroke(skPaint);
        SkSTArray<4, uint32_t, true> key;
        key.reset(1 + stroke.computeUniqueKeyFragmentData32Cnt());
        key[0] = skBlob->uniqueID();
        stroke.asUniqueKeyFragment(&key[1]);
        if (TextBlob** found = fBlobKeyCache.find(key)) {
            fLRUList.remove(*found);
            fLRUList.addToTail(*found);
            return **found;
        }
        TextBlob* blob = new TextBlob(key, skBlob, skPaint, fContext, &fSurfaceProps);
        this->purgeToFit(*blob);
        fBlobKeyCache.set(blob);
        fLRUList.addToTail(blob);
        fCacheSize += blob->cpuMemorySize();
        return *blob;
    }
}
void GrStencilAndCoverTextContext::purgeToFit(const TextBlob& blob) {
    static const size_t maxCacheSize = 4 * 1024 * 1024; // Allow up to 4 MB for caching text blobs.

    size_t maxSizeForNewBlob = maxCacheSize - blob.cpuMemorySize();
    while (fCacheSize && fCacheSize > maxSizeForNewBlob) {
        TextBlob* lru = fLRUList.head();
        if (1 == lru->key().count()) {
            // 1-length keys are unterstood to be the blob id.
            fBlobIdCache.remove(lru->key()[0]);
        } else {
            fBlobKeyCache.remove(lru->key());
        }
        fLRUList.remove(lru);
        fCacheSize -= lru->cpuMemorySize();
        delete lru;
    }
}