blob: d096c2a2c17911413973c3fee3ead6ef1be5df8c [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001#include "jni.h"
2#include <android_runtime/AndroidRuntime.h>
3
4#include "GraphicsJNI.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005#include "SkStream.h"
6#include "SkTypeface.h"
Mathias Agopianb13b9bd2012-02-17 18:27:36 -08007#include <android_runtime/android_util_AssetManager.h>
8#include <androidfw/AssetManager.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009
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
Ashok Bhata0398432014-01-20 20:08:01 +000030static jlong Typeface_create(JNIEnv* env, jobject, jstring name,
31 jint styleHandle) {
32 SkTypeface::Style style = static_cast<SkTypeface::Style>(styleHandle);
Derek Sollenberger89ec8292013-09-18 15:07:46 -040033 SkTypeface* face = NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
Derek Sollenberger89ec8292013-09-18 15:07:46 -040035 if (NULL != name) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036 AutoJavaStringToUTF8 str(env, name);
The Android Open Source Project4df24232009-03-05 14:34:35 -080037 face = SkTypeface::CreateFromName(str.c_str(), style);
Raph Levien4f0064f2013-11-06 11:12:11 -080038 // 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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 }
Derek Sollenberger89ec8292013-09-18 15:07:46 -040046
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 }
Ashok Bhata0398432014-01-20 20:08:01 +000051 return reinterpret_cast<jlong>(face);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052}
53
Ashok Bhata0398432014-01-20 20:08:01 +000054static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandle, jint style) {
55 SkTypeface* family = reinterpret_cast<SkTypeface*>(familyHandle);
Derek Sollenbergerfe8e21f2013-09-23 08:32:16 -040056 SkTypeface* face = SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)style);
Raph Levien4f0064f2013-11-06 11:12:11 -080057 // 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 }
Derek Sollenbergerfe8e21f2013-09-23 08:32:16 -040064 if (NULL == face) {
65 face = SkTypeface::CreateFromName(NULL, (SkTypeface::Style)style);
66 }
Ashok Bhata0398432014-01-20 20:08:01 +000067 return reinterpret_cast<jlong>(face);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068}
Elliott Hughes4cb17532011-04-12 16:10:26 -070069
Ashok Bhata0398432014-01-20 20:08:01 +000070static void Typeface_unref(JNIEnv* env, jobject obj, jlong faceHandle) {
71 SkTypeface* face = reinterpret_cast<SkTypeface*>(faceHandle);
Mike Reed31a69fd2009-12-14 14:57:01 -050072 SkSafeUnref(face);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073}
74
Ashok Bhata0398432014-01-20 20:08:01 +000075static jint Typeface_getStyle(JNIEnv* env, jobject obj, jlong faceHandle) {
76 SkTypeface* face = reinterpret_cast<SkTypeface*>(faceHandle);
77 return static_cast<jint>(face->style());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078}
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 }
Elliott Hughes4cb17532011-04-12 16:10:26 -070091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 virtual const void* getMemoryBase()
93 {
94 return fMemoryBase;
95 }
96
97 virtual bool rewind()
98 {
Kenny Rootddb76c42010-11-24 12:56:06 -080099 off64_t pos = fAsset->seek(0, SEEK_SET);
100 return pos != (off64_t)-1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 }
Elliott Hughes4cb17532011-04-12 16:10:26 -0700102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 virtual size_t read(void* buffer, size_t size)
104 {
105 ssize_t amount;
Elliott Hughes4cb17532011-04-12 16:10:26 -0700106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 if (NULL == buffer)
108 {
109 if (0 == size) // caller is asking us for our total length
110 return fAsset->getLength();
Elliott Hughes4cb17532011-04-12 16:10:26 -0700111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 // asset->seek returns new total offset
113 // we want to return amount that was skipped
Elliott Hughes4cb17532011-04-12 16:10:26 -0700114
Kenny Rootddb76c42010-11-24 12:56:06 -0800115 off64_t oldOffset = fAsset->seek(0, SEEK_CUR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 if (-1 == oldOffset)
117 return 0;
Kenny Rootddb76c42010-11-24 12:56:06 -0800118 off64_t newOffset = fAsset->seek(size, SEEK_CUR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 if (-1 == newOffset)
120 return 0;
Elliott Hughes4cb17532011-04-12 16:10:26 -0700121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 amount = newOffset - oldOffset;
123 }
124 else
125 {
126 amount = fAsset->read(buffer, size);
127 }
Elliott Hughes4cb17532011-04-12 16:10:26 -0700128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 if (amount < 0)
130 amount = 0;
131 return amount;
132 }
Elliott Hughes4cb17532011-04-12 16:10:26 -0700133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134private:
135 Asset* fAsset;
136 const void* fMemoryBase;
137};
138
Ashok Bhata0398432014-01-20 20:08:01 +0000139static jlong Typeface_createFromAsset(JNIEnv* env, jobject,
140 jobject jassetMgr,
141 jstring jpath) {
Elliott Hughes4cb17532011-04-12 16:10:26 -0700142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 NPE_CHECK_RETURN_ZERO(env, jassetMgr);
144 NPE_CHECK_RETURN_ZERO(env, jpath);
Elliott Hughes4cb17532011-04-12 16:10:26 -0700145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
147 if (NULL == mgr) {
148 return NULL;
149 }
Elliott Hughes4cb17532011-04-12 16:10:26 -0700150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 AutoJavaStringToUTF8 str(env, jpath);
152 Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
153 if (NULL == asset) {
154 return NULL;
155 }
Elliott Hughes4cb17532011-04-12 16:10:26 -0700156
Romain Guya1db5742010-07-20 13:09:13 -0700157 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
Ashok Bhata0398432014-01-20 20:08:01 +0000163 return reinterpret_cast<jlong>(face);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164}
165
Ashok Bhata0398432014-01-20 20:08:01 +0000166static jlong Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) {
Romain Guya87a1322009-05-12 13:22:18 -0700167 NPE_CHECK_RETURN_ZERO(env, jpath);
168
169 AutoJavaStringToUTF8 str(env, jpath);
170
Ashok Bhata0398432014-01-20 20:08:01 +0000171 return reinterpret_cast<jlong>(SkTypeface::CreateFromFile(str.c_str()));
Romain Guya87a1322009-05-12 13:22:18 -0700172}
173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174///////////////////////////////////////////////////////////////////////////////
175
176static JNINativeMethod gTypefaceMethods[] = {
Ashok Bhata0398432014-01-20 20:08:01 +0000177 { "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",
Romain Guya87a1322009-05-12 13:22:18 -0700182 (void*)Typeface_createFromAsset },
Ashok Bhata0398432014-01-20 20:08:01 +0000183 { "nativeCreateFromFile", "(Ljava/lang/String;)J",
Mike Reeddbade9d2009-08-25 13:20:19 -0400184 (void*)Typeface_createFromFile },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185};
186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187int 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}