diff options
-rw-r--r-- | core/jni/Android.mk | 11 | ||||
-rw-r--r-- | core/jni/android/graphics/Canvas.cpp | 105 | ||||
-rw-r--r-- | core/jni/android/graphics/MinikinSkia.cpp | 82 | ||||
-rw-r--r-- | core/jni/android/graphics/MinikinSkia.h | 42 | ||||
-rw-r--r-- | core/jni/android/graphics/Paint.cpp | 5 | ||||
-rw-r--r-- | core/jni/android/graphics/Typeface.cpp | 123 | ||||
-rw-r--r-- | core/jni/android/graphics/TypefaceImpl.cpp | 256 | ||||
-rw-r--r-- | core/jni/android/graphics/TypefaceImpl.h | 60 | ||||
-rw-r--r-- | graphics/java/android/graphics/Canvas.java | 24 | ||||
-rw-r--r-- | graphics/java/android/graphics/Paint.java | 7 | ||||
-rw-r--r-- | graphics/java/android/graphics/Typeface.java | 5 |
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; |