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

Commit f7b9e784 authored by Fabrice Di Meglio's avatar Fabrice Di Meglio Committed by Android (Google) Code Review
Browse files

Merge "Add Unicode BiDi Algo before drawing text in Canvas"

parents 95814b02 689e515e
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