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

Commit 689e515e authored by Fabrice Di Meglio's avatar Fabrice Di Meglio
Browse files

Add Unicode BiDi Algo before drawing text in Canvas

- only for temporary API
- update BiDiTest

Change-Id: Ifd445799dc0fda4da896246e41978cd8d71aa035
parent 0343a7eb
Loading
Loading
Loading
Loading
+27 −33
Original line number Diff line number Diff line
@@ -756,26 +756,36 @@ public:
        env->ReleaseStringChars(text, textArray);
    }

    static void drawTextWithGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
                                      jcharArray text, int index, int count,
                                      jfloat x, jfloat y, int flags, SkPaint* paint) {
        jchar* textArray = env->GetCharArrayElements(text, NULL);
#if RTL_USE_HARFBUZZ && USE_TEXT_LAYOUT_CACHE
        sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
                paint, textArray + index, 0, count, count, flags);
        if (value != NULL) {
#if DEBUG_GLYPHS
    static void logGlyphs(sp<TextLayoutCacheValue> value) {
        LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount());
        for (size_t i = 0; i < value->getGlyphsCount(); i++) {
            LOGD("                          glyphs[%d]=%d", i, value->getGlyphs()[i]);
        }
    }

    static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
            int start, int end,
            jfloat x, jfloat y, int flags, SkPaint* paint) {

        jint count = end - start;
        sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
                paint, textArray, start, count, count, flags);
        if (value == NULL) {
            LOGE("drawTextWithGlyphs -- cannot get Cache value");
            return ;
        }
#if DEBUG_GLYPHS
        logGlyphs(value);
#endif
        doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
                x, y, flags, paint);
    }
#else
        TextLayout::drawText(paint, textArray + index, count, flags, x, y, canvas);
#endif

    static void drawTextWithGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
                                      jcharArray text, int index, int count,
                                      jfloat x, jfloat y, int flags, SkPaint* paint) {
        jchar* textArray = env->GetCharArrayElements(text, NULL);
        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
        env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
    }

@@ -785,23 +795,7 @@ public:
                                          jfloat x, jfloat y, int flags, SkPaint* paint) {

        const jchar* textArray = env->GetStringChars(text, NULL);
#if RTL_USE_HARFBUZZ && USE_TEXT_LAYOUT_CACHE
        size_t count = end - start;
        sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
                paint, textArray, start, count, count, flags);
        if (value != NULL) {
#if DEBUG_GLYPHS
            LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount());
            for (size_t i = 0; i < value->getGlyphsCount(); i++) {
                LOGD("                          glyphs[%d]=%d", i, value->getGlyphs()[i]);
            }
#endif
            doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
                    x, y, flags, paint);
        }
#else
        TextLayout::drawText(paint, textArray + start, end - start, flags, x, y, canvas);
#endif
        drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
        env->ReleaseStringChars(text, textArray);
    }

