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