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

Commit e829bc0f authored by Chet Haase's avatar Chet Haase Committed by Android (Google) Code Review
Browse files

Merge "Make glyph cache more flexible"

parents ee4d45f3 7de0cb12
Loading
Loading
Loading
Loading
+142 −87
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include "Caches.h"
#include "Debug.h"
#include "FontRenderer.h"
#include "Caches.h"

namespace android {
namespace uirenderer {
@@ -35,10 +36,28 @@ namespace uirenderer {

#define DEFAULT_TEXT_CACHE_WIDTH 1024
#define DEFAULT_TEXT_CACHE_HEIGHT 256

// We should query these values from the GL context
#define MAX_TEXT_CACHE_WIDTH 2048
#define MAX_TEXT_CACHE_HEIGHT 2048
#define TEXTURE_BORDER_SIZE 2

///////////////////////////////////////////////////////////////////////////////
// CacheTextureLine
///////////////////////////////////////////////////////////////////////////////

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

    if (mCurrentCol + glyph.fWidth + TEXTURE_BORDER_SIZE < mMaxWidth) {
        *retOriginX = mCurrentCol + 1;
        *retOriginY = mCurrentRow + 1;
        mCurrentCol += glyph.fWidth + TEXTURE_BORDER_SIZE;
        mDirty = true;
        return true;
    }

    return false;
}

///////////////////////////////////////////////////////////////////////////////
// Font
@@ -108,7 +127,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);
            nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture);
}

void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
@@ -119,8 +138,9 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
    uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
    uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;

    uint32_t cacheWidth = mState->getCacheWidth();
    const uint8_t* cacheBuffer = mState->getTextTextureData();
    CacheTexture *cacheTexture = glyph->mCachedTextureLine->mCacheTexture;
    uint32_t cacheWidth = cacheTexture->mWidth;
    const uint8_t* cacheBuffer = cacheTexture->mTexture;

    uint32_t cacheX = 0, cacheY = 0;
    int32_t bX = 0, bY = 0;
@@ -134,10 +154,9 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
            bitmap[bY * bitmapW + bX] = tempCol;
        }
    }

}

Font::CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
    CachedGlyphInfo* cachedGlyph = NULL;
    ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
    if (index >= 0) {
@@ -246,7 +265,7 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp

    // Get the bitmap for the glyph
    paint->findImage(skiaGlyph);
    glyph->mIsValid = mState->cacheBitmap(skiaGlyph, &startX, &startY);
    mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY);

    if (!glyph->mIsValid) {
        return;
@@ -260,8 +279,8 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
    glyph->mBitmapWidth = skiaGlyph.fWidth;
    glyph->mBitmapHeight = skiaGlyph.fHeight;

    uint32_t cacheWidth = mState->getCacheWidth();
    uint32_t cacheHeight = mState->getCacheHeight();
    uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth;
    uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight;

    glyph->mBitmapMinU = (float) startX / (float) cacheWidth;
    glyph->mBitmapMinV = (float) startY / (float) cacheHeight;
@@ -271,7 +290,7 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
    mState->mUploadTexture = true;
}

