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

Commit 726aeba8 authored by Romain Guy's avatar Romain Guy
Browse files

Add support to OpenGLRendere to draw BiDi text.

Bug #4350336

Change-Id: I1cf31693f7ca9653fa3a41b5b91c27ef288d680f
parent f09ef518
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@
#include <SkiaColorFilter.h>
#include <Rect.h>

#include "TextLayout.h"
#include <TextLayout.h>

namespace android {

@@ -419,7 +419,7 @@ static void android_view_GLES20Canvas_setupShadow(JNIEnv* env, jobject clazz,

static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
        jfloat x, jfloat y, int flags, SkPaint* paint) {
#if 0 // TODO: replace "0" by "RTL_USE_HARFBUZZ" when renderer->drawGlyphs() is implemented
#if RTL_USE_HARFBUZZ
    sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
            paint, text, 0, count, count, flags);
    if (value == NULL) {
@@ -431,7 +431,8 @@ static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
#endif
    const jchar* glyphArray = value->getGlyphs();
    int glyphCount = value->getGlyphsCount();
    renderer->drawGlyphs((const char*) glyphArray, 0, glyphCount << 1, x, y, paint);
    int bytesCount = glyphCount * sizeof(jchar);
    renderer->drawText((const char*) glyphArray, bytesCount, glyphCount, x, y, paint);
#else
    const jchar *workText;
    jchar* buffer = NULL;
@@ -446,7 +447,7 @@ static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
        jint start, jint count, jint contextCount, jfloat x, jfloat y,
        int flags, SkPaint* paint) {
#if 0 // TODO: replace "0" by "RTL_USE_HARFBUZZ" when renderer->drawGlyphs() is implemented
#if RTL_USE_HARFBUZZ
    sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
            paint, text, start, count, contextCount, flags);
    if (value == NULL) {
@@ -458,7 +459,8 @@ static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
#endif
    const jchar* glyphArray = value->getGlyphs();
    int glyphCount = value->getGlyphsCount();
    renderer->drawGlyphs((const char*) glyphArray, 0, glyphCount << 1, x, y, paint);
    int bytesCount = glyphCount * sizeof(jchar);
    renderer->drawText((const char*) glyphArray, bytesCount, glyphCount, x, y, paint);
#else
    uint8_t rtl = flags & 0x1;
    if (rtl) {
+1 −0
Original line number Diff line number Diff line
@@ -1151,6 +1151,7 @@ void DisplayListRenderer::drawPoints(float* points, int count, SkPaint* paint) {

void DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
        float x, float y, SkPaint* paint) {
    if (count <= 0) return;
    addOp(DisplayList::DrawText);
    addText(text, bytesCount);
    addInt(count);
+22 −21
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ 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

@@ -58,8 +59,7 @@ Font::~Font() {
    }

    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
        CachedGlyphInfo* glyph = mCachedGlyphs.valueAt(i);
        delete glyph;
        delete mCachedGlyphs.valueAt(i);
    }
}

@@ -134,48 +134,49 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,

}

Font::CachedGlyphInfo* Font::getCachedUTFChar(SkPaint* paint, int32_t utfChar) {
Font::CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
    CachedGlyphInfo* cachedGlyph = NULL;
    ssize_t index = mCachedGlyphs.indexOfKey(utfChar);
    ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
    if (index >= 0) {
        cachedGlyph = mCachedGlyphs.valueAt(index);
    } else {
        cachedGlyph = cacheGlyph(paint, utfChar);
        cachedGlyph = cacheGlyph(paint, textUnit);
    }

    // Is the glyph still in texture cache?
    if (!cachedGlyph->mIsValid) {
        const SkGlyph& skiaGlyph = paint->getUnicharMetrics(utfChar);
        const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit);
        updateGlyphCache(paint, skiaGlyph, cachedGlyph);
    }

    return cachedGlyph;
}

void Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
        int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
    if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) {
        renderUTF(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
        render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
                bitmapW, bitmapH, NULL);
    } else {
        renderUTF(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 0, 0, NULL);
        render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
                0, 0, NULL);
    }

}

