ShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32_t len,
        int numGlyphs, uint32_t radius, const float* positions) {
    ShadowText entry(paint, radius, len, text, positions);
    ShadowTexture* texture = mCache.get(entry);

    if (!texture) {
        SkPaint paintCopy(*paint);
        paintCopy.setTextAlign(SkPaint::kLeft_Align);
        FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(&paintCopy, text, 0,
                len, numGlyphs, radius, positions);

        texture = new ShadowTexture;
        texture->left = shadow.penX;
        texture->top = shadow.penY;
        texture->width = shadow.width;
        texture->height = shadow.height;
        texture->generation = 0;
        texture->blend = true;

        const uint32_t size = shadow.width * shadow.height;
        texture->bitmapSize = size;

        // Don't even try to cache a bitmap that's bigger than the cache
        if (size < mMaxSize) {
            while (mSize + size > mMaxSize) {
                mCache.removeOldest();
            }
        }

        glGenTextures(1, &texture->id);

        glBindTexture(GL_TEXTURE_2D, texture->id);
        // Textures are Alpha8
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
                GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image);

        texture->setFilter(GL_LINEAR);
        texture->setWrap(GL_CLAMP_TO_EDGE);

        if (size < mMaxSize) {
            if (mDebugEnabled) {
                ALOGD("Shadow texture created, size = %d", texture->bitmapSize);
            }

            entry.copyTextLocally();

            mSize += size;
            mCache.put(entry, texture);
        } else {
            texture->cleanup = true;
        }

        // Cleanup shadow
        delete[] shadow.image;
    }

    return texture;
}
ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
                                        float radius, const float* positions) {
    ShadowText entry(paint, radius, numGlyphs, glyphs, positions);
    ShadowTexture* texture = mCache.get(entry);

    if (!texture) {
        SkPaint paintCopy(*paint);
        paintCopy.setTextAlign(SkPaint::kLeft_Align);
        FontRenderer::DropShadow shadow =
                mRenderer->renderDropShadow(&paintCopy, glyphs, numGlyphs, radius, positions);

        if (!shadow.image) {
            return nullptr;
        }

        Caches& caches = Caches::getInstance();

        texture = new ShadowTexture(caches);
        texture->left = shadow.penX;
        texture->top = shadow.penY;
        texture->generation = 0;
        texture->blend = true;

        const uint32_t size = shadow.width * shadow.height;

        // Don't even try to cache a bitmap that's bigger than the cache
        if (size < mMaxSize) {
            while (mSize + size > mMaxSize) {
                LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(),
                                    "Failed to remove oldest from cache. mSize = %" PRIu32
                                    ", mCache.size() = %zu",
                                    mSize, mCache.size());
            }
        }

        // Textures are Alpha8
        texture->upload(GL_ALPHA, shadow.width, shadow.height, GL_ALPHA, GL_UNSIGNED_BYTE,
                        shadow.image);
        texture->setFilter(GL_LINEAR);
        texture->setWrap(GL_CLAMP_TO_EDGE);

        if (size < mMaxSize) {
            if (mDebugEnabled) {
                ALOGD("Shadow texture created, size = %d", texture->bitmapSize);
            }

            entry.copyTextLocally();

            mSize += texture->objectSize();
            mCache.put(entry, texture);
        } else {
            texture->cleanup = true;
        }

        // Cleanup shadow
        free(shadow.image);
    }

    return texture;
}