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

Commit f296e317 authored by Victoria Lease's avatar Victoria Lease Committed by Android (Google) Code Review
Browse files

Merge "Support RGBA fonts and bitmap fonts (and RGBA bitmap fonts)"

parents 2f3efcf1 1e546815
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9343,6 +9343,7 @@ package android.graphics {
    field public static final int ANTI_ALIAS_FLAG = 1; // 0x1
    field public static final int DEV_KERN_TEXT_FLAG = 256; // 0x100
    field public static final int DITHER_FLAG = 4; // 0x4
    field public static final int EMBEDDED_BITMAP_TEXT_FLAG = 1024; // 0x400
    field public static final int FAKE_BOLD_TEXT_FLAG = 32; // 0x20
    field public static final int FILTER_BITMAP_FLAG = 2; // 0x2
    field public static final int HINTING_OFF = 0; // 0x0
+9 −1
Original line number Diff line number Diff line
@@ -105,9 +105,17 @@ public class Paint {
    public static final int SUBPIXEL_TEXT_FLAG  = 0x80;
    /** bit mask for the flag enabling device kerning for text */
    public static final int DEV_KERN_TEXT_FLAG  = 0x100;
    /** @hide bit mask for the flag enabling subpixel glyph rendering for text */
    public static final int LCD_RENDER_TEXT_FLAG = 0x200;
    /** bit mask for the flag enabling embedded bitmap strikes for text */
    public static final int EMBEDDED_BITMAP_TEXT_FLAG = 0x400;
    /** @hide bit mask for the flag forcing freetype's autohinter on for text */
    public static final int AUTO_HINTING_TEXT_FLAG = 0x800;
    /** @hide bit mask for the flag enabling vertical rendering for text */
    public static final int VERTICAL_TEXT_FLAG = 0x1000;

    // we use this when we first create a paint
    static final int DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG;
    static final int DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG;

    /**
     * Option for {@link #setHinting}: disable hinting.
+8 −3
Original line number Diff line number Diff line
@@ -256,8 +256,12 @@ void Caches::dumpMemoryUsage(String8 &log) {
    log.appendFormat("  PatchCache           %8d / %8d\n",
            patchCache.getSize(), patchCache.getMaxSize());
    for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
        const uint32_t size = fontRenderer->getFontRendererSize(i);
        log.appendFormat("  FontRenderer %d       %8d / %8d\n", i, size, size);
        const uint32_t sizeA8 = fontRenderer->getFontRendererSize(i, GL_ALPHA);
        const uint32_t sizeRGBA = fontRenderer->getFontRendererSize(i, GL_RGBA);
        log.appendFormat("  FontRenderer %d A8    %8d / %8d\n", i, sizeA8, sizeA8);
        log.appendFormat("  FontRenderer %d RGBA  %8d / %8d\n", i, sizeRGBA, sizeRGBA);
        log.appendFormat("  FontRenderer %d total %8d / %8d\n", i, sizeA8 + sizeRGBA,
                sizeA8 + sizeRGBA);
    }
    log.appendFormat("Other:\n");
    log.appendFormat("  FboCache             %8d / %8d\n",
@@ -272,7 +276,8 @@ void Caches::dumpMemoryUsage(String8 &log) {
    total += dropShadowCache.getSize();
    total += patchCache.getSize();
    for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
        total += fontRenderer->getFontRendererSize(i);
        total += fontRenderer->getFontRendererSize(i, GL_ALPHA);
        total += fontRenderer->getFontRendererSize(i, GL_RGBA);
    }

    log.appendFormat("Total memory usage:\n");
+216 −81
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@

#include <cutils/properties.h>

#include <utils/Functor.h>
#include <utils/Log.h>

#ifdef ANDROID_ENABLE_RENDERSCRIPT
@@ -35,6 +34,7 @@
#include "Debug.h"
#include "Extensions.h"
#include "FontRenderer.h"
#include "OpenGLRenderer.h"
#include "PixelBuffer.h"
#include "Rect.h"

@@ -44,6 +44,52 @@ namespace uirenderer {
// blur inputs smaller than this constant will bypass renderscript
#define RS_MIN_INPUT_CUTOFF 10000

///////////////////////////////////////////////////////////////////////////////
// TextSetupFunctor
///////////////////////////////////////////////////////////////////////////////
status_t TextSetupFunctor::operator ()(int what, void* data) {
    Data* typedData = reinterpret_cast<Data*>(data);
    GLenum glyphFormat = typedData ? typedData->glyphFormat : GL_ALPHA;

    renderer->setupDraw();
    renderer->setupDrawTextGamma(paint);
    renderer->setupDrawDirtyRegionsDisabled();
    renderer->setupDrawWithTexture(glyphFormat == GL_ALPHA);
    switch (glyphFormat) {
        case GL_ALPHA: {
            renderer->setupDrawAlpha8Color(paint->getColor(), alpha);
            break;
        }
        case GL_RGBA: {
            float floatAlpha = alpha / 255.0f;
            renderer->setupDrawColor(floatAlpha, floatAlpha, floatAlpha, floatAlpha);
            break;
        }
        default: {
#if DEBUG_FONT_RENDERER
            ALOGD("TextSetupFunctor: called with unknown glyph format %x", glyphFormat);
#endif
            break;
        }
    }
    renderer->setupDrawColorFilter();
    renderer->setupDrawShader();
    renderer->setupDrawBlending(true, mode);
    renderer->setupDrawProgram();
    renderer->setupDrawModelView(x, y, x, y, pureTranslate, true);
    // Calling setupDrawTexture with the name 0 will enable the
    // uv attributes and increase the texture unit count
    // texture binding will be performed by the font renderer as
    // needed
    renderer->setupDrawTexture(0);
    renderer->setupDrawPureColorUniforms();
    renderer->setupDrawColorFilterUniforms();
    renderer->setupDrawShaderUniforms(pureTranslate);
    renderer->setupDrawTextGammaUniforms();

    return NO_ERROR;
}

///////////////////////////////////////////////////////////////////////////////
// FontRenderer
///////////////////////////////////////////////////////////////////////////////
@@ -103,11 +149,16 @@ FontRenderer::FontRenderer() :
    sLogFontRendererCreate = false;
}

FontRenderer::~FontRenderer() {
    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
        delete mCacheTextures[i];
void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
        delete cacheTextures[i];
    }
    cacheTextures.clear();
}
    mCacheTextures.clear();

FontRenderer::~FontRenderer() {
    clearCacheTextures(mACacheTextures);
    clearCacheTextures(mRGBACacheTextures);

    LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
    while (it.next()) {
@@ -124,15 +175,19 @@ void FontRenderer::flushAllAndInvalidate() {
        it.value()->invalidateTextureCache();
    }

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

    for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
        mRGBACacheTextures[i]->init();
    }
}

void FontRenderer::flushLargeCaches() {
void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
    // Start from 1; don't deallocate smallest/default texture
    for (uint32_t i = 1; i < mCacheTextures.size(); i++) {
        CacheTexture* cacheTexture = mCacheTextures[i];
    for (uint32_t i = 1; i < cacheTextures.size(); i++) {
        CacheTexture* cacheTexture = cacheTextures[i];
        if (cacheTexture->getPixelBuffer()) {
            cacheTexture->init();
            LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
@@ -144,11 +199,16 @@ void FontRenderer::flushLargeCaches() {
    }
}

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];
void FontRenderer::flushLargeCaches() {
    flushLargeCaches(mACacheTextures);
    flushLargeCaches(mRGBACacheTextures);
}

CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
        const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
        if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
            return cacheTextures[i];
        }
    }
    // Could not fit glyph into current cache textures
@@ -169,9 +229,26 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp

    cachedGlyph->mIsValid = false;

    // choose an appropriate cache texture list for this glyph format
    SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
    Vector<CacheTexture*>* cacheTextures = NULL;
    switch (format) {
        case SkMask::kA8_Format:
            cacheTextures = &mACacheTextures;
            break;
        case SkMask::kARGB32_Format:
            cacheTextures = &mRGBACacheTextures;
            break;
        default:
#if DEBUG_FONT_RENDERER
            ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
#endif
        return;
    }

    // If the glyph is too tall, don't cache it
    if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
                mCacheTextures[mCacheTextures.size() - 1]->getHeight()) {
                (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
        ALOGE("Font size too large to fit in cache. width, height = %i, %i",
                (int) glyph.fWidth, (int) glyph.fHeight);
        return;
@@ -181,14 +258,14 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
    uint32_t startX = 0;
    uint32_t startY = 0;

    CacheTexture* cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);
    CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);

    if (!cacheTexture) {
        if (!precaching) {
            // If the new glyph didn't fit and we are not just trying to precache it,
            // clear out the cache and try again
            flushAllAndInvalidate();
            cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);
            cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
        }

        if (!cacheTexture) {
@@ -216,24 +293,21 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
        cacheTexture->allocateMesh();
    }

    // Tells us whether the glyphs is B&W (1 bit per pixel)
    // or anti-aliased (8 bits per pixel)
    SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);

    uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;

    // Copy the glyph image, taking the mask format into account
    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
    int stride = glyph.rowBytes();

    uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
    memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
    int srcStride = glyph.rowBytes();

    // Copy the glyph image, taking the mask format into account
    switch (format) {
        case SkMask::kA8_Format: {
            uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
            uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
                    - TEXTURE_BORDER_SIZE;
            // write leading border line
            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
            // write glyph data
            if (mGammaTable) {
                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += stride) {
                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
                    row = cacheY * cacheWidth;
                    cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
                    for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
@@ -243,21 +317,55 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
                    cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
                }
            } else {
                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += stride) {
                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
                    row = cacheY * cacheWidth;
                    memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
                    cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
                    cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
                }
            }
            // write trailing border line
            row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
            break;
        }
        case SkMask::kARGB32_Format: {
            // prep data lengths
            const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
            const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
            size_t rowSize = formatSize * glyph.fWidth;
            // prep advances
            size_t dstStride = formatSize * cacheWidth;
            // prep indices
            // - we actually start one row early, and then increment before first copy
            uint8_t* src = &bitmapBuffer[0 - srcStride];
            uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
            uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
            uint8_t* dstL = dst - borderSize;
            uint8_t* dstR = dst + rowSize;
            // write leading border line
            memset(dstL, 0, rowSize + 2 * borderSize);
            // write glyph data
            while (dst < dstEnd) {
                memset(dstL += dstStride, 0, borderSize); // leading border column
                memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
                memset(dstR += dstStride, 0, borderSize); // trailing border column
            }
            // write trailing border line
            memset(dstL, 0, rowSize + 2 * borderSize);
            break;
        }
        case SkMask::kBW_Format: {
            uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
            uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
                    - TEXTURE_BORDER_SIZE;
            static const uint8_t COLORS[2] = { 0, 255 };

            // write leading border line
            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
            // write glyph data
            for (cacheY = startY; cacheY < endY; cacheY++) {
                cacheX = startX;
                int rowBytes = stride;
                int rowBytes = srcStride;
                uint8_t* buffer = bitmapBuffer;

                row = cacheY * cacheWidth;
@@ -270,23 +378,24 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
                }
                cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;

                bitmapBuffer += stride;
                bitmapBuffer += srcStride;
            }
            // write trailing border line
            row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
            break;
        }
        default:
            ALOGW("Unkown glyph format: 0x%x", format);
            ALOGW("Unknown glyph format: 0x%x", format);
            break;
    }

    row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
    memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);

    cachedGlyph->mIsValid = true;
}

CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) {
    CacheTexture* cacheTexture = new CacheTexture(width, height, gMaxNumberOfQuads);
CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
        bool allocate) {
    CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);

    if (allocate) {
        Caches::getInstance().activeTexture(0);
@@ -298,17 +407,23 @@ CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool alloc
}

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

    mUploadTexture = false;
    mCacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true));
    mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, false));
    mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, false));
    mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, false));
    mCurrentCacheTexture = mCacheTextures[0];
    mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
            GL_ALPHA, true));
    mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
            GL_ALPHA, false));
    mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
            GL_ALPHA, false));
    mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
            GL_ALPHA, false));
    mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
            GL_RGBA, false));
    mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
            GL_RGBA, false));
    mCurrentCacheTexture = mACacheTextures[0];
}

// We don't want to allocate anything unless we actually draw text
@@ -322,20 +437,10 @@ void FontRenderer::checkInit() {
    mInitialized = true;
}

void FontRenderer::checkTextureUpdate() {
    if (!mUploadTexture) {
        return;
    }

    Caches& caches = Caches::getInstance();
    GLuint lastTextureId = 0;

    bool resetPixelStore = false;
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    // 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];
void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
        bool& resetPixelStore, GLuint& lastTextureId) {
    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
        CacheTexture* cacheTexture = cacheTextures[i];
        if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
            if (cacheTexture->getTextureId() != lastTextureId) {
                lastTextureId = cacheTexture->getTextureId();
@@ -346,13 +451,24 @@ void FontRenderer::checkTextureUpdate() {
            if (cacheTexture->upload()) {
                resetPixelStore = true;
            }

#if DEBUG_FONT_RENDERER
            ALOGD("glTexSubimage for cacheTexture %d: x, y, width height = %d, %d, %d, %d",
                    i, x, y, width, height);
#endif
        }
    }
}

void FontRenderer::checkTextureUpdate() {
    if (!mUploadTexture) {
        return;
    }

    Caches& caches = Caches::getInstance();
    GLuint lastTextureId = 0;

    bool resetPixelStore = false;
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    // Iterate over all the cache textures and see which ones need to be updated
    checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
    checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);

    // Unbind any PBO we might have used to update textures
    caches.unbindPixelBuffer();
@@ -366,18 +482,18 @@ void FontRenderer::checkTextureUpdate() {
    mUploadTexture = false;
}

void FontRenderer::issueDrawCommand() {
void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
    Caches& caches = Caches::getInstance();
    bool first = true;
    bool force = false;

    GLuint lastId = 0;
    Caches& caches = Caches::getInstance();

    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
        CacheTexture* texture = mCacheTextures[i];
    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
        CacheTexture* texture = cacheTextures[i];
        if (texture->canDraw()) {
            if (first) {
                if (mFunctor) (*mFunctor)(0, NULL);
                if (mFunctor) {
                    TextSetupFunctor::Data functorData(texture->getFormat());
                    (*mFunctor)(0, &functorData);
                }

                checkTextureUpdate();
                caches.bindIndicesBuffer();
@@ -407,6 +523,11 @@ void FontRenderer::issueDrawCommand() {
            texture->resetMesh();
        }
    }
}

void FontRenderer::issueDrawCommand() {
    issueDrawCommand(mACacheTextures);
    issueDrawCommand(mRGBACacheTextures);

    mDrawn = true;
}
@@ -582,13 +703,13 @@ bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *t

bool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text,
        uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path,
        float hOffset, float vOffset, Rect* bounds) {
        float hOffset, float vOffset, Rect* bounds, Functor* functor) {
    if (!mCurrentFont) {
        ALOGE("No font set");
        return false;
    }

    initRender(clip, bounds, NULL);
    initRender(clip, bounds, functor);
    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
    finishRender();

@@ -646,10 +767,10 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int
    delete[] scratch;
}

uint32_t FontRenderer::getCacheSize() const {
static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
    uint32_t size = 0;
    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
        CacheTexture* cacheTexture = mCacheTextures[i];
    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
        CacheTexture* cacheTexture = cacheTextures[i];
        if (cacheTexture && cacheTexture->getPixelBuffer()) {
            size += cacheTexture->getPixelBuffer()->getSize();
        }
@@ -657,5 +778,19 @@ uint32_t FontRenderer::getCacheSize() const {
    return size;
}

uint32_t FontRenderer::getCacheSize(GLenum format) const {
    switch (format) {
        case GL_ALPHA: {
            return calculateCacheSize(mACacheTextures);
        }
        case GL_RGBA: {
            return calculateCacheSize(mRGBACacheTextures);
        }
        default: {
            return 0;
        }
    }
}

}; // namespace uirenderer
}; // namespace android
+44 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#ifndef ANDROID_HWUI_FONT_RENDERER_H
#define ANDROID_HWUI_FONT_RENDERER_H

#include <utils/Functor.h>
#include <utils/LruCache.h>
#include <utils/Vector.h>
#include <utils/StrongPointer.h>
@@ -46,8 +47,40 @@ class Functor;
namespace android {
namespace uirenderer {

class OpenGLRenderer;

///////////////////////////////////////////////////////////////////////////////
// TextSetupFunctor
///////////////////////////////////////////////////////////////////////////////
class TextSetupFunctor: public Functor {
public:
    struct Data {
        Data(GLenum glyphFormat) : glyphFormat(glyphFormat) {
        }

        GLenum glyphFormat;
    };

    TextSetupFunctor(OpenGLRenderer* renderer, float x, float y, bool pureTranslate,
            int alpha, SkXfermode::Mode mode, SkPaint* paint): Functor(),
            renderer(renderer), x(x), y(y), pureTranslate(pureTranslate),
            alpha(alpha), mode(mode), paint(paint) {
    }
    ~TextSetupFunctor() { }

    status_t operator ()(int what, void* data);

    OpenGLRenderer* renderer;
    float x;
    float y;
    bool pureTranslate;
    int alpha;
    SkXfermode::Mode mode;
    SkPaint* paint;
};

///////////////////////////////////////////////////////////////////////////////
// Renderer
// FontRenderer
///////////////////////////////////////////////////////////////////////////////

class FontRenderer {
@@ -55,6 +88,7 @@ public:
    FontRenderer();
    ~FontRenderer();

    void flushLargeCaches(Vector<CacheTexture*>& cacheTextures);
    void flushLargeCaches();

    void setGammaTable(const uint8_t* gammaTable) {
@@ -73,7 +107,8 @@ public:

    // bounds is an out parameter
    bool renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
            uint32_t len, int numGlyphs, SkPath* path, float hOffset, float vOffset, Rect* bounds);
            uint32_t len, int numGlyphs, SkPath* path, float hOffset, float vOffset, Rect* bounds,
            Functor* functor);

    struct DropShadow {
        DropShadow() { };
@@ -100,7 +135,7 @@ public:
        mLinearFiltering = linearFiltering;
    }

    uint32_t getCacheSize() const;
    uint32_t getCacheSize(GLenum format) const;

private:
    friend class Font;
@@ -110,10 +145,11 @@ private:
    void allocateTextureMemory(CacheTexture* cacheTexture);
    void deallocateTextureMemory(CacheTexture* cacheTexture);
    void initTextTexture();
    CacheTexture* createCacheTexture(int width, int height, bool allocate);
    CacheTexture* createCacheTexture(int width, int height, GLenum format, bool allocate);
    void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
            uint32_t *retOriginX, uint32_t *retOriginY, bool precaching);
    CacheTexture* cacheBitmapInTexture(const SkGlyph& glyph, uint32_t* startX, uint32_t* startY);
    CacheTexture* cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures, const SkGlyph& glyph,
            uint32_t* startX, uint32_t* startY);

    void flushAllAndInvalidate();

@@ -121,6 +157,7 @@ private:
    void initRender(const Rect* clip, Rect* bounds, Functor* functor);
    void finishRender();

    void issueDrawCommand(Vector<CacheTexture*>& cacheTextures);
    void issueDrawCommand();
    void appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
            float x2, float y2, float u2, float v2,
@@ -148,7 +185,8 @@ private:
    uint32_t mLargeCacheWidth;
    uint32_t mLargeCacheHeight;

    Vector<CacheTexture*> mCacheTextures;
    Vector<CacheTexture*> mACacheTextures;
    Vector<CacheTexture*> mRGBACacheTextures;

    Font* mCurrentFont;
    LruCache<Font::FontDescription, Font*> mActiveFonts;
Loading