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 "ani_common.h"
17 #include "ani_drawing_converter.h"
18 #include "ani_text_style_converter.h"
19 #include "ani_text_utils.h"
20 #include "utils/text_log.h"
21
22 namespace OHOS::Text::ANI {
23 using namespace OHOS::Rosen;
ParseTextStyleToNative(ani_env * env,ani_object obj,TextStyle & textStyle)24 ani_status AniTextStyleConverter::ParseTextStyleToNative(ani_env* env, ani_object obj, TextStyle& textStyle)
25 {
26 ani_class cls = nullptr;
27 ani_status ret = env->FindClass(ANI_INTERFACE_TEXT_STYLE, &cls);
28 if (ret != ANI_OK) {
29 TEXT_LOGE("Failed to find class, ret %{public}d", ret);
30 return ret;
31 }
32 ani_boolean isObj = false;
33 ret = env->Object_InstanceOf(obj, cls, &isObj);
34 if (!isObj) {
35 TEXT_LOGE("Object mismatch, ret %{public}d", ret);
36 return ret;
37 }
38
39 ParseDecorationToNative(env, obj, textStyle);
40 AniDrawingConverter::ParseDrawingColorToNative(env, obj, "color", textStyle.color);
41
42 AniTextUtils::ReadOptionalEnumField(env, obj, "fontWeight", textStyle.fontWeight);
43 AniTextUtils::ReadOptionalEnumField(env, obj, "fontStyle", textStyle.fontStyle);
44 if (textStyle.fontStyle == FontStyle::OBLIQUE) {
45 textStyle.fontStyle = FontStyle::ITALIC;
46 }
47 AniTextUtils::ReadOptionalEnumField(env, obj, "baseline", textStyle.baseline);
48
49 AniTextUtils::ReadOptionalArrayField<std::string>(
50 env, obj, "fontFamilies", textStyle.fontFamilies, [](ani_env* env, ani_ref ref) {
51 std::string utf8Str;
52 AniTextUtils::AniToStdStringUtf8(env, reinterpret_cast<ani_string>(ref), utf8Str);
53 return utf8Str;
54 });
55 AniTextUtils::ReadOptionalDoubleField(env, obj, "fontSize", textStyle.fontSize);
56 AniTextUtils::ReadOptionalDoubleField(env, obj, "letterSpacing", textStyle.letterSpacing);
57 AniTextUtils::ReadOptionalDoubleField(env, obj, "wordSpacing", textStyle.wordSpacing);
58 AniTextUtils::ReadOptionalDoubleField(env, obj, "heightScale", textStyle.heightScale);
59 AniTextUtils::ReadOptionalBoolField(env, obj, "halfLeading", textStyle.halfLeading);
60 AniTextUtils::ReadOptionalBoolField(env, obj, "heightOnly", textStyle.heightOnly);
61 AniTextUtils::ReadOptionalU16StringField(env, obj, "ellipsis", textStyle.ellipsis);
62 AniTextUtils::ReadOptionalEnumField(env, obj, "ellipsisMode", textStyle.ellipsisModal);
63 AniTextUtils::ReadOptionalStringField(env, obj, "locale", textStyle.locale);
64 AniTextUtils::ReadOptionalDoubleField(env, obj, "baselineShift", textStyle.baseLineShift);
65 ParseTextShadowToNative(env, obj, textStyle.shadows);
66 ParseFontFeatureToNative(env, obj, textStyle.fontFeatures);
67 ParseFontVariationToNative(env, obj, textStyle.fontVariations);
68
69 ani_ref backgroundRectRef = nullptr;
70 if (AniTextUtils::ReadOptionalField(env, obj, "backgroundRect", backgroundRectRef) == ANI_OK
71 && backgroundRectRef != nullptr) {
72 ParseRectStyleToNative(env, reinterpret_cast<ani_object>(backgroundRectRef), textStyle.backgroundRect);
73 }
74
75 return ANI_OK;
76 }
77
ParseDecorationToNative(ani_env * env,ani_object obj,TextStyle & textStyle)78 void AniTextStyleConverter::ParseDecorationToNative(ani_env* env, ani_object obj, TextStyle& textStyle)
79 {
80 ani_ref decorationRef = nullptr;
81 if (AniTextUtils::ReadOptionalField(env, obj, "decoration", decorationRef) == ANI_OK && decorationRef != nullptr) {
82 AniTextUtils::ReadOptionalEnumField(
83 env, reinterpret_cast<ani_object>(decorationRef), "textDecoration", textStyle.decoration);
84 AniTextUtils::ReadOptionalEnumField(
85 env, reinterpret_cast<ani_object>(decorationRef), "decorationStyle", textStyle.decorationStyle);
86 AniTextUtils::ReadOptionalDoubleField(env, reinterpret_cast<ani_object>(decorationRef),
87 "decorationThicknessScale", textStyle.decorationThicknessScale);
88 AniDrawingConverter::ParseDrawingColorToNative(
89 env, reinterpret_cast<ani_object>(decorationRef), "color", textStyle.decorationColor);
90 }
91 }
92
GetPointXFromJsBumber(ani_env * env,ani_object argValue,Drawing::Point & point)93 inline void GetPointXFromJsBumber(ani_env* env, ani_object argValue, Drawing::Point& point)
94 {
95 ani_double objValue{0};
96 ani_status ret = env->Object_GetPropertyByName_Double(argValue, "x", &objValue);
97 if (ret != ANI_OK) {
98 TEXT_LOGE("Param x is invalid, ret %{public}d", ret);
99 return;
100 }
101 point.SetX(objValue);
102 }
103
GetPointYFromJsBumber(ani_env * env,ani_object argValue,Drawing::Point & point)104 inline void GetPointYFromJsBumber(ani_env* env, ani_object argValue, Drawing::Point& point)
105 {
106 ani_double objValue{0};
107 ani_status ret = env->Object_GetPropertyByName_Double(argValue, "y", &objValue);
108 if (ret != ANI_OK) {
109 TEXT_LOGE("Param y is invalid, ret %{public}d", ret);
110 return;
111 }
112 point.SetY(objValue);
113 }
114
GetTextShadowPoint(ani_env * env,ani_object obj,Drawing::Point & point)115 inline void GetTextShadowPoint(ani_env* env, ani_object obj, Drawing::Point& point)
116 {
117 GetPointXFromJsBumber(env, obj, point);
118 GetPointYFromJsBumber(env, obj, point);
119 }
120
ParseTextShadowToNative(ani_env * env,ani_object obj,std::vector<TextShadow> & textShadow)121 void AniTextStyleConverter::ParseTextShadowToNative(ani_env* env, ani_object obj, std::vector<TextShadow>& textShadow)
122 {
123 std::vector<std::string> array;
124 AniTextUtils::ReadOptionalArrayField<std::string>(
125 env, obj, "textShadows", array, [&textShadow](ani_env* env, ani_ref ref) {
126 ani_object shadowObj = reinterpret_cast<ani_object>(ref);
127 ani_class cls = nullptr;
128 ani_status ret = env->FindClass(ANI_INTERFACE_TEXTSHADOW, &cls);
129 if (ret != ANI_OK) {
130 TEXT_LOGE("Failed to find class, ret %{public}d", ret);
131 return "";
132 }
133 ani_boolean isObj = false;
134 ret = env->Object_InstanceOf(shadowObj, cls, &isObj);
135 if (!isObj) {
136 TEXT_LOGE("Object mismatch, ret %{public}d", ret);
137 return "";
138 }
139
140 double runTimeRadius;
141 AniTextUtils::ReadOptionalDoubleField(env, shadowObj, "blurRadius", runTimeRadius);
142
143 Drawing::Color colorSrc = OHOS::Rosen::Drawing::Color::COLOR_BLACK;
144 AniDrawingConverter::ParseDrawingColorToNative(env, shadowObj, "color", colorSrc);
145
146 Drawing::Point offset(0, 0);
147 ani_ref pointValue = nullptr;
148 ret = AniTextUtils::ReadOptionalField(env, shadowObj, "point", pointValue);
149 if (ret == ANI_OK && pointValue != nullptr) {
150 GetTextShadowPoint(env, reinterpret_cast<ani_object>(pointValue), offset);
151 }
152
153 textShadow.emplace_back(TextShadow(colorSrc, offset, runTimeRadius));
154 return "";
155 });
156 }
157
ParseFontFeatureToNative(ani_env * env,ani_object obj,FontFeatures & fontFeatures)158 void AniTextStyleConverter::ParseFontFeatureToNative(ani_env* env, ani_object obj, FontFeatures& fontFeatures)
159 {
160 std::vector<std::string> array;
161 AniTextUtils::ReadOptionalArrayField<std::string>(
162 env, obj, "fontFeatures", array, [&fontFeatures](ani_env* env, ani_ref ref) {
163 ani_object obj = reinterpret_cast<ani_object>(ref);
164 ani_class cls = nullptr;
165 ani_status ret = env->FindClass(ANI_INTERFACE_FONT_FEATURE, &cls);
166 if (ret != ANI_OK) {
167 TEXT_LOGE("Failed to find class, ret %{public}d", ret);
168 return "";
169 }
170 ani_boolean isObj = false;
171 ret = env->Object_InstanceOf(obj, cls, &isObj);
172 if (!isObj) {
173 TEXT_LOGE("Object mismatch, ret %{public}d", ret);
174 return "";
175 }
176 ani_ref nameRef = nullptr;
177 ret = env->Object_GetPropertyByName_Ref(obj, "name", &nameRef);
178 if (ret != ANI_OK) {
179 TEXT_LOGE("Failed to get name, ret %{public}d", ret);
180 return "";
181 }
182 std::string name;
183 ret = AniTextUtils::AniToStdStringUtf8(env, reinterpret_cast<ani_string>(nameRef), name);
184 if (ret != ANI_OK) {
185 return "";
186 }
187
188 ani_double valueDouble;
189 ret = env->Object_GetPropertyByName_Double(obj, "value", &valueDouble);
190 if (ret != ANI_OK) {
191 TEXT_LOGE("Failed to get value, ret %{public}d", ret);
192 return "";
193 }
194 fontFeatures.SetFeature(name, static_cast<int>(valueDouble));
195 return "";
196 });
197 }
198
ParseFontVariationToNative(ani_env * env,ani_object obj,FontVariations & fontVariations)199 void AniTextStyleConverter::ParseFontVariationToNative(ani_env* env, ani_object obj, FontVariations& fontVariations)
200 {
201 std::vector<std::string> array;
202 AniTextUtils::ReadOptionalArrayField<std::string>(
203 env, obj, "fontVariations", array, [&fontVariations](ani_env* env, ani_ref ref) {
204 ani_object obj = reinterpret_cast<ani_object>(ref);
205 ani_class cls = nullptr;
206 ani_status ret = env->FindClass(ANI_INTERFACE_FONT_VARIATION, &cls);
207 if (ret != ANI_OK) {
208 TEXT_LOGE("Failed to find class, ret %{public}d", ret);
209 return "";
210 }
211 ani_boolean isObj = false;
212 ret = env->Object_InstanceOf(obj, cls, &isObj);
213 if (!isObj) {
214 TEXT_LOGE("Object mismatch, ret %{public}d", ret);
215 return "";
216 }
217 ani_ref axisRef = nullptr;
218 ret = env->Object_GetPropertyByName_Ref(obj, "axis", &axisRef);
219 if (ret != ANI_OK) {
220 TEXT_LOGE("Failed to get filed axis, ret %{public}d", ret);
221 return "";
222 }
223 std::string axis;
224 ret = AniTextUtils::AniToStdStringUtf8(env, static_cast<ani_string>(axisRef), axis);
225 if (ret != ANI_OK) {
226 TEXT_LOGE("Failed to parse string filed axis, ret %{public}d", ret);
227 return "";
228 }
229 ani_double valueDouble;
230 ret = env->Object_GetPropertyByName_Double(obj, "value", &valueDouble);
231 if (ret != ANI_OK) {
232 TEXT_LOGE("Failed to get filed value, ret %{public}d", ret);
233 return "";
234 }
235 fontVariations.SetAxisValue(axis, static_cast<int>(valueDouble));
236 return "";
237 });
238 }
239
ParseRectStyleToNative(ani_env * env,ani_object obj,RectStyle & rectStyle)240 void AniTextStyleConverter::ParseRectStyleToNative(ani_env* env, ani_object obj, RectStyle& rectStyle)
241 {
242 ani_class cls = nullptr;
243 ani_status ret = env->FindClass(ANI_INTERFACE_RECT_STYLE, &cls);
244 if (ret != ANI_OK) {
245 TEXT_LOGE("Failed to find class, ret %{public}d", ret);
246 return;
247 }
248 ani_boolean isObj = false;
249 ret = env->Object_InstanceOf(obj, cls, &isObj);
250 if (!isObj) {
251 TEXT_LOGE("Object mismatch, ret %{public}d", ret);
252 return;
253 }
254 env->Object_GetPropertyByName_Double(obj, "leftTopRadius", &rectStyle.leftTopRadius);
255 env->Object_GetPropertyByName_Double(obj, "rightTopRadius", &rectStyle.rightTopRadius);
256 env->Object_GetPropertyByName_Double(obj, "rightBottomRadius", &rectStyle.rightBottomRadius);
257 env->Object_GetPropertyByName_Double(obj, "leftBottomRadius", &rectStyle.leftBottomRadius);
258 }
259
ParseTextStyleToAni(ani_env * env,const TextStyle & textStyle)260 ani_object AniTextStyleConverter::ParseTextStyleToAni(ani_env* env, const TextStyle& textStyle)
261 {
262 ani_object aniObj = AniTextUtils::CreateAniObject(env, ANI_CLASS_TEXT_STYLE, ":V");
263 env->Object_SetPropertyByName_Ref(
264 aniObj, "decoration", AniTextStyleConverter::ParseDecorationToAni(env, textStyle));
265 env->Object_SetPropertyByName_Ref(aniObj, "fontWeight",
266 AniTextUtils::CreateAniEnum(env, ANI_ENUM_FONT_WEIGHT, static_cast<int>(textStyle.fontWeight)));
267 env->Object_SetPropertyByName_Ref(aniObj, "fontStyle",
268 AniTextUtils::CreateAniEnum(env, ANI_ENUM_FONT_STYLE, static_cast<int>(textStyle.fontStyle)));
269 env->Object_SetPropertyByName_Ref(aniObj, "baseline",
270 AniTextUtils::CreateAniEnum(env, ANI_ENUM_TEXT_BASELINE, static_cast<int>(textStyle.baseline)));
271 ani_object fontFamiliesAniObj =
272 AniTextUtils::CreateAniArrayAndInitData(env, textStyle.fontFamilies, textStyle.fontFamilies.size(),
273 [](ani_env* env, const std::string& item) { return AniTextUtils::CreateAniStringObj(env, item); });
274 env->Object_SetPropertyByName_Ref(aniObj, "fontFamilies", fontFamiliesAniObj);
275 env->Object_SetPropertyByName_Ref(aniObj, "fontSize", AniTextUtils::CreateAniDoubleObj(env, textStyle.fontSize));
276 env->Object_SetPropertyByName_Ref(
277 aniObj, "letterSpacing", AniTextUtils::CreateAniDoubleObj(env, textStyle.letterSpacing));
278 env->Object_SetPropertyByName_Ref(
279 aniObj, "wordSpacing", AniTextUtils::CreateAniDoubleObj(env, textStyle.wordSpacing));
280 env->Object_SetPropertyByName_Ref(
281 aniObj, "heightScale", AniTextUtils::CreateAniDoubleObj(env, textStyle.heightScale));
282 env->Object_SetPropertyByName_Ref(
283 aniObj, "halfLeading", AniTextUtils::CreateAniBooleanObj(env, textStyle.halfLeading));
284 env->Object_SetPropertyByName_Ref(
285 aniObj, "heightOnly", AniTextUtils::CreateAniBooleanObj(env, textStyle.heightOnly));
286 env->Object_SetPropertyByName_Ref(aniObj, "ellipsis", AniTextUtils::CreateAniStringObj(env, textStyle.ellipsis));
287 env->Object_SetPropertyByName_Ref(aniObj, "ellipsisMode",
288 AniTextUtils::CreateAniEnum(env, ANI_ENUM_ELLIPSIS_MODE, static_cast<int>(textStyle.ellipsisModal)));
289 env->Object_SetPropertyByName_Ref(aniObj, "locale", AniTextUtils::CreateAniStringObj(env, textStyle.locale));
290 env->Object_SetPropertyByName_Ref(
291 aniObj, "baselineShift", AniTextUtils::CreateAniDoubleObj(env, textStyle.baseLineShift));
292 env->Object_SetPropertyByName_Ref(
293 aniObj, "backgroundRect", AniTextStyleConverter::ParseRectStyleToAni(env, textStyle.backgroundRect));
294 ani_object shadowsAniObj = AniTextUtils::CreateAniArrayAndInitData(env, textStyle.shadows, textStyle.shadows.size(),
295 [](ani_env* env, const TextShadow& item) { return AniTextStyleConverter::ParseTextShadowToAni(env, item); });
296 env->Object_SetPropertyByName_Ref(aniObj, "textShadows", shadowsAniObj);
297 env->Object_SetPropertyByName_Ref(aniObj, "fontFeatures", ParseFontFeaturesToAni(env, textStyle.fontFeatures));
298 return aniObj;
299 }
300
ParseTextShadowToAni(ani_env * env,const TextShadow & textShadow)301 ani_object AniTextStyleConverter::ParseTextShadowToAni(ani_env* env, const TextShadow& textShadow)
302 {
303 ani_object aniObj = AniTextUtils::CreateAniObject(env, ANI_CLASS_TEXTSHADOW, ":V");
304 env->Object_SetPropertyByName_Double(aniObj, "blurRadius", ani_double(textShadow.blurRadius));
305 return aniObj;
306 }
307
ParseDecorationToAni(ani_env * env,const TextStyle & textStyle)308 ani_object AniTextStyleConverter::ParseDecorationToAni(ani_env* env, const TextStyle& textStyle)
309 {
310 ani_object aniObj = AniTextUtils::CreateAniObject(env, ANI_CLASS_DECORATION, ":V");
311 env->Object_SetPropertyByName_Ref(aniObj, "textDecoration",
312 AniTextUtils::CreateAniEnum(env, ANI_ENUM_TEXT_DECORATION_TYPE, static_cast<int>(textStyle.decoration)));
313 env->Object_SetPropertyByName_Ref(aniObj, "decorationStyle",
314 AniTextUtils::CreateAniEnum(env, ANI_ENUM_TEXT_DECORATION_STYLE, static_cast<int>(textStyle.decorationStyle)));
315 env->Object_SetPropertyByName_Double(aniObj, "blurRadius", textStyle.decorationThicknessScale);
316 return aniObj;
317 }
318
ParseRectStyleToAni(ani_env * env,const RectStyle & rectStyle)319 ani_object AniTextStyleConverter::ParseRectStyleToAni(ani_env* env, const RectStyle& rectStyle)
320 {
321 ani_object aniObj = AniTextUtils::CreateAniObject(env, ANI_CLASS_RECT_STYLE, ":V");
322 env->Object_SetPropertyByName_Double(aniObj, "leftTopRadius", rectStyle.leftTopRadius);
323 env->Object_SetPropertyByName_Double(aniObj, "rightTopRadius", rectStyle.rightTopRadius);
324 env->Object_SetPropertyByName_Double(aniObj, "rightBottomRadius", rectStyle.rightBottomRadius);
325 env->Object_SetPropertyByName_Double(aniObj, "leftBottomRadius", rectStyle.leftBottomRadius);
326 return aniObj;
327 }
328
ParseFontFeaturesToAni(ani_env * env,const FontFeatures & fontFeatures)329 ani_object AniTextStyleConverter::ParseFontFeaturesToAni(ani_env* env, const FontFeatures& fontFeatures)
330 {
331 const std::vector<std::pair<std::string, int>> featureSet = fontFeatures.GetFontFeatures();
332 ani_object arrayObj = AniTextUtils::CreateAniArrayAndInitData(
333 env, featureSet, featureSet.size(), [](ani_env* env, const std::pair<std::string, int>& feature) {
334 ani_object aniObj = AniTextUtils::CreateAniObject(env, ANI_CLASS_FONT_FEATURE, ":V");
335 env->Object_SetPropertyByName_Ref(aniObj, "name", AniTextUtils::CreateAniStringObj(env, feature.first));
336 env->Object_SetPropertyByName_Double(aniObj, "value", feature.second);
337 return aniObj;
338 });
339 return arrayObj;
340 }
341
ParseFontVariationsToAni(ani_env * env,const FontVariations & fontVariations)342 ani_object AniTextStyleConverter::ParseFontVariationsToAni(ani_env* env, const FontVariations& fontVariations)
343 {
344 ani_object aniObj = AniTextUtils::CreateAniObject(env, ANI_CLASS_FONT_VARIATION, ":V");
345 return aniObj;
346 }
347 } // namespace OHOS::Text::ANI