1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <codecvt>
17 #include <cstdint>
18 #include <sys/stat.h>
19
20 #include "ani_common.h"
21 #include "ani_font_collection.h"
22 #include "ani_resource_parser.h"
23 #include "ani_text_utils.h"
24 #include "utils/text_log.h"
25
26 namespace OHOS::Text::ANI {
27 using namespace OHOS::Rosen;
28
29 namespace {
LoadString(ani_env * env,ani_object path,std::shared_ptr<OHOS::Rosen::FontCollection> fontCollection,std::string familyName)30 void LoadString(
31 ani_env* env, ani_object path, std::shared_ptr<OHOS::Rosen::FontCollection> fontCollection, std::string familyName)
32 {
33 std::unique_ptr<uint8_t[]> data;
34 size_t dataLen = 0;
35
36 std::string pathStr;
37 ani_status ret = AniTextUtils::AniToStdStringUtf8(env, reinterpret_cast<ani_string>(path), pathStr);
38 if (ret != ANI_OK) {
39 return;
40 }
41 if (!AniTextUtils::SplitAbsoluteFontPath(pathStr) || !AniTextUtils::ReadFile(pathStr, dataLen, data)) {
42 TEXT_LOGE("Failed to split absolute font path");
43 return;
44 }
45 fontCollection->LoadFont(familyName, data.get(), dataLen);
46 }
47
LoadResource(ani_env * env,ani_object path,std::shared_ptr<OHOS::Rosen::FontCollection> fontCollection,std::string familyName)48 void LoadResource(
49 ani_env* env, ani_object path, std::shared_ptr<OHOS::Rosen::FontCollection> fontCollection, std::string familyName)
50 {
51 std::unique_ptr<uint8_t[]> data;
52 size_t dataLen = 0;
53
54 AniResource resource = AniResourceParser::ParseResource(env, path);
55 if (!AniResourceParser::ResolveResource(resource, dataLen, data)) {
56 TEXT_LOGE("Failed to resolve resource");
57 return;
58 }
59 fontCollection->LoadFont(familyName, data.get(), dataLen);
60 }
61 } // namespace
62
AniFontCollection()63 AniFontCollection::AniFontCollection()
64 {
65 fontCollection_ = FontCollection::From(nullptr);
66 }
67
AniFontCollection(std::shared_ptr<FontCollection> fc)68 AniFontCollection::AniFontCollection(std::shared_ptr<FontCollection> fc)
69 {
70 fontCollection_ = fc;
71 }
72
Constructor(ani_env * env,ani_object object)73 void AniFontCollection::Constructor(ani_env* env, ani_object object)
74 {
75 AniFontCollection* aniFontCollection = new AniFontCollection();
76 ani_status ret = env->Object_SetFieldByName_Long(object, NATIVE_OBJ, reinterpret_cast<ani_long>(aniFontCollection));
77 if (ret != ANI_OK) {
78 TEXT_LOGE("Failed to create ani font collection obj");
79 delete aniFontCollection;
80 aniFontCollection = nullptr;
81 return;
82 }
83 }
84
GetGlobalInstance(ani_env * env,ani_class cls)85 ani_object AniFontCollection::GetGlobalInstance(ani_env* env, ani_class cls)
86 {
87 static AniFontCollection aniFontCollection = AniFontCollection(FontCollection::Create());
88
89 ani_object obj = AniTextUtils::CreateAniObject(env, ANI_CLASS_FONT_COLLECTION, ":V");
90 ani_status ret = env->Object_SetFieldByName_Long(obj, NATIVE_OBJ, reinterpret_cast<ani_long>(&aniFontCollection));
91 if (ret != ANI_OK) {
92 TEXT_LOGE("Failed to create ani font collection obj");
93 return nullptr;
94 }
95 return obj;
96 }
97
LoadFontSync(ani_env * env,ani_object obj,ani_string name,ani_object path)98 void AniFontCollection::LoadFontSync(ani_env* env, ani_object obj, ani_string name, ani_object path)
99 {
100 std::string familyName;
101 ani_status ret = AniTextUtils::AniToStdStringUtf8(env, name, familyName);
102 if (ret != ANI_OK) {
103 return;
104 }
105 auto aniFontCollection = AniTextUtils::GetNativeFromObj<AniFontCollection>(env, obj);
106 if (aniFontCollection == nullptr || aniFontCollection->fontCollection_ == nullptr) {
107 TEXT_LOGE("Null font collection");
108 return;
109 }
110
111 ani_class stringClass;
112 env->FindClass("Lstd/core/String;", &stringClass);
113 ani_boolean isString = false;
114 env->Object_InstanceOf(path, stringClass, &isString);
115
116 if (isString) {
117 LoadString(env, path, aniFontCollection->fontCollection_, familyName);
118 return;
119 }
120
121 ani_class resourceClass;
122 env->FindClass("Lglobal/resource/Resource", &resourceClass);
123 ani_boolean isResource = false;
124 env->Object_InstanceOf(path, resourceClass, &isResource);
125 if (isResource) {
126 LoadResource(env, path, aniFontCollection->fontCollection_, familyName);
127 return;
128 }
129 }
130
ClearCaches(ani_env * env,ani_object obj)131 void AniFontCollection::ClearCaches(ani_env* env, ani_object obj)
132 {
133 auto aniFontCollection = AniTextUtils::GetNativeFromObj<AniFontCollection>(env, obj);
134 if (aniFontCollection == nullptr || aniFontCollection->fontCollection_ == nullptr) {
135 TEXT_LOGE("Null font collection");
136 return;
137 }
138 aniFontCollection->fontCollection_->ClearCaches();
139 }
140
AniInit(ani_vm * vm,uint32_t * result)141 ani_status AniFontCollection::AniInit(ani_vm* vm, uint32_t* result)
142 {
143 ani_env* env;
144 ani_status ret = vm->GetEnv(ANI_VERSION_1, &env);
145 if (ret != ANI_OK) {
146 TEXT_LOGE("null env");
147 return ANI_NOT_FOUND;
148 }
149
150 ani_class cls = nullptr;
151 ret = env->FindClass(ANI_CLASS_FONT_COLLECTION, &cls);
152 if (ret != ANI_OK) {
153 TEXT_LOGE("Failed to find class: %{public}s", ANI_CLASS_FONT_COLLECTION);
154 return ANI_NOT_FOUND;
155 }
156
157 std::string globalInstance = ":" + std::string(ANI_CLASS_FONT_COLLECTION);
158 std::string loadFontSync = "Lstd/core/String;Lstd/core/Object;:V";
159
160 std::array methods = {
161 ani_native_function{"constructorNative", ":V", reinterpret_cast<void*>(Constructor)},
162 ani_native_function{"getGlobalInstance", globalInstance.c_str(), reinterpret_cast<void*>(GetGlobalInstance)},
163 ani_native_function{"loadFontSync", loadFontSync.c_str(), reinterpret_cast<void*>(LoadFontSync)},
164 ani_native_function{"clearCaches", ":V", reinterpret_cast<void*>(ClearCaches)},
165 };
166
167 ret = env->Class_BindNativeMethods(cls, methods.data(), methods.size());
168 if (ret != ANI_OK) {
169 TEXT_LOGE("Failed to bind methods: %{public}s", ANI_CLASS_FONT_COLLECTION);
170 return ANI_NOT_FOUND;
171 }
172 return ANI_OK;
173 }
174
GetFontCollection()175 std::shared_ptr<FontCollection> AniFontCollection::GetFontCollection()
176 {
177 return fontCollection_;
178 }
179 } // namespace OHOS::Text::ANI