• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #include "frameworks/bridge/declarative_frontend/jsview/js_symbol.h"
16 
17 #include "core/components_ng/pattern/symbol/constants.h"
18 #include "frameworks/bridge/declarative_frontend/engine/bindings.h"
19 #include "frameworks/bridge/declarative_frontend/engine/js_ref_ptr.h"
20 #include "frameworks/bridge/declarative_frontend/jsview/js_interactable_view.h"
21 #include "frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h"
22 #include "frameworks/bridge/declarative_frontend/engine/jsi/js_ui_index.h"
23 #include "frameworks/core/components_ng/pattern/symbol/symbol_model.h"
24 #include "frameworks/core/components_ng/pattern/symbol/symbol_model_ng.h"
25 
26 namespace OHOS::Ace {
27 constexpr int32_t SYSTEM_SYMBOL_BOUNDARY = 0XFFFFF;
28 const std::string DEFAULT_SYMBOL_FONTFAMILY = "HM Symbol";
29 constexpr int32_t NUM2 = 2;
30 constexpr float DEFAULT_GRADIENT_ANGLE = 180.0f;
31 
32 std::unique_ptr<SymbolModel> SymbolModel::instance_ = nullptr;
33 std::mutex SymbolModel::mutex_;
34 
GetInstance()35 SymbolModel* SymbolModel::GetInstance()
36 {
37     static NG::SymbolModelNG instance;
38     return &instance;
39 }
40 
41 } // namespace OHOS::Ace
42 
43 namespace OHOS::Ace::Framework {
44 
45 const std::map<std::string, Ace::SymbolEffectType> SYMBOL_EFFECT_TYPE_MAP = {
46     { "ScaleSymbolEffect", SymbolEffectType::SCALE },
47     { "HierarchicalSymbolEffect", SymbolEffectType::HIERARCHICAL },
48     { "AppearSymbolEffect", SymbolEffectType::APPEAR },
49     { "DisappearSymbolEffect", SymbolEffectType::DISAPPEAR },
50     { "BounceSymbolEffect", SymbolEffectType::BOUNCE },
51     { "ReplaceSymbolEffect", SymbolEffectType::REPLACE },
52     { "PulseSymbolEffect", SymbolEffectType::PULSE },
53     { "QuickReplaceSymbolEffect", SymbolEffectType::QUICK_REPLACE },
54     { "DisableSymbolEffect", SymbolEffectType::DISABLE },
55 };
56 
57 const std::map<std::string, Ace::SymbolGradientType> SYMBOL_SHADER_TYPE_MAP = {
58     { "ColorShaderStyle", SymbolGradientType::COLOR_SHADER },
59     { "RadialGradientStyle", SymbolGradientType::RADIAL_GRADIENT },
60     { "LinearGradientStyle", SymbolGradientType::LINEAR_GRADIENT },
61 };
62 
JSBind(BindingTarget globalObj)63 void JSSymbol::JSBind(BindingTarget globalObj)
64 {
65     JSClass<JSSymbol>::Declare("SymbolGlyph");
66 
67     MethodOptions opt = MethodOptions::NONE;
68     JSClass<JSSymbol>::StaticMethod("create", &JSSymbol::Create, opt);
69     JSClass<JSSymbol>::StaticMethod("fontWeight", &JSSymbol::SetFontWeight, opt);
70     JSClass<JSSymbol>::StaticMethod("fontSize", &JSSymbol::SetFontSize, opt);
71     JSClass<JSSymbol>::StaticMethod("renderingStrategy", &JSSymbol::SetSymbolRenderingStrategy, opt);
72     JSClass<JSSymbol>::StaticMethod("fontColor", &JSSymbol::SetFontColor, opt);
73     JSClass<JSSymbol>::StaticMethod("effectStrategy", &JSSymbol::SetSymbolEffect, opt);
74     JSClass<JSSymbol>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
75     JSClass<JSSymbol>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
76     JSClass<JSSymbol>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
77     JSClass<JSSymbol>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
78     JSClass<JSSymbol>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
79     JSClass<JSSymbol>::StaticMethod("clip", &JSSymbol::JsClip);
80     JSClass<JSSymbol>::StaticMethod("symbolEffect", &JSSymbol::SetSymbolEffectOptions, opt);
81     JSClass<JSSymbol>::StaticMethod("minFontScale", &JSSymbol::SetMinFontScale);
82     JSClass<JSSymbol>::StaticMethod("maxFontScale", &JSSymbol::SetMaxFontScale);
83     JSClass<JSSymbol>::StaticMethod("symbolShadow", &JSSymbol::SetSymbolShadow, opt);
84     JSClass<JSSymbol>::StaticMethod("shaderStyle", &JSSymbol::SetShaderStyle, opt);
85     JSClass<JSSymbol>::InheritAndBind<JSViewAbstract>(globalObj);
86 }
87 
Create(const JSCallbackInfo & info)88 void JSSymbol::Create(const JSCallbackInfo& info)
89 {
90     if (info[0]->IsUndefined()) {
91         SymbolModel::GetInstance()->Create(0);
92         return;
93     }
94     uint32_t symbolId;
95     RefPtr<ResourceObject> resourceObject;
96     ParseJsSymbolId(info[0], symbolId, resourceObject);
97     SymbolModel::GetInstance()->Create(symbolId);
98     std::vector<std::string> familyNames;
99     if (symbolId > SYSTEM_SYMBOL_BOUNDARY) {
100         ParseJsSymbolCustomFamilyNames(familyNames, info[0]);
101         SymbolModel::GetInstance()->SetFontFamilies(familyNames);
102         SymbolModel::GetInstance()->SetSymbolType(SymbolType::CUSTOM);
103     } else {
104         familyNames.push_back(DEFAULT_SYMBOL_FONTFAMILY);
105         SymbolModel::GetInstance()->SetFontFamilies(familyNames);
106         SymbolModel::GetInstance()->SetSymbolType(SymbolType::SYSTEM);
107     }
108 }
109 
SetFontSize(const JSCallbackInfo & info)110 void JSSymbol::SetFontSize(const JSCallbackInfo& info)
111 {
112     if (info.Length() < 1) {
113         return;
114     }
115     auto theme = GetTheme<TextTheme>();
116     CHECK_NULL_VOID(theme);
117     CalcDimension fontSize = theme->GetTextStyle().GetFontSize();
118     RefPtr<ResourceObject> resObj;
119     UnRegisterResource("FontSize");
120     if (!ParseJsDimensionFpNG(info[0], fontSize, resObj, false)) {
121         fontSize = theme->GetTextStyle().GetFontSize();
122         SymbolModel::GetInstance()->SetFontSize(fontSize);
123         return;
124     }
125     if (SystemProperties::ConfigChangePerform() && resObj) {
126         RegisterResource<CalcDimension>("FontSize", resObj, fontSize);
127     }
128     if (fontSize.IsNegative()) {
129         fontSize = theme->GetTextStyle().GetFontSize();
130     }
131 
132     SymbolModel::GetInstance()->SetFontSize(fontSize);
133 }
134 
SetFontWeight(const std::string & value)135 void JSSymbol::SetFontWeight(const std::string& value)
136 {
137     SymbolModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(value));
138 }
139 
SetSymbolRenderingStrategy(const JSCallbackInfo & info)140 void JSSymbol::SetSymbolRenderingStrategy(const JSCallbackInfo& info)
141 {
142     uint32_t strategy = 0;
143     ParseJsInteger(info[0], strategy);
144     SymbolModel::GetInstance()->SetSymbolRenderingStrategy(strategy);
145 }
146 
SetFontColor(const JSCallbackInfo & info)147 void JSSymbol::SetFontColor(const JSCallbackInfo& info)
148 {
149     std::vector<Color> symbolColor;
150     if (SystemProperties::ConfigChangePerform()) {
151         std::vector<std::pair<int32_t, RefPtr<ResourceObject>>> resObjArr;
152         if (!ParseJsSymbolColor(info[0], symbolColor, true, resObjArr)) {
153             return;
154         }
155         if (!resObjArr.empty()) {
156             SymbolModel::GetInstance()->RegisterSymbolFontColorResource("symbolColor",
157                 symbolColor, resObjArr);
158         } else {
159             UnRegisterResource("symbolColor");
160         }
161         SymbolModel::GetInstance()->SetFontColor(symbolColor);
162         return;
163     }
164     if (!ParseJsSymbolColor(info[0], symbolColor)) {
165         return;
166     }
167     SymbolModel::GetInstance()->SetFontColor(symbolColor);
168 }
169 
SetSymbolEffect(const JSCallbackInfo & info)170 void JSSymbol::SetSymbolEffect(const JSCallbackInfo& info)
171 {
172     uint32_t strategy = 0;
173     ParseJsInteger(info[0], strategy);
174     SymbolModel::GetInstance()->SetSymbolEffect(strategy);
175 }
176 
JsClip(const JSCallbackInfo & info)177 void JSSymbol::JsClip(const JSCallbackInfo& info)
178 {
179     JSViewAbstract::JsClip(info);
180     if (info[0]->IsBoolean()) {
181         SymbolModel::GetInstance()->SetClipEdge();
182     }
183 }
184 
SetSymbolEffectOptions(const JSCallbackInfo & info)185 void JSSymbol::SetSymbolEffectOptions(const JSCallbackInfo& info)
186 {
187     if (info.Length() < 1 || !info[0]->IsObject()) {
188         return;
189     }
190 
191     auto symbolEffectObj = JSRef<JSObject>::Cast(info[0]);
192     NG::SymbolEffectOptions symbolEffectOptions;
193     parseSymbolEffect(symbolEffectObj, symbolEffectOptions);
194 
195     if (info.Length() > 1 && !info[1]->IsUndefined()) {
196         parseSymbolSwitch(info[1], symbolEffectOptions);
197     }
198 
199     SymbolModel::GetInstance()->SetSymbolEffectOptions(symbolEffectOptions);
200 }
201 
SetMinFontScale(const JSCallbackInfo & info)202 void JSSymbol::SetMinFontScale(const JSCallbackInfo& info)
203 {
204     double minFontScale;
205     RefPtr<ResourceObject> resObj;
206     if (info.Length() < 1 || !ParseJsDouble(info[0], minFontScale, resObj)) {
207         return;
208     }
209     UnRegisterResource("MinFontScale");
210     if (LessOrEqual(minFontScale, 0.0f)) {
211         SymbolModel::GetInstance()->SetMinFontScale(0.0f);
212         return;
213     }
214     if (GreatOrEqual(minFontScale, 1.0f)) {
215         SymbolModel::GetInstance()->SetMinFontScale(1.0f);
216         return;
217     }
218     if (SystemProperties::ConfigChangePerform() && resObj) {
219         RegisterResource<float>("MinFontScale", resObj, static_cast<float>(minFontScale));
220     }
221     SymbolModel::GetInstance()->SetMinFontScale(static_cast<float>(minFontScale));
222 }
223 
SetMaxFontScale(const JSCallbackInfo & info)224 void JSSymbol::SetMaxFontScale(const JSCallbackInfo& info)
225 {
226     double maxFontScale;
227     RefPtr<ResourceObject> resObj;
228     if (info.Length() < 1 || !ParseJsDouble(info[0], maxFontScale, resObj)) {
229         return;
230     }
231     UnRegisterResource("MaxFontScale");
232     if (LessOrEqual(maxFontScale, 1.0f)) {
233         SymbolModel::GetInstance()->SetMaxFontScale(1.0f);
234         return;
235     }
236 
237     if (SystemProperties::ConfigChangePerform() && resObj) {
238         RegisterResource<float>("MaxFontScale", resObj, static_cast<float>(maxFontScale));
239     }
240     SymbolModel::GetInstance()->SetMaxFontScale(static_cast<float>(maxFontScale));
241 }
242 
parseSymbolEffect(const JSRef<JSObject> symbolEffectObj,NG::SymbolEffectOptions & symbolEffectOptions)243 void JSSymbol::parseSymbolEffect(const JSRef<JSObject> symbolEffectObj, NG::SymbolEffectOptions& symbolEffectOptions)
244 {
245     auto typeParam = symbolEffectObj->GetProperty("type");
246     if (typeParam->IsString()) {
247         auto type = typeParam->ToString();
248         auto iter = SYMBOL_EFFECT_TYPE_MAP.find(type);
249         if (iter != SYMBOL_EFFECT_TYPE_MAP.end()) {
250             symbolEffectOptions.SetEffectType(iter->second);
251         }
252     }
253 
254     auto scopeTypeProperty = symbolEffectObj->GetProperty("scope");
255     if (scopeTypeProperty->IsNumber()) {
256         auto scopeTypeNum = scopeTypeProperty->ToNumber<uint32_t>();
257         if (scopeTypeNum >= static_cast<uint32_t>(ScopeType::LAYER) &&
258             scopeTypeNum <= static_cast<uint32_t>(ScopeType::WHOLE)) {
259             symbolEffectOptions.SetScopeType(static_cast<ScopeType>(scopeTypeNum));
260         }
261     }
262 
263     auto commonSubTypeProperty = symbolEffectObj->GetProperty("direction");
264     if (commonSubTypeProperty->IsNumber()) {
265         auto commonSubTypeNum = commonSubTypeProperty->ToNumber<uint32_t>();
266         if (commonSubTypeNum >= static_cast<uint32_t>(CommonSubType::DOWN) &&
267             commonSubTypeNum <= static_cast<uint32_t>(CommonSubType::UP)) {
268             symbolEffectOptions.SetCommonSubType(static_cast<CommonSubType>(commonSubTypeNum));
269         }
270     }
271 
272     auto fillStyleProperty = symbolEffectObj->GetProperty("fillStyle");
273     if (fillStyleProperty->IsNumber()) {
274         auto fillStyleNum = fillStyleProperty->ToNumber<uint32_t>();
275         if (fillStyleNum >= static_cast<uint32_t>(FillStyle::CUMULATIVE) &&
276             fillStyleNum <= static_cast<uint32_t>(FillStyle::ITERATIVE)) {
277             symbolEffectOptions.SetFillStyle(static_cast<FillStyle>(fillStyleNum));
278         }
279     }
280 }
281 
parseSymbolSwitch(const JSRef<JSVal> jsVal,NG::SymbolEffectOptions & symbolEffectOptions)282 void JSSymbol::parseSymbolSwitch(const JSRef<JSVal> jsVal, NG::SymbolEffectOptions& symbolEffectOptions)
283 {
284     if (jsVal->IsBoolean()) {
285         symbolEffectOptions.SetIsActive(jsVal->ToBoolean());
286     }
287 
288     if (jsVal->IsNumber()) {
289         int32_t triggerValue = -1;
290         ParseJsInteger(jsVal, triggerValue);
291         symbolEffectOptions.SetTriggerNum(triggerValue);
292     }
293 }
294 
SetSymbolShadow(const JSCallbackInfo & info)295 void JSSymbol::SetSymbolShadow(const JSCallbackInfo& info)
296 {
297     SymbolShadow symbolShadow;
298     if (info.Length() < 1 || !info[0]->IsObject()) {
299         SymbolModel::GetInstance()->SetSymbolShadow(symbolShadow);
300         return;
301     }
302 
303     auto symbolShadowObj = JSRef<JSObject>::Cast(info[0]);
304     ParseSymbolShadow(symbolShadowObj, symbolShadow);
305 
306     SymbolModel::GetInstance()->SetSymbolShadow(symbolShadow);
307 }
308 
SetShaderStyle(const JSCallbackInfo & info)309 void JSSymbol::SetShaderStyle(const JSCallbackInfo& info)
310 {
311     std::vector<SymbolGradient> gradients;
312     if (info.Length() < 1 || !info[0]->IsObject()) {
313         SymbolModel::GetInstance()->ResetShaderStyle();
314         return;
315     }
316 
317     if (!info[0]->IsArray()) {
318         JSRef<JSObject> jsGradientObj = JSRef<JSObject>::Cast(info[0]);
319         SymbolGradient gradient;
320         gradient.gradientType = GradientDefinedStatus::GRADIENT_TYPE;
321         ParseShaderStyle(jsGradientObj, gradient);
322         gradients.emplace_back(std::move(gradient));
323         SymbolModel::GetInstance()->SetShaderStyle(gradients);
324         return;
325     }
326 
327     JSRef<JSArray> jsArray = JSRef<JSArray>::Cast(info[0]);
328     gradients.reserve(jsArray->Length());
329 
330     for (size_t i = 0; i < jsArray->Length(); ++i) {
331         auto jsValue = jsArray->GetValueAt(i);
332         SymbolGradient gradient;
333         if (!jsValue->IsObject()) {
334             gradients.emplace_back(std::move(gradient));
335             continue;
336         }
337         JSRef<JSObject> jsGradientObj = JSRef<JSObject>::Cast(jsValue);
338         ParseShaderStyle(jsGradientObj, gradient);
339         gradients.emplace_back(std::move(gradient));
340     }
341 
342     SymbolModel::GetInstance()->SetShaderStyle(gradients);
343 }
344 
ParseShaderStyle(const JSRef<JSObject> & shaderStyleObj,SymbolGradient & gradient)345 bool JSSymbol::ParseShaderStyle(const JSRef<JSObject>& shaderStyleObj, SymbolGradient& gradient)
346 {
347     auto typeParam = shaderStyleObj->GetProperty("type");
348     if (!typeParam->IsString()) {
349         return false;
350     }
351 
352     auto type = typeParam->ToString();
353     auto iter = SYMBOL_SHADER_TYPE_MAP.find(type);
354     if (iter == SYMBOL_SHADER_TYPE_MAP.end()) {
355         return false;
356     }
357 
358     gradient.type = iter->second;
359     if (gradient.type == SymbolGradientType::COLOR_SHADER) {
360         auto colorValue = shaderStyleObj->GetProperty("color");
361         Color color;
362         if (ParseJsColor(colorValue, color)) {
363             gradient.symbolColor.push_back(color);
364         }
365     } else if (gradient.type == SymbolGradientType::RADIAL_GRADIENT) {
366         auto optionsValue = shaderStyleObj->GetProperty("options");
367         if (!optionsValue->IsObject()) {
368             return false;
369         }
370         auto optionsObj = JSRef<JSObject>::Cast(optionsValue);
371         ParseCommonGradientOptions(optionsObj, gradient);
372         auto centerValue = optionsObj->GetProperty("center");
373         ParseGradientCenter(centerValue, gradient);
374         ParseJsValueToDimension(optionsObj, static_cast<int32_t>(ArkUIIndex::RADIUS), gradient.radius);
375     } else if (gradient.type == SymbolGradientType::LINEAR_GRADIENT) {
376         auto optionsValue = shaderStyleObj->GetProperty("options");
377         if (!optionsValue->IsObject()) {
378             return false;
379         }
380         auto optionsObj = JSRef<JSObject>::Cast(optionsValue);
381         ParseCommonGradientOptions(optionsObj, gradient);
382         auto angleProperty = optionsObj->GetProperty("angle");
383         if (!angleProperty->IsEmpty() && !angleProperty->IsNull() && !angleProperty->IsUndefined()) {
384             JSViewAbstract::GetJsAngleWithDefault(static_cast<int32_t>(ArkUIIndex::ANGLE), optionsObj,
385                                                   gradient.angle, DEFAULT_GRADIENT_ANGLE);
386         }
387         if (!gradient.angle.has_value()) {
388             auto directionValue = optionsObj->GetProperty("direction");
389             gradient.angle = DirectionToAngle(JsiRef<JsiValue>(directionValue));
390         }
391     }
392     return true;
393 }
394 
ParseCommonGradientOptions(const JSRef<JSObject> & optionsObj,SymbolGradient & gradient)395 void JSSymbol::ParseCommonGradientOptions(const JSRef<JSObject>& optionsObj, SymbolGradient& gradient)
396 {
397     auto colorsValue = optionsObj->GetProperty("colors");
398     ParseJsColorArray(colorsValue, gradient);
399     gradient.repeating = optionsObj->GetPropertyValue<bool>("repeating", false);
400 }
401 
ParseJsColorArray(const JSRef<JSVal> & jsValue,SymbolGradient & gradient)402 void JSSymbol::ParseJsColorArray(const JSRef<JSVal>& jsValue, SymbolGradient& gradient)
403 {
404     if (!jsValue->IsArray()) {
405         return;
406     }
407 
408     JSRef<JSArray> array = JSRef<JSArray>::Cast(jsValue);
409     for (size_t i = 0; i < array->Length(); i++) {
410         JSRef<JSVal> value = array->GetValueAt(i);
411         if (!value->IsArray()) {
412             continue;
413         }
414         JSRef<JSArray> nestedArray = JSRef<JSArray>::Cast(value);
415         if (nestedArray->Length() < NUM2) {
416             continue;
417         }
418         float opacity;
419         Color color;
420         JSRef<JSVal> colorVal = nestedArray->GetValueAt(0);
421         JSRef<JSVal> opacityVal = nestedArray->GetValueAt(1);
422         if (opacityVal->IsNumber()) {
423             opacity = static_cast<float>(opacityVal->ToNumber<double>());
424             gradient.symbolOpacities.emplace_back(opacity);
425         }
426 
427         if (ParseJsColor(colorVal, color)) {
428             gradient.symbolColor.emplace_back(color);
429         }
430     }
431 }
432 
ParseSymbolShadow(const JSRef<JSObject> & symbolShadowObj,SymbolShadow & symbolShadow)433 void JSSymbol::ParseSymbolShadow(const JSRef<JSObject>& symbolShadowObj, SymbolShadow& symbolShadow)
434 {
435     auto colorValue = symbolShadowObj->GetProperty(static_cast<int32_t>(ArkUIIndex::COLOR));
436     Color color;
437     if (ParseJsColor(colorValue, color)) {
438         symbolShadow.color = color;
439     }
440 
441     ParseJsValueToFloat(symbolShadowObj, static_cast<int32_t>(ArkUIIndex::RADIUS), symbolShadow.radius);
442     ParseJsValueToFloat(symbolShadowObj, static_cast<int32_t>(ArkUIIndex::OFFSET_X), symbolShadow.offset.first);
443     ParseJsValueToFloat(symbolShadowObj, static_cast<int32_t>(ArkUIIndex::OFFSET_Y), symbolShadow.offset.second);
444 }
445 
ParseGradientCenter(const JSRef<JSArray> & center,SymbolGradient & gradient)446 void JSSymbol::ParseGradientCenter(const JSRef<JSArray>& center, SymbolGradient& gradient)
447 {
448     if (center->IsArray() && JSRef<JSArray>::Cast(center)->Length() == NUM2) {
449         CalcDimension value;
450         JSRef<JSArray> centerArray = JSRef<JSArray>::Cast(center);
451         if (ParseJsDimensionVp(centerArray->GetValueAt(0), value)) {
452             gradient.radialCenterX = CalcDimension(value);
453         }
454         if (ParseJsDimensionVp(centerArray->GetValueAt(1), value)) {
455             gradient.radialCenterY= CalcDimension(value);
456         }
457     }
458 }
459 
ParseJsValueToFloat(const JSRef<JSObject> & jsObj,int32_t key,float & output)460 void JSSymbol::ParseJsValueToFloat(const JSRef<JSObject>& jsObj, int32_t key, float& output)
461 {
462     CalcDimension offset;
463     auto jsOffset = jsObj->GetProperty(key);
464     if (ParseJsDimensionVp(jsOffset, offset) || ParseJsResource(jsOffset, offset)) {
465         output = static_cast<float>(offset.GetNativeValue(DimensionUnit::PX));
466     }
467 }
468 
ParseJsValueToDimension(const JSRef<JSObject> & jsObj,int32_t key,std::optional<Dimension> & output)469 void JSSymbol::ParseJsValueToDimension(const JSRef<JSObject>& jsObj, int32_t key, std::optional<Dimension>& output)
470 {
471     CalcDimension offset;
472     auto jsOffset = jsObj->GetProperty(key);
473     if (ParseJsDimensionVp(jsOffset, offset) || ParseJsResource(jsOffset, offset)) {
474         output = CalcDimension(offset);
475     }
476 }
477 
DirectionToAngle(const JsiRef<JsiValue> & directionValue)478 float JSSymbol::DirectionToAngle(const JsiRef<JsiValue>& directionValue)
479 {
480     if (!directionValue->IsNumber()) {
481         //direction: Direction of Linear Gradient. The default value is GradientDirection.Bottom;
482         return DEFAULT_GRADIENT_ANGLE;
483     }
484 
485     int32_t dirValue = 0;
486     if (!ParseJsInt32(directionValue, dirValue)) {
487         return DEFAULT_GRADIENT_ANGLE;
488     }
489 
490     auto dir = static_cast<SDKGradientDirection>(dirValue);
491     auto it = GRADIENT_DIRECTION_TO_ANGLE.find(dir);
492 
493     return (it != GRADIENT_DIRECTION_TO_ANGLE.end()) ? it->second : DEFAULT_GRADIENT_ANGLE;
494 }
495 } // namespace OHOS::Ace::Framework