1 /*
2 * Copyright (c) 2024 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 "bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_navigation_utils.h"
17
18 #include "core/components_ng/pattern/navigation/navigation_model_ng.h"
19 #include "core/common/resource/resource_parse_utils.h"
20
21 namespace OHOS::Ace::NG {
ParseBarItems(EcmaVM * vm,const Local<JSValueRef> & jsValue,std::vector<ArkUIBarItem> & items)22 void NativeNavigationUtils::ParseBarItems(
23 EcmaVM* vm, const Local<JSValueRef>& jsValue, std::vector<ArkUIBarItem>& items)
24 {
25 auto array = panda::Local<panda::ArrayRef>(jsValue);
26 auto length = array->Length(vm);
27 for (uint32_t index = 0; index < length; index++) {
28 auto item = panda::ArrayRef::GetValueAt(vm, array, index);
29 if (!item->IsObject(vm)) {
30 continue;
31 }
32 auto obj = item->ToObject(vm);
33 ArkUIBarItem menuItem;
34 ParseBarItemsValue(vm, obj, menuItem);
35 ParseBarItemsIcon(vm, obj, menuItem);
36 auto itemEnabledObject = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "isEnabled"));
37 if (itemEnabledObject->IsBoolean()) {
38 menuItem.isEnable = { 1, itemEnabledObject->ToBoolean(vm)->Value() };
39 }
40 items.push_back(menuItem);
41 }
42 }
43
ParseBarItemsValue(EcmaVM * vm,const Local<panda::ObjectRef> & itemObject,ArkUIBarItem & toolBarItem)44 void NativeNavigationUtils::ParseBarItemsValue(
45 EcmaVM* vm, const Local<panda::ObjectRef>& itemObject, ArkUIBarItem& toolBarItem)
46 {
47 std::string value;
48 auto itemValueObject = itemObject->Get(vm, panda::StringRef::NewFromUtf8(vm, "value"));
49 toolBarItem.isStringText = true;
50 if (SystemProperties::ConfigChangePerform()) {
51 RefPtr<ResourceObject> itemValueResObj;
52 if (ArkTSUtils::ParseJsString(vm, itemValueObject, value, itemValueResObj)) {
53 toolBarItem.text.isSet = 1;
54 toolBarItem.text.value = new char[value.length() + 1];
55 DeepCopyStringValue(toolBarItem.text.value, value.length() + 1, value);
56 }
57 if (itemValueResObj) {
58 toolBarItem.isStringText = false;
59 auto&& updateFunc = [](const RefPtr<ResourceObject>& itemValueResObj, ArkUIBarItem& toolBarItem) {
60 std::string valueResult;
61 if (ResourceParseUtils::ParseResString(itemValueResObj, valueResult)) {
62 toolBarItem.text.isSet = 1;
63 toolBarItem.text.value = new char[valueResult.length() + 1];
64 DeepCopyStringValue(toolBarItem.text.value, valueResult.length() + 1, valueResult);
65 }
66 };
67 toolBarItem.AddResource("toolBarItem.value", itemValueResObj, std::move(updateFunc));
68 }
69 } else {
70 if (ArkTSUtils::ParseJsString(vm, itemValueObject, value)) {
71 toolBarItem.text.isSet = 1;
72 toolBarItem.text.value = new char[value.length() + 1];
73 DeepCopyStringValue(toolBarItem.text.value, value.length() + 1, value);
74 }
75 }
76 }
77
ParseBarItemsIcon(EcmaVM * vm,const Local<panda::ObjectRef> & itemObject,ArkUIBarItem & toolBarItem)78 void NativeNavigationUtils::ParseBarItemsIcon(
79 EcmaVM* vm, const Local<panda::ObjectRef>& itemObject, ArkUIBarItem& toolBarItem)
80 {
81 std::string icon;
82 auto itemIconObject = itemObject->Get(vm, panda::StringRef::NewFromUtf8(vm, "icon"));
83 toolBarItem.isStringIcon = true;
84 if (SystemProperties::ConfigChangePerform()) {
85 RefPtr<ResourceObject> itemIconResObj;
86 if (ArkTSUtils::ParseJsMedia(vm, itemIconObject, icon, itemIconResObj)) {
87 toolBarItem.icon.isSet = 1;
88 toolBarItem.icon.value = new char[icon.length() + 1];
89 DeepCopyStringValue(toolBarItem.icon.value, icon.length() + 1, icon);
90 }
91 if (itemIconResObj) {
92 toolBarItem.isStringIcon = false;
93 auto&& updateFunc = [](const RefPtr<ResourceObject>& itemIconResObj, ArkUIBarItem& toolBarItem) {
94 std::string iconResult;
95 if (ResourceParseUtils::ParseResMedia(itemIconResObj, iconResult)) {
96 toolBarItem.icon.isSet = 1;
97 toolBarItem.icon.value = new char[iconResult.length() + 1];
98 DeepCopyStringValue(toolBarItem.icon.value, iconResult.length() + 1, iconResult);
99 }
100 };
101 toolBarItem.AddResource("navigation.barItem.icon", itemIconResObj, std::move(updateFunc));
102 }
103 } else {
104 if (ArkTSUtils::ParseJsMedia(vm, itemIconObject, icon)) {
105 toolBarItem.icon.isSet = 1;
106 toolBarItem.icon.value = new char[icon.length() + 1];
107 DeepCopyStringValue(toolBarItem.icon.value, icon.length() + 1, icon);
108 }
109 }
110 }
111
ParseTitleOptions(const EcmaVM * vm,const Local<JSValueRef> & jsValue,ArkUINodeHandle nativeNode,ArkUINavigationTitlebarOptions & options)112 void NativeNavigationUtils::ParseTitleOptions(const EcmaVM* vm, const Local<JSValueRef>& jsValue,
113 ArkUINodeHandle nativeNode, ArkUINavigationTitlebarOptions& options)
114 {
115 auto obj = jsValue->ToObject(vm);
116 UpdateNavigationBackgroundColor(vm, obj, nativeNode, options);
117 auto blurProperty = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "backgroundBlurStyle"));
118 if (blurProperty->IsNumber()) {
119 auto blurStyle = blurProperty->Int32Value(vm);
120 if (blurStyle >= static_cast<int>(BlurStyle::NO_MATERIAL) &&
121 blurStyle <= static_cast<int>(BlurStyle::COMPONENT_ULTRA_THICK)) {
122 options.blurStyle = ArkUIOptionalInt { 1, blurStyle };
123 }
124 }
125 auto barStyleProperty = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "barStyle"));
126 if (barStyleProperty->IsNumber()) {
127 auto barStyle = barStyleProperty->Int32Value(vm);
128 if (barStyle >= static_cast<int32_t>(NG::BarStyle::STANDARD) &&
129 barStyle <= static_cast<int32_t>(NG::BarStyle::STACK)) {
130 options.barStyle = ArkUIOptionalInt { 1, barStyle };
131 } else {
132 options.barStyle = ArkUIOptionalInt { 1, static_cast<int32_t>(NG::BarStyle::STANDARD) };
133 }
134 }
135 CalcDimension paddingStart;
136 auto paddingStartProperty = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "paddingStart"));
137 if (ArkTSUtils::ParseJsLengthMetrics(vm, paddingStartProperty, paddingStart)) {
138 options.paddingStart.isSet = 1;
139 options.paddingStart.dimension.value = paddingStart.Value();
140 options.paddingStart.dimension.units = static_cast<int32_t>(paddingStart.Unit());
141 }
142 CalcDimension paddingEnd;
143 auto paddingEndProperty = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "paddingEnd"));
144 if (ArkTSUtils::ParseJsLengthMetrics(vm, paddingEndProperty, paddingEnd)) {
145 options.paddingEnd.isSet = 1;
146 options.paddingEnd.dimension.value = paddingEnd.Value();
147 options.paddingEnd.dimension.units = static_cast<int32_t>(paddingEnd.Unit());
148 }
149 auto enableHoverModeProperty = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "enableHoverMode"));
150 if (enableHoverModeProperty->IsBoolean()) {
151 options.enableHoverMode.isSet = 1;
152 options.enableHoverMode.value = enableHoverModeProperty->ToBoolean(vm)->Value();
153 }
154 }
155
UpdateNavigationBackgroundColor(const EcmaVM * vm,const Local<panda::ObjectRef> & obj,ArkUINodeHandle nativeNode,ArkUINavigationTitlebarOptions & options)156 void NativeNavigationUtils::UpdateNavigationBackgroundColor(const EcmaVM* vm, const Local<panda::ObjectRef>& obj,
157 ArkUINodeHandle nativeNode, ArkUINavigationTitlebarOptions& options)
158 {
159 auto colorProperty = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "backgroundColor"));
160 Color color;
161 if (!SystemProperties::ConfigChangePerform()) {
162 if (ArkTSUtils::ParseJsColor(vm, colorProperty, color)) {
163 options.colorValue = ArkUIOptionalUint { 1, color.GetValue() };
164 }
165 return;
166 }
167 RefPtr<ResourceObject> backgroundColorResObj;
168 auto nodeInfo = ArkTSUtils::MakeNativeNodeInfo(nativeNode);
169 if (ArkTSUtils::ParseJsColor(vm, colorProperty, color, backgroundColorResObj, nodeInfo)) {
170 options.colorValue = ArkUIOptionalUint { 1, color.GetValue() };
171 }
172 if (backgroundColorResObj) {
173 AddBackgroundColorResource(backgroundColorResObj, options);
174 }
175 }
176
AddBackgroundColorResource(const RefPtr<ResourceObject> & backgroundColorResObj,ArkUINavigationTitlebarOptions & options)177 void NativeNavigationUtils::AddBackgroundColorResource(
178 const RefPtr<ResourceObject>& backgroundColorResObj, ArkUINavigationTitlebarOptions& options)
179 {
180 auto&& updateBackgroundColorFunc = [](const RefPtr<ResourceObject>& resObj,
181 ArkUINavigationTitlebarOptions& options) {
182 Color backgroundColor;
183 if (ResourceParseUtils::ParseResColor(resObj, backgroundColor)) {
184 options.colorValue = ArkUIOptionalUint { 1, backgroundColor.GetValue() };
185 }
186 };
187 options.AddResource(
188 "navigationTitleOptionsModifier.backgroundColor", backgroundColorResObj, std::move(updateBackgroundColorFunc));
189 }
190
ParseAndSendFunctionParam(ArkUIRuntimeCallInfo * runtimeCallInfo,const Local<JSValueRef> & jsValue,ParamSendFunction & actionSendFunc,ParamSendFunction & symbolSendFunc)191 void NativeNavigationUtils::ParseAndSendFunctionParam(ArkUIRuntimeCallInfo* runtimeCallInfo,
192 const Local<JSValueRef>& jsValue, ParamSendFunction& actionSendFunc, ParamSendFunction& symbolSendFunc)
193 {
194 EcmaVM* vm = runtimeCallInfo->GetVM();
195 CHECK_NULL_VOID(vm);
196 Local<JSValueRef> nodeArg = runtimeCallInfo->GetCallArgRef(0);
197 auto nativeNode = nodePtr(nodeArg->ToNativePointer(vm)->Value());
198 auto frameNode = reinterpret_cast<FrameNode*>(nativeNode);
199 CHECK_NULL_VOID(frameNode);
200 Framework::JsiCallbackInfo info = Framework::JsiCallbackInfo(runtimeCallInfo);
201 auto jsArray = Framework::JSRef<Framework::JSArray>::Cast(info[1]);
202 auto array = panda::Local<panda::ArrayRef>(jsValue);
203 auto length = array->Length(vm);
204 for (uint32_t index = 0; index < length; index++) {
205 auto item = panda::ArrayRef::GetValueAt(vm, array, index);
206 if (!item->IsObject(vm)) {
207 continue;
208 }
209 auto obj = item->ToObject(vm);
210 auto itemSymbolIconObject = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "symbolIcon"));
211 if (itemSymbolIconObject->IsObject(vm)) {
212 std::function<void(WeakPtr<NG::FrameNode>)> iconSymbol = nullptr;
213 auto jsItem = jsArray->GetValueAt(index);
214 auto jsItemObject = Framework::JSRef<Framework::JSObject>::Cast(jsItem);
215 auto jsItemSymbolIconObject = jsItemObject->GetProperty("symbolIcon");
216 Framework::JSViewAbstract::SetSymbolOptionApply(runtimeCallInfo, iconSymbol, jsItemSymbolIconObject);
217 symbolSendFunc(nativeNode, reinterpret_cast<void*>(&iconSymbol), index);
218 }
219 auto itemActionValue = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "action"));
220 if (itemActionValue->IsFunction(vm)) {
221 panda::Local<panda::FunctionRef> func = itemActionValue->ToObject(vm);
222 std::function<void(void)> onItemClick = [vm, frameNode, func = panda::CopyableGlobal(vm, func)] () {
223 panda::LocalScope pandaScope(vm);
224 panda::TryCatch trycatch(vm);
225 PipelineContext::SetCallBackNode(AceType::WeakClaim(frameNode));
226 func->Call(vm, func.ToLocal(), nullptr, 0);
227 };
228 actionSendFunc(nativeNode, reinterpret_cast<void*>(&onItemClick), index);
229 }
230 }
231 }
232
DeepCopyStringValue(char * des,uint32_t desLength,const std::string & src)233 void NativeNavigationUtils::DeepCopyStringValue(char* des, uint32_t desLength, const std::string& src)
234 {
235 if (des == nullptr || desLength == 0) {
236 TAG_LOGW(AceLogTag::ACE_NAVIGATION, "destination char space allocated failed");
237 return;
238 }
239 if (src.length() == 0) {
240 des[0] = '\0';
241 return;
242 }
243 auto copyedSize = src.copy(des, desLength - 1 < src.length() ? desLength - 1 : src.length());
244 if (copyedSize == 0) {
245 TAG_LOGW(AceLogTag::ACE_NAVIGATION, "copy string to destination char failed");
246 }
247 des[copyedSize] = '\0';
248 }
249 } // namespace OHOS::Ace::NG