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

Commit cd1b8d36 authored by Alex Sakhartchouk's avatar Alex Sakhartchouk Committed by Android (Google) Code Review
Browse files

Merge "Adding text metrics to renderscript."

parents 38014763 10825a07
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