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

Commit 10825a07 authored by Alex Sakhartchouk's avatar Alex Sakhartchouk
Browse files

Adding text metrics to renderscript.

Change-Id: Ica460525243d714a278e4ad5e436af43e1008e0c
parent c0ed31d7
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -84,8 +84,6 @@ public class RsRenderStatesRS {
    private Allocation mTexTransparent;
    private Allocation mTexChecker;

    private Allocation mAllocPV;

    private Mesh mMbyNMesh;
    private Mesh mTorus;

@@ -95,7 +93,6 @@ public class RsRenderStatesRS {
    Font mFontSerifItalic;
    Font mFontSerifBoldItalic;
    Font mFontMono;

    private Allocation mTextAlloc;

    private ScriptC_rsrenderstates mScript;
@@ -267,12 +264,15 @@ public class RsRenderStatesRS {
        mFontSerifBoldItalic = Font.createFromFamily(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8);
        mFontMono = Font.createFromFamily(mRS, mRes, "mono", Font.Style.NORMAL, 8);

        mTextAlloc = Allocation.createFromString(mRS, "String from allocation");

        mScript.set_gFontSans(mFontSans);
        mScript.set_gFontSerif(mFontSerif);
        mScript.set_gFontSerifBold(mFontSerifBold);
        mScript.set_gFontSerifItalic(mFontSerifItalic);
        mScript.set_gFontSerifBoldItalic(mFontSerifBoldItalic);
        mScript.set_gFontMono(mFontMono);
        mScript.set_gTextAlloc(mTextAlloc);
    }

    private void initMesh() {
+44 −2
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ rs_font gFontSerifBold;
rs_font gFontSerifItalic;
rs_font gFontSerifBoldItalic;
rs_font gFontMono;
rs_allocation gTextAlloc;

int gDisplayMode;

@@ -70,7 +71,7 @@ rs_program_fragment gProgFragmentMultitex;
#pragma rs export_var(gProgStoreBlendNoneDepth, gProgStoreBlendNone, gProgStoreBlendAlpha, gProgStoreBlendAdd)
#pragma rs export_var(gTexOpaque, gTexTorus, gTexTransparent, gTexChecker)
#pragma rs export_var(gMbyNMesh, gTorusMesh)
#pragma rs export_var(gFontSans, gFontSerif, gFontSerifBold, gFontSerifItalic, gFontSerifBoldItalic, gFontMono)
#pragma rs export_var(gFontSans, gFontSerif, gFontSerifBold, gFontSerifItalic, gFontSerifBoldItalic, gFontMono, gTextAlloc)
#pragma rs export_var(gLinearClamp, gLinearWrap, gMipLinearWrap, gMipLinearAniso8, gMipLinearAniso15, gNearestClamp)
#pragma rs export_var(gCullBack, gCullFront, gCullNone)
#pragma rs export_var(gVSConstants, gFSConstants, gVSInputs, gProgVertexCustom, gProgFragmentCustom, gProgFragmentMultitex)
@@ -85,7 +86,7 @@ void init() {

void displayFontSamples() {
    rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
    int yPos = 30;
    int yPos = 100;
    rsgBindFont(gFontSans);
    rsgDrawText("Sans font sample", 30, yPos);
    yPos += 30;
@@ -107,6 +108,47 @@ void displayFontSamples() {
    yPos += 30;
    rsgBindFont(gFontMono);
    rsgDrawText("Monospace font sample", 30, yPos);
    yPos += 50;

    // Now use text metrics to center the text
    uint width = rsgGetWidth();
    uint height = rsgGetHeight();
    int left = 0, right = 0, top = 0, bottom = 0;

    rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f);
    rsgBindFont(gFontSerifBoldItalic);

    rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom);
    int centeredPos = width / 2 - (right - left) / 2;
    rsgDrawText(gTextAlloc, centeredPos, yPos);
    yPos += 30;

    const char* text = "Centered Text Sample";
    rsgMeasureText(text, &left, &right, &top, &bottom);
    centeredPos = width / 2 - (right - left) / 2;
    rsgDrawText(text, centeredPos, yPos);
    yPos += 30;

    rsgBindFont(gFontSans);
    text = "More Centered Text Samples";
    rsgMeasureText(text, &left, &right, &top, &bottom);
    centeredPos = width / 2 - (right - left) / 2;
    rsgDrawText(text, centeredPos, yPos);
    yPos += 30;

    // Now draw bottom and top right aligned text
    text = "Top-right aligned text";
    rsgMeasureText(text, &left, &right, &top, &bottom);
    rsgDrawText(text, width - right, top);

    text = "Top-left";
    rsgMeasureText(text, &left, &right, &top, &bottom);
    rsgDrawText(text, -left, top);

    text = "Bottom-right aligned text";
    rsgMeasureText(text, &left, &right, &top, &bottom);
    rsgDrawText(text, width - right, height + bottom);

}

void bindProgramVertexOrtho() {
+5 −5
Original line number Diff line number Diff line
@@ -258,14 +258,14 @@ void Context::displayDebugStats()
    sprintf(buffer, "Frame %i ms, Script %i ms", mTimeMSLastFrame, mTimeMSLastScript);
    float oldR, oldG, oldB, oldA;
    mStateFont.getFontColor(&oldR, &oldG, &oldB, &oldA);
    uint32_t bufferLen = strlen(buffer);

    float shadowCol = 0.2f;
    float shadowCol = 0.1f;
    mStateFont.setFontColor(shadowCol, shadowCol, shadowCol, 1.0f);
    mStateFont.renderText(buffer, 5, getHeight() - 5);
    mStateFont.renderText(buffer, bufferLen, 5, getHeight() - 5);

    float textCol = 0.9f;
    mStateFont.setFontColor(textCol, textCol, textCol, 1.0f);
    mStateFont.renderText(buffer, 4, getHeight() - 6);
    mStateFont.setFontColor(1.0f, 0.7f, 0.0f, 1.0f);
    mStateFont.renderText(buffer, bufferLen, 4, getHeight() - 6);

    mStateFont.setFontColor(oldR, oldG, oldB, oldA);
}
+104 −52
Original line number Diff line number Diff line
@@ -84,34 +84,95 @@ void Font::invalidateTextureCache()
    }
}

void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y)
void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y)
{
    FontState *state = &mRSC->mStateFont;

    int nPenX = x + glyph->mBitmapLeft;
    int nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
    int32_t nPenX = x + glyph->mBitmapLeft;
    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;

    state->appendMeshQuad(nPenX, nPenY, 0,
                            glyph->mBitmapMinU, glyph->mBitmapMaxV,
    float u1 = glyph->mBitmapMinU;
    float u2 = glyph->mBitmapMaxU;
    float v1 = glyph->mBitmapMinV;
    float v2 = glyph->mBitmapMaxV;

                            nPenX + (int)glyph->mBitmapWidth, nPenY, 0,
                            glyph->mBitmapMaxU, glyph->mBitmapMaxV,
    int32_t width = (int32_t) glyph->mBitmapWidth;
    int32_t height = (int32_t) glyph->mBitmapHeight;

                            nPenX + (int)glyph->mBitmapWidth, nPenY - (int)glyph->mBitmapHeight, 0,
                            glyph->mBitmapMaxU, glyph->mBitmapMinV,
    state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
                          nPenX + width, nPenY, 0, u2, v2,
                          nPenX + width, nPenY - height, 0, u2, v1,
                          nPenX, nPenY - height, 0, u1, v1);
}

