1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #define LOG_TAG "SystemFonts"
19 
20 #include <jni.h>
21 
22 #include <array>
23 #include <string>
24 #include <vector>
25 
26 #include <android/font.h>
27 #include <android/font_matcher.h>
28 #include <android/log.h>
29 #include <android/system_fonts.h>
30 
31 namespace {
32 
33 class ScopedUtfChars {
34 public:
ScopedUtfChars(JNIEnv * env,jstring s)35     ScopedUtfChars(JNIEnv* env, jstring s) : mEnv(env), mString(s) {
36         if (s == nullptr) {
37             mUtfChars = nullptr;
38             mSize = 0;
39         } else {
40             mUtfChars = mEnv->GetStringUTFChars(mString, nullptr);
41             mSize = mEnv->GetStringUTFLength(mString);
42         }
43     }
44 
~ScopedUtfChars()45     ~ScopedUtfChars() {
46         if (mUtfChars) {
47             mEnv->ReleaseStringUTFChars(mString, mUtfChars);
48         }
49     }
50 
c_str() const51     const char* c_str() const {
52         return mUtfChars;
53     }
54 
size() const55     size_t size() const {
56       return mSize;
57     }
58 
59 private:
60     JNIEnv* mEnv;
61     jstring mString;
62     const char* mUtfChars;
63     size_t mSize;
64 };
65 
66 class ScopedStringChars {
67 public:
ScopedStringChars(JNIEnv * env,jstring s)68     ScopedStringChars(JNIEnv* env, jstring s) : mEnv(env), mString(s) {
69         if (s == nullptr) {
70             mChars = nullptr;
71             mSize = 0;
72         } else {
73             mChars = mEnv->GetStringChars(mString, NULL);
74             mSize = mEnv->GetStringLength(mString);
75         }
76     }
77 
~ScopedStringChars()78     ~ScopedStringChars() {
79         if (mChars != nullptr) {
80             mEnv->ReleaseStringChars(mString, mChars);
81         }
82     }
83 
get() const84     const jchar* get() const {
85         return mChars;
86     }
87 
size() const88     size_t size() const {
89         return mSize;
90     }
91 
92 
93 private:
94     JNIEnv* const mEnv;
95     const jstring mString;
96     const jchar* mChars;
97     size_t mSize;
98 };
99 
100 struct FontMatcherDeleter {
operator ()__anon6417662e0111::FontMatcherDeleter101   void operator()(AFontMatcher* matcher) { AFontMatcher_destroy(matcher); }
102 };
103 
104 using FontMatcherUniquePtr = std::unique_ptr<AFontMatcher, FontMatcherDeleter>;
105 
106 class FontMatcher {
107 public:
FontMatcher()108       FontMatcher() : mMatcher(AFontMatcher_create()) {}
109 
setStyle(uint16_t weight,bool italic)110       FontMatcher& setStyle(uint16_t weight, bool italic) {
111           AFontMatcher_setStyle(mMatcher.get(), weight, italic);
112           return *this;
113       }
114 
setLocales(const std::string & locales)115       FontMatcher& setLocales(const std::string& locales) {
116           AFontMatcher_setLocales(mMatcher.get(), locales.c_str());
117           return *this;
118       }
119 
setFamilyVariant(uint32_t familyVariant)120       FontMatcher& setFamilyVariant(uint32_t familyVariant) {
121           AFontMatcher_setFamilyVariant(mMatcher.get(), familyVariant);
122           return *this;
123       }
124 
match(const std::string familyName,const std::vector<uint16_t> & text)125       std::pair<AFont*, uint32_t> match(const std::string familyName,
126                                         const std::vector<uint16_t>& text) {
127           uint32_t runLength;
128           AFont* font = AFontMatcher_match(mMatcher.get(), familyName.c_str(), text.data(),
129                                            text.size(), &runLength);
130           return std::make_pair(font, runLength);
131       }
132 
133 private:
134       FontMatcherUniquePtr mMatcher;
135 };
136 
137 
nOpenIterator(JNIEnv *,jclass)138 jlong nOpenIterator(JNIEnv*, jclass) {
139     return reinterpret_cast<jlong>(ASystemFontIterator_open());
140 }
141 
nCloseIterator(JNIEnv *,jclass,jlong ptr)142 void nCloseIterator(JNIEnv*, jclass, jlong ptr) {
143     ASystemFontIterator_close(reinterpret_cast<ASystemFontIterator*>(ptr));
144 }
145 
nGetNext(JNIEnv *,jclass,jlong ptr)146 jlong nGetNext(JNIEnv*, jclass, jlong ptr) {
147     return reinterpret_cast<jlong>(ASystemFontIterator_next(
148             reinterpret_cast<ASystemFontIterator*>(ptr)));
149 }
150 
nCloseFont(JNIEnv *,jclass,jlong ptr)151 void nCloseFont(JNIEnv*, jclass, jlong ptr) {
152     return AFont_close(reinterpret_cast<AFont*>(ptr));
153 }
154 
nGetFilePath(JNIEnv * env,jclass,jlong ptr)155 jstring nGetFilePath(JNIEnv* env, jclass, jlong ptr) {
156     return env->NewStringUTF(AFont_getFontFilePath(reinterpret_cast<AFont*>(ptr)));
157 }
158 
nGetWeight(JNIEnv *,jclass,jlong ptr)159 jint nGetWeight(JNIEnv*, jclass, jlong ptr) {
160     return AFont_getWeight(reinterpret_cast<AFont*>(ptr));
161 }
162 
nIsItalic(JNIEnv *,jclass,jlong ptr)163 jboolean nIsItalic(JNIEnv*, jclass, jlong ptr) {
164     return AFont_isItalic(reinterpret_cast<AFont*>(ptr));
165 }
166 
nGetLocale(JNIEnv * env,jclass,jlong ptr)167 jstring nGetLocale(JNIEnv* env, jclass, jlong ptr) {
168     return env->NewStringUTF(AFont_getLocale(reinterpret_cast<AFont*>(ptr)));
169 }
170 
nGetCollectionIndex(JNIEnv *,jclass,jlong ptr)171 jint nGetCollectionIndex(JNIEnv*, jclass, jlong ptr) {
172     return AFont_getCollectionIndex(reinterpret_cast<AFont*>(ptr));
173 }
174 
nGetAxisCount(JNIEnv *,jclass,jlong ptr)175 jint nGetAxisCount(JNIEnv*, jclass, jlong ptr) {
176     return AFont_getAxisCount(reinterpret_cast<AFont*>(ptr));
177 }
178 
nGetAxisTag(JNIEnv *,jclass,jlong ptr,jint axisIndex)179 jint nGetAxisTag(JNIEnv*, jclass, jlong ptr, jint axisIndex) {
180     return AFont_getAxisTag(reinterpret_cast<AFont*>(ptr), axisIndex);
181 }
182 
nGetAxisValue(JNIEnv *,jclass,jlong ptr,jint axisIndex)183 jfloat nGetAxisValue(JNIEnv*, jclass, jlong ptr, jint axisIndex) {
184     return AFont_getAxisValue(reinterpret_cast<AFont*>(ptr), axisIndex);
185 }
186 
nMatchFamilyStyleCharacter(JNIEnv * env,jclass,jstring familyName,jint weight,jboolean italic,jstring langTags,jint familyVariant,jstring text)187 jlong nMatchFamilyStyleCharacter(JNIEnv* env, jclass, jstring familyName, jint weight,
188                                  jboolean italic, jstring langTags, jint familyVariant,
189                                  jstring text) {
190     ScopedUtfChars familyNameChars(env, familyName);
191     ScopedUtfChars langTagsChars(env, langTags);
192     ScopedStringChars textChars(env, text);
193     std::vector<uint16_t> utf16(textChars.get(), textChars.get() + textChars.size());
194     return reinterpret_cast<jlong>(
195         FontMatcher()
196             .setStyle(weight, italic)
197             .setLocales(langTagsChars.c_str())
198             .setFamilyVariant(familyVariant)
199             .match(familyNameChars.c_str(), utf16).first);
200 }
201 
nMatchFamilyStyleCharacter_runLength(JNIEnv * env,jclass,jstring familyName,jint weight,jboolean italic,jstring langTags,jint familyVariant,jstring text)202 jint nMatchFamilyStyleCharacter_runLength(JNIEnv* env, jclass, jstring familyName, jint weight,
203                                           jboolean italic, jstring langTags, jint familyVariant,
204                                           jstring text) {
205     ScopedUtfChars familyNameChars(env, familyName);
206     ScopedUtfChars langTagsChars(env, langTags);
207     ScopedStringChars textChars(env, text);
208     std::vector<uint16_t> utf16(textChars.get(), textChars.get() + textChars.size());
209     return FontMatcher()
210             .setStyle(weight, italic)
211             .setLocales(langTagsChars.c_str())
212             .setFamilyVariant(familyVariant)
213             .match(familyNameChars.c_str(), utf16).second;
214 }
215 
216 const std::array<JNINativeMethod, 14> JNI_METHODS = {{
217     { "nOpenIterator", "()J", (void*) nOpenIterator },
218     { "nCloseIterator", "(J)V", (void*) nCloseIterator },
219     { "nNext", "(J)J", (void*) nGetNext },
220     { "nCloseFont", "(J)V", (void*) nCloseFont },
221     { "nGetFilePath", "(J)Ljava/lang/String;", (void*) nGetFilePath },
222     { "nGetWeight", "(J)I", (void*) nGetWeight },
223     { "nIsItalic", "(J)Z", (void*) nIsItalic },
224     { "nGetLocale", "(J)Ljava/lang/String;", (void*) nGetLocale },
225     { "nGetCollectionIndex", "(J)I", (void*) nGetCollectionIndex },
226     { "nGetAxisCount", "(J)I", (void*) nGetAxisCount },
227     { "nGetAxisTag", "(JI)I", (void*) nGetAxisTag },
228     { "nGetAxisValue", "(JI)F", (void*) nGetAxisValue },
229     { "nMatchFamilyStyleCharacter",
230           "(Ljava/lang/String;IZLjava/lang/String;ILjava/lang/String;)J",
231           (void*) nMatchFamilyStyleCharacter },
232     { "nMatchFamilyStyleCharacter_runLength",
233           "(Ljava/lang/String;IZLjava/lang/String;ILjava/lang/String;)I",
234           (void*) nMatchFamilyStyleCharacter_runLength },
235 
236 }};
237 
238 }
239 
register_android_graphics_fonts_cts_SystemFontTest(JNIEnv * env)240 int register_android_graphics_fonts_cts_SystemFontTest(JNIEnv* env) {
241     jclass clazz = env->FindClass("android/graphics/fonts/NativeSystemFontHelper");
242     return env->RegisterNatives(clazz, JNI_METHODS.data(), JNI_METHODS.size());
243 }
244