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

Commit f2114d56 authored by Raph Levien's avatar Raph Levien
Browse files

Better Minikin integration

This patch improves the Minikin integration in a number of ways,
including:

Software rendering does text decorations and handles alignment
correctly. This fixes bug 15139067 "Centered text isn't working".

Paint implements getTextPath. This fixes bug 15143354 "Text rendering in
Maps Navigation wrong typeface?"

Also a bit of refactoring, since there was duplicated code for iterating
font runs that's now a static method in MinikinUtils.

Change-Id: I4cfdb2c0559982376348325a757d95235fab1768
parent 1b3718ee
Loading
Loading
Loading
Loading
+38 −25
Original line number Diff line number Diff line
@@ -821,32 +821,45 @@ public:
    }

#ifdef USE_MINIKIN
    static void drawGlyphsToSkia(SkCanvas* canvas, SkPaint* paint, Layout* layout, float x, float y) {
        size_t nGlyphs = layout->nGlyphs();
    class DrawTextFunctor {
    public:
        DrawTextFunctor(const Layout& layout, SkCanvas* canvas, jfloat x, jfloat y, SkPaint* paint,
                    uint16_t* glyphs, SkPoint* pos)
                : layout(layout), canvas(canvas), x(x), y(y), paint(paint), glyphs(glyphs),
                    pos(pos) { }

        void operator()(SkTypeface* t, size_t start, size_t end) {
            for (size_t i = start; i < end; i++) {
                glyphs[i] = layout.getGlyphId(i);
                pos[i].fX = x + layout.getX(i);
                pos[i].fY = y + layout.getY(i);
            }
            paint->setTypeface(t);
            canvas->drawPosText(glyphs + start, (end - start) << 1, pos + start, *paint);
        }
    private:
        const Layout& layout;
        SkCanvas* canvas;
        jfloat x;
        jfloat y;
        SkPaint* paint;
        uint16_t* glyphs;
        SkPoint* pos;
    };

    static void drawGlyphsToSkia(SkCanvas* canvas, SkPaint* paint, const Layout& layout, float x, float y) {
        size_t nGlyphs = layout.nGlyphs();
        uint16_t* glyphs = new uint16_t[nGlyphs];
        SkPoint* pos = new SkPoint[nGlyphs];
        SkTypeface *lastFace = NULL;
        SkTypeface *skFace = NULL;
        size_t start = 0;

        x += MinikinUtils::xOffsetForTextAlign(paint, layout);
        SkPaint::Align align = paint->getTextAlign();
        paint->setTextAlign(SkPaint::kLeft_Align);
        paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
        for (size_t i = 0; i < nGlyphs; i++) {
            MinikinFontSkia *mfs = static_cast<MinikinFontSkia *>(layout->getFont(i));
            skFace = mfs->GetSkTypeface();
            glyphs[i] = layout->getGlyphId(i);
            pos[i].fX = x + layout->getX(i);
            pos[i].fY = y + layout->getY(i);
            if (i > 0 && skFace != lastFace) {
                paint->setTypeface(lastFace);
                canvas->drawPosText(glyphs + start, (i - start) << 1, pos + start, *paint);
                start = i;
            }
            lastFace = skFace;
        }
        if (skFace != NULL) {
            paint->setTypeface(skFace);
            canvas->drawPosText(glyphs + start, (nGlyphs - start) << 1, pos + start, *paint);
        }
        DrawTextFunctor f(layout, canvas, x, y, paint, glyphs, pos);
        MinikinUtils::forFontRun(layout, f);
        doDrawTextDecorations(canvas, x, y, layout.getAdvance(), paint);
        paint->setTextAlign(align);
        delete[] glyphs;
        delete[] pos;
    }
@@ -868,7 +881,7 @@ public:
        Layout layout;
        MinikinUtils::SetLayoutProperties(&layout, paint, flags, typeface);
        layout.doLayout(textArray + start, count);
        drawGlyphsToSkia(canvas, paint, &layout, x, y);
        drawGlyphsToSkia(canvas, paint, layout, x, y);
#else
        sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
                textArray, start, count, contextCount, flags);
+16 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "SkPaint.h"
#include "minikin/Layout.h"
#include "TypefaceImpl.h"
#include "MinikinSkia.h"

#include "MinikinUtils.h"

@@ -42,4 +43,18 @@ void MinikinUtils::SetLayoutProperties(Layout* layout, SkPaint* paint, int flags
    layout->setProperties(css);
}

