Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 378e919c authored by Chet Haase's avatar Chet Haase
Browse files

Remove CacheTextureLine structure from FontRenderer

CacheTextureLine was useful before we were packing the glyph
textures; it allowed simple packing of any particular texture according to
how many lines there were in a texture, and how tall those lines were.
Now that we are packing more efficiently (both horizontally and vertically
in any given texture line), it is more efficient to have
open space in every texture, removing the need for CacheTextureLine (which
now gets in the way since it limits how much can be stored in each line).

This change removes CacheTextureLine and just uses CacheTexture directly,
allowing caching of glyphs anywhere in the open space of each texture. As before,
the packing of these glyphs is determined by the CacheBlock structure, which
is a linked list of open spaces in each CacheTexture.

Change-Id: Id6f628170df0f676f8743ac7de76f2377fc6a012
parent 6b7d46b7
Loading
Loading
Loading
Loading
+73 −147
Original line number Diff line number Diff line
@@ -109,11 +109,11 @@ CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock *blockToRemove)
}

///////////////////////////////////////////////////////////////////////////////
// CacheTextureLine
// CacheTexture
///////////////////////////////////////////////////////////////////////////////

bool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
    if (glyph.fHeight + TEXTURE_BORDER_SIZE > mMaxHeight) {
bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
    if (glyph.fHeight + TEXTURE_BORDER_SIZE > mHeight) {
        return false;
    }

@@ -138,7 +138,7 @@ bool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uin
                roundedUpW = glyphW;
            }
            *retOriginX = cacheBlock->mX;
            *retOriginY = mCurrentRow + cacheBlock->mY;
            *retOriginY = cacheBlock->mY;
            // If this is the remainder space, create a new cache block for this column. Otherwise,
            // adjust the info about this column.
            if (cacheBlock->mY == TEXTURE_BORDER_SIZE) {
@@ -146,10 +146,10 @@ bool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uin
                // Adjust remainder space dimensions
                cacheBlock->mWidth -= roundedUpW;
                cacheBlock->mX += roundedUpW;
                if (mMaxHeight - glyphH >= glyphH) {
                if (mHeight - glyphH >= glyphH) {
                    // There's enough height left over to create a new CacheBlock
                    CacheBlock *newBlock = new CacheBlock(oldX, glyphH, roundedUpW,
                            mMaxHeight - glyphH);
                            mHeight - glyphH);
#if DEBUG_FONT_RENDERER
                    ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d",
                            newBlock, newBlock->mX, newBlock->mY,
@@ -213,10 +213,10 @@ Font::~Font() {
    }
}

void Font::invalidateTextureCache(CacheTextureLine *cacheLine) {
void Font::invalidateTextureCache(CacheTexture *cacheTexture) {
    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
        CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i);
        if (cacheLine == NULL || cachedGlyph->mCachedTextureLine == cacheLine) {
        if (cacheTexture == NULL || cachedGlyph->mCacheTexture == cacheTexture) {
            cachedGlyph->mIsValid = false;
        }
    }
@@ -260,7 +260,7 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
    mState->appendMeshQuad(nPenX, nPenY, u1, v2,
            nPenX + width, nPenY, u2, v2,
            nPenX + width, nPenY - height, u2, v1,
            nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture);
            nPenX, nPenY - height, u1, v1, glyph->mCacheTexture);
}

void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
@@ -271,7 +271,7 @@ void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
    uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
    uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;

    CacheTexture *cacheTexture = glyph->mCachedTextureLine->mCacheTexture;
    CacheTexture *cacheTexture = glyph->mCacheTexture;
    uint32_t cacheWidth = cacheTexture->mWidth;
    const uint8_t* cacheBuffer = cacheTexture->mTexture;

@@ -325,7 +325,7 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float
            position->fY + destination[2].fY, u2, v1,
            position->fX + destination[3].fX,
            position->fY + destination[3].fY, u1, v1,
            glyph->mCachedTextureLine->mCacheTexture);
            glyph->mCacheTexture);
}

CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
@@ -556,8 +556,8 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
    glyph->mBitmapWidth = skiaGlyph.fWidth;
    glyph->mBitmapHeight = skiaGlyph.fHeight;

    uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth;
    uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight;
    uint32_t cacheWidth = glyph->mCacheTexture->mWidth;
    uint32_t cacheHeight = glyph->mCacheTexture->mHeight;

    glyph->mBitmapMinU = startX / (float) cacheWidth;
    glyph->mBitmapMinV = startY / (float) cacheHeight;
