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

Commit 9d2b5e19 authored by Raph Levien's avatar Raph Levien
Browse files

Implement drawTextOnPath with Minikin

This patch contains an implementation of drawTextOnPath for both
software and hardware Canvas using Minikin for text layout. One of the
steps for switching all remaining text operations to Minikin so the old
TextLayout and Skia fallback fonts mechanisms can be deleted.

Bug: 11750374 Resolve TODO items for Minikin
Change-Id: I06bfe74a101fa1dcdfc38f530f7194d71e522a85
parent f62d690b
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -981,22 +981,24 @@ class GLES20Canvas extends HardwareCanvas {
        }

        nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
                paint.mBidiFlags, paint.mNativePaint);
                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    }

    private static native void nDrawTextOnPath(long renderer, char[] text, int index, int count,
            long path, float hOffset, float vOffset, int bidiFlags, long nativePaint);
            long path, float hOffset, float vOffset, int bidiFlags, long nativePaint,
            long typeface);

    @Override
    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
        if (text.length() == 0) return;

        nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
                paint.mBidiFlags, paint.mNativePaint);
                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    }

    private static native void nDrawTextOnPath(long renderer, String text, int start, int end,
            long path, float hOffset, float vOffset, int bidiFlags, long nativePaint);
            long path, float hOffset, float vOffset, int bidiFlags, long nativePaint,
            long typeface);

    @Override
    public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
+61 −8
Original line number Diff line number Diff line
@@ -1123,29 +1123,82 @@ public:
        delete[] posPtr;
    }

#ifdef USE_MINIKIN
    class DrawTextOnPathFunctor {
    public:
        DrawTextOnPathFunctor(const Layout& layout, SkCanvas* canvas, float hOffset,
                    float vOffset, SkPaint* paint, SkPath* path)
                : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset),
                    paint(paint), path(path) {
        }
        void operator()(size_t start, size_t end) {
            uint16_t glyphs[1];
            for (size_t i = start; i < end; i++) {
                glyphs[0] = layout.getGlyphId(i);
                float x = hOffset + layout.getX(i);
                float y = vOffset + layout.getY(i);
                canvas->drawTextOnPathHV(glyphs, sizeof(glyphs), *path, x, y, *paint);
            }
        }
    private:
        const Layout& layout;
        SkCanvas* canvas;
        float hOffset;
        float vOffset;
        SkPaint* paint;
        SkPath* path;
    };
#endif

    static void doDrawTextOnPath(SkPaint* paint, const jchar* text, int count, int bidiFlags,
            float hOffset, float vOffset, SkPath* path, SkCanvas* canvas, TypefaceImpl* typeface) {
#ifdef USE_MINIKIN
        Layout layout;
        std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
        layout.doLayout(text, 0, count, count, css);
        hOffset += MinikinUtils::hOffsetForTextAlign(paint, layout, *path);
        // Set align to left for drawing, as we don't want individual
        // glyphs centered or right-aligned; the offset above takes
        // care of all alignment.
        SkPaint::Align align = paint->getTextAlign();
        paint->setTextAlign(SkPaint::kLeft_Align);

        DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paint, path);
        MinikinUtils::forFontRun(layout, paint, f);
        paint->setTextAlign(align);
#else
        TextLayout::drawTextOnPath(paint, text, count, bidiFlags, hOffset, vOffset, path, canvas);
#endif
    }

    static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
            jlong canvasHandle, jcharArray text, jint index, jint count,
            jlong pathHandle, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle) {
            jlong pathHandle, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle,
            jlong typefaceHandle) {
        SkCanvas* canvas = getNativeCanvas(canvasHandle);
        SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
        SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);

        jchar* textArray = env->GetCharArrayElements(text, NULL);
        TextLayout::drawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset,
                                   path, canvas);
        doDrawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset,
                                   path, canvas, typeface);
        env->ReleaseCharArrayElements(text, textArray, 0);
    }

    static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
            jlong canvasHandle, jstring text, jlong pathHandle,
            jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle) {
            jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle,
            jlong typefaceHandle) {
        SkCanvas* canvas = getNativeCanvas(canvasHandle);
        SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
        SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);

        const jchar* text_ = env->GetStringChars(text, NULL);
        int count = env->GetStringLength(text);
        TextLayout::drawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset,
                                   path, canvas);
        doDrawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset,
                                   path, canvas, typeface);
        env->ReleaseStringChars(text, text_);
    }