float MinikinUtils::xOffsetForTextAlign(SkPaint* paint, const Layout& layout) {
    switch (paint->getTextAlign()) {
        case SkPaint::kCenter_Align:
            return layout.getAdvance() * -0.5f;
            break;
        case SkPaint::kRight_Align:
            return -layout.getAdvance();
            break;
        default:
            break;
    }
    return 0;
}

}
+21 −0
Original line number Diff line number Diff line
@@ -30,6 +30,27 @@ class MinikinUtils {
public:
    static void SetLayoutProperties(Layout* layout, SkPaint* paint, int flags,
        TypefaceImpl* face);
    static float xOffsetForTextAlign(SkPaint* paint, const Layout& layout);

    // f is a functor of type void f(SkTypeface *, size_t start, size_t end);
    template <typename F>
    static void forFontRun(const Layout& layout, F& f) {
        SkTypeface* lastFace = NULL;
        size_t start = 0;
        size_t nGlyphs = layout.nGlyphs();
        for (size_t i = 0; i < nGlyphs; i++) {
            MinikinFontSkia* mfs = static_cast<MinikinFontSkia*>(layout.getFont(i));
            SkTypeface* skFace = mfs->GetSkTypeface();
            if (i > 0 && skFace != lastFace) {
                f(lastFace, start, i);
                start = i;
            }
            lastFace = skFace;
        }
        if (nGlyphs > start) {
            f(lastFace, start, nGlyphs);
        }
    }
};

}  // namespace android
+65 −8
Original line number Diff line number Diff line
@@ -822,26 +822,83 @@ public:
        return result;
    }

    static void getTextPath(JNIEnv* env, SkPaint* paint, const jchar* text, jint count,
                            jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
#ifdef USE_MINIKIN
    class GetTextFunctor {
    public:
        GetTextFunctor(const Layout& layout, SkPath* path, jfloat x, jfloat y, SkPaint* paint,
                    uint16_t* glyphs, SkPoint* pos)
                : layout(layout), path(path), x(x), y(y), paint(paint), glyphs(glyphs), pos(pos) {
        }

        void operator()(SkTypeface* t, size_t start, size_t end) {
            for (size_t i = start; i < end; i++) {
                glyphs[i] = layout.getGlyphId(i);
                pos[i].fX = x + layout.getX(i);
                pos[i].fY = y + layout.getY(i);
            }
            paint->setTypeface(t);
            if (start == 0) {
                paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, path);
            } else {
                paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, &tmpPath);
                path->addPath(tmpPath);
            }
        }
    private:
        const Layout& layout;
        SkPath* path;
        jfloat x;
        jfloat y;
        SkPaint* paint;
        uint16_t* glyphs;
        SkPoint* pos;
        SkPath tmpPath;
    };
#endif

    static void getTextPath(JNIEnv* env, SkPaint* paint, TypefaceImpl* typeface, const jchar* text,
            jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
#ifdef USE_MINIKIN
        Layout layout;
        MinikinUtils::SetLayoutProperties(&layout, paint, bidiFlags, typeface);
        layout.doLayout(text, count);
        size_t nGlyphs = layout.nGlyphs();
        uint16_t* glyphs = new uint16_t[nGlyphs];
        SkPoint* pos = new SkPoint[nGlyphs];

        x += MinikinUtils::xOffsetForTextAlign(paint, layout);
        SkPaint::Align align = paint->getTextAlign();
        paint->setTextAlign(SkPaint::kLeft_Align);
        paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
        GetTextFunctor f(layout, path, x, y, paint, glyphs, pos);
        MinikinUtils::forFontRun(layout, f);
        paint->setTextAlign(align);
        delete[] glyphs;
        delete[] pos;
#else
        TextLayout::getTextPath(paint, text, count, bidiFlags, x, y, path);
#endif
    }

    static void getTextPath___C(JNIEnv* env, jobject clazz, jlong paintHandle, jint bidiFlags,
    static void getTextPath___C(JNIEnv* env, jobject clazz, jlong paintHandle,
            jlong typefaceHandle, jint bidiFlags,
            jcharArray text, jint index, jint count, jfloat x, jfloat y, jlong pathHandle) {
        SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
        SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
        const jchar* textArray = env->GetCharArrayElements(text, NULL);
        getTextPath(env, paint, textArray + index, count, bidiFlags, x, y, path);
        getTextPath(env, paint, typeface, textArray + index, count, bidiFlags, x, y, path);
        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
    }

    static void getTextPath__String(JNIEnv* env, jobject clazz, jlong paintHandle, jint bidiFlags,
    static void getTextPath__String(JNIEnv* env, jobject clazz, jlong paintHandle,
            jlong typefaceHandle, jint bidiFlags,
            jstring text, jint start, jint end, jfloat x, jfloat y, jlong pathHandle) {
        SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
        SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
        const jchar* textArray = env->GetStringChars(text, NULL);
        getTextPath(env, paint, textArray + start, end - start, bidiFlags, x, y, path);
        getTextPath(env, paint, typeface, textArray + start, end - start, bidiFlags, x, y, path);
        env->ReleaseStringChars(text, textArray);
    }

@@ -1035,8 +1092,8 @@ static JNINativeMethod methods[] = {
    {"native_getTextRunCursor", "(J[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
    {"native_getTextRunCursor", "(JLjava/lang/String;IIIII)I",
        (void*) SkPaintGlue::getTextRunCursor__String},
    {"native_getTextPath","(JI[CIIFFJ)V", (void*) SkPaintGlue::getTextPath___C},
    {"native_getTextPath","(JILjava/lang/String;IIFFJ)V", (void*) SkPaintGlue::getTextPath__String},
    {"native_getTextPath","(JJI[CIIFFJ)V", (void*) SkPaintGlue::getTextPath___C},
    {"native_getTextPath","(JJILjava/lang/String;IIFFJ)V", (void*) SkPaintGlue::getTextPath__String},
    {"nativeGetStringBounds", "(JLjava/lang/String;IIILandroid/graphics/Rect;)V",
                                        (void*) SkPaintGlue::getStringBounds },
    {"nativeGetCharArrayBounds", "(J[CIIILandroid/graphics/Rect;)V",
+6 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#define LOG_TAG "TextLayoutCache"

#include <utils/JenkinsHash.h>
#include <utils/CallStack.h>

#include "TextLayoutCache.h"
#include "TextLayout.h"
@@ -89,6 +90,11 @@ void TextLayoutCache::purgeCaches() {
sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
            const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) {
    AutoMutex _l(mLock);
#ifdef USE_MINIKIN
    // We want to get rid of all legacy calls in the Minikin case, so log
    ALOGW("TextLayoutCache being invoked!");
    CallStack _cs(LOG_TAG);
#endif
    nsecs_t startTime = 0;
    if (mDebugEnabled) {
        startTime = systemTime(SYSTEM_TIME_MONOTONIC);
Loading