Start of Minikin integration

This is the current state of the Minikin integration. All changes are
hidden behind USE_MINIKIN #ifdef, so it should be safe to apply. To
play with the Minikin branch, set this in your BoardConfig.mk .

This change also merges in 64-bit changes that were happenening in
parallel.

Change-Id: Idd94553bcbe324c5875d0ff06495c966c3e95b7f
This commit is contained in:
Raph Levien
2014-01-30 16:06:28 -08:00
parent e2b2514342
commit 1a73f732f9
19 changed files with 467 additions and 73 deletions

View File

@ -1138,14 +1138,15 @@ class GLES20Canvas extends HardwareCanvas {
int modifiers = setupModifiers(paint);
try {
nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint,
paint.mNativeTypeface);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
}
private static native void nDrawText(long renderer, char[] text, int index, int count,
float x, float y, int bidiFlags, long paint);
float x, float y, int bidiFlags, long paint, long typeface);
@Override
public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
@ -1154,7 +1155,7 @@ class GLES20Canvas extends HardwareCanvas {
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
paint.mNativePaint);
paint.mNativePaint, paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawText(this, start, end, x, y,
paint);
@ -1162,7 +1163,7 @@ class GLES20Canvas extends HardwareCanvas {
char[] buf = TemporaryBuffer.obtain(end - start);
TextUtils.getChars(text, start, end, buf, 0);
nDrawText(mRenderer, buf, 0, end - start, x, y,
paint.mBidiFlags, paint.mNativePaint);
paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
} finally {
@ -1178,21 +1179,22 @@ class GLES20Canvas extends HardwareCanvas {
int modifiers = setupModifiers(paint);
try {
nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint,
paint.mNativeTypeface);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
}
private static native void nDrawText(long renderer, String text, int start, int end,
float x, float y, int bidiFlags, long paint);
float x, float y, int bidiFlags, long paint, long typeface);
@Override
public void drawText(String text, float x, float y, Paint paint) {
int modifiers = setupModifiers(paint);
try {
nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
paint.mNativePaint);
paint.mNativePaint, paint.mNativeTypeface);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
@ -1246,14 +1248,14 @@ class GLES20Canvas extends HardwareCanvas {
int modifiers = setupModifiers(paint);
try {
nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
paint.mNativePaint);
paint.mNativePaint, paint.mNativeTypeface);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
}
private static native void nDrawTextRun(long renderer, char[] text, int index, int count,
int contextIndex, int contextCount, float x, float y, int dir, long nativePaint);
int contextIndex, int contextCount, float x, float y, int dir, long nativePaint, long nativeTypeface);
@Override
public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
@ -1268,7 +1270,7 @@ class GLES20Canvas extends HardwareCanvas {
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
contextEnd, x, y, flags, paint.mNativePaint);
contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawTextRun(this, start, end,
contextStart, contextEnd, x, y, flags, paint);
@ -1278,7 +1280,7 @@ class GLES20Canvas extends HardwareCanvas {
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
x, y, flags, paint.mNativePaint);
x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
} finally {
@ -1287,7 +1289,7 @@ class GLES20Canvas extends HardwareCanvas {
}
private static native void nDrawTextRun(long renderer, String text, int start, int end,
int contextStart, int contextEnd, float x, float y, int flags, long nativePaint);
int contextStart, int contextEnd, float x, float y, int flags, long nativePaint, long nativeTypeface);
@Override
public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,

View File

@ -94,6 +94,7 @@ LOCAL_SRC_FILES:= \
android/graphics/Canvas.cpp \
android/graphics/ColorFilter.cpp \
android/graphics/DrawFilter.cpp \
android/graphics/FontFamily.cpp \
android/graphics/CreateJavaOutputStreamAdaptor.cpp \
android/graphics/Graphics.cpp \
android/graphics/HarfBuzzNGFaceSkia.cpp \
@ -227,7 +228,8 @@ ifeq ($(USE_MINIKIN), true)
LOCAL_CFLAGS += -DUSE_MINIKIN
LOCAL_C_INCLUDES += frameworks/minikin/include \
external/freetype/include
LOCAL_SRC_FILES += android/graphics/MinikinSkia.cpp
LOCAL_SRC_FILES += android/graphics/MinikinSkia.cpp \
android/graphics/MinikinUtils.cpp
# note: the freetype include is spurious; minikin itself probably
# shouldn't depend on it
LOCAL_SHARED_LIBRARIES += libminikin libstlport

View File