void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
                           uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
    int32_t nPenX = x + glyph->mBitmapLeft;
    int32_t nPenY = y + glyph->mBitmapTop;

    uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
    uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;

    FontState *state = &mRSC->mStateFont;
    uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
    const uint8_t* cacheBuffer = state->getTextTextureData();

    uint32_t cacheX = 0, cacheY = 0;
    int32_t bX = 0, bY = 0;
    for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
        for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
                LOGE("Skipping invalid index");
                continue;
            }
            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
            bitmap[bY * bitmapW + bX] = tempCol;
        }
    }

                            nPenX, nPenY - (int)glyph->mBitmapHeight, 0,
                            glyph->mBitmapMinU, glyph->mBitmapMinV);
}

void Font::renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y)
void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
    int32_t nPenX = x + glyph->mBitmapLeft;
    int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;

    int32_t width = (int32_t) glyph->mBitmapWidth;
    int32_t height = (int32_t) glyph->mBitmapHeight;

    if (bounds->bottom > nPenY) {
        bounds->bottom = nPenY;
    }
    if (bounds->left > nPenX) {
        bounds->left = nPenX;
    }
    if (bounds->right < nPenX + width) {
        bounds->right = nPenX + width;
    }
    if (bounds->top < nPenY + height) {
        bounds->top = nPenY + height;
    }
}