Font::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) {
CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) {
    CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
    mCachedGlyphs.add(glyph, newGlyph);

@@ -320,25 +339,29 @@ FontRenderer::FontRenderer() {
    mInitialized = false;
    mMaxNumberOfQuads = 1024;
    mCurrentQuadIndex = 0;
    mTextureId = 0;

    mTextMeshPtr = NULL;
    mTextTexture = NULL;
    mCurrentCacheTexture = NULL;
    mLastCacheTexture = NULL;
    mCacheTextureSmall = NULL;
    mCacheTexture128 = NULL;
    mCacheTexture256 = NULL;
    mCacheTexture512 = NULL;

    mIndexBufferID = 0;

    mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH;
    mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT;
    mSmallCacheWidth = DEFAULT_TEXT_CACHE_WIDTH;
    mSmallCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT;

    char property[PROPERTY_VALUE_MAX];
    if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) {
        if (sLogFontRendererCreate) {
            INIT_LOGD("  Setting text cache width to %s pixels", property);
        }
        mCacheWidth = atoi(property);
        mSmallCacheWidth = atoi(property);
    } else {
        if (sLogFontRendererCreate) {
            INIT_LOGD("  Using default text cache width of %i pixels", mCacheWidth);
            INIT_LOGD("  Using default text cache width of %i pixels", mSmallCacheWidth);
        }
    }

@@ -346,10 +369,10 @@ FontRenderer::FontRenderer() {
        if (sLogFontRendererCreate) {
            INIT_LOGD("  Setting text cache width to %s pixels", property);
        }
        mCacheHeight = atoi(property);
        mSmallCacheHeight = atoi(property);
    } else {
        if (sLogFontRendererCreate) {
            INIT_LOGD("  Using default text cache height of %i pixels", mCacheHeight);
            INIT_LOGD("  Using default text cache height of %i pixels", mSmallCacheHeight);
        }
    }

@@ -364,11 +387,10 @@ FontRenderer::~FontRenderer() {

    if (mInitialized) {
        delete[] mTextMeshPtr;
        delete[] mTextTexture;
    }

    if (mTextureId) {
        glDeleteTextures(1, &mTextureId);
        delete mCacheTextureSmall;
        delete mCacheTexture128;
        delete mCacheTexture256;
        delete mCacheTexture512;
    }

    Vector<Font*> fontsToDereference = mActiveFonts;
@@ -390,20 +412,21 @@ void FontRenderer::flushAllAndInvalidate() {
    }
}

bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
    // If the glyph is too tall, don't cache it
    if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
        if (mCacheHeight < MAX_TEXT_CACHE_HEIGHT) {
            // Default cache not large enough for large glyphs - resize cache to
            // max size and try again
            flushAllAndInvalidate();
            initTextTexture(true);
uint8_t* FontRenderer::allocateTextureMemory(int width, int height) {
    uint8_t* textureMemory = new uint8_t[width * height];
    memset(textureMemory, 0, width * height * sizeof(uint8_t));

    return textureMemory;
}
        if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {

void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
        uint32_t* retOriginX, uint32_t* retOriginY) {
    cachedGlyph->mIsValid = false;
    // If the glyph is too tall, don't cache it
    if (glyph.fHeight + TEXTURE_BORDER_SIZE > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
        LOGE("Font size to large to fit in cache. width, height = %i, %i",
                (int) glyph.fWidth, (int) glyph.fHeight);
            return false;
        }
        return;
    }

    // Now copy the bitmap into the cache texture
@@ -411,9 +434,11 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3
    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;
        }
    }
@@ -426,27 +451,33 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3
        for (uint32_t i = 0; i < mCacheLines.size(); i++) {
            bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
            if (bitmapFit) {
                cacheLine = mCacheLines[i];
                break;
            }
        }

        // if we still don't fit, something is wrong and we shouldn't draw
        if (!bitmapFit) {
            LOGE("Bitmap doesn't fit in cache. width, height = %i, %i",
                    (int) glyph.fWidth, (int) glyph.fHeight);
            return false;
            return;
        }
    }

    cachedGlyph->mCachedTextureLine = cacheLine;

    *retOriginX = startX;
    *retOriginY = startY;

    uint32_t endX = startX + glyph.fWidth;
    uint32_t endY = startY + glyph.fHeight;

    uint32_t cacheWidth = mCacheWidth;
    uint32_t cacheWidth = cacheLine->mMaxWidth;

    uint8_t* cacheBuffer = mTextTexture;
    CacheTexture *cacheTexture = cacheLine->mCacheTexture;
    if (cacheTexture->mTexture == NULL) {
        // Large-glyph texture memory is allocated only as needed
        cacheTexture->mTexture = allocateTextureMemory(cacheTexture->mWidth, cacheTexture->mHeight);
    }
    uint8_t* cacheBuffer = cacheTexture->mTexture;
    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
    unsigned int stride = glyph.rowBytes();

@@ -457,30 +488,17 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3
            cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol];
        }
    }

    return true;
}