@ -107,6 +107,7 @@ extern int register_android_emoji_EmojiFactory(JNIEnv* env);
extern int register_android_graphics_Canvas(JNIEnv* env);
extern int register_android_graphics_ColorFilter(JNIEnv* env);
extern int register_android_graphics_DrawFilter(JNIEnv* env);
extern int register_android_graphics_FontFamily(JNIEnv* env);
extern int register_android_graphics_Matrix(JNIEnv* env);
extern int register_android_graphics_Paint(JNIEnv* env);
extern int register_android_graphics_Path(JNIEnv* env);
@ -1223,6 +1224,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_Canvas),
REG_JNI(register_android_graphics_ColorFilter),
REG_JNI(register_android_graphics_DrawFilter),
REG_JNI(register_android_graphics_FontFamily),
REG_JNI(register_android_graphics_Interpolator),
REG_JNI(register_android_graphics_LayerRasterizer),
REG_JNI(register_android_graphics_MaskFilter),

View File

@ -30,6 +30,7 @@
#ifdef USE_MINIKIN
#include <minikin/Layout.h>
#include "MinikinSkia.h"
#include "MinikinUtils.h"
#endif
#include "TextLayout.h"
@ -820,7 +821,7 @@ public:
}
#ifdef USE_MINIKIN
static void drawGlyphsToSkia(SkCanvas *canvas, SkPaint *paint, Layout *layout, float x, float y) {
static void drawGlyphsToSkia(SkCanvas* canvas, SkPaint* paint, Layout* layout, float x, float y) {
size_t nGlyphs = layout->nGlyphs();
uint16_t *glyphs = new uint16_t[nGlyphs];
SkPoint *pos = new SkPoint[nGlyphs];
@ -865,15 +866,7 @@ public:
#ifdef USE_MINIKIN
Layout layout;
TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
layout.setFontCollection(resolvedFace->fFontCollection);
FontStyle style = resolvedFace->fStyle;
char css[256];
sprintf(css, "font-size: %d; font-weight: %d; font-style: %s",
(int)paint->getTextSize(),
style.getWeight() * 100,
style.getItalic() ? "italic" : "normal");
layout.setProperties(css);
MinikinUtils::SetLayoutProperties(&layout, paint, typeface);
layout.doLayout(textArray + start, count);
drawGlyphsToSkia(canvas, paint, &layout, x, y);
#else

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "Minikin"
#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include "SkTypeface.h"
#include "GraphicsJNI.h"
#include <ScopedPrimitiveArray.h>
#include <ScopedUtfChars.h>
#ifdef USE_MINIKIN
#include <minikin/FontFamily.h>
#include "MinikinSkia.h"
#endif
namespace android {
static jlong FontFamily_create(JNIEnv* env, jobject clazz) {
#ifdef USE_MINIKIN
return (jlong)new FontFamily();
#else
return 0;
#endif
}
static void FontFamily_destroy(JNIEnv* env, jobject clazz, jlong ptr) {
// TODO: work out lifetime issues
}
static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr, jstring path) {
#ifdef USE_MINIKIN
NPE_CHECK_RETURN_ZERO(env, path);
ScopedUtfChars str(env, path);
ALOGD("addFont %s", str.c_str());
SkTypeface* face = SkTypeface::CreateFromFile(str.c_str());
MinikinFont* minikinFont = new MinikinFontSkia(face);
FontFamily* fontFamily = (FontFamily*)familyPtr;
return fontFamily->addFont(minikinFont);
#else
return false;
#endif
}
///////////////////////////////////////////////////////////////////////////////
static JNINativeMethod gFontFamilyMethods[] = {
{ "nCreateFamily", "()J", (void*)FontFamily_create },
{ "nDestroyFamily", "(J)V", (void*)FontFamily_destroy },
{ "nAddFont", "(JLjava/lang/String;)Z", (void*)FontFamily_addFont },
};
int register_android_graphics_FontFamily(JNIEnv* env)
{
return android::AndroidRuntime::registerNativeMethods(env,
"android/graphics/FontFamily",
gFontFamilyMethods, NELEM(gFontFamilyMethods));
}
}

View File

@ -167,6 +167,7 @@ static jfieldID gCanvas_nativeInstanceID;
static jclass gPaint_class;
static jfieldID gPaint_nativeInstanceID;
static jfieldID gPaint_nativeTypefaceID;
static jclass gPicture_class;
static jfieldID gPicture_nativeInstanceID;
@ -334,6 +335,16 @@ SkPaint* GraphicsJNI::getNativePaint(JNIEnv* env, jobject paint) {
return p;
}
android::TypefaceImpl* GraphicsJNI::getNativeTypeface(JNIEnv* env, jobject paint) {
SkASSERT(env);
SkASSERT(paint);
SkASSERT(env->IsInstanceOf(paint, gPaint_class));
jlong typefaceHandle = env->GetLongField(paint, gPaint_nativeTypefaceID);
android::TypefaceImpl* p = reinterpret_cast<android::TypefaceImpl*>(typefaceHandle);
SkASSERT(p);
return p;
}
SkPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
{
SkASSERT(env);
@ -698,6 +709,7 @@ int register_android_graphics_Graphics(JNIEnv* env)
gPaint_class = make_globalref(env, "android/graphics/Paint");
gPaint_nativeInstanceID = getFieldIDCheck(env, gPaint_class, "mNativePaint", "J");
gPaint_nativeTypefaceID = getFieldIDCheck(env, gPaint_class, "mNativeTypeface", "J");
gPicture_class = make_globalref(env, "android/graphics/Picture");
gPicture_nativeInstanceID = getFieldIDCheck(env, gPicture_class, "mNativePicture", "J");

View File

@ -8,6 +8,7 @@
#include "SkPoint.h"
#include "SkRect.h"
#include "SkImageDecoder.h"
#include "TypefaceImpl.h"
#include <jni.h>
class SkBitmapRegionDecoder;
@ -46,6 +47,7 @@ public:
static SkCanvas* getNativeCanvas(JNIEnv*, jobject canvas);
static SkPaint* getNativePaint(JNIEnv*, jobject paint);
static android::TypefaceImpl* getNativeTypeface(JNIEnv*, jobject paint);
static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
static SkPicture* getNativePicture(JNIEnv*, jobject picture);
static SkRegion* getNativeRegion(JNIEnv*, jobject region);

View File

@ -16,7 +16,6 @@
#include <SkTypeface.h>
#include <SkPaint.h>
#include <SkFP.h>
#define LOG_TAG "Minikin"
#include <cutils/log.h>
@ -44,19 +43,35 @@ bool MinikinFontSkia::GetGlyph(uint32_t codepoint, uint32_t *glyph) const {
return !!glyph;
}
static void MinikinFontSkia_SetSkiaPaint(SkTypeface* typeface, SkPaint* skPaint, const MinikinPaint& paint) {
skPaint->setTypeface(typeface);
skPaint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
// TODO: set more paint parameters from Minikin
skPaint->setTextSize(paint.size);
}
float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id,
const MinikinPaint &paint) const {
SkPaint skpaint;
skpaint.setTypeface(mTypeface);
skpaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
// TODO: set more paint parameters from Minikin
skpaint.setTextSize(paint.size);
SkPaint skPaint;
uint16_t glyph16 = glyph_id;
SkScalar skWidth;
MinikinFontSkia_SetSkiaPaint(mTypeface, &skPaint, paint);
skPaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, NULL);
ALOGD("width for typeface %d glyph %d = %f", mTypeface->uniqueID(), glyph_id, skWidth);
return skWidth;
}
void MinikinFontSkia::GetBounds(MinikinRect* bounds, uint32_t glyph_id,
const MinikinPaint& paint) const {
SkPaint skPaint;
uint16_t glyph16 = glyph_id;
SkRect skBounds;
skpaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, &skBounds);
// TODO: get bounds information
return SkScalarToFP(skWidth);
MinikinFontSkia_SetSkiaPaint(mTypeface, &skPaint, paint);
skPaint.getTextWidths(&glyph16, sizeof(glyph16), NULL, &skBounds);
bounds->mLeft = skBounds.fLeft;
bounds->mTop = skBounds.fTop;
bounds->mRight = skBounds.fRight;
bounds->mBottom = skBounds.fBottom;
}
bool MinikinFontSkia::GetTable(uint32_t tag, uint8_t *buf, size_t *size) {

View File

@ -27,6 +27,9 @@ public:
float GetHorizontalAdvance(uint32_t glyph_id,
const MinikinPaint &paint) const;
void GetBounds(MinikinRect* bounds, uint32_t glyph_id,
const MinikinPaint &paint) const;
// If buf is NULL, just update size
bool GetTable(uint32_t tag, uint8_t *buf, size_t *size);
@ -36,7 +39,6 @@ public:
private:
SkTypeface *mTypeface;
};
} // namespace android

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SkPaint.h"
#include "minikin/Layout.h"
#include "TypefaceImpl.h"
#include "MinikinUtils.h"
namespace android {
void MinikinUtils::SetLayoutProperties(Layout* layout, SkPaint* paint,
TypefaceImpl* typeface) {
TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
layout->setFontCollection(resolvedFace->fFontCollection);
FontStyle style = resolvedFace->fStyle;
char css[256];
sprintf(css, "font-size: %d; font-weight: %d; font-style: %s",
(int)paint->getTextSize(),
style.getWeight() * 100,
style.getItalic() ? "italic" : "normal");
layout->setProperties(css);
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Utilities for making Minikin work, especially from existing objects like
* SkPaint and so on.
**/
// TODO: does this really need to be separate from MinikinSkia?
#ifndef ANDROID_MINIKIN_UTILS_H
#define ANDROID_MINIKIN_UTILS_H
namespace android {
class MinikinUtils {
public:
static void SetLayoutProperties(Layout* layout, SkPaint* paint,
TypefaceImpl* face);
};
} // namespace android
#endif // ANDROID_MINIKIN_UTILS_H

View File

@ -35,6 +35,12 @@
#include "unicode/ushape.h"
#include "TextLayout.h"
#ifdef USE_MINIKIN
#include <minikin/Layout.h>
#include "MinikinSkia.h"
#include "MinikinUtils.h"
#endif
// temporary for debugging
#include <Caches.h>
#include <utils/Log.h>
@ -493,8 +499,16 @@ public:
const jchar* textArray = env->GetCharArrayElements(text, NULL);
jfloat result = 0;
#ifdef USE_MINIKIN
Layout layout;
TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
MinikinUtils::SetLayoutProperties(&layout, paint, typeface);
layout.doLayout(textArray + index, count);
result = layout.getAdvance();
#else
TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
bidiFlags, NULL /* dont need all advances */, &result);
#endif
env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
return result;
@ -519,8 +533,16 @@ public:
SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
jfloat width = 0;
#ifdef USE_MINIKIN
Layout layout;
TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
MinikinUtils::SetLayoutProperties(&layout, paint, typeface);
layout.doLayout(textArray + start, count);
width = layout.getAdvance();
#else
TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
bidiFlags, NULL /* dont need all advances */, &width);
#endif
env->ReleaseStringChars(text, textArray);
return width;
@ -539,15 +561,23 @@ public:
SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
jfloat width = 0;
#ifdef USE_MINIKIN
Layout layout;
TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
MinikinUtils::SetLayoutProperties(&layout, paint, typeface);
layout.doLayout(textArray, textLength);
width = layout.getAdvance();
#else
TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
bidiFlags, NULL /* dont need all advances */, &width);
#endif
env->ReleaseStringChars(text, textArray);
return width;
}
static int dotextwidths(JNIEnv* env, SkPaint* paint, const jchar text[], int count, jfloatArray widths,
jint bidiFlags) {
static int dotextwidths(JNIEnv* env, SkPaint* paint, TypefaceImpl* typeface, const jchar text[], int count,
jfloatArray widths, jint bidiFlags) {
NPE_CHECK_RETURN_ZERO(env, paint);
NPE_CHECK_RETURN_ZERO(env, text);
@ -567,27 +597,36 @@ public:
AutoJavaFloatArray autoWidths(env, widths, count);
jfloat* widthsArray = autoWidths.ptr();
#ifdef USE_MINIKIN
Layout layout;
MinikinUtils::SetLayoutProperties(&layout, paint, typeface);
layout.doLayout(text, count);
layout.getAdvances(widthsArray);
#else
TextLayout::getTextRunAdvances(paint, text, 0, count, count,
bidiFlags, widthsArray, NULL /* dont need totalAdvance */);
#endif
return count;
}
static jint getTextWidths___CIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
static jint getTextWidths___CIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray text,
jint index, jint count, jint bidiFlags, jfloatArray widths) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
const jchar* textArray = env->GetCharArrayElements(text, NULL);
count = dotextwidths(env, paint, textArray + index, count, widths, bidiFlags);
count = dotextwidths(env, paint, typeface, textArray + index, count, widths, bidiFlags);
env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
JNI_ABORT);
return count;
}
static jint getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text,
static jint getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring text,
jint start, jint end, jint bidiFlags, jfloatArray widths) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
const jchar* textArray = env->GetStringChars(text, NULL);
int count = dotextwidths(env, paint, textArray + start, end - start, widths, bidiFlags);
int count = dotextwidths(env, paint, typeface, textArray + start, end - start, widths, bidiFlags);
env->ReleaseStringChars(text, textArray);
return count;
}
@ -633,7 +672,7 @@ public:
return count;
}
static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text,
static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, TypefaceImpl* typeface, const jchar *text,
jint start, jint count, jint contextCount, jint flags,
jfloatArray advances, jint advancesIndex) {
NPE_CHECK_RETURN_ZERO(env, paint);
@ -656,8 +695,16 @@ public:
jfloat* advancesArray = new jfloat[count];
jfloat totalAdvance = 0;
#ifdef USE_MINIKIN
Layout layout;
MinikinUtils::SetLayoutProperties(&layout, paint, typeface);
layout.doLayout(text + start, count);
layout.getAdvances(advancesArray);
totalAdvance = layout.getAdvance();
#else
TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags,
advancesArray, &totalAdvance);
#endif
if (advances != NULL) {
env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
@ -667,22 +714,26 @@ public:
}
static jfloat getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
jlong typefaceHandle,
jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
jint flags, jfloatArray advances, jint advancesIndex) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
jchar* textArray = env->GetCharArrayElements(text, NULL);
jfloat result = doTextRunAdvances(env, paint, textArray + contextIndex,
jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextIndex,
index - contextIndex, count, contextCount, flags, advances, advancesIndex);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
return result;
}
static jfloat getTextRunAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
jlong typefaceHandle,
jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
jfloatArray advances, jint advancesIndex) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
const jchar* textArray = env->GetStringChars(text, NULL);
jfloat result = doTextRunAdvances(env, paint, textArray + contextStart,
jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextStart,
start - contextStart, end - start, contextEnd - contextStart, flags,
advances, advancesIndex);
env->ReleaseStringChars(text, textArray);
@ -949,11 +1000,11 @@ static JNINativeMethod methods[] = {
{"native_measureText","(Ljava/lang/String;III)F", (void*) SkPaintGlue::measureText_StringIII},
{"native_breakText","([CIIFI[F)I", (void*) SkPaintGlue::breakTextC},
{"native_breakText","(Ljava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS},
{"native_getTextWidths","(J[CIII[F)I", (void*) SkPaintGlue::getTextWidths___CIII_F},
{"native_getTextWidths","(JLjava/lang/String;III[F)I", (void*) SkPaintGlue::getTextWidths__StringIII_F},
{"native_getTextRunAdvances","(J[CIIIII[FI)F",
{"native_getTextWidths","(JJ[CIII[F)I", (void*) SkPaintGlue::getTextWidths___CIII_F},
{"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) SkPaintGlue::getTextWidths__StringIII_F},
{"native_getTextRunAdvances","(JJ[CIIIII[FI)F",
(void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI},
{"native_getTextRunAdvances","(JLjava/lang/String;IIIII[FI)F",
{"native_getTextRunAdvances","(JJLjava/lang/String;IIIII[FI)F",
(void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI},

View File

@ -18,6 +18,7 @@
#include <android_runtime/AndroidRuntime.h>
#include "GraphicsJNI.h"
#include <ScopedPrimitiveArray.h>
#include "SkStream.h"
#include "SkTypeface.h"
#include "TypefaceImpl.h"
@ -62,7 +63,7 @@ static jlong Typeface_create(JNIEnv* env, jobject, jstring name,
}
static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandle, jint style) {
SkTypeface* family = reinterpret_cast<SkTypeface*>(familyHandle);
TypefaceImpl* family = reinterpret_cast<TypefaceImpl*>(familyHandle);
TypefaceImpl* face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)style);
// Try to find the closest matching font, using the standard heuristic
if (NULL == face) {
@ -114,6 +115,11 @@ static jlong Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) {
return reinterpret_cast<jlong>(TypefaceImpl_createFromFile(str.c_str()));
}
static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray) {
ScopedLongArrayRO families(env, familyArray);
return reinterpret_cast<jlong>(TypefaceImpl_createFromFamilies(families.get(), families.size()));
}
///////////////////////////////////////////////////////////////////////////////
static JNINativeMethod gTypefaceMethods[] = {
@ -125,6 +131,8 @@ static JNINativeMethod gTypefaceMethods[] = {
(void*)Typeface_createFromAsset },
{ "nativeCreateFromFile", "(Ljava/lang/String;)J",
(void*)Typeface_createFromFile },
{ "nativeCreateFromArray", "([J)J",
(void*)Typeface_createFromArray },
};
int register_android_graphics_Typeface(JNIEnv* env)

View File

@ -20,6 +20,10 @@
* being, that choice is hidden under the USE_MINIKIN compile-time flag.
*/
#define LOG_TAG "TypefaceImpl"
#include "jni.h" // for jlong, remove when being passed proper type
#include "SkStream.h"
#include "SkTypeface.h"
@ -146,6 +150,19 @@ TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset) {
return createFromSkTypeface(face);
}
TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
ALOGD("createFromFamilies size=%d", size);
std::vector<FontFamily *>familyVec;
for (size_t i = 0; i < size; i++) {
FontFamily* family = reinterpret_cast<FontFamily*>(families[i]);
familyVec.push_back(family);
}
TypefaceImpl* result = new TypefaceImpl;
result->fFontCollection = new FontCollection(familyVec);
result->fStyle = FontStyle(); // TODO: improve
return result;
}
void TypefaceImpl_unref(TypefaceImpl* face) {
delete face;
}
@ -189,6 +206,11 @@ TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset) {
return face;
}
TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size) {
// Should never be called in non-Minikin builds
return 0;
}
void TypefaceImpl_unref(TypefaceImpl* face) {
SkSafeUnref(face);
}

