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 "bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_menu_bridge.h"
16 #include "core/interfaces/arkoala/arkoala_api.h"
17 #include "frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_utils.h"
18 
19 namespace OHOS::Ace::NG {
20 const std::string FORMAT_FONT = "%s|%s|%s";
21 const std::string DEFAULT_ERR_CODE = "-1";
22 constexpr int ARG_INDEX_0 = 0;
23 constexpr int ARG_INDEX_1 = 1;
24 constexpr int ARG_INDEX_2 = 2;
25 constexpr int ARG_INDEX_3 = 3;
26 constexpr int ARG_INDEX_4 = 4;
27 
BuildMenuDividerOptions(EcmaVM * vm,Local<JSValueRef> strokeWidthArg,Local<JSValueRef> colorArg,Local<JSValueRef> startMarginArg,Local<JSValueRef> endMarginArg)28 ArkUIMenuDividerOptions BuildMenuDividerOptions(EcmaVM* vm, Local<JSValueRef> strokeWidthArg,
29     Local<JSValueRef> colorArg, Local<JSValueRef> startMarginArg, Local<JSValueRef> endMarginArg)
30 {
31     ArkUIDimensionType strokeWidthOption;
32     ArkUIDimensionType startMarginOption;
33     ArkUIDimensionType endMarginOption;
34 
35     CalcDimension strokeWidth;
36     if (!ArkTSUtils::ParseJsLengthMetrics(vm, strokeWidthArg, strokeWidth)) {
37         strokeWidth = Dimension(0.0);
38     }
39     strokeWidthOption.value = strokeWidth.Value();
40     strokeWidthOption.units = static_cast<int32_t>(strokeWidth.Unit());
41 
42     Color color;
43     if (!ArkTSUtils::ParseJsColorAlpha(vm, colorArg, color)) {
44         color = Color::TRANSPARENT;
45     }
46 
47     CalcDimension startMargin;
48     if (!ArkTSUtils::ParseJsLengthMetrics(vm, startMarginArg, startMargin)) {
49         startMargin = Dimension(0.0);
50     }
51     startMarginOption.value = startMargin.Value();
52     startMarginOption.units = static_cast<int32_t>(startMargin.Unit());
53 
54     CalcDimension endMargin;
55     if (!ArkTSUtils::ParseJsLengthMetrics(vm, endMarginArg, endMargin)) {
56         endMargin = Dimension(0.0);
57     }
58     endMarginOption.value = endMargin.Value();
59     endMarginOption.units = static_cast<int32_t>(endMargin.Unit());
60 
61     ArkUIMenuDividerOptions dividerOptions;
62     dividerOptions.strokeWidth = strokeWidthOption;
63     dividerOptions.color = color.GetValue();
64     dividerOptions.startMargin = startMarginOption;
65     dividerOptions.endMargin = endMarginOption;
66     return dividerOptions;
67 }
68 
SetMenuDivider(ArkUIRuntimeCallInfo * runtimeCallInfo,bool isGroupDivider)69 ArkUINativeModuleValue SetMenuDivider(ArkUIRuntimeCallInfo* runtimeCallInfo, bool isGroupDivider)
70 {
71     EcmaVM* vm = runtimeCallInfo->GetVM();
72     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
73     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(ARG_INDEX_0);
74     Local<JSValueRef> strokeWidthArg = runtimeCallInfo->GetCallArgRef(ARG_INDEX_1);
75     Local<JSValueRef> colorArg = runtimeCallInfo->GetCallArgRef(ARG_INDEX_2);
76     Local<JSValueRef> startMarginArg = runtimeCallInfo->GetCallArgRef(ARG_INDEX_3);
77     Local<JSValueRef> endMarginArg = runtimeCallInfo->GetCallArgRef(ARG_INDEX_4);
78     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
79     if (strokeWidthArg->IsUndefined() && colorArg->IsUndefined() && startMarginArg->IsUndefined()
80         && endMarginArg->IsUndefined()) {
81         if (isGroupDivider) {
82             GetArkUINodeModifiers()->getMenuModifier()->resetMenuItemGroupDivider(nativeNode);
83         } else {
84             GetArkUINodeModifiers()->getMenuModifier()->resetMenuItemDivider(nativeNode);
85         }
86         return panda::JSValueRef::Undefined(vm);
87     }
88     auto dividerOptions = BuildMenuDividerOptions(vm, strokeWidthArg, colorArg, startMarginArg,
89         endMarginArg);
90     if (isGroupDivider) {
91         GetArkUINodeModifiers()->getMenuModifier()->setMenuItemGroupDivider(nativeNode, &dividerOptions);
92     } else {
93         GetArkUINodeModifiers()->getMenuModifier()->setMenuItemDivider(nativeNode, &dividerOptions);
94     }
95     return panda::JSValueRef::Undefined(vm);
96 }
97 
ResetMenuDivider(ArkUIRuntimeCallInfo * runtimeCallInfo,bool isGroupDivider)98 ArkUINativeModuleValue ResetMenuDivider(ArkUIRuntimeCallInfo* runtimeCallInfo, bool isGroupDivider)
99 {
100     EcmaVM* vm = runtimeCallInfo->GetVM();
101     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
102     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
103     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
104     if (isGroupDivider) {
105         GetArkUINodeModifiers()->getMenuModifier()->resetMenuItemGroupDivider(nativeNode);
106     } else {
107         GetArkUINodeModifiers()->getMenuModifier()->resetMenuItemDivider(nativeNode);
108     }
109     return panda::JSValueRef::Undefined(vm);
110 }
111 
SetMenuFontColor(ArkUIRuntimeCallInfo * runtimeCallInfo)112 ArkUINativeModuleValue MenuBridge::SetMenuFontColor(ArkUIRuntimeCallInfo* runtimeCallInfo)
113 {
114     EcmaVM* vm = runtimeCallInfo->GetVM();
115     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
116     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
117     Local<JSValueRef> secondArg = runtimeCallInfo->GetCallArgRef(1);
118     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
119     Color color;
120     if (!ArkTSUtils::ParseJsColorAlpha(vm, secondArg, color)) {
121         GetArkUINodeModifiers()->getMenuModifier()->resetMenuFontColor(nativeNode);
122     } else {
123         GetArkUINodeModifiers()->getMenuModifier()->setMenuFontColor(nativeNode, color.GetValue());
124     }
125 
126     return panda::JSValueRef::Undefined(vm);
127 }
128 
ResetMenuFontColor(ArkUIRuntimeCallInfo * runtimeCallInfo)129 ArkUINativeModuleValue MenuBridge::ResetMenuFontColor(ArkUIRuntimeCallInfo* runtimeCallInfo)
130 {
131     EcmaVM* vm = runtimeCallInfo->GetVM();
132     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
133     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
134     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
135     GetArkUINodeModifiers()->getMenuModifier()->resetMenuFontColor(nativeNode);
136     return panda::JSValueRef::Undefined(vm);
137 }
138 
SetFont(ArkUIRuntimeCallInfo * runtimeCallInfo)139 ArkUINativeModuleValue MenuBridge::SetFont(ArkUIRuntimeCallInfo* runtimeCallInfo)
140 {
141     EcmaVM* vm = runtimeCallInfo->GetVM();
142     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
143     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
144     Local<JSValueRef> sizeArg = runtimeCallInfo->GetCallArgRef(1);   // 1: index of font size value
145     Local<JSValueRef> weightArg = runtimeCallInfo->GetCallArgRef(2); // 2: index of font weight value
146     Local<JSValueRef> familyArg = runtimeCallInfo->GetCallArgRef(3); // 3: index of font family value
147     Local<JSValueRef> styleArg = runtimeCallInfo->GetCallArgRef(4);  // 4: index of font style value
148     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
149     if (sizeArg->IsUndefined() && weightArg->IsUndefined() && familyArg->IsUndefined() && styleArg->IsUndefined()) {
150         GetArkUINodeModifiers()->getMenuModifier()->resetFont(nativeNode);
151         return panda::JSValueRef::Undefined(vm);
152     }
153 
154     CalcDimension fontSize;
155     if (!ArkTSUtils::ParseJsDimensionFp(vm, sizeArg, fontSize, false)) {
156         fontSize = Dimension(0.0);
157     }
158     std::string weight = DEFAULT_ERR_CODE;
159     if (weightArg->IsNumber()) {
160         weight = std::to_string(weightArg->Int32Value(vm));
161     } else {
162         if (!ArkTSUtils::ParseJsString(vm, weightArg, weight) || weight.empty()) {
163             weight = DEFAULT_ERR_CODE;
164         }
165     }
166 
167     int32_t style = -1;
168     if (styleArg->IsNumber()) {
169         style = styleArg->Int32Value(vm);
170     }
171 
172     std::string family;
173     if (!ArkTSUtils::ParseJsFontFamiliesToString(vm, familyArg, family) || family.empty()) {
174         family = DEFAULT_ERR_CODE;
175     }
176     std::string fontSizeStr = fontSize.ToString();
177     std::string fontInfo =
178         StringUtils::FormatString(FORMAT_FONT.c_str(), fontSizeStr.c_str(), weight.c_str(), family.c_str());
179 
180     GetArkUINodeModifiers()->getMenuModifier()->setFont(nativeNode, fontInfo.c_str(), style);
181     return panda::JSValueRef::Undefined(vm);
182 }
183 
ResetFont(ArkUIRuntimeCallInfo * runtimeCallInfo)184 ArkUINativeModuleValue MenuBridge::ResetFont(ArkUIRuntimeCallInfo* runtimeCallInfo)
185 {
186     EcmaVM* vm = runtimeCallInfo->GetVM();
187     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
188     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
189     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
190     GetArkUINodeModifiers()->getMenuModifier()->resetFont(nativeNode);
191     return panda::JSValueRef::Undefined(vm);
192 }
193 
ParseRadius(EcmaVM * vm,ArkUIRuntimeCallInfo * runtimeCallInfo,ArkUINodeHandle nativeNode,std::vector<ArkUI_Float32> & radiusValues,std::vector<int32_t> & radiusUnits)194 bool MenuBridge::ParseRadius(EcmaVM* vm, ArkUIRuntimeCallInfo* runtimeCallInfo, ArkUINodeHandle nativeNode,
195     std::vector<ArkUI_Float32>& radiusValues, std::vector<int32_t>& radiusUnits)
196 {
197     Local<JSValueRef> topLeftArgs = runtimeCallInfo->GetCallArgRef(1);     // 1: index of top left value
198     Local<JSValueRef> topRightArgs = runtimeCallInfo->GetCallArgRef(2);    // 2: index of top right value
199     Local<JSValueRef> bottomLeftArgs = runtimeCallInfo->GetCallArgRef(3);  // 3: index of bottom left value
200     Local<JSValueRef> bottomRightArgs = runtimeCallInfo->GetCallArgRef(4); // 4: index of bottom right value
201     Local<JSValueRef> isObjectArgs = runtimeCallInfo->GetCallArgRef(5);    // 5: check is object radius
202     if (topLeftArgs->IsUndefined() && topRightArgs->IsUndefined() && bottomLeftArgs->IsUndefined() &&
203         bottomRightArgs->IsUndefined()) {
204         GetArkUINodeModifiers()->getMenuModifier()->resetRadius(nativeNode);
205         return false;
206     }
207 
208     CalcDimension topLeft;
209     CalcDimension topRight;
210     CalcDimension bottomLeft;
211     CalcDimension bottomRight;
212     if (isObjectArgs->IsBoolean() && !isObjectArgs->ToBoolean(vm)->Value()) {
213         if (!ArkTSUtils::ParseJsDimensionVpNG(vm, topLeftArgs, topLeft, true)) {
214             GetArkUINodeModifiers()->getMenuModifier()->resetRadius(nativeNode);
215             return false;
216         }
217         if (LessNotEqual(topLeft.Value(), 0.0)) {
218             GetArkUINodeModifiers()->getMenuModifier()->resetRadius(nativeNode);
219             return false;
220         }
221         topRight = topLeft;
222         bottomLeft = topLeft;
223         bottomRight = topLeft;
224     } else {
225         if (!ArkTSUtils::ParseJsDimensionVpNG(vm, topLeftArgs, topLeft, true)) {
226             topLeft = CalcDimension(0.0, DimensionUnit::VP);
227         }
228 
229         if (!ArkTSUtils::ParseJsDimensionVpNG(vm, topRightArgs, topRight, true)) {
230             topRight = CalcDimension(0.0, DimensionUnit::VP);
231         }
232 
233         if (!ArkTSUtils::ParseJsDimensionVpNG(vm, bottomLeftArgs, bottomLeft, true)) {
234             bottomLeft = CalcDimension(0.0, DimensionUnit::VP);
235         }
236 
237         if (!ArkTSUtils::ParseJsDimensionVpNG(vm, bottomRightArgs, bottomRight, true)) {
238             bottomRight = CalcDimension(0.0, DimensionUnit::VP);
239         }
240     }
241     radiusUnits.push_back(static_cast<int32_t>(topLeft.Unit()));
242     radiusUnits.push_back(static_cast<int32_t>(topRight.Unit()));
243     radiusUnits.push_back(static_cast<int32_t>(bottomLeft.Unit()));
244     radiusUnits.push_back(static_cast<int32_t>(bottomRight.Unit()));
245     radiusValues.push_back(topLeft.Value());
246     radiusValues.push_back(topRight.Value());
247     radiusValues.push_back(bottomLeft.Value());
248     radiusValues.push_back(bottomRight.Value());
249     return true;
250 }
251 
SetRadius(ArkUIRuntimeCallInfo * runtimeCallInfo)252 ArkUINativeModuleValue MenuBridge::SetRadius(ArkUIRuntimeCallInfo* runtimeCallInfo)
253 {
254     EcmaVM* vm = runtimeCallInfo->GetVM();
255     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
256     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
257     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
258     std::vector<ArkUI_Float32> radiusValues;
259     std::vector<int32_t> radiusUnits;
260     if (!ParseRadius(vm, runtimeCallInfo, nativeNode, radiusValues, radiusUnits)) {
261         return panda::JSValueRef::Undefined(vm);
262     }
263     GetArkUINodeModifiers()->getMenuModifier()->setRadius(nativeNode, radiusValues.data(), radiusUnits.data());
264     return panda::JSValueRef::Undefined(vm);
265 }
266 
ResetRadius(ArkUIRuntimeCallInfo * runtimeCallInfo)267 ArkUINativeModuleValue MenuBridge::ResetRadius(ArkUIRuntimeCallInfo* runtimeCallInfo)
268 {
269     EcmaVM* vm = runtimeCallInfo->GetVM();
270     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
271     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
272     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
273     GetArkUINodeModifiers()->getMenuModifier()->resetRadius(nativeNode);
274     return panda::JSValueRef::Undefined(vm);
275 }
276 
SetWidth(ArkUIRuntimeCallInfo * runtimeCallInfo)277 ArkUINativeModuleValue MenuBridge::SetWidth(ArkUIRuntimeCallInfo* runtimeCallInfo)
278 {
279     EcmaVM* vm = runtimeCallInfo->GetVM();
280     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
281     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
282     Local<JSValueRef> widthArg = runtimeCallInfo->GetCallArgRef(1);
283     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
284     CalcDimension width;
285     if (!ArkTSUtils::ParseJsDimensionVp(vm, widthArg, width, false)) {
286         GetArkUINodeModifiers()->getMenuModifier()->resetMenuWidth(nativeNode);
287         return panda::JSValueRef::Undefined(vm);
288     }
289     GetArkUINodeModifiers()->getMenuModifier()->setMenuWidth(
290         nativeNode, width.Value(), static_cast<int32_t>(width.Unit()));
291     return panda::JSValueRef::Undefined(vm);
292 }
293 
ResetWidth(ArkUIRuntimeCallInfo * runtimeCallInfo)294 ArkUINativeModuleValue MenuBridge::ResetWidth(ArkUIRuntimeCallInfo* runtimeCallInfo)
295 {
296     EcmaVM* vm = runtimeCallInfo->GetVM();
297     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
298     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
299     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
300     GetArkUINodeModifiers()->getMenuModifier()->resetMenuWidth(nativeNode);
301     return panda::JSValueRef::Undefined(vm);
302 }
303 
SetMenuItemDivider(ArkUIRuntimeCallInfo * runtimeCallInfo)304 ArkUINativeModuleValue MenuBridge::SetMenuItemDivider(ArkUIRuntimeCallInfo* runtimeCallInfo)
305 {
306     return SetMenuDivider(runtimeCallInfo, false);
307 }
308 
ResetMenuItemDivider(ArkUIRuntimeCallInfo * runtimeCallInfo)309 ArkUINativeModuleValue MenuBridge::ResetMenuItemDivider(ArkUIRuntimeCallInfo* runtimeCallInfo)
310 {
311     return ResetMenuDivider(runtimeCallInfo, false);
312 }
313 
SetMenuItemGroupDivider(ArkUIRuntimeCallInfo * runtimeCallInfo)314 ArkUINativeModuleValue MenuBridge::SetMenuItemGroupDivider(ArkUIRuntimeCallInfo* runtimeCallInfo)
315 {
316     return SetMenuDivider(runtimeCallInfo, true);
317 }
318 
ResetMenuItemGroupDivider(ArkUIRuntimeCallInfo * runtimeCallInfo)319 ArkUINativeModuleValue MenuBridge::ResetMenuItemGroupDivider(ArkUIRuntimeCallInfo* runtimeCallInfo)
320 {
321     return ResetMenuDivider(runtimeCallInfo, true);
322 }
323 
SetSubMenuExpandingMode(ArkUIRuntimeCallInfo * runtimeCallInfo)324 ArkUINativeModuleValue MenuBridge::SetSubMenuExpandingMode(ArkUIRuntimeCallInfo* runtimeCallInfo)
325 {
326     EcmaVM* vm = runtimeCallInfo->GetVM();
327     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
328     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
329     Local<JSValueRef> secondArg = runtimeCallInfo->GetCallArgRef(1);
330     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
331     if (secondArg->IsUndefined() || secondArg->IsNull()) {
332         GetArkUINodeModifiers()->getMenuModifier()->resetSubMenuExpandingMode(nativeNode);
333         return panda::JSValueRef::Undefined(vm);
334     }
335     if (secondArg->IsNumber()) {
336         GetArkUINodeModifiers()->getMenuModifier()->setSubMenuExpandingMode(nativeNode,
337             secondArg->ToNumber(vm)->Value());
338     } else {
339         GetArkUINodeModifiers()->getMenuModifier()->resetSubMenuExpandingMode(nativeNode);
340     }
341     return panda::JSValueRef::Undefined(vm);
342 }
343 
ResetSubMenuExpandingMode(ArkUIRuntimeCallInfo * runtimeCallInfo)344 ArkUINativeModuleValue MenuBridge::ResetSubMenuExpandingMode(ArkUIRuntimeCallInfo* runtimeCallInfo)
345 {
346     EcmaVM* vm = runtimeCallInfo->GetVM();
347     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
348     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
349     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
350     GetArkUINodeModifiers()->getMenuModifier()->resetSubMenuExpandingMode(nativeNode);
351     return panda::JSValueRef::Undefined(vm);
352 }
353 } // namespace OHOS::Ace::NG
354