void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
                     uint32_t start, int32_t numGlyphs,
                     RenderMode mode, Rect *bounds,
                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
{
    if(!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
        return;
    }

    int penX = x, penY = y;
    int glyphsLeft = 1;
    if(mode == Font::MEASURE) {
        if (bounds == NULL) {
            LOGE("No return rectangle provided to measure text");
            return;
        }
        // Reset min and max of the bounding box to something large
        bounds->set(1e6, -1e6, -1e6, 1e6);
    }

    int32_t penX = x, penY = y;
    int32_t glyphsLeft = 1;
    if(numGlyphs > 0) {
        glyphsLeft = numGlyphs;
    }
@@ -135,7 +196,17 @@ void Font::renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyp

        // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
        if(cachedGlyph->mIsValid) {
            switch(mode) {
            case FRAMEBUFFER:
                drawCachedGlyph(cachedGlyph, penX, penY);
                break;
            case BITMAP:
                drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
                break;
            case MEASURE:
                measureCachedGlyph(cachedGlyph, penX, penY, bounds);
                break;
            }
        }

        penX += (cachedGlyph->mAdvance.x >> 6);
@@ -283,7 +354,7 @@ FontState::FontState()
    }

    // Get the black gamma threshold
    int blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
    int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
    if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
        LOGD("  Setting text black gamma threshold to %s", property);
        blackThreshold = atoi(property);
@@ -294,7 +365,7 @@ FontState::FontState()
    mBlackThreshold = (float)(blackThreshold) / 255.0f;

    // Get the white gamma threshold
    int whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
    int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
    if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
        LOGD("  Setting text white gamma threshold to %s", property);
        whiteThreshold = atoi(property);
@@ -397,13 +468,13 @@ bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *r

    uint32_t cacheWidth = getCacheTextureType()->getDimX();

    unsigned char *cacheBuffer = (unsigned char*)mTextTexture->getPtr();
    unsigned char *bitmapBuffer = bitmap->buffer;
    uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
    uint8_t *bitmapBuffer = bitmap->buffer;

    uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
    for(cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
        for(cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
            unsigned char tempCol = bitmapBuffer[bY * bitmap->width + bX];
            uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
            cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
        }
    }
@@ -487,7 +558,7 @@ void FontState::initTextTexture()
    mTextTexture->deferedUploadToTexture(mRSC, false, 0);

    // Split up our cache texture into lines of certain widths
    int nextLine = 0;
    int32_t nextLine = 0;
    mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
    nextLine += mCacheLines.top()->mMaxHeight;
    mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
@@ -519,8 +590,8 @@ void FontState::initVertexArrayBuffers()

    // Four verts, two triangles , six indices per quad
    for(uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
        int i6 = i * 6;
        int i4 = i * 4;
        int32_t i6 = i * 6;
        int32_t i4 = i * 4;

        indexPtr[i6 + 0] = i4 + 0;
        indexPtr[i6 + 1] = i4 + 1;
@@ -713,7 +784,11 @@ void FontState::precacheLatin(Font *font) {
}


void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y)
void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
                           uint32_t startIndex, int32_t numGlyphs,
                           Font::RenderMode mode,
                           Font::Rect *bounds,
                           uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH)
{
    checkInit();

@@ -730,7 +805,8 @@ void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex,
        return;
    }

    currentFont->renderUTF(text, len, startIndex, numGlyphs, x, y);
    currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
                           mode, bounds, bitmap, bitmapW, bitmapH);

    if(mCurrentQuadIndex != 0) {
        issueDrawCommand();
@@ -738,32 +814,8 @@ void FontState::renderText(const char *text, uint32_t len, uint32_t startIndex,
    }
}

void FontState::renderText(const char *text, int x, int y)
{
    size_t textLen = strlen(text);
    renderText(text, textLen, 0, -1, x, y);
}