View File

@ -18,6 +18,8 @@
#ifndef ANDROID_TYPEFACE_IMPL_H
#define ANDROID_TYPEFACE_IMPL_H
#include "jni.h" // for jlong, eventually remove
#include "SkTypeface.h"
#include <androidfw/AssetManager.h>
#ifdef USE_MINIKIN
@ -51,6 +53,10 @@ TypefaceImpl* TypefaceImpl_createFromFile(const char* filename);
TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset);
// When we remove the USE_MINIKIN ifdef, probably a good idea to move the casting
// (from jlong to FontFamily*) to the caller in Typeface.cpp.
TypefaceImpl* TypefaceImpl_createFromFamilies(const jlong* families, size_t size);
void TypefaceImpl_unref(TypefaceImpl* face);
int TypefaceImpl_getStyle(TypefaceImpl* face);

View File

@ -50,6 +50,12 @@
#include <Rect.h>
#include <RenderNode.h>
#ifdef USE_MINIKIN
#include <minikin/Layout.h>
#include "MinikinSkia.h"
#include "MinikinUtils.h"
#endif
#include <TextLayout.h>
#include <TextLayoutCache.h>
@ -684,8 +690,58 @@ static float xOffsetForTextAlign(SkPaint* paint, float totalAdvance) {
return 0;
}
#ifdef USE_MINIKIN
static void renderTextLayout(OpenGLRenderer* renderer, Layout* layout,
jfloat x, jfloat y, SkPaint* paint) {
size_t nGlyphs = layout->nGlyphs();
float* pos = new float[nGlyphs * 2];
uint16_t* glyphs = new uint16_t[nGlyphs];
SkTypeface* lastFace = 0;
SkTypeface* skFace = 0;
size_t start = 0;
MinikinRect b;
layout->getBounds(&b);
android::uirenderer::Rect bounds(b.mLeft, b.mTop, b.mRight, b.mBottom);
bounds.translate(x, y);
float totalAdvance = layout->getAdvance();
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[2 * i] = SkFloatToScalar(layout->getX(i));
pos[2 * i + 1] = SkFloatToScalar(layout->getY(i));
if (i > 0 && skFace != lastFace) {
paint->setTypeface(lastFace);
size_t glyphsCount = i - start;
int bytesCount = glyphsCount * sizeof(jchar);
renderer->drawText((const char*) (glyphs + start), bytesCount, glyphsCount,
x, y, pos + 2 * start, paint, totalAdvance, bounds);
start = i;
}
lastFace = skFace;
}
if (skFace != NULL) {
paint->setTypeface(skFace);
size_t glyphsCount = nGlyphs - start;
int bytesCount = glyphsCount * sizeof(jchar);
renderer->drawText((const char*) (glyphs + start), bytesCount, glyphsCount,
x, y, pos + 2 * start, paint, totalAdvance, bounds);
}
delete[] glyphs;
delete[] pos;
}
#endif
static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) {
#ifdef USE_MINIKIN
Layout layout;
MinikinUtils::SetLayoutProperties(&layout, paint, typeface);
layout.doLayout(text, count);
x += xOffsetForTextAlign(paint, layout.getAdvance());
renderTextLayout(renderer, &layout, x, y, paint);
#else
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
text, 0, count, count, flags);
if (value == NULL) {
@ -703,6 +759,7 @@ static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
renderer->drawText((const char*) glyphs, bytesCount, glyphsCount,
x, y, positions, paint, totalAdvance, bounds);
#endif
}
static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
@ -721,7 +778,14 @@ static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int co
static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
jint start, jint count, jint contextCount, jfloat x, jfloat y,
int flags, SkPaint* paint) {
int flags, SkPaint* paint, TypefaceImpl* typeface) {
#ifdef USE_MINIKIN
Layout layout;
MinikinUtils::SetLayoutProperties(&layout, paint, typeface);
layout.doLayout(text + start, count);
x += xOffsetForTextAlign(paint, layout.getAdvance());
renderTextLayout(renderer, &layout, x, y, paint);
#else
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
text, start, count, contextCount, flags);
if (value == NULL) {
@ -739,27 +803,30 @@ static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
renderer->drawText((const char*) glyphs, bytesCount, glyphsCount,
x, y, positions, paint, totalAdvance, bounds);
#endif
}
static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
jlong rendererPtr, jcharArray text, jint index, jint count,
jfloat x, jfloat y, jint flags, jlong paintPtr) {
jfloat x, jfloat y, jint flags, jlong paintPtr, jlong typefacePtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
jchar* textArray = env->GetCharArrayElements(text, NULL);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
renderText(renderer, textArray + index, count, x, y, flags, paint);
renderText(renderer, textArray + index, count, x, y, flags, paint, typeface);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,
jlong rendererPtr, jstring text, jint start, jint end,
jfloat x, jfloat y, jint flags, jlong paintPtr) {
jfloat x, jfloat y, jint flags, jlong paintPtr, jlong typefacePtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
const jchar* textArray = env->GetStringChars(text, NULL);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
renderText(renderer, textArray + start, end - start, x, y, flags, paint);
renderText(renderer, textArray + start, end - start, x, y, flags, paint, typeface);
env->ReleaseStringChars(text, textArray);
}
@ -792,28 +859,30 @@ static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz,
static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz,
jlong rendererPtr, jcharArray text, jint index, jint count,
jint contextIndex, jint contextCount, jfloat x, jfloat y, jint dirFlags,
jlong paintPtr) {
jlong paintPtr, jlong typefacePtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
jchar* textArray = env->GetCharArrayElements(text, NULL);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
renderTextRun(renderer, textArray + contextIndex, index - contextIndex,
count, contextCount, x, y, dirFlags, paint);
count, contextCount, x, y, dirFlags, paint, typeface);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz,
jlong rendererPtr, jstring text, jint start, jint end,
jint contextStart, int contextEnd, jfloat x, jfloat y, jint dirFlags,
jlong paintPtr) {
jlong paintPtr, jlong typefacePtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
const jchar* textArray = env->GetStringChars(text, NULL);
jint count = end - start;
jint contextCount = contextEnd - contextStart;
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
renderTextRun(renderer, textArray + contextStart, start - contextStart,
count, contextCount, x, y, dirFlags, paint);
count, contextCount, x, y, dirFlags, paint, typeface);
env->ReleaseStringChars(text, textArray);
}
@ -1055,16 +1124,16 @@ static JNINativeMethod gMethods[] = {
{ "nSetupPaintFilter", "(JII)V", (void*) android_view_GLES20Canvas_setupPaintFilter },
{ "nResetPaintFilter", "(J)V", (void*) android_view_GLES20Canvas_resetPaintFilter },
{ "nDrawText", "(J[CIIFFIJ)V", (void*) android_view_GLES20Canvas_drawTextArray },
{ "nDrawText", "(JLjava/lang/String;IIFFIJ)V",
{ "nDrawText", "(J[CIIFFIJJ)V", (void*) android_view_GLES20Canvas_drawTextArray },
{ "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",
(void*) android_view_GLES20Canvas_drawTextOnPath },
{ "nDrawTextRun", "(J[CIIIIFFIJ)V", (void*) android_view_GLES20Canvas_drawTextRunArray },
{ "nDrawTextRun", "(JLjava/lang/String;IIIIFFIJ)V",
{ "nDrawTextRun", "(J[CIIIIFFIJJ)V", (void*) android_view_GLES20Canvas_drawTextRunArray },
{ "nDrawTextRun", "(JLjava/lang/String;IIIIFFIJJ)V",
(void*) android_view_GLES20Canvas_drawTextRun },
{ "nDrawPosText", "(J[CII[FJ)V", (void*) android_view_GLES20Canvas_drawPosTextArray },

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.graphics;
import java.io.File;
/**
* A family of typefaces with different styles.
*
* @hide
*/
public class FontFamily {
public long mNativePtr;
public FontFamily() {
mNativePtr = nCreateFamily();
}
// TODO: finalization
public boolean addFont(File path) {
return nAddFont(mNativePtr, path.getAbsolutePath());
}
static native long nCreateFamily();
static native void nDestroyFamily(long nativePtr);
static native boolean nAddFont(long nativeFamily, String path);
}

View File

@ -1686,12 +1686,12 @@ public class Paint {
return 0;
}
if (!mHasCompatScaling) {
return native_getTextWidths(mNativePaint, text, index, count, mBidiFlags, widths);
return native_getTextWidths(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, widths);
}
final float oldSize = getTextSize();
setTextSize(oldSize*mCompatScaling);
int res = native_getTextWidths(mNativePaint, text, index, count, mBidiFlags, widths);
int res = native_getTextWidths(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, widths);
setTextSize(oldSize);
for (int i=0; i<res; i++) {
widths[i] *= mInvCompatScaling;
@ -1768,12 +1768,12 @@ public class Paint {
return 0;
}
if (!mHasCompatScaling) {
return native_getTextWidths(mNativePaint, text, start, end, mBidiFlags, widths);
return native_getTextWidths(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, widths);
}
final float oldSize = getTextSize();
setTextSize(oldSize*mCompatScaling);
int res = native_getTextWidths(mNativePaint, text, start, end, mBidiFlags, widths);
int res = native_getTextWidths(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, widths);
setTextSize(oldSize);
for (int i=0; i<res; i++) {
widths[i] *= mInvCompatScaling;
@ -1863,13 +1863,13 @@ public class Paint {
return 0f;
}
if (!mHasCompatScaling) {
return native_getTextRunAdvances(mNativePaint, chars, index, count,
return native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
contextIndex, contextCount, flags, advances, advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
float res = native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
contextIndex, contextCount, flags, advances, advancesIndex);
setTextSize(oldSize);
@ -1994,13 +1994,13 @@ public class Paint {
}
if (!mHasCompatScaling) {
return native_getTextRunAdvances(mNativePaint, text, start, end,
return native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
contextStart, contextEnd, flags, advances, advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
float totalAdvance = native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
contextStart, contextEnd, flags, advances, advancesIndex);
setTextSize(oldSize);
@ -2265,19 +2265,19 @@ public class Paint {
private static native void native_setTextLocale(long native_object,
String locale);
private static native int native_getTextWidths(long native_object,
private static native int native_getTextWidths(long native_object, long native_typeface,
char[] text, int index, int count, int bidiFlags, float[] widths);
private static native int native_getTextWidths(long native_object,
private static native int native_getTextWidths(long native_object, long native_typeface,
String text, int start, int end, int bidiFlags, float[] widths);
private static native int native_getTextGlyphs(long native_object,
String text, int start, int end, int contextStart, int contextEnd,
int flags, char[] glyphs);
private static native float native_getTextRunAdvances(long native_object,
private static native float native_getTextRunAdvances(long native_object, long native_typeface,
char[] text, int index, int count, int contextIndex, int contextCount,
int flags, float[] advances, int advancesIndex);
private static native float native_getTextRunAdvances(long native_object,
private static native float native_getTextRunAdvances(long native_object, long native_typeface,
String text, int start, int end, int contextStart, int contextEnd,
int flags, float[] advances, int advancesIndex);

View File

@ -17,6 +17,7 @@
package android.graphics;
import android.content.res.AssetManager;
import android.util.Log;
import android.util.SparseArray;
import android.util.LongSparseArray;
@ -173,6 +174,22 @@ public class Typeface {
return new Typeface(nativeCreateFromFile(path));
}
/**
* Create a new typeface from an array of font families.
*
* @param families array of font families
* @hide
*/
public static Typeface createFromFamilies(FontFamily[] families) {
long[] ptrArray = new long[families.length];
Log.d("Minikin", "# of families: " + families.length);
for (int i = 0; i < families.length; i++) {
Log.d("Minikin", "family ptr: " + families[i].mNativePtr);
ptrArray[i] = families[i].mNativePtr;
}
return new Typeface(nativeCreateFromArray(ptrArray));
}
// don't allow clients to call this directly
private Typeface(long ni) {
if (ni == 0) {
@ -234,4 +251,5 @@ public class Typeface {
private static native int nativeGetStyle(long native_instance);
private static native long nativeCreateFromAsset(AssetManager mgr, String path);
private static native long nativeCreateFromFile(String path);
private static native long nativeCreateFromArray(long[] familyArray);
}