void FontRenderer::initTextTexture(bool largeFonts) {
    mCacheLines.clear();
    if (largeFonts) {
        mCacheWidth = MAX_TEXT_CACHE_WIDTH;
        mCacheHeight = MAX_TEXT_CACHE_HEIGHT;
    cachedGlyph->mIsValid = true;
}

    mTextTexture = new uint8_t[mCacheWidth * mCacheHeight];
    memset(mTextTexture, 0, mCacheWidth * mCacheHeight * sizeof(uint8_t));

    mUploadTexture = false;

    if (mTextureId != 0) {
        glDeleteTextures(1, &mTextureId);
    }
    glGenTextures(1, &mTextureId);
    glBindTexture(GL_TEXTURE_2D, mTextureId);
CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) {
    uint8_t* textureMemory = allocate ? allocateTextureMemory(width, height) : NULL;
    GLuint textureId;
    glGenTextures(1, &textureId);
    glBindTexture(GL_TEXTURE_2D, textureId);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    // Initialize texture dimensions
    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0,
    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
            GL_ALPHA, GL_UNSIGNED_BYTE, 0);

    mLinearFiltering = false;
@@ -490,30 +508,55 @@ void FontRenderer::initTextTexture(bool largeFonts) {
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    // Split up our cache texture into lines of certain widths
    return new CacheTexture(textureMemory, textureId, width, height);
}

void FontRenderer::initTextTexture() {
    mCacheLines.clear();

    // Next, use other, separate caches for large glyphs.
    uint16_t maxWidth = 0;
    if (Caches::hasInstance()) {
        maxWidth = Caches::getInstance().maxTextureSize;
    }
    if (maxWidth > MAX_TEXT_CACHE_WIDTH || maxWidth == 0) {
        maxWidth = MAX_TEXT_CACHE_WIDTH;
    }
    if (mCacheTextureSmall != NULL) {
        delete mCacheTextureSmall;
        delete mCacheTexture128;
        delete mCacheTexture256;
        delete mCacheTexture512;
    }
    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(mCacheWidth, 18, nextLine, 0));
    nextLine += mCacheLines.top()->mMaxHeight;
    mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0));
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, 0, mCacheTextureSmall));
    nextLine += mCacheLines.top()->mMaxHeight;
    mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0));
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall));
    nextLine += mCacheLines.top()->mMaxHeight;
    mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0));
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall));
    nextLine += mCacheLines.top()->mMaxHeight;
    mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0));
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall));
    nextLine += mCacheLines.top()->mMaxHeight;
    mCacheLines.push(new CacheTextureLine(mCacheWidth, 42, nextLine, 0));
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall));
    nextLine += mCacheLines.top()->mMaxHeight;
    if (largeFonts) {
        int nextSize = 76;
        // Make several new lines with increasing font sizes
        while (nextSize < (int)(mCacheHeight - nextLine - (2 * nextSize))) {
            mCacheLines.push(new CacheTextureLine(mCacheWidth, nextSize, nextLine, 0));
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, 0, mCacheTextureSmall));
    nextLine += mCacheLines.top()->mMaxHeight;
            nextSize += 50;
        }
    }
    mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0));
    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine,
            nextLine, 0, 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, 0, mCacheTexture128));
    mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, 0, mCacheTexture128));
    mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, 0, mCacheTexture256));
    mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, 0, mCacheTexture512));
}

// Avoid having to reallocate memory and render quad by quad
@@ -568,22 +611,22 @@ void FontRenderer::checkInit() {
}

void FontRenderer::checkTextureUpdate() {
    if (!mUploadTexture) {
    if (!mUploadTexture && mLastCacheTexture == mCurrentCacheTexture) {
        return;
    }

    glBindTexture(GL_TEXTURE_2D, mTextureId);

    // 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) {
        if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) {
            CacheTexture* cacheTexture = cl->mCacheTexture;
            uint32_t xOffset = 0;
            uint32_t yOffset = cl->mCurrentRow;
            uint32_t width   = mCacheWidth;
            uint32_t width   = cl->mMaxWidth;
            uint32_t height  = cl->mMaxHeight;
            void* textureData = mTextTexture + yOffset * width;
            void* textureData = cacheTexture->mTexture + (yOffset * width);

            glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
            glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height,
                    GL_ALPHA, GL_UNSIGNED_BYTE, textureData);

@@ -591,6 +634,9 @@ void FontRenderer::checkTextureUpdate() {
        }
    }

    glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId);
    mLastCacheTexture = mCurrentCacheTexture;

    mUploadTexture = false;
}