@@ -620,10 +620,6 @@ FontRenderer::FontRenderer() {
    mTextMeshPtr = NULL;
    mCurrentCacheTexture = NULL;
    mLastCacheTexture = NULL;
    mCacheTextureSmall = NULL;
    mCacheTexture128 = NULL;
    mCacheTexture256 = NULL;
    mCacheTexture512 = NULL;

    mLinearFiltering = false;

@@ -659,10 +655,10 @@ FontRenderer::FontRenderer() {
}

FontRenderer::~FontRenderer() {
    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
        delete mCacheLines[i];
    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
        delete mCacheTextures[i];
    }
    mCacheLines.clear();
    mCacheTextures.clear();

    if (mInitialized) {
        // Unbinding the buffer shouldn't be necessary but it crashes with some drivers
@@ -670,10 +666,6 @@ FontRenderer::~FontRenderer() {
        glDeleteBuffers(1, &mIndexBufferID);

        delete[] mTextMeshPtr;
        delete mCacheTextureSmall;
        delete mCacheTexture128;
        delete mCacheTexture256;
        delete mCacheTexture512;
    }

    Vector<Font*> fontsToDereference = mActiveFonts;
@@ -692,29 +684,19 @@ void FontRenderer::flushAllAndInvalidate() {
        mActiveFonts[i]->invalidateTextureCache();
    }

    uint16_t totalGlyphs = 0;
    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
        totalGlyphs += mCacheLines[i]->mNumGlyphs;
        mCacheLines[i]->init();
    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
        mCacheTextures[i]->init();
    }

    #if DEBUG_FONT_RENDERER
    uint16_t totalGlyphs = 0;
    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
        totalGlyphs += mCacheTextures[i]->mNumGlyphs;
        // Erase caches, just as a debugging facility
    if (mCacheTextureSmall && mCacheTextureSmall->mTexture) {
        memset(mCacheTextureSmall->mTexture, 0,
                mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight);
    }
    if (mCacheTexture128 && mCacheTexture128->mTexture) {
        memset(mCacheTexture128->mTexture, 0,
                mCacheTexture128->mWidth * mCacheTexture128->mHeight);
    }
    if (mCacheTexture256 && mCacheTexture256->mTexture) {
        memset(mCacheTexture256->mTexture, 0,
                mCacheTexture256->mWidth * mCacheTexture256->mHeight);
        if (mCacheTextures[i]->mTexture) {
            memset(mCacheTextures[i]->mTexture, 0,
                    mCacheTextures[i]->mWidth * mCacheTextures[i]->mHeight);
        }
    if (mCacheTexture512 && mCacheTexture512->mTexture) {
        memset(mCacheTexture512->mTexture, 0,
                mCacheTexture512->mWidth * mCacheTexture512->mHeight);
    }
    ALOGD("Flushing caches: glyphs cached = %d", totalGlyphs);
#endif
@@ -730,40 +712,19 @@ void FontRenderer::deallocateTextureMemory(CacheTexture *cacheTexture) {
}

void FontRenderer::flushLargeCaches() {
    if ((!mCacheTexture128 || !mCacheTexture128->mTexture) &&
            (!mCacheTexture256 || !mCacheTexture256->mTexture) &&
            (!mCacheTexture512 || !mCacheTexture512->mTexture)) {
        // Typical case; no large glyph caches allocated
        return;
    }

    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
        CacheTextureLine* cacheLine = mCacheLines[i];
        if ((cacheLine->mCacheTexture == mCacheTexture128 ||
                cacheLine->mCacheTexture == mCacheTexture256 ||
                cacheLine->mCacheTexture == mCacheTexture512) &&
                cacheLine->mCacheTexture->mTexture != NULL) {
#if DEBUG_FONT_RENDERER
            if (cacheLine->mCacheTexture == mCacheTexture128) {
                ALOGD("flushing cacheTexture128");
            } else if (cacheLine->mCacheTexture == mCacheTexture256) {
                ALOGD("flushing cacheTexture256");
            } else {
                ALOGD("flushing cacheTexture512");
    // Start from 1; don't deallocate smallest/default texture
    for (uint32_t i = 1; i < mCacheTextures.size(); i++) {
        CacheTexture* cacheTexture = mCacheTextures[i];
        if (cacheTexture->mTexture != NULL) {
            cacheTexture->init();
            for (uint32_t j = 0; j < mActiveFonts.size(); j++) {
                mActiveFonts[j]->invalidateTextureCache(cacheTexture);
            }
#endif
            cacheLine->init();
            for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
                mActiveFonts[i]->invalidateTextureCache(cacheLine);
            deallocateTextureMemory(cacheTexture);
        }
    }
}

    deallocateTextureMemory(mCacheTexture128);
    deallocateTextureMemory(mCacheTexture256);
    deallocateTextureMemory(mCacheTexture512);
}

void FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) {
    int width = cacheTexture->mWidth;
    int height = cacheTexture->mHeight;
@@ -789,12 +750,24 @@ void FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) {
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}

CacheTexture* FontRenderer::cacheBitmapInTexture(const SkGlyph& glyph,
        uint32_t* startX, uint32_t* startY) {
    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
        if (mCacheTextures[i]->fitBitmap(glyph, startX, startY)) {
            return mCacheTextures[i];
        }
    }
    // Could not fit glyph into current cache textures
    return NULL;
}

void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
        uint32_t* retOriginX, uint32_t* retOriginY) {
    checkInit();
    cachedGlyph->mIsValid = false;
    // If the glyph is too tall, don't cache it
    if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
    if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
                mCacheTextures[mCacheTextures.size() - 1]->mHeight) {
        ALOGE("Font size too large to fit in cache. width, height = %i, %i",
                (int) glyph.fWidth, (int) glyph.fHeight);
        return;
@@ -804,36 +777,22 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
    uint32_t startX = 0;
    uint32_t startY = 0;

    bool bitmapFit = false;
    CacheTextureLine *cacheLine;
    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
        bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
        if (bitmapFit) {
            cacheLine = mCacheLines[i];
            break;
        }
    }
    CacheTexture* cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);

    // If the new glyph didn't fit, flush the state so far and invalidate everything
    if (!bitmapFit) {
    if (!cacheTexture) {
        flushAllAndInvalidate();

        // Try to fit it again
        for (uint32_t i = 0; i < mCacheLines.size(); i++) {
            bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
            if (bitmapFit) {
                cacheLine = mCacheLines[i];
                break;
            }
        }
        cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);

        // if we still don't fit, something is wrong and we shouldn't draw
        if (!bitmapFit) {
        if (!cacheTexture) {
            return;
        }
    }

    cachedGlyph->mCachedTextureLine = cacheLine;
    cachedGlyph->mCacheTexture = cacheTexture;

    *retOriginX = startX;
    *retOriginY = startY;
@@ -841,9 +800,8 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
    uint32_t endX = startX + glyph.fWidth;
    uint32_t endY = startY + glyph.fHeight;

    uint32_t cacheWidth = cacheLine->mMaxWidth;
    uint32_t cacheWidth = cacheTexture->mWidth;

    CacheTexture* cacheTexture = cacheLine->mCacheTexture;
    if (!cacheTexture->mTexture) {
        // Large-glyph texture memory is allocated only as needed
        allocateTextureMemory(cacheTexture);
@@ -896,17 +854,10 @@ CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool alloc
}

void FontRenderer::initTextTexture() {
    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
        delete mCacheLines[i];
    }
    mCacheLines.clear();

    if (mCacheTextureSmall) {
        delete mCacheTextureSmall;
        delete mCacheTexture128;
        delete mCacheTexture256;
        delete mCacheTexture512;
    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
        delete mCacheTextures[i];
    }
    mCacheTextures.clear();

    // Next, use other, separate caches for large glyphs.
    uint16_t maxWidth = 0;
@@ -918,35 +869,12 @@ void FontRenderer::initTextTexture() {
        maxWidth = MAX_TEXT_CACHE_WIDTH;
    }

    mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true);
    mCacheTexture128 = createCacheTexture(maxWidth, 256, false);
    mCacheTexture256 = createCacheTexture(maxWidth, 256, false);
    mCacheTexture512 = createCacheTexture(maxWidth, 512, false);
    mCurrentCacheTexture = mCacheTextureSmall;

    mUploadTexture = false;
    // Split up our default cache texture into lines of certain widths
    int nextLine = 0;
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, mCacheTextureSmall));
    nextLine += mCacheLines.top()->mMaxHeight;
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, mCacheTextureSmall));
    nextLine += mCacheLines.top()->mMaxHeight;
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, mCacheTextureSmall));
    nextLine += mCacheLines.top()->mMaxHeight;
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, mCacheTextureSmall));
    nextLine += mCacheLines.top()->mMaxHeight;
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, mCacheTextureSmall));
    nextLine += mCacheLines.top()->mMaxHeight;
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, mCacheTextureSmall));
    nextLine += mCacheLines.top()->mMaxHeight;
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine,
            nextLine, mCacheTextureSmall));

    //  The first cache is split into 2 lines of height 128, the rest have just one cache line.
    mCacheLines.push(new CacheTextureLine(maxWidth, 128, 0, mCacheTexture128));
    mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, mCacheTexture128));
    mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, mCacheTexture256));
    mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, mCacheTexture512));
    mCacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true));
    mCacheTextures.push(createCacheTexture(maxWidth, 256, false));
    mCacheTextures.push(createCacheTexture(maxWidth, 256, false));
    mCacheTextures.push(createCacheTexture(maxWidth, 512, false));
    mCurrentCacheTexture = mCacheTextures[0];
}

