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