summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/jni/Android.mk11
-rw-r--r--core/jni/android/graphics/Canvas.cpp105
-rw-r--r--core/jni/android/graphics/MinikinSkia.cpp82
-rw-r--r--core/jni/android/graphics/MinikinSkia.h42
-rw-r--r--core/jni/android/graphics/Paint.cpp5
-rw-r--r--core/jni/android/graphics/Typeface.cpp123
-rw-r--r--core/jni/android/graphics/TypefaceImpl.cpp256
-rw-r--r--core/jni/android/graphics/TypefaceImpl.h60
-rw-r--r--graphics/java/android/graphics/Canvas.java24
-rw-r--r--graphics/java/android/graphics/Paint.java7
-rw-r--r--graphics/java/android/graphics/Typeface.java5
11 files changed, 594 insertions, 126 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 2e0c28e..04661d7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -115,6 +115,7 @@ LOCAL_SRC_FILES:= \
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 \
@@ -217,6 +218,16 @@ ifeq ($(USE_OPENGL_RENDERER),true)
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..9a00d53 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 @@ public:
}
- 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 @@ public:
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 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l
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 @@ static JNINativeMethod gCanvasMethods[] = {
(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 @@ public:
}
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 @@ private:
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 @@ static SkTypeface* Typeface_createFromAsset(JNIEnv* env, jobject,
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 @@ public class Canvas {
throw new IndexOutOfBoundsException();
}
native_drawText(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
- paint.mNativePaint);
+ paint.mNativePaint, paint.mNativeTypeface);
}
/**
@@ -1417,7 +1417,7 @@ public class Canvas {
*/
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 @@ public class Canvas {
throw new IndexOutOfBoundsException();
}
native_drawText(mNativeCanvas, text, start, end, x, y, paint.mBidiFlags,
- paint.mNativePaint);
+ paint.mNativePaint, paint.mNativeTypeface);
}
/**
@@ -1456,7 +1456,7 @@ public class Canvas {
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 @@ public class Canvas {
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 @@ public class Canvas {
}
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 @@ public class Canvas {
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 @@ public class Canvas {
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 @@ public class Canvas {
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 @@ public class Paint {
* @hide
*/
public int mNativePaint;
+ /**
+ * @hide
+ */
+ public int mNativeTypeface;
private ColorFilter mColorFilter;
private MaskFilter mMaskFilter;
@@ -481,6 +485,7 @@ public class Paint {
mRasterizer = null;
mShader = null;
mTypeface = null;
+ mNativeTypeface = 0;
mXfermode = null;
mHasCompatScaling = false;
@@ -525,6 +530,7 @@ public class Paint {
mShader = null;
}
mTypeface = paint.mTypeface;
+ mNativeTypeface = paint.mNativeTypeface;
mXfermode = paint.mXfermode;
mHasCompatScaling = paint.mHasCompatScaling;
@@ -1087,6 +1093,7 @@ public class Paint {
}
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 @@ public class Typeface {
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;