void Font::measureUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
        int numGlyphs, Rect *bounds) {
    if (bounds == NULL) {
        LOGE("No return rectangle provided to measure text");
        return;
    }
    bounds->set(1e6, -1e6, -1e6, 1e6);
    renderUTF(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds);
    render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds);
}

#define SkAutoKern_AdjustF(prev, next) (((next) - (prev) + 32) >> 6 << 16)

void Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
        int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
        uint32_t bitmapW, uint32_t bitmapH,Rect *bounds) {
    if (numGlyphs == 0 || text == NULL || len == 0) {
@@ -195,14 +196,14 @@ void Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t
    text += start;

    while (glyphsLeft > 0) {
        int32_t utfChar = SkUTF16_NextUnichar((const uint16_t**) &text);
        glyph_t glyph = GET_GLYPH(text);

        // Reached the end of the string
        if (utfChar < 0) {
        if (IS_END_OF_STRING(glyph)) {
            break;
        }

        CachedGlyphInfo* cachedGlyph = getCachedUTFChar(paint, utfChar);
        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
        penX += SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta);
        prevRsbDelta = cachedGlyph->mRsbDelta;

@@ -268,11 +269,11 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
    mState->mUploadTexture = true;
}

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

    const SkGlyph& skiaGlyph = paint->getUnicharMetrics(glyph);
    const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
    newGlyph->mGlyphIndex = skiaGlyph.fID;
    newGlyph->mIsValid = false;

@@ -672,7 +673,7 @@ void FontRenderer::precacheLatin(SkPaint* paint) {
    uint32_t remainingCapacity = getRemainingCacheCapacity();
    uint32_t precacheIdx = 0;
    while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
        mCurrentFont->getCachedUTFChar(paint, (int32_t) mLatinPrecache[precacheIdx]);
        mCurrentFont->getCachedGlyph(paint, (int32_t) mLatinPrecache[precacheIdx]);
        remainingCapacity = getRemainingCacheCapacity();
        precacheIdx ++;
    }
@@ -714,7 +715,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
    }

    Rect bounds;
    mCurrentFont->measureUTF(paint, text, startIndex, len, numGlyphs, &bounds);
    mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds);
    uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
    uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
    uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight];
@@ -725,7 +726,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
    int penX = radius - bounds.left;
    int penY = radius - bounds.bottom;

    mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, penX, penY,
    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
            dataBuffer, paddedWidth, paddedHeight);
    blurImage(dataBuffer, paddedWidth, paddedHeight, radius);

