Initial integration of Minikin to framework

With this patch, framework does at least some of its text rendering
using Minikin instead of TextLayoutCache. There's a lot of stuff broken
and not yet implemented, but the phone will boot.

Changes are hidden behind USE_MINIKIN, which should be set in
BoardConfig.mk for the brave. Without that, there are changes to
signatures in JNI methods and so on, but shouldn't be any visible
changes.

This commit also introduces a new abstraction for Typeface:

The new TypefaceImpl abstraction represents the functionality that
corresponds to a Java Typeface object. Currently it is backed by
SkTypeface, but in the migration to Minikin it is a FontCollection
combined with a FontStyle. This patch introduces a USE_MINIKIN
preprocessor switch, so there is no substantial change to existing
Skia-based code, but which lets us start replacing the implementation
with the Minikin version.

Change-Id: I532c4c2d32d4f4c1f349dc1db37caa112af587ea
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 5983120..f874b20 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -114,6 +114,7 @@
 	android/graphics/TextLayout.cpp \
 	android/graphics/TextLayoutCache.cpp \
 	android/graphics/Typeface.cpp \
+	android/graphics/TypefaceImpl.cpp \
 	android/graphics/Utils.cpp \
 	android/graphics/Xfermode.cpp \
 	android/graphics/YuvToJpegEncoder.cpp \
@@ -216,6 +217,16 @@
 	LOCAL_SHARED_LIBRARIES += libhwui
 endif
 
+ifeq ($(USE_MINIKIN), true)
+	LOCAL_CFLAGS += -DUSE_MINIKIN
+	LOCAL_C_INCLUDES += frameworks/minikin/include \
+		external/freetype/include
+	LOCAL_SRC_FILES += 	android/graphics/MinikinSkia.cpp
+# note: the freetype include is spurious; minikin itself probably
+# shouldn't depend on it
+	LOCAL_SHARED_LIBRARIES += libminikin libstlport
+endif
+
 LOCAL_SHARED_LIBRARIES += \
 	libdl
 # we need to access the private Bionic header
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 813dd5a..9a00d538 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -27,8 +27,14 @@
 #include "SkShader.h"
 #include "SkTemplates.h"
 
+#ifdef USE_MINIKIN
+#include <minikin/Layout.h>
+#include "MinikinSkia.h"
+#endif
+
 #include "TextLayout.h"
 #include "TextLayoutCache.h"
+#include "TypefaceImpl.h"
 
 #include "unicode/ubidi.h"
 #include "unicode/ushape.h"
@@ -742,35 +748,83 @@
     }
 
 
-    static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+    static void drawText___CIIFFIPaintTypeface(JNIEnv* env, jobject, SkCanvas* canvas,
                                       jcharArray text, int index, int count,
-                                      jfloat x, jfloat y, int flags, SkPaint* paint) {
+                                      jfloat x, jfloat y, int flags, SkPaint* paint,
+                                      TypefaceImpl *typeface) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
+        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint, typeface);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
     }
 
-    static void drawText__StringIIFFIPaint(JNIEnv* env, jobject,
+    static void drawText__StringIIFFIPaintTypeface(JNIEnv* env, jobject,
                                           SkCanvas* canvas, jstring text,
                                           int start, int end,
-                                          jfloat x, jfloat y, int flags, SkPaint* paint) {
+                                          jfloat x, jfloat y, int flags, SkPaint* paint,
+                                          TypefaceImpl *typeface) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
+        drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint, typeface);
         env->ReleaseStringChars(text, textArray);
     }
 
