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
This commit is contained in:
Raph Levien
2014-06-15 23:53:57 -07:00
parent f62d690b00
commit 9d2b5e1930
6 changed files with 141 additions and 23 deletions

View File

@@ -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,

View File

@@ -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},

View File

@@ -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());
}
}

View File

@@ -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) {

View File

@@ -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 },

View File

@@ -1770,7 +1770,7 @@ public class Canvas {
}
native_drawTextOnPath(mNativeCanvasWrapper, text, index, count,
path.ni(), hOffset, vOffset,
paint.mBidiFlags, paint.mNativePaint);
paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
}
/**
@@ -1790,7 +1790,7 @@ public class Canvas {
float vOffset, @NonNull Paint paint) {
if (text.length() > 0) {
native_drawTextOnPath(mNativeCanvasWrapper, text, path.ni(), hOffset, vOffset,
paint.mBidiFlags, paint.mNativePaint);
paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
}
}
@@ -2021,11 +2021,11 @@ public class Canvas {
int count, long nativePath,
float hOffset,
float vOffset, int bidiFlags,
long nativePaint);
long nativePaint, long nativeTypeface);
private static native void native_drawTextOnPath(long nativeCanvas,
String text, long nativePath,
float hOffset,
float vOffset,
int flags, long nativePaint);
int flags, long nativePaint, long nativeTypeface);
private static native void finalizer(long nativeCanvas);
}