void FontState::renderText(Allocation *alloc, int x, int y)
{
    if(!alloc) {
        return;
    }

    const char *text = (const char *)alloc->getPtr();
    size_t allocSize = alloc->getType()->getSizeBytes();
    renderText(text, allocSize, 0, -1, x, y);
}

void FontState::renderText(Allocation *alloc, uint32_t start, int len, int x, int y)
{
    if(!alloc) {
        return;
    }

    const char *text = (const char *)alloc->getPtr();
    size_t allocSize = alloc->getType()->getSizeBytes();
    renderText(text, allocSize, start, len, x, y);
void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
    renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
}

void FontState::setFontColor(float r, float g, float b, float a) {
@@ -773,7 +825,7 @@ void FontState::setFontColor(float r, float g, float b, float a) {
    mConstants.mFontColor[3] = a;

    mConstants.mGamma = 1.0f;
    const int luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
    const int32_t luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
    if (luminance <= mBlackThreshold) {
        mConstants.mGamma = mBlackGamma;
    } else if (luminance >= mWhiteThreshold) {
+41 −10
Original line number Diff line number Diff line
@@ -45,12 +45,26 @@ class FontState;
class Font : public ObjectBase
{
public:
    ~Font();
    enum RenderMode {
        FRAMEBUFFER,
        BITMAP,
        MEASURE,
    };

    // Pointer to the utf data, length of data, where to start, number of glyphs ot read
    // (each glyph may be longer than a char because we are dealing with utf data)
    // Last two variables are the initial pen position
    void renderUTF(const char *text, uint32_t len, uint32_t start, int numGlyphs, int x, int y);
    struct Rect {
        int32_t left;
        int32_t top;
        int32_t right;
        int32_t bottom;
        void set(int32_t l, int32_t r, int32_t t, int32_t b) {
            left = l;
            right = r;
            top = t;
            bottom = b;
        }
    };

    ~Font();

    // Currently files do not get serialized,
    // but we need to inherit from ObjectBase for ref tracking
@@ -66,6 +80,14 @@ protected:

    friend class FontState;

    // Pointer to the utf data, length of data, where to start, number of glyphs ot read
    // (each glyph may be longer than a char because we are dealing with utf data)
    // Last two variables are the initial pen position
    void renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
                   uint32_t start, int32_t numGlyphs,
                   RenderMode mode = FRAMEBUFFER, Rect *bounds = NULL,
                   uint8_t *bitmap = NULL, uint32_t bitmapW = 0, uint32_t bitmapH = 0);

    void invalidateTextureCache();
    struct CachedGlyphInfo
    {
@@ -106,7 +128,10 @@ protected:

    CachedGlyphInfo *cacheGlyph(uint32_t glyph);
    void updateGlyphCache(CachedGlyphInfo *glyph);
    void drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y);
    void measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds);
    void drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y);
    void drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y,
                         uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH);
};

class FontState
@@ -121,10 +146,13 @@ public:
    ObjectBaseRef<Font> mDefault;
    ObjectBaseRef<Font> mLast;

    void renderText(const char *text, uint32_t len, uint32_t startIndex, int numGlyphs, int x, int y);
    void renderText(const char *text, int x, int y);
    void renderText(Allocation *alloc, int x, int y);
    void renderText(Allocation *alloc, uint32_t start, int len, int x, int y);
    void renderText(const char *text, uint32_t len, int32_t x, int32_t y,
                    uint32_t startIndex = 0, int numGlyphs = -1,
                    Font::RenderMode mode = Font::FRAMEBUFFER,
                    Font::Rect *bounds = NULL,
                    uint8_t *bitmap = NULL, uint32_t bitmapW = 0, uint32_t bitmapH = 0);

    void measureText(const char *text, uint32_t len, Font::Rect *bounds);

    void setFontColor(float r, float g, float b, float a);
    void getFontColor(float *r, float *g, float *b, float *a) const;
@@ -198,6 +226,9 @@ protected:
    // Texture to cache glyph bitmaps
    ObjectBaseRef<Allocation> mTextTexture;
    void initTextTexture();
    const uint8_t* getTextTextureData() const {
        return (uint8_t*)mTextTexture->getPtr();
    }

    bool cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY);
    const Type* getCacheTextureType() {
Loading