// Avoid having to reallocate memory and render quad by quad
@@ -1001,16 +929,14 @@ void FontRenderer::checkTextureUpdate() {

    Caches& caches = Caches::getInstance();
    GLuint lastTextureId = 0;
    // Iterate over all the cache lines and see which ones need to be updated
    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
        CacheTextureLine* cl = mCacheLines[i];
        if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) {
            CacheTexture* cacheTexture = cl->mCacheTexture;
    // Iterate over all the cache textures and see which ones need to be updated
    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
        CacheTexture* cacheTexture = mCacheTextures[i];
        if (cacheTexture->mDirty && cacheTexture->mTexture != NULL) {
            uint32_t xOffset = 0;
            uint32_t yOffset = cl->mCurrentRow;
            uint32_t width   = cl->mMaxWidth;
            uint32_t height  = cl->mMaxHeight;
            void* textureData = cacheTexture->mTexture + (yOffset * width);
            uint32_t width   = cacheTexture->mWidth;
            uint32_t height  = cacheTexture->mHeight;
            void* textureData = cacheTexture->mTexture;

            if (cacheTexture->mTextureId != lastTextureId) {
                caches.activeTexture(0);
@@ -1018,13 +944,13 @@ void FontRenderer::checkTextureUpdate() {
                lastTextureId = cacheTexture->mTextureId;
            }
#if DEBUG_FONT_RENDERER
            ALOGD("glTextSubimage for cacheLine %d: xOff, yOff, width height = %d, %d, %d, %d", i,
                    xOffset, yOffset, width, height);
            ALOGD("glTextSubimage for cacheTexture %d: xOff, width height = %d, %d, %d",
                    i, xOffset, width, height);
#endif
            glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height,
            glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, 0, width, height,
                    GL_ALPHA, GL_UNSIGNED_BYTE, textureData);

            cl->mDirty = false;
            cacheTexture->mDirty = false;
        }
    }

