1/* 2 * Copyright (c) 2021 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/jsview/js_view_common_def.h" 17 18#include <string> 19#include <type_traits> 20 21#include "base/geometry/dimension.h" 22#include "base/log/log.h" 23#include "bridge/declarative_frontend/view_stack_processor.h" 24#include "bridge/declarative_frontend/jsview/js_view_abstract.h" 25#include "core/components/common/properties/color.h" 26 27namespace OHOS::Ace::Framework { 28 29template<class T> 30JSRef<JSVal> ConvertToJSValue(T&& value) 31{ 32 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>; 33 if constexpr (std::is_arithmetic_v<ValueType> || std::is_same_v<ValueType, std::string> || 34 std::is_same_v<ValueType, std::u16string>) { 35 return JSRef<JSVal>::Make(ToJSValue(std::forward<T>(value))); 36 } else if constexpr (std::is_enum_v<ValueType>) { 37 return JSRef<JSVal>::Make(ToJSValue(static_cast<std::make_signed_t<ValueType>>(value))); 38 } else if constexpr (std::is_same_v<ValueType, Dimension> || std::is_same_v<ValueType, CalcDimension>) { 39 if (value.Unit() == DimensionUnit::VP) { 40 return JSRef<JSVal>::Make(ToJSValue(value.Value())); 41 } else { 42 LOGE("Failed to convert to JS value with dimension which it not using 'VP' unit"); 43 return JSRef<JSVal>(); 44 } 45 } else { 46 LOGE("Failed to convert to JS value"); 47 return JSRef<JSVal>(); 48 } 49} 50 51template<class T> 52void ConvertToJSValuesImpl(std::vector<JSRef<JSVal>>& result, T&& value) 53{ 54 result.emplace_back(ConvertToJSValue(std::forward<T>(value))); 55} 56 57template<class T, class V, class... Args> 58void ConvertToJSValuesImpl(std::vector<JSRef<JSVal>>& result, T&& value, V&& nextValue, Args&&... args) 59{ 60 result.emplace_back(ConvertToJSValue(std::forward<T>(value))); 61 ConvertToJSValuesImpl(result, std::forward<V>(nextValue), std::forward<Args>(args)...); 62} 63 64template<class... Args> 65std::vector<JSRef<JSVal>> ConvertToJSValues(Args... args) 66{ 67 std::vector<JSRef<JSVal>> result; 68 ConvertToJSValuesImpl(result, args...); 69 return result; 70} 71 72template<class T> 73bool ConvertFromJSValueNG(const JSRef<JSVal>& jsValue, T& result) 74{ 75 if constexpr (std::is_same_v<T, bool>) { 76 if (jsValue->IsBoolean()) { 77 result = jsValue->ToBoolean(); 78 return true; 79 } 80 result = false; 81 } else if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) { 82 double value; 83 if (JSViewAbstract::ParseJsDouble(jsValue, value)) { 84 result = static_cast<T>(value); 85 return true; 86 } 87 result = 0; 88 } else if constexpr (std::is_same_v<T, std::string>) { 89 if (jsValue->IsString()) { 90 result = jsValue->ToString(); 91 return true; 92 } 93 } else if constexpr (std::is_same_v<T, Dimension>) { 94 CalcDimension calc; 95 bool ret = JSViewAbstract::ParseJsDimensionVpNG(jsValue, calc); 96 result = calc; 97 return ret; 98 } else if constexpr (std::is_same_v<T, CalcDimension>) { 99 return JSViewAbstract::ParseJsDimensionVpNG(jsValue, result); 100 } else if constexpr (std::is_same_v<T, NG::CalcLength>) { 101 return JSViewAbstract::ParseJsLengthVpNG(jsValue, result); 102 } else if constexpr (std::is_same_v<T, Color>) { 103 return JSViewAbstract::ParseJsColor(jsValue, result); 104 } 105 return false; 106} 107 108template<class T> 109bool ConvertFromJSValue(const JSRef<JSVal>& jsValue, T& result) 110{ 111 if constexpr (std::is_same_v<T, bool>) { 112 if (jsValue->IsBoolean()) { 113 result = jsValue->ToBoolean(); 114 return true; 115 } 116 result = false; 117 } else if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) { 118 double value; 119 if (JSViewAbstract::ParseJsDouble(jsValue, value)) { 120 result = static_cast<T>(value); 121 return true; 122 } 123 result = 0; 124 } else if constexpr (std::is_same_v<T, std::string>) { 125 if (jsValue->IsString()) { 126 result = jsValue->ToString(); 127 return true; 128 } 129 } else if constexpr (std::is_same_v<T, Dimension>) { 130 CalcDimension calc; 131 bool ret = JSViewAbstract::ParseJsDimensionVp(jsValue, calc); 132 result = calc; 133 return ret; 134 } else if constexpr (std::is_same_v<T, CalcDimension>) { 135 return JSViewAbstract::ParseJsDimensionVp(jsValue, result); 136 } else if constexpr (std::is_same_v<T, Color>) { 137 return JSViewAbstract::ParseJsColor(jsValue, result); 138 } 139 return false; 140} 141 142template<class T, size_t N> 143bool ConvertFromJSValue(const JSRef<JSVal>& jsValue, const T (&enumValues)[N], T& result) 144{ 145 int32_t value = 0; 146 if (!ConvertFromJSValue(jsValue, value) || value < 0 || static_cast<size_t>(value) >= N) { 147 return false; 148 } 149 result = enumValues[value]; 150 return true; 151} 152 153template<class T> 154T FastConvertFromJSValue(const JSRef<JSVal>& jsValue) 155{ 156 T result; 157 if (!ConvertFromJSValue(jsValue, result)) { 158 LOGE("Failed to convert from JS value"); 159 } 160 return result; 161} 162 163template<class C, class V, class T, size_t N> 164void JSViewSetProperty(void (C::*setMethod)(V), int32_t param, const T (&enumValues)[N], T defValue) 165{ 166#ifndef NG_BUILD 167 auto component = AceType::DynamicCast<C>(ViewStackProcessor::GetInstance()->GetMainComponent()); 168 if (!component) { 169 LOGW("Failed to get '%{public}s' in view stack", AceType::TypeName<C>()); 170 return; 171 } 172 T value = defValue; 173 if (param >= 0 && static_cast<size_t>(param) < N) { 174 value = enumValues[param]; 175 } 176 ((*component).*setMethod)(value); 177#else 178 LOGE("do not support JSViewSetProperty in new pipeline"); 179#endif 180} 181 182template<class C, class V, class T> 183void JSViewSetProperty(void (C::*setMethod)(V), T&& param) 184{ 185#ifndef NG_BUILD 186 auto component = AceType::DynamicCast<C>(ViewStackProcessor::GetInstance()->GetMainComponent()); 187 if (!component) { 188 LOGW("Failed to get '%{public}s' in view stack", AceType::TypeName<C>()); 189 return; 190 } 191 ((*component).*setMethod)(std::forward<T>(param)); 192#else 193 LOGE("do not support JSViewSetProperty in new pipeline"); 194#endif 195} 196 197template<class C, class F> 198bool JSViewBindEvent( 199 void (C::*setMethod)(std::function<F>&&), const JSExecutionContext& context, const JSRef<JSVal>& jsValue) 200{ 201#ifndef NG_BUILD 202 if (!jsValue->IsFunction()) { 203 LOGW("Argument is not a function object"); 204 return false; 205 } 206 auto component = AceType::DynamicCast<C>(ViewStackProcessor::GetInstance()->GetMainComponent()); 207 if (!component) { 208 LOGW("Failed to get '%{public}s' in view stack", AceType::TypeName<C>()); 209 return false; 210 } 211 ((*component).*setMethod)(JsEventCallback<F>(context, JSRef<JSFunc>::Cast(jsValue))); 212 return true; 213#else 214 LOGE("do not support JSViewBindEvent in new pipeline"); 215 return false; 216#endif 217} 218 219template<class C, class F> 220bool JSViewBindEvent(void (C::*setMethod)(std::function<F>&&), const JSCallbackInfo& args) 221{ 222 if (args.Length() < 1) { 223 LOGW("Must contain at least 1 argument"); 224 return false; 225 } 226 return JSViewBindEvent(setMethod, args.GetExecutionContext(), args[0]); 227} 228 229} // namespace OHOS::Ace::Framework 230