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