+#ifdef USE_MINIKIN
+    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];
+        SkTypeface *lastFace = NULL;
+        SkTypeface *skFace = NULL;
+        size_t start = 0;
+
+        paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        for (size_t i = 0; i < nGlyphs; i++) {
+            MinikinFontSkia *mfs = static_cast<MinikinFontSkia *>(layout->getFont(i));
+            skFace = mfs->GetSkTypeface();
+            glyphs[i] = layout->getGlyphId(i);
+            pos[i].fX = SkFloatToScalar(x + layout->getX(i));
+            pos[i].fY = SkFloatToScalar(y + layout->getY(i));
+            if (i > 0 && skFace != lastFace) {
+                paint->setTypeface(lastFace);
+                canvas->drawPosText(glyphs + start, (i - start) << 1, pos + start, *paint);
+                start = i;
+            }
+            lastFace = skFace;
+        }
+        if (skFace != NULL) {
+            paint->setTypeface(skFace);
+            canvas->drawPosText(glyphs + start, (nGlyphs - start) << 1, pos + start, *paint);
+        }
+        delete[] glyphs;
+        delete[] pos;
+    }
+#endif
+
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int end,
-            jfloat x, jfloat y, int flags, SkPaint* paint) {
+            jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) {
 
         jint count = end - start;
-        drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint);
+        drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint, typeface);
     }
 
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int count, int contextCount,
-            jfloat x, jfloat y, int flags, SkPaint* paint) {
+            jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) {
 
+#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);
+        layout.doLayout(textArray + start, count);
+        drawGlyphsToSkia(canvas, paint, &layout, x, y);
+#else
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
                 textArray, start, count, contextCount, flags);
         if (value == NULL) {
@@ -786,6 +840,7 @@
         doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, flags, paint);
         doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint);
         paint->setTextAlign(align);
+#endif
     }
 
 // Same values used by Skia
@@ -842,27 +897,29 @@
         delete[] posPtr;
     }
 
-    static void drawTextRun___CIIIIFFIPaint(
+    static void drawTextRun___CIIIIFFIPaintTypeface(
         JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
         int count, int contextIndex, int contextCount,
-        jfloat x, jfloat y, int dirFlags, SkPaint* paint) {
+        jfloat x, jfloat y, int dirFlags, SkPaint* paint,
+        TypefaceImpl* typeface) {
 
         jchar* chars = env->GetCharArrayElements(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
-                count, contextCount, x, y, dirFlags, paint);
+                count, contextCount, x, y, dirFlags, paint, typeface);
         env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
     }
 
-    static void drawTextRun__StringIIIIFFIPaint(
+    static void drawTextRun__StringIIIIFFIPaintTypeface(
         JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, jint start,
         jint end, jint contextStart, jint contextEnd,
-        jfloat x, jfloat y, jint dirFlags, SkPaint* paint) {
+        jfloat x, jfloat y, jint dirFlags, SkPaint* paint,
+        TypefaceImpl* typeface) {
 
         jint count = end - start;
         jint contextCount = contextEnd - contextStart;
         const jchar* chars = env->GetStringChars(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
-                count, contextCount, x, y, dirFlags, paint);
+                count, contextCount, x, y, dirFlags, paint, typeface);
         env->ReleaseStringChars(text, chars);
     }
 
@@ -1070,14 +1127,14 @@
         (void*)SkCanvasGlue::drawBitmapMesh},
     {"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
         (void*)SkCanvasGlue::drawVertices},