+30 −58
Original line number Diff line number Diff line
@@ -61,35 +61,14 @@ namespace uirenderer {

class FontRenderer;

class CacheTexture {
public:
    CacheTexture(uint16_t width, uint16_t height) :
            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
            mLinearFiltering(false) { }
    ~CacheTexture() {
        if (mTexture) {
            delete[] mTexture;
        }
        if (mTextureId) {
            glDeleteTextures(1, &mTextureId);
        }
    }

    uint8_t* mTexture;
    GLuint mTextureId;
    uint16_t mWidth;
    uint16_t mHeight;
    bool mLinearFiltering;
};

/**
 * CacheBlock is a noce in a linked list of current free space areas in a CacheTextureLine.
 * Using CacheBlocks enables us to pack the cache line from top to bottom as well as left to right.
 * CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
 * Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right.
 * When we add a glyph to the cache, we see if it fits within one of the existing columns that
 * have already been started (this is the case if the glyph fits vertically as well as
 * horizontally, and if its width is sufficiently close to the column width to avoid
 * sub-optimal packing of small glyphs into wide columns). If there is no column in which the
 * glyph fits, we check the final node, which is the remaining space in the cache line, creating
 * glyph fits, we check the final node, which is the remaining space in the cache, creating
 * a new column as appropriate.
 *
 * As columns fill up, we remove their CacheBlock from the list to avoid having to check
@@ -122,21 +101,22 @@ struct CacheBlock {
    }
};

class CacheTextureLine {
class CacheTexture {
public:
    CacheTextureLine(uint16_t maxWidth, uint16_t maxHeight, uint32_t currentRow,
            CacheTexture* cacheTexture):
                mMaxHeight(maxHeight),
                mMaxWidth(maxWidth),
                mCurrentRow(currentRow),
                mDirty(false),
                mNumGlyphs(0),
                mCacheTexture(cacheTexture) {
    CacheTexture(uint16_t width, uint16_t height) :
            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
            mLinearFiltering(false), mDirty(false), mNumGlyphs(0) {
        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
                maxWidth - TEXTURE_BORDER_SIZE, maxHeight - TEXTURE_BORDER_SIZE, true);
                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
    }

    ~CacheTextureLine() {
    ~CacheTexture() {
        if (mTexture) {
            delete[] mTexture;
        }
        if (mTextureId) {
            glDeleteTextures(1, &mTextureId);
        }
        reset();
    }

@@ -154,17 +134,18 @@ public:
        // reset, then create a new remainder space to start again
        reset();
        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
                mMaxWidth - TEXTURE_BORDER_SIZE, mMaxHeight - TEXTURE_BORDER_SIZE, true);
                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
    }

    bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY);

    uint16_t mMaxHeight;
    uint16_t mMaxWidth;
    uint32_t mCurrentRow;
    uint8_t* mTexture;
    GLuint mTextureId;
    uint16_t mWidth;
    uint16_t mHeight;
    bool mLinearFiltering;
    bool mDirty;
    uint16_t mNumGlyphs;
    CacheTexture* mCacheTexture;
    CacheBlock* mCacheBlocks;
};

@@ -193,7 +174,7 @@ struct CachedGlyphInfo {
    // Auto-kerning
    SkFixed mLsbDelta;
    SkFixed mRsbDelta;
    CacheTextureLine* mCachedTextureLine;
    CacheTexture* mCacheTexture;
};


@@ -260,7 +241,7 @@ protected:
    // Cache of glyphs
    DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;

    void invalidateTextureCache(CacheTextureLine *cacheLine = NULL);
    void invalidateTextureCache(CacheTexture *cacheTexture = NULL);

    CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph);
    void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph);
@@ -364,17 +345,11 @@ public:

    uint32_t getCacheSize() const {
        uint32_t size = 0;
        if (mCacheTextureSmall != NULL && mCacheTextureSmall->mTexture != NULL) {
            size += mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight;
        }
        if (mCacheTexture128 != NULL && mCacheTexture128->mTexture != NULL) {
            size += mCacheTexture128->mWidth * mCacheTexture128->mHeight;
        }
        if (mCacheTexture256 != NULL && mCacheTexture256->mTexture != NULL) {
            size += mCacheTexture256->mWidth * mCacheTexture256->mHeight;
        for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
            CacheTexture* cacheTexture = mCacheTextures[i];
            if (cacheTexture != NULL && cacheTexture->mTexture != NULL) {
                size += cacheTexture->mWidth * cacheTexture->mHeight;
            }
        if (mCacheTexture512 != NULL && mCacheTexture512->mTexture != NULL) {
            size += mCacheTexture512->mWidth * mCacheTexture512->mHeight;
        }
        return size;
    }
@@ -390,6 +365,7 @@ protected:
    CacheTexture* createCacheTexture(int width, int height, bool allocate);
    void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
            uint32_t *retOriginX, uint32_t *retOriginY);
    CacheTexture* cacheBitmapInTexture(const SkGlyph& glyph, uint32_t* startX, uint32_t* startY);

    void flushAllAndInvalidate();
    void initVertexArrayBuffers();
@@ -415,17 +391,13 @@ protected:
    uint32_t mSmallCacheWidth;
    uint32_t mSmallCacheHeight;

    Vector<CacheTextureLine*> mCacheLines;
    Vector<CacheTexture*> mCacheTextures;

    Font* mCurrentFont;
    Vector<Font*> mActiveFonts;

    CacheTexture* mCurrentCacheTexture;
    CacheTexture* mLastCacheTexture;
    CacheTexture* mCacheTextureSmall;
    CacheTexture* mCacheTexture128;
    CacheTexture* mCacheTexture256;
    CacheTexture* mCacheTexture512;

    void checkTextureUpdate();
    bool mUploadTexture;