@@ -617,12 +663,21 @@ void FontRenderer::issueDrawCommand() {
void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
        float x2, float y2, float u2, float v2,
        float x3, float y3, float u3, float v3,
        float x4, float y4, float u4, float v4) {
        float x4, float y4, float u4, float v4, CacheTexture* texture) {

    if (mClip &&
            (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
        return;
    }
    if (texture != mCurrentCacheTexture) {
        if (mCurrentQuadIndex != 0) {
            // First, draw everything stored already which uses the previous texture
            issueDrawCommand();
            mCurrentQuadIndex = 0;
        }
        // Now use the new texture id
        mCurrentCacheTexture = texture;
    }

    const uint32_t vertsPerQuad = 4;
    const uint32_t floatsPerVert = 4;
+104 −79
Original line number Diff line number Diff line
@@ -55,6 +55,77 @@ namespace uirenderer {

class FontRenderer;

class CacheTexture {
public:
    CacheTexture(){}
    CacheTexture(uint8_t* texture, GLuint textureId, uint16_t width, uint16_t height) :
        mTexture(texture), mTextureId(textureId), mWidth(width), mHeight(height) {}
    ~CacheTexture() {
        if (mTexture != NULL) {
            delete[] mTexture;
        }
        if (mTextureId != 0) {
            glDeleteTextures(1, &mTextureId);
        }
    }

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

class CacheTextureLine {
public:
    CacheTextureLine(uint16_t maxWidth, uint16_t maxHeight, uint32_t currentRow,
            uint32_t currentCol, CacheTexture* cacheTexture):
                mMaxHeight(maxHeight),
                mMaxWidth(maxWidth),
                mCurrentRow(currentRow),
                mCurrentCol(currentCol),
                mDirty(false),
                mCacheTexture(cacheTexture){
    }

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

    uint16_t mMaxHeight;
    uint16_t mMaxWidth;
    uint32_t mCurrentRow;
    uint32_t mCurrentCol;
    bool mDirty;
    CacheTexture *mCacheTexture;
};

struct CachedGlyphInfo {
    // Has the cache been invalidated?
    bool mIsValid;
    // Location of the cached glyph in the bitmap
    // in case we need to resize the texture or
    // render to bitmap
    uint32_t mStartX;
    uint32_t mStartY;
    uint32_t mBitmapWidth;
    uint32_t mBitmapHeight;
    // Also cache texture coords for the quad
    float mBitmapMinU;
    float mBitmapMinV;
    float mBitmapMaxU;
    float mBitmapMaxV;
    // Minimize how much we call freetype
    uint32_t mGlyphIndex;
    uint32_t mAdvanceX;
    uint32_t mAdvanceY;
    // Values below contain a glyph's origin in the bitmap
    int32_t mBitmapLeft;
    int32_t mBitmapTop;
    // Auto-kerning
    SkFixed mLsbDelta;
    SkFixed mRsbDelta;
    CacheTextureLine* mCachedTextureLine;
};


///////////////////////////////////////////////////////////////////////////////
// Font
///////////////////////////////////////////////////////////////////////////////
@@ -101,33 +172,6 @@ protected:
    void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
            int numGlyphs, Rect *bounds);

    struct CachedGlyphInfo {
        // Has the cache been invalidated?
        bool mIsValid;
        // Location of the cached glyph in the bitmap
        // in case we need to resize the texture or
        // render to bitmap
        uint32_t mStartX;
        uint32_t mStartY;
        uint32_t mBitmapWidth;
        uint32_t mBitmapHeight;
        // Also cache texture coords for the quad
        float mBitmapMinU;
        float mBitmapMinV;
        float mBitmapMaxU;
        float mBitmapMaxV;
        // Minimize how much we call freetype
        uint32_t mGlyphIndex;
        uint32_t mAdvanceX;
        uint32_t mAdvanceY;
        // Values below contain a glyph's origin in the bitmap
        int32_t mBitmapLeft;
        int32_t mBitmapTop;
        // Auto-kerning
        SkFixed mLsbDelta;
        SkFixed mRsbDelta;
    };

    Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle,
            uint32_t scaleX, SkPaint::Style style, uint32_t strokeWidth);

@@ -209,19 +253,28 @@ public:
            mLinearFiltering = linearFiltering;
            const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;

            glBindTexture(GL_TEXTURE_2D, mTextureId);
            glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
        }
        return mTextureId;
        return mCurrentCacheTexture->mTextureId;
    }

    uint32_t getCacheWidth() const {
        return mCacheWidth;
    uint32_t getCacheSize() const {
        uint32_t size = 0;
        if (mCacheTextureSmall != NULL && mCacheTextureSmall->mTexture != NULL) {
            size += mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight;
        }

    uint32_t getCacheHeight() const {
        return mCacheHeight;
        if (mCacheTexture128 != NULL && mCacheTexture128->mTexture != NULL) {
            size += mCacheTexture128->mWidth * mCacheTexture128->mHeight;
        }
        if (mCacheTexture256 != NULL && mCacheTexture256->mTexture != NULL) {
            size += mCacheTexture256->mWidth * mCacheTexture256->mHeight;
        }
        if (mCacheTexture512 != NULL && mCacheTexture512->mTexture != NULL) {
            size += mCacheTexture512->mWidth * mCacheTexture512->mHeight;
        }
        return size;
    }

protected:
@@ -229,41 +282,11 @@ protected:

    const uint8_t* mGammaTable;

    struct CacheTextureLine {
        uint16_t mMaxHeight;
        uint16_t mMaxWidth;
        uint32_t mCurrentRow;
        uint32_t mCurrentCol;
        bool mDirty;

        CacheTextureLine(uint16_t maxWidth, uint16_t maxHeight, uint32_t currentRow,
                uint32_t currentCol):
                    mMaxHeight(maxHeight),
                    mMaxWidth(maxWidth),
                    mCurrentRow(currentRow),
                    mCurrentCol(currentCol),
                    mDirty(false) {
        }

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

            if (mCurrentCol + glyph.fWidth + 2 < mMaxWidth) {
                *retOriginX = mCurrentCol + 1;
                *retOriginY = mCurrentRow + 1;
                mCurrentCol += glyph.fWidth + 2;
                mDirty = true;
                return true;
            }

            return false;
        }
    };

    void initTextTexture(bool largeFonts = false);
    bool cacheBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY);
    uint8_t* allocateTextureMemory(int width, int height);
    void initTextTexture();
    CacheTexture *createCacheTexture(int width, int height, bool allocate);
    void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
            uint32_t *retOriginX, uint32_t *retOriginY);

    void flushAllAndInvalidate();
    void initVertexArrayBuffers();