@@ -1271,9 +1324,9 @@ static JNINativeMethod gCanvasMethods[] = {
        (void*) SkCanvasGlue::drawPosText___CII_FPaint},
    {"native_drawPosText","(JLjava/lang/String;[FJ)V",
        (void*) SkCanvasGlue::drawPosText__String_FPaint},
    {"native_drawTextOnPath","(J[CIIJFFIJ)V",
    {"native_drawTextOnPath","(J[CIIJFFIJJ)V",
        (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
    {"native_drawTextOnPath","(JLjava/lang/String;JFFIJ)V",
    {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V",
        (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},

    {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches},
+17 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <string>

#include "SkPaint.h"
#include "SkPathMeasure.h"
#include "minikin/Layout.h"
#include "TypefaceImpl.h"
#include "MinikinSkia.h"
@@ -76,4 +77,20 @@ float MinikinUtils::xOffsetForTextAlign(SkPaint* paint, const Layout& layout) {
    return 0;
}

float MinikinUtils::hOffsetForTextAlign(SkPaint* paint, const Layout& layout, const SkPath& path) {
    float align = 0;
    switch (paint->getTextAlign()) {
        case SkPaint::kCenter_Align:
            align = -0.5f;
            break;
        case SkPaint::kRight_Align:
            align = -1;
            break;
        default:
            return 0;
    }
    SkPathMeasure measure(path, false);
    return align * (layout.getAdvance() - measure.getLength());
}

}
+1 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ public:

    static float xOffsetForTextAlign(SkPaint* paint, const Layout& layout);

    static float hOffsetForTextAlign(SkPaint* paint, const Layout& layout, const SkPath& path);
    // f is a functor of type void f(size_t start, size_t end);
    template <typename F>
    static void forFontRun(const Layout& layout, SkPaint* paint, F& f) {
+52 −7
Original line number Diff line number Diff line
@@ -669,8 +669,48 @@ static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
#endif
}

#ifdef USE_MINIKIN
class RenderTextOnPathFunctor {
public:
    RenderTextOnPathFunctor(const Layout& layout, OpenGLRenderer* renderer, float hOffset,
                float vOffset, SkPaint* paint, SkPath* path)
            : layout(layout), renderer(renderer), hOffset(hOffset), vOffset(vOffset),
                paint(paint), path(path) {
    }
    void operator()(size_t start, size_t end) {
        uint16_t glyphs[1];
        for (size_t i = start; i < end; i++) {
            glyphs[0] = layout.getGlyphId(i);
            float x = hOffset + layout.getX(i);
            float y = vOffset + layout.getY(i);
            renderer->drawTextOnPath((const char*) glyphs, sizeof(glyphs), 1, path, x, y, paint);
        }
    }
private:
    const Layout& layout;
    OpenGLRenderer* renderer;
    float hOffset;
    float vOffset;
    SkPaint* paint;
    SkPath* path;
};
#endif

static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
        SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, SkPaint* paint) {
        SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, SkPaint* paint,
        TypefaceImpl* typeface) {
#ifdef USE_MINIKIN
    Layout layout;
    std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
    layout.doLayout(text, 0, count, count, css);
    hOffset += MinikinUtils::hOffsetForTextAlign(paint, layout, *path);
    SkPaint::Align align = paint->getTextAlign();
    paint->setTextAlign(SkPaint::kLeft_Align);

    RenderTextOnPathFunctor f(layout, renderer, hOffset, vOffset, paint, path);
    MinikinUtils::forFontRun(layout, paint, f);
    paint->setTextAlign(align);
#else
    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
            text, 0, count, count, bidiFlags);
    if (value == NULL) {
@@ -681,6 +721,7 @@ static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int co
    int bytesCount = glyphsCount * sizeof(jchar);
    renderer->drawTextOnPath((const char*) glyphs, bytesCount, glyphsCount, path,
            hOffset, vOffset, paint);
#endif
}

static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
@@ -739,27 +780,31 @@ static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,

static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz,
        jlong rendererPtr, jcharArray text, jint index, jint count,
        jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr) {
        jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr,
        jlong typefacePtr) {
    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
    jchar* textArray = env->GetCharArrayElements(text, NULL);
    SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
    SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);

    renderTextOnPath(renderer, textArray + index, count, path,
            hOffset, vOffset, bidiFlags, paint);
            hOffset, vOffset, bidiFlags, paint, typeface);
    env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}

static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz,
        jlong rendererPtr, jstring text, jint start, jint end,
        jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr) {
        jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr,
        jlong typefacePtr) {
    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
    const jchar* textArray = env->GetStringChars(text, NULL);
    SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
    SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
    TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);

    renderTextOnPath(renderer, textArray + start, end - start, path,
            hOffset, vOffset, bidiFlags, paint);
            hOffset, vOffset, bidiFlags, paint, typeface);
    env->ReleaseStringChars(text, textArray);
}

@@ -986,8 +1031,8 @@ static JNINativeMethod gMethods[] = {
    { "nDrawText",          "(JLjava/lang/String;IIFFIJJ)V",
            (void*) android_view_GLES20Canvas_drawText },

    { "nDrawTextOnPath",    "(J[CIIJFFIJ)V",   (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
    { "nDrawTextOnPath",    "(JLjava/lang/String;IIJFFIJ)V",
    { "nDrawTextOnPath",    "(J[CIIJFFIJJ)V",  (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
    { "nDrawTextOnPath",    "(JLjava/lang/String;IIJFFIJJ)V",
            (void*) android_view_GLES20Canvas_drawTextOnPath },

    { "nDrawTextRun",       "(J[CIIIIFFZJJ)V",  (void*) android_view_GLES20Canvas_drawTextRunArray },
Loading