-    {"native_drawText","(I[CIIFFII)V",
-        (void*) SkCanvasGlue::drawText___CIIFFIPaint},
-    {"native_drawText","(ILjava/lang/String;IIFFII)V",
-        (void*) SkCanvasGlue::drawText__StringIIFFIPaint},
-    {"native_drawTextRun","(I[CIIIIFFII)V",
-        (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
-    {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
-        (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint},
+    {"native_drawText","(I[CIIFFIII)V",
+        (void*) SkCanvasGlue::drawText___CIIFFIPaintTypeface},
+    {"native_drawText","(ILjava/lang/String;IIFFIII)V",
+        (void*) SkCanvasGlue::drawText__StringIIFFIPaintTypeface},
+    {"native_drawTextRun","(I[CIIIIFFIII)V",
+        (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaintTypeface},
+    {"native_drawTextRun","(ILjava/lang/String;IIIIFFIII)V",
+        (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaintTypeface},
     {"native_drawPosText","(I[CII[FI)V",
         (void*) SkCanvasGlue::drawPosText___CII_FPaint},
     {"native_drawPosText","(ILjava/lang/String;[FI)V",
diff --git a/core/jni/android/graphics/MinikinSkia.cpp b/core/jni/android/graphics/MinikinSkia.cpp
new file mode 100644
index 0000000..622c935
--- /dev/null
+++ b/core/jni/android/graphics/MinikinSkia.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013 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 <SkTypeface.h>
+#include <SkPaint.h>
+#include <SkFP.h>
+
+#define LOG_TAG "Minikin"
+#include <cutils/log.h>
+
+#include <minikin/MinikinFont.h>
+#include "MinikinSkia.h"
+
+namespace android {
+
+MinikinFontSkia::MinikinFontSkia(SkTypeface *typeface) :
+    mTypeface(typeface) {
+}
+
+MinikinFontSkia::~MinikinFontSkia() {
+    SkSafeUnref(mTypeface);
+}
+
+bool MinikinFontSkia::GetGlyph(uint32_t codepoint, uint32_t *glyph) const {
+    SkPaint paint;
+    paint.setTypeface(mTypeface);
+    paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
+    uint16_t glyph16;
+    paint.textToGlyphs(&codepoint, sizeof(codepoint), &glyph16);
+    *glyph  = glyph16;
+    return !!glyph;
+}
+
+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);
+    uint16_t glyph16 = glyph_id;
+    SkScalar skWidth;
+    SkRect skBounds;
+    skpaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, &skBounds);
+    // TODO: get bounds information
+    return SkScalarToFP(skWidth);
+}
+
+bool MinikinFontSkia::GetTable(uint32_t tag, uint8_t *buf, size_t *size) {
+    if (buf == NULL) {
+        const size_t tableSize = mTypeface->getTableSize(tag);
+        *size = tableSize;
+        return tableSize != 0;
+    } else {
+        const size_t actualSize = mTypeface->getTableData(tag, 0, *size, buf);
+        *size = actualSize;
+        return actualSize != 0;
+    }
+}
+
+SkTypeface *MinikinFontSkia::GetSkTypeface() {
+    return mTypeface;
+}
+
+int32_t MinikinFontSkia::GetUniqueId() const {
+    return mTypeface->uniqueID();
+}
+
+}
diff --git a/core/jni/android/graphics/MinikinSkia.h b/core/jni/android/graphics/MinikinSkia.h
new file mode 100644
index 0000000..0edb557
--- /dev/null
+++ b/core/jni/android/graphics/MinikinSkia.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+namespace android {
+
+class MinikinFontSkia : public MinikinFont {
+public:
+    explicit MinikinFontSkia(SkTypeface *typeface);
+
+    ~MinikinFontSkia();
+
+    bool GetGlyph(uint32_t codepoint, uint32_t *glyph) const;
+
+    float GetHorizontalAdvance(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);
+
+    int32_t GetUniqueId() const;
+
+    SkTypeface *GetSkTypeface();
+
+private:
+    SkTypeface *mTypeface;
+
+};
+
+}  // namespace android
\ No newline at end of file
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 40e0731..1ca3f3a 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -245,7 +245,12 @@
     }
 
     static SkTypeface* setTypeface(JNIEnv* env, jobject clazz, SkPaint* obj, SkTypeface* typeface) {
+#ifndef USE_MINIKIN
         return obj->setTypeface(typeface);
+#else
+        // TODO(raph): not yet implemented
+        return NULL;
+#endif
     }
 
     static SkRasterizer* setRasterizer(JNIEnv* env, jobject clazz, SkPaint* obj, SkRasterizer* rasterizer) {
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index ccd75d5..04f9fe1 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -1,9 +1,26 @@
+/*
+ * Copyright (C) 2013 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 "jni.h"
 #include <android_runtime/AndroidRuntime.h>
 
 #include "GraphicsJNI.h"
 #include "SkStream.h"
 #include "SkTypeface.h"
+#include "TypefaceImpl.h"
 #include <android_runtime/android_util_AssetManager.h>
 #include <androidfw/AssetManager.h>
 
@@ -27,112 +44,46 @@
     const char* fCStr;
 };
 
-static SkTypeface* Typeface_create(JNIEnv* env, jobject, jstring name,
+static TypefaceImpl* Typeface_create(JNIEnv* env, jobject, jstring name,
                                    SkTypeface::Style style) {
-    SkTypeface* face = NULL;
+    TypefaceImpl* face = NULL;
 
     if (NULL != name) {
         AutoJavaStringToUTF8    str(env, name);
-        face = SkTypeface::CreateFromName(str.c_str(), style);
-        // Try to find the closest matching font, using the standard heuristic
-        if (NULL == face) {
-            face = SkTypeface::CreateFromName(str.c_str(), (SkTypeface::Style)(style ^ SkTypeface::kItalic));
-        }
-        for (int i = 0; NULL == face && i < 4; i++) {
-            face = SkTypeface::CreateFromName(str.c_str(), (SkTypeface::Style)i);
-        }
+        face = TypefaceImpl_createFromName(str.c_str(), style);
     }
 
     // return the default font at the best style if no exact match exists
     if (NULL == face) {
-        face = SkTypeface::CreateFromName(NULL, style);
+        face = TypefaceImpl_createFromName(NULL, style);
     }
     return face;
 }
 
-static SkTypeface* Typeface_createFromTypeface(JNIEnv* env, jobject, SkTypeface* family, int style) {
-    SkTypeface* face = SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)style);
+static TypefaceImpl* Typeface_createFromTypeface(JNIEnv* env, jobject, TypefaceImpl* family, int style) {
+    TypefaceImpl* face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)style);
     // Try to find the closest matching font, using the standard heuristic
     if (NULL == face) {
-        face = SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));
+        face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));
     }
     for (int i = 0; NULL == face && i < 4; i++) {
-        face = SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)i);
+        face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)i);
     }
     if (NULL == face) {
-        face = SkTypeface::CreateFromName(NULL, (SkTypeface::Style)style);
+        face = TypefaceImpl_createFromName(NULL, (SkTypeface::Style)style);
     }
     return face;
 }
 
-static void Typeface_unref(JNIEnv* env, jobject obj, SkTypeface* face) {
-    SkSafeUnref(face);
+static void Typeface_unref(JNIEnv* env, jobject obj, TypefaceImpl* face) {
+    TypefaceImpl_unref(face);
 }
 
-static int Typeface_getStyle(JNIEnv* env, jobject obj, SkTypeface* face) {
-    return face->style();
+static int Typeface_getStyle(JNIEnv* env, jobject obj, TypefaceImpl* face) {
+    return TypefaceImpl_getStyle(face);
 }
 
-class AssetStream : public SkStream {
-public:
-    AssetStream(Asset* asset, bool hasMemoryBase) : fAsset(asset)
-    {
-        fMemoryBase = hasMemoryBase ? fAsset->getBuffer(false) : NULL;
-    }
-
-    virtual ~AssetStream()
-    {
-        delete fAsset;
-    }
-
-    virtual const void* getMemoryBase()
-    {
-        return fMemoryBase;
-    }
-
-	virtual bool rewind()
-    {
-        off64_t pos = fAsset->seek(0, SEEK_SET);
-        return pos != (off64_t)-1;
-    }
-
-	virtual size_t read(void* buffer, size_t size)
-    {
-        ssize_t amount;
-
-        if (NULL == buffer)
-        {
-            if (0 == size)  // caller is asking us for our total length
-                return fAsset->getLength();
-
-            // asset->seek returns new total offset
-            // we want to return amount that was skipped
-
-            off64_t oldOffset = fAsset->seek(0, SEEK_CUR);
-            if (-1 == oldOffset)
-                return 0;
-            off64_t newOffset = fAsset->seek(size, SEEK_CUR);
-            if (-1 == newOffset)
-                return 0;
-
-            amount = newOffset - oldOffset;
-        }
-        else
-        {
-            amount = fAsset->read(buffer, size);
-        }
-
-        if (amount < 0)
-            amount = 0;
-        return amount;
-    }
-
-private:
-    Asset*      fAsset;
-    const void* fMemoryBase;
-};
-
-static SkTypeface* Typeface_createFromAsset(JNIEnv* env, jobject,
+static TypefaceImpl* Typeface_createFromAsset(JNIEnv* env, jobject,
                                             jobject jassetMgr,
                                             jstring jpath) {
 
@@ -150,21 +101,15 @@
         return NULL;
     }
 
-    SkStream* stream = new AssetStream(asset, true);
-    SkTypeface* face = SkTypeface::CreateFromStream(stream);
-    // SkTypeFace::CreateFromStream calls ref() on the stream, so we
-    // need to unref it here or it won't be freed later on
-    stream->unref();
-
-    return face;
+    return TypefaceImpl_createFromAsset(asset);
 }
 
-static SkTypeface* Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) {
+static TypefaceImpl* Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) {
     NPE_CHECK_RETURN_ZERO(env, jpath);
 
     AutoJavaStringToUTF8 str(env, jpath);
 
-    return SkTypeface::CreateFromFile(str.c_str());
+    return TypefaceImpl_createFromFile(str.c_str());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android/graphics/TypefaceImpl.cpp b/core/jni/android/graphics/TypefaceImpl.cpp
new file mode 100644
index 0000000..8874db8
--- /dev/null
+++ b/core/jni/android/graphics/TypefaceImpl.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+/**
+ * This is the implementation of the Typeface object. Historically, it has
+ * just been SkTypeface, but we are migrating to Minikin. For the time
+ * being, that choice is hidden under the USE_MINIKIN compile-time flag.
+ */
+
+#include "SkStream.h"
+#include "SkTypeface.h"
+
+#ifdef USE_MINIKIN
+#include <vector>
+#include <minikin/FontCollection.h>
+#include <minikin/FontFamily.h>
+#include <minikin/Layout.h>
+#include "MinikinSkia.h"
+#endif
+
+#include "TypefaceImpl.h"
+
+namespace android {
+
+class AssetStream : public SkStream {
+public:
+    AssetStream(Asset* asset, bool hasMemoryBase) : fAsset(asset)
+    {
+        fMemoryBase = hasMemoryBase ? fAsset->getBuffer(false) : NULL;
+    }
+
+    virtual ~AssetStream()
+    {
+        delete fAsset;
+    }
+
+    virtual const void* getMemoryBase()
+    {
+        return fMemoryBase;
+    }
+
+    virtual bool rewind()
+    {
+        off64_t pos = fAsset->seek(0, SEEK_SET);
+        return pos != (off64_t)-1;
+    }
+
+    virtual size_t read(void* buffer, size_t size)
+    {
+        ssize_t amount;
+
+        if (NULL == buffer)
+        {
+            if (0 == size)  // caller is asking us for our total length
+                return fAsset->getLength();
+
+            // asset->seek returns new total offset
+            // we want to return amount that was skipped
+
+            off64_t oldOffset = fAsset->seek(0, SEEK_CUR);
+            if (-1 == oldOffset)
+                return 0;
+            off64_t newOffset = fAsset->seek(size, SEEK_CUR);
+            if (-1 == newOffset)
+                return 0;
+
+            amount = newOffset - oldOffset;
+        }
+        else
+        {
+            amount = fAsset->read(buffer, size);
+        }
+
+        if (amount < 0)
+            amount = 0;
+        return amount;
+    }
+
+private:
+    Asset*      fAsset;
+    const void* fMemoryBase;
+};
+
+#ifdef USE_MINIKIN
+
+// Any weight greater than or equal to this is considered "bold" for
+// legacy API.
+static const int kBoldThreshold = 6;
+
+static FontStyle styleFromSkiaStyle(SkTypeface::Style skiaStyle) {
+    int weight = (skiaStyle & SkTypeface::kBold) != 0 ? 7 : 4;
+    bool italic = (skiaStyle & SkTypeface::kItalic) != 0;
+    return FontStyle(weight, italic);
+}
+
+TypefaceImpl* gDefaultTypeface;
+pthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT;
+
+// TODO: this currently builds a font collection from hardcoded paths.
+// It will get replaced by an implementation that parses the XML files.
+static FontCollection *makeFontCollection() {
+    std::vector<FontFamily *>typefaces;
+    const char *fns[] = {
+        "/system/fonts/Roboto-Regular.ttf",
+        "/system/fonts/Roboto-Italic.ttf",
+        "/system/fonts/Roboto-BoldItalic.ttf",
+        "/system/fonts/Roboto-Light.ttf",
+        "/system/fonts/Roboto-Thin.ttf",
+        "/system/fonts/Roboto-Bold.ttf",
+        "/system/fonts/Roboto-ThinItalic.ttf",
+        "/system/fonts/Roboto-LightItalic.ttf"
+    };
+
+    FontFamily *family = new FontFamily();
+    for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) {
+        const char *fn = fns[i];
+        SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
+        MinikinFont *font = new MinikinFontSkia(skFace);
+        family->addFont(font);
+    }
+    typefaces.push_back(family);
+
+    family = new FontFamily();
+    const char *fn = "/system/fonts/NotoSansDevanagari-Regular.ttf";
+    SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
+    MinikinFont *font = new MinikinFontSkia(skFace);
+    family->addFont(font);
+    typefaces.push_back(family);
+
+    return new FontCollection(typefaces);
+}
+
+static void getDefaultTypefaceOnce() {
+    Layout::init();
+    gDefaultTypeface = new TypefaceImpl;
+    gDefaultTypeface->fFontCollection = makeFontCollection();
+    gDefaultTypeface->fStyle = FontStyle();
+}
+
+TypefaceImpl* TypefaceImpl_resolveDefault(TypefaceImpl* src) {
+    if (src == NULL) {
+        pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce);
+        return gDefaultTypeface;
+    } else {
+        return src;
+    }
+}
+
+TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style) {
+    TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(src);
+    TypefaceImpl* result = new TypefaceImpl;
+    if (result != 0) {
+        result->fFontCollection = resolvedFace->fFontCollection;
+        result->fStyle = styleFromSkiaStyle(style);
+    }
+    return result;
+}
+
+static TypefaceImpl* createFromSkTypeface(SkTypeface* typeface) {
+    MinikinFont* minikinFont = new MinikinFontSkia(typeface);
+    std::vector<FontFamily *> typefaces;
+    FontFamily* family = new FontFamily();
+    family->addFont(minikinFont);
+    typefaces.push_back(family);
+    TypefaceImpl* result = new TypefaceImpl;
+    result->fFontCollection = new FontCollection(typefaces);
+    result->fStyle = FontStyle();  // TODO: improve
+    return result;
+}
+
+TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style) {
+    // TODO: should create a font collection with all styles corresponding to
+    // the name
+    SkTypeface* face = SkTypeface::CreateFromName(name, style);
+    return createFromSkTypeface(face);
+}
+
+TypefaceImpl* TypefaceImpl_createFromFile(const char* filename) {
+    SkTypeface* face = SkTypeface::CreateFromFile(filename);
+    return createFromSkTypeface(face);
+}
+
+TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset) {
+    SkStream* stream = new AssetStream(asset, true);
+    SkTypeface* face = SkTypeface::CreateFromStream(stream);
+    // SkTypeFace::CreateFromStream calls ref() on the stream, so we
+    // need to unref it here or it won't be freed later on
+    stream->unref();
+    return createFromSkTypeface(face);
+}
+
+void TypefaceImpl_unref(TypefaceImpl* face) {
+    delete face;
+}
+
+int TypefaceImpl_getStyle(TypefaceImpl* face) {
+    FontStyle style = face->fStyle;
+    int result = style.getItalic() ? SkTypeface::kItalic : 0;
+    if (style.getWeight() >= kBoldThreshold) {
+        result |= SkTypeface::kBold;
+    }
+    return result;
+}
+
+#else  // USE_MINIKIN
+
+/* Just use SkTypeface instead. */
+
+typedef SkTypeface TypefaceImpl;
+
+TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style) {
+    return SkTypeface::CreateFromTypeface(src, style);
+}
+
+TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style) {
+    return SkTypeface::CreateFromName(name, style);
+}
+
+TypefaceImpl* TypefaceImpl_createFromFile(const char* filename) {
+    return SkTypeface::CreateFromFile(filename);
+}
+
+TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset) {
+    SkStream* stream = new AssetStream(asset, true);
+    SkTypeface* face = SkTypeface::CreateFromStream(stream);
+    // SkTypeFace::CreateFromStream calls ref() on the stream, so we
+    // need to unref it here or it won't be freed later on
+    stream->unref();
+
+    return face;
+}
+
+void TypefaceImpl_unref(TypefaceImpl* face) {
+    SkSafeUnref(face);
+}
+
+int TypefaceImpl_getStyle(TypefaceImpl* face) {
+    return face->style();
+}
+
+#endif  // USE_MINIKIN
+
+}
diff --git a/core/jni/android/graphics/TypefaceImpl.h b/core/jni/android/graphics/TypefaceImpl.h
new file mode 100644
index 0000000..4c51bec
--- /dev/null
+++ b/core/jni/android/graphics/TypefaceImpl.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+
+#ifndef ANDROID_TYPEFACE_IMPL_H
+#define ANDROID_TYPEFACE_IMPL_H
+
+#include <androidfw/AssetManager.h>
+
+#ifdef USE_MINIKIN
+#include <minikin/FontCollection.h>
+#endif
+
+namespace android {
+
+#ifdef USE_MINIKIN
+struct TypefaceImpl {
+    FontCollection *fFontCollection;
+    FontStyle fStyle;
+};
+
+// Note: it would be cleaner if the following functions were member
+// functions (static or otherwise) of the TypefaceImpl class. However,
+// that can't be easily accommodated in the case where TypefaceImpl
+// is just a pointer to SkTypeface, in the non-USE_MINIKIN case.
+// TODO: when #ifdef USE_MINIKIN is removed, move to member functions.
+
+TypefaceImpl* TypefaceImpl_resolveDefault(TypefaceImpl* src);
+#else
+typedef SkTypeface TypefaceImpl;
+#endif
+
+TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style);
+
+TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style);
+
+TypefaceImpl* TypefaceImpl_createFromFile(const char* filename);
+
+TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset);
+
+void TypefaceImpl_unref(TypefaceImpl* face);
+
+int TypefaceImpl_getStyle(TypefaceImpl* face);
+
+}
+
+#endif  // ANDROID_TYPEFACE_IMPL_H
\ No newline at end of file
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index d46238f..13f4299 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1403,7 +1403,7 @@
             throw new IndexOutOfBoundsException();
         }
         native_drawText(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
-                paint.mNativePaint);
+                paint.mNativePaint, paint.mNativeTypeface);
     }
 
     /**
@@ -1417,7 +1417,7 @@
      */
     public void drawText(String text, float x, float y, Paint paint) {
         native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
-                paint.mNativePaint);
+                paint.mNativePaint, paint.mNativeTypeface);
     }
 
     /**
@@ -1436,7 +1436,7 @@
             throw new IndexOutOfBoundsException();
         }
         native_drawText(mNativeCanvas, text, start, end, x, y, paint.mBidiFlags,
-                paint.mNativePaint);
+                paint.mNativePaint, paint.mNativeTypeface);
     }
 
     /**
@@ -1456,7 +1456,7 @@
         if (text instanceof String || text instanceof SpannedString ||
             text instanceof SpannableString) {
             native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
-                    paint.mBidiFlags, paint.mNativePaint);
+                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawText(this, start, end, x, y,
                     paint);
@@ -1464,7 +1464,7 @@
             char[] buf = TemporaryBuffer.obtain(end - start);
             TextUtils.getChars(text, start, end, buf, 0);
             native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
-                    paint.mBidiFlags, paint.mNativePaint);
+                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1507,7 +1507,7 @@
         }
 
         native_drawTextRun(mNativeCanvas, text, index, count,
-                contextIndex, contextCount, x, y, dir, paint.mNativePaint);
+                contextIndex, contextCount, x, y, dir, paint.mNativePaint, paint.mNativeTypeface);
     }
 
     /**
@@ -1545,7 +1545,7 @@
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             native_drawTextRun(mNativeCanvas, text.toString(), start, end,
-                    contextStart, contextEnd, x, y, flags, paint.mNativePaint);
+                    contextStart, 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);
@@ -1555,7 +1555,7 @@
             char[] buf = TemporaryBuffer.obtain(contextLen);
             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
             native_drawTextRun(mNativeCanvas, buf, start - contextStart, len,
-                    0, contextLen, x, y, flags, paint.mNativePaint);
+                    0, contextLen, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1814,18 +1814,18 @@
     
     private static native void native_drawText(int nativeCanvas, char[] text,
                                                int index, int count, float x,
-                                               float y, int flags, int paint);
+                                               float y, int flags, int paint, int typeface);
     private static native void native_drawText(int nativeCanvas, String text,
                                                int start, int end, float x,
-                                               float y, int flags, int paint);
+                                               float y, int flags, int paint, int typeface);
 
     private static native void native_drawTextRun(int nativeCanvas, String text,
             int start, int end, int contextStart, int contextEnd,
-            float x, float y, int flags, int paint);
+            float x, float y, int flags, int paint, int typeface);
 
     private static native void native_drawTextRun(int nativeCanvas, char[] text,
             int start, int count, int contextStart, int contextCount,
-            float x, float y, int flags, int paint);
+            float x, float y, int flags, int paint, int typeface);
 
     private static native void native_drawPosText(int nativeCanvas,
                                                   char[] text, int index,
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 5fc2588..c2d4df2 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -33,6 +33,10 @@
      * @hide
      */
     public int mNativePaint;
+    /**
+     * @hide
+     */
+    public int mNativeTypeface;
 
     private ColorFilter mColorFilter;
     private MaskFilter  mMaskFilter;
@@ -481,6 +485,7 @@
         mRasterizer = null;
         mShader = null;
         mTypeface = null;
+        mNativeTypeface = 0;
         mXfermode = null;
 
         mHasCompatScaling = false;
@@ -525,6 +530,7 @@
             mShader = null;
         }
         mTypeface = paint.mTypeface;
+        mNativeTypeface = paint.mNativeTypeface;
         mXfermode = paint.mXfermode;
 
         mHasCompatScaling = paint.mHasCompatScaling;
@@ -1087,6 +1093,7 @@
         }
         native_setTypeface(mNativePaint, typefaceNative);
         mTypeface = typeface;
+        mNativeTypeface = typefaceNative;
         return typeface;
     }
     
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index c68c9f7..aea3ee5 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -48,7 +48,10 @@
     private static final SparseArray<SparseArray<Typeface>> sTypefaceCache =
             new SparseArray<SparseArray<Typeface>>(3);
 
-    int native_instance;
+    /**
+     * @hide
+     */
+    public int native_instance;
 
     // Style
     public static final int NORMAL = 0;