+1 −1
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ static RtlDebugLevel readRtlDebugLevel() {
#define DEBUG_ADVANCES 0

// Define if we want (1) to have Glyphs debug values or not (0)
#define DEBUG_GLYPHS 0
#define DEBUG_GLYPHS 1

} // namespace android
#endif // ANDROID_RTL_PROPERTIES_H
+17 −17
Original line number Diff line number Diff line
@@ -46,16 +46,6 @@ namespace android {
    static TextLayoutCache gTextLayoutCache;
#endif

class TextLayout {
public:

    enum {
        kDirection_LTR = 0,
        kDirection_RTL = 1,

        kDirection_Mask = 0x1
    };

enum {
    kBidi_LTR = 0,
    kBidi_RTL = 1,
@@ -67,6 +57,16 @@ public:
    kBidi_Mask = 0x7
};

enum {
    kDirection_LTR = 0,
    kDirection_RTL = 1,

    kDirection_Mask = 0x1
};

class TextLayout {
public:

    /*
     * Draws a unidirectional run of text.
     */
+117 −2
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */

#include "TextLayoutCache.h"
#include "TextLayout.h"

namespace android {

@@ -381,13 +382,127 @@ void TextLayoutCacheValue::shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontR
    }
}

struct GlyphRun {
    inline GlyphRun() {}
    inline GlyphRun(jchar* glyphs, size_t glyphsCount, bool isRTL) :
            glyphs(glyphs), glyphsCount(glyphsCount), isRTL(isRTL) { }
    jchar* glyphs;
    size_t glyphsCount;
    int isRTL;
};

void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
        size_t start, size_t count, size_t contextCount, int dirFlags,
        jfloat* outAdvances, jfloat* outTotalAdvance,
        jchar** outGlyphs, size_t* outGlyphsCount) {

        UBiDiLevel bidiReq = 0;
        bool forceLTR = false;
        bool forceRTL = false;

        switch (dirFlags) {
            case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
            case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
            case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
            case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
            case kBidi_Force_LTR: forceLTR = true; break; // every char is LTR
            case kBidi_Force_RTL: forceRTL = true; break; // every char is RTL
        }

        if (forceLTR || forceRTL) {
#if DEBUG_GLYPHS
                    LOGD("computeValuesWithHarfbuzz -- forcing run with LTR=%d RTL=%d",
                            forceLTR, forceRTL);
#endif
            computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
                    outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount);
        } else {
            UBiDi* bidi = ubidi_open();
            if (bidi) {
                UErrorCode status = U_ZERO_ERROR;
                LOGD("computeValuesWithHarfbuzz -- bidiReq=%d", bidiReq);
                ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status);
                if (U_SUCCESS(status)) {
                    int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
                    size_t rc = ubidi_countRuns(bidi, &status);
#if DEBUG_GLYPHS
                    LOGD("computeValuesWithHarfbuzz -- dirFlags=%d run-count=%d paraDir=%d", dirFlags, rc, paraDir);
#endif

                    if (rc == 1 || !U_SUCCESS(status)) {
                        LOGD("HERE !!!");
                        computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount,
                                dirFlags, outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount);
                        ubidi_close(bidi);
                        return;
                    }

                    size_t runIndex = 0;
                    Vector<GlyphRun> glyphRuns;
                    for (size_t i = 0; i < rc; ++i) {
                        int32_t startRun;
                        int32_t lengthRun;
                        UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);

                        int newFlags = (runDir == UBIDI_RTL) ? kDirection_RTL : kDirection_LTR;
                        jfloat runTotalAdvance = 0;
                        jchar* runGlyphs;
                        size_t runGlyphsCount = 0;

#if DEBUG_GLYPHS
                        LOGD("computeValuesWithHarfbuzz -- run-start=%d run-len=%d newFlags=%d",
                                startRun, lengthRun, newFlags);
#endif
                        computeRunValuesWithHarfbuzz(paint, chars, startRun,
                                lengthRun, contextCount, newFlags,
                                outAdvances + runIndex, &runTotalAdvance,
                                &runGlyphs, &runGlyphsCount);

                        runIndex += lengthRun;

                        *outTotalAdvance += runTotalAdvance;
                        *outGlyphsCount += runGlyphsCount;

#if DEBUG_GLYPHS
                        LOGD("computeValuesWithHarfbuzz -- run=%d run-glyphs-count=%d",
                                i, runGlyphsCount);
                        for (size_t j = 0; j < runGlyphsCount; j++) {
                            LOGD("                          -- glyphs[%d]=%d", j, runGlyphs[j]);
                        }
#endif
                        glyphRuns.push(GlyphRun(runGlyphs, runGlyphsCount, newFlags));
                    }

#if DEBUG_GLYPHS
                    LOGD("computeValuesWithHarfbuzz -- total-glyphs-count=%d", *outGlyphsCount);
#endif
                    *outGlyphs = new jchar[*outGlyphsCount];
                    jchar* glyphs = *outGlyphs;
                    for (size_t i = 0; i < glyphRuns.size(); i++) {
                        const GlyphRun& glyphRun = glyphRuns.itemAt(i);
                        if (glyphRun.isRTL) {
                            for (size_t n = 0; n < glyphRun.glyphsCount; n++) {
                                glyphs[glyphRun.glyphsCount - n - 1] = glyphRun.glyphs[n];
                            }
                        } else {
                            memcpy(glyphs, glyphRun.glyphs, glyphRun.glyphsCount * sizeof(jchar));
                        }
                        glyphs += glyphRun.glyphsCount;
                        delete[] glyphRun.glyphs;
                    }
                }
                ubidi_close(bidi);
            }
        }
}

void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
        size_t start, size_t count, size_t contextCount, int dirFlags,
        jfloat* outAdvances, jfloat* outTotalAdvance,
        jchar** outGlyphs, size_t* outGlyphsCount) {

    bool isRTL = dirFlags & 0x1;

    // TODO: need to run BiDi algo here to breakdown the text in several runs
    HB_ShaperItem shaperItem;
    HB_FontRec font;
    FontData fontData;
@@ -397,7 +512,7 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar
#if DEBUG_GLYPHS
    LOGD("HARFBUZZ -- num_glypth=%d - kerning_applied=%d", shaperItem.num_glyphs,
            shaperItem.kerning_applied);
    LOGD("         -- string= '%s'", String8(chars, contextCount).string());
    LOGD("         -- string= '%s'", String8(chars + start, count).string());
    LOGD("         -- isDevKernText=%d", paint->isDevKernText());
#endif

+4 −0
Original line number Diff line number Diff line
@@ -178,6 +178,10 @@ private:
    static void createGlyphArrays(HB_ShaperItem* shaperItem, int size);
    static void resetGlyphArrays(HB_ShaperItem* shaperItem);

    static void computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start,
            size_t count, size_t contextCount, int dirFlags,
            jfloat* outAdvances, jfloat* outTotalAdvance,
            jchar** outGlyphs, size_t* outGlyphsCount);
}; // TextLayoutCacheValue

/**
Loading