Typeface.cpp revision a0398430fcf365fba6e42ad0bdca2fbf45ed6fe0
1#include "jni.h" 2#include <android_runtime/AndroidRuntime.h> 3 4#include "GraphicsJNI.h" 5#include "SkStream.h" 6#include "SkTypeface.h" 7#include <android_runtime/android_util_AssetManager.h> 8#include <androidfw/AssetManager.h> 9 10using namespace android; 11 12class AutoJavaStringToUTF8 { 13public: 14 AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str) 15 { 16 fCStr = env->GetStringUTFChars(str, NULL); 17 } 18 ~AutoJavaStringToUTF8() 19 { 20 fEnv->ReleaseStringUTFChars(fJStr, fCStr); 21 } 22 const char* c_str() const { return fCStr; } 23 24private: 25 JNIEnv* fEnv; 26 jstring fJStr; 27 const char* fCStr; 28}; 29 30static jlong Typeface_create(JNIEnv* env, jobject, jstring name, 31 jint styleHandle) { 32 SkTypeface::Style style = static_cast<SkTypeface::Style>(styleHandle); 33 SkTypeface* face = NULL; 34 35 if (NULL != name) { 36 AutoJavaStringToUTF8 str(env, name); 37 face = SkTypeface::CreateFromName(str.c_str(), style); 38 // Try to find the closest matching font, using the standard heuristic 39 if (NULL == face) { 40 face = SkTypeface::CreateFromName(str.c_str(), (SkTypeface::Style)(style ^ SkTypeface::kItalic)); 41 } 42 for (int i = 0; NULL == face && i < 4; i++) { 43 face = SkTypeface::CreateFromName(str.c_str(), (SkTypeface::Style)i); 44 } 45 } 46 47 // return the default font at the best style if no exact match exists 48 if (NULL == face) { 49 face = SkTypeface::CreateFromName(NULL, style); 50 } 51 return reinterpret_cast<jlong>(face); 52} 53 54static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandle, jint style) { 55 SkTypeface* family = reinterpret_cast<SkTypeface*>(familyHandle); 56 SkTypeface* face = SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)style); 57 // Try to find the closest matching font, using the standard heuristic 58 if (NULL == face) { 59 face = SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic)); 60 } 61 for (int i = 0; NULL == face && i < 4; i++) { 62 face = SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)i); 63 } 64 if (NULL == face) { 65 face = SkTypeface::CreateFromName(NULL, (SkTypeface::Style)style); 66 } 67 return reinterpret_cast<jlong>(face); 68} 69 70static void Typeface_unref(JNIEnv* env, jobject obj, jlong faceHandle) { 71 SkTypeface* face = reinterpret_cast<SkTypeface*>(faceHandle); 72 SkSafeUnref(face); 73} 74 75static jint Typeface_getStyle(JNIEnv* env, jobject obj, jlong faceHandle) { 76 SkTypeface* face = reinterpret_cast<SkTypeface*>(faceHandle); 77 return static_cast<jint>(face->style()); 78} 79 80class AssetStream : public SkStream { 81public: 82 AssetStream(Asset* asset, bool hasMemoryBase) : fAsset(asset) 83 { 84 fMemoryBase = hasMemoryBase ? fAsset->getBuffer(false) : NULL; 85 } 86 87 virtual ~AssetStream() 88 { 89 delete fAsset; 90 } 91 92 virtual const void* getMemoryBase() 93 { 94 return fMemoryBase; 95 } 96 97 virtual bool rewind() 98 { 99 off64_t pos = fAsset->seek(0, SEEK_SET); 100 return pos != (off64_t)-1; 101 } 102 103 virtual size_t read(void* buffer, size_t size) 104 { 105 ssize_t amount; 106 107 if (NULL == buffer) 108 { 109 if (0 == size) // caller is asking us for our total length 110 return fAsset->getLength(); 111 112 // asset->seek returns new total offset 113 // we want to return amount that was skipped 114 115 off64_t oldOffset = fAsset->seek(0, SEEK_CUR); 116 if (-1 == oldOffset) 117 return 0; 118 off64_t newOffset = fAsset->seek(size, SEEK_CUR); 119 if (-1 == newOffset) 120 return 0; 121 122 amount = newOffset - oldOffset; 123 } 124 else 125 { 126 amount = fAsset->read(buffer, size); 127 } 128 129 if (amount < 0) 130 amount = 0; 131 return amount; 132 } 133 134private: 135 Asset* fAsset; 136 const void* fMemoryBase; 137}; 138 139static jlong Typeface_createFromAsset(JNIEnv* env, jobject, 140 jobject jassetMgr, 141 jstring jpath) { 142 143 NPE_CHECK_RETURN_ZERO(env, jassetMgr); 144 NPE_CHECK_RETURN_ZERO(env, jpath); 145 146 AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr); 147 if (NULL == mgr) { 148 return NULL; 149 } 150 151 AutoJavaStringToUTF8 str(env, jpath); 152 Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER); 153 if (NULL == asset) { 154 return NULL; 155 } 156 157 SkStream* stream = new AssetStream(asset, true); 158 SkTypeface* face = SkTypeface::CreateFromStream(stream); 159 // SkTypeFace::CreateFromStream calls ref() on the stream, so we 160 // need to unref it here or it won't be freed later on 161 stream->unref(); 162 163 return reinterpret_cast<jlong>(face); 164} 165 166static jlong Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) { 167 NPE_CHECK_RETURN_ZERO(env, jpath); 168 169 AutoJavaStringToUTF8 str(env, jpath); 170 171 return reinterpret_cast<jlong>(SkTypeface::CreateFromFile(str.c_str())); 172} 173 174/////////////////////////////////////////////////////////////////////////////// 175 176static JNINativeMethod gTypefaceMethods[] = { 177 { "nativeCreate", "(Ljava/lang/String;I)J", (void*)Typeface_create }, 178 { "nativeCreateFromTypeface", "(JI)J", (void*)Typeface_createFromTypeface }, 179 { "nativeUnref", "(J)V", (void*)Typeface_unref }, 180 { "nativeGetStyle", "(J)I", (void*)Typeface_getStyle }, 181 { "nativeCreateFromAsset", "(Landroid/content/res/AssetManager;Ljava/lang/String;)J", 182 (void*)Typeface_createFromAsset }, 183 { "nativeCreateFromFile", "(Ljava/lang/String;)J", 184 (void*)Typeface_createFromFile }, 185}; 186 187int register_android_graphics_Typeface(JNIEnv* env) 188{ 189 return android::AndroidRuntime::registerNativeMethods(env, 190 "android/graphics/Typeface", 191 gTypefaceMethods, 192 SK_ARRAY_COUNT(gTypefaceMethods)); 193} 194