@@ -277,10 +300,10 @@ protected:
    void appendMeshQuad(float x1, float y1, float u1, float v1,
            float x2, float y2, float u2, float v2,
            float x3, float y3, float u3, float v3,
            float x4, float y4, float u4, float v4);
            float x4, float y4, float u4, float v4, CacheTexture* texture);

    uint32_t mCacheWidth;
    uint32_t mCacheHeight;
    uint32_t mSmallCacheWidth;
    uint32_t mSmallCacheHeight;

    Vector<CacheTextureLine*> mCacheLines;
    uint32_t getRemainingCacheCapacity();
@@ -288,12 +311,14 @@ protected:
    Font* mCurrentFont;
    Vector<Font*> mActiveFonts;

    // Texture to cache glyph bitmaps
    uint8_t* mTextTexture;
    const uint8_t* getTextTextureData() const {
        return mTextTexture;
    }
    GLuint mTextureId;
    CacheTexture* mCurrentCacheTexture;
    CacheTexture* mLastCacheTexture;
    CacheTexture* mCacheTextureSmall;
    CacheTexture* mCacheTexture128;
    CacheTexture* mCacheTexture256;
    CacheTexture* mCacheTexture512;


    void checkTextureUpdate();
    bool mUploadTexture;

+1 −1
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ struct GammaFontRenderer {
        FontRenderer* renderer = mRenderers[fontRenderer];
        if (!renderer) return 0;

        return renderer->getCacheHeight() * renderer->getCacheWidth();
        return renderer->getCacheSize();
    }

private: