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
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 34b85d9..1b26202 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -1138,14 +1138,15 @@
 
         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 @@
             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 @@
                 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 @@
 
         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 @@
         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 @@
             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 @@
                 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 @@
     }
 
     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,
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index ee59c8a..8796126 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -94,6 +94,7 @@
 	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 @@
 	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
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f964cd2..d2f8062 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -107,6 +107,7 @@
 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 @@
     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),
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 2adbf3a..9e0996a 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -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 @@
     }
 
 #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 @@
 
 #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
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
new file mode 100644
index 0000000..5782312
--- /dev/null
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -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));
+}
+
+}
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index e4c74b2..ed28c24 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -167,6 +167,7 @@
 
 static jclass   gPaint_class;
 static jfieldID gPaint_nativeInstanceID;
+static jfieldID gPaint_nativeTypefaceID;
 
 static jclass   gPicture_class;
 static jfieldID gPicture_nativeInstanceID;
@@ -334,6 +335,16 @@
     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 @@
 
     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");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index cb154aa..4c42341 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -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 @@
 
     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);
diff --git a/core/jni/android/graphics/MinikinSkia.cpp b/core/jni/android/graphics/MinikinSkia.cpp
index 622c935..60d1fd8 100644
--- a/core/jni/android/graphics/MinikinSkia.cpp
+++ b/core/jni/android/graphics/MinikinSkia.cpp
@@ -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 @@
     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) {
diff --git a/core/jni/android/graphics/MinikinSkia.h b/core/jni/android/graphics/MinikinSkia.h
index 0edb557..7a8954d 100644
--- a/core/jni/android/graphics/MinikinSkia.h
+++ b/core/jni/android/graphics/MinikinSkia.h
@@ -27,6 +27,9 @@
     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 @@
 
 private:
     SkTypeface *mTypeface;
-
 };
 
 }  // namespace android
\ No newline at end of file
diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp
new file mode 100644
index 0000000..0f13271
--- /dev/null
+++ b/core/jni/android/graphics/MinikinUtils.cpp
@@ -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);
+}
+
+}
diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h
new file mode 100644
index 0000000..5668ad7
--- /dev/null
+++ b/core/jni/android/graphics/MinikinUtils.h
@@ -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
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 08a88d1..a4c2dd2 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -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 @@
         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 @@
         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 @@
         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 @@
         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 @@
         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 @@
         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 @@
     }
 
     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 @@
     {"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},
 
 
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index a349a7f..02b04de 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -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_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 @@
     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 @@
                                            (void*)Typeface_createFromAsset },
     { "nativeCreateFromFile",     "(Ljava/lang/String;)J",
                                            (void*)Typeface_createFromFile },
+    { "nativeCreateFromArray",    "([J)J",
+                                           (void*)Typeface_createFromArray },
 };
 
 int register_android_graphics_Typeface(JNIEnv* env)
diff --git a/core/jni/android/graphics/TypefaceImpl.cpp b/core/jni/android/graphics/TypefaceImpl.cpp
index f6d3a6e..a60dd7e 100644
--- a/core/jni/android/graphics/TypefaceImpl.cpp
+++ b/core/jni/android/graphics/TypefaceImpl.cpp
@@ -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 @@
     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 @@
     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);
 }
diff --git a/core/jni/android/graphics/TypefaceImpl.h b/core/jni/android/graphics/TypefaceImpl.h
index 4c51bec..4e021cd 100644
--- a/core/jni/android/graphics/TypefaceImpl.h
+++ b/core/jni/android/graphics/TypefaceImpl.h
@@ -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_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);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index ef5ebd0..eca2767 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -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 @@
     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 @@
 
     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 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 @@
 
     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_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 @@
     { "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 },