@@ -755,7 +756,7 @@ bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text
    mDrawn = false;
    mBounds = bounds;
    mClip = clip;
    mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, x, y);
    mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y);
    mBounds = NULL;

    if (mCurrentQuadIndex != 0) {
+48 −13
Original line number Diff line number Diff line
@@ -33,8 +33,32 @@
namespace android {
namespace uirenderer {

///////////////////////////////////////////////////////////////////////////////
// Defines
///////////////////////////////////////////////////////////////////////////////

#if RENDER_TEXT_AS_GLYPHS
    typedef uint16_t glyph_t;
    #define GET_METRICS(paint, glyph) paint->getGlyphMetrics(glyph)
    #define GET_GLYPH(text) nextGlyph((const uint16_t**) &text)
    #define IS_END_OF_STRING(glyph) false
#else
    typedef SkUnichar glyph_t;
    #define GET_METRICS(paint, glyph) paint->getUnicharMetrics(glyph)
    #define GET_GLYPH(text) SkUTF16_NextUnichar((const uint16_t**) &text)
    #define IS_END_OF_STRING(glyph) glyph < 0
#endif

///////////////////////////////////////////////////////////////////////////////
// Declarations
///////////////////////////////////////////////////////////////////////////////

class FontRenderer;

///////////////////////////////////////////////////////////////////////////////
// Font
///////////////////////////////////////////////////////////////////////////////

/**
 * Represents a font, defined by a Skia font id and a font size. A font is used
 * to generate glyphs and cache them in the FontState.
@@ -51,9 +75,9 @@ public:
     * Renders the specified string of text.
     * If bitmap is specified, it will be used as the render target
     */
    void renderUTF(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
                     int numGlyphs, int x, int y,
                     uint8_t *bitmap = NULL, uint32_t bitmapW = 0, uint32_t bitmapH = 0);
    void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
            int numGlyphs, int x, int y, uint8_t *bitmap = NULL,
            uint32_t bitmapW = 0, uint32_t bitmapH = 0);
    /**
     * Creates a new font associated with the specified font state.
     */
@@ -69,12 +93,11 @@ protected:
        MEASURE,
    };

    void renderUTF(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
                     int numGlyphs, int x, int y, RenderMode mode,
                     uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
                     Rect *bounds);
    void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
            int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
            uint32_t bitmapW, uint32_t bitmapH, Rect *bounds);

    void measureUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
    void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
            int numGlyphs, Rect *bounds);

    struct CachedGlyphInfo {
@@ -107,18 +130,26 @@ protected:
    Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle,
            uint32_t scaleX);

    DefaultKeyedVector<int32_t, CachedGlyphInfo*> mCachedGlyphs;
    // Cache of glyphs
    DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;

    void invalidateTextureCache();

    CachedGlyphInfo* cacheGlyph(SkPaint* paint, int32_t glyph);
    CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph);
    void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo *glyph);
    void measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, Rect *bounds);
    void drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y);
    void drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
            uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH);

    CachedGlyphInfo* getCachedUTFChar(SkPaint* paint, int32_t utfChar);
    CachedGlyphInfo* getCachedGlyph(SkPaint* paint, glyph_t textUnit);

    static glyph_t nextGlyph(const uint16_t** srcPtr) {
        const uint16_t* src = *srcPtr;
        glyph_t g = *src++;
        *srcPtr = src;
        return g;
    }

    FontRenderer* mState;
    uint32_t mFontId;
@@ -128,6 +159,10 @@ protected:
    uint32_t mScaleX;
};

///////////////////////////////////////////////////////////////////////////////
// Renderer
///////////////////////////////////////////////////////////////////////////////

class FontRenderer {
public:
    FontRenderer();
+10 −12
Original line number Diff line number Diff line
@@ -2073,11 +2073,6 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
    drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
}

void OpenGLRenderer::drawGlyphs(const char* glyphs, int index, int count, float x, float y,
        SkPaint* paint) {
    // TODO
}

void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
    if (mSnapshot->isIgnored()) return;

@@ -2230,14 +2225,19 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float
    // Handle underline and strike-through
    uint32_t flags = paint->getFlags();
    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
        SkPaint paintCopy(*paint);
#if RENDER_TEXT_AS_GLYPHS
        paintCopy.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
#endif

        float underlineWidth = length;
        // If length is > 0.0f, we already measured the text for the text alignment
        if (length <= 0.0f) {
            underlineWidth = paint->measureText(text, bytesCount);
            underlineWidth = paintCopy.measureText(text, bytesCount);
        }

        float offsetX = 0;
        switch (paint->getTextAlign()) {
        switch (paintCopy.getTextAlign()) {
            case SkPaint::kCenter_Align:
                offsetX = underlineWidth * 0.5f;
                break;
@@ -2249,8 +2249,7 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float
        }

        if (underlineWidth > 0.0f) {
            const float textSize = paint->getTextSize();
            // TODO: Support stroke width < 1.0f when we have AA lines
            const float textSize = paintCopy.getTextSize();
            const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);

            const float left = x - offsetX;
@@ -2280,10 +2279,9 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float
                points[currentPoint++] = top;
            }

            SkPaint linesPaint(*paint);
            linesPaint.setStrokeWidth(strokeWidth);
            paintCopy.setStrokeWidth(strokeWidth);

            drawLines(&points[0], pointsCount, &linesPaint);
            drawLines(&points[0], pointsCount, &paintCopy);
        }
    }
}
Loading