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, Color>) { 100 return JSViewAbstract::ParseJsColor(jsValue, result); 101 } 102 return false; 103} 104 105template<class T> 106bool ConvertFromJSValue(const JSRef<JSVal>& jsValue, T& result) 107{ 108 if constexpr (std::is_same_v<T, bool>) { 109 if (jsValue->IsBoolean()) { 110 result = jsValue->ToBoolean(); 111 return true; 112 } 113 result = false; 114 } else if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) { 115 double value; 116 if (JSViewAbstract::ParseJsDouble(jsValue, value)) { 117 result = static_cast<T>(value); 118 return true; 119 } 120 result = 0; 121 } else if constexpr (std::is_same_v<T, std::string>) { 122 if (jsValue->IsString()) { 123 result = jsValue->ToString(); 124 return true; 125 } 126 } else if constexpr (std::is_same_v<T, Dimension>) { 127 CalcDimension calc; 128 bool ret = JSViewAbstract::ParseJsDimensionVp(jsValue, calc); 129 result = calc; 130 return ret; 131 } else if constexpr (std::is_same_v<T, CalcDimension>) { 132 return JSViewAbstract::ParseJsDimensionVp(jsValue, result); 133 } else if constexpr (std::is_same_v<T, Color>) { 134 return JSViewAbstract::ParseJsColor(jsValue, result); 135 } 136 return false; 137} 138 139template<class T, size_t N> 140bool ConvertFromJSValue(const JSRef<JSVal>& jsValue, const T (&enumValues)[N], T& result) 141{ 142 int32_t value = 0; 143 if (!ConvertFromJSValue(jsValue, value) || value < 0 || static_cast<size_t>(value) >= N) { 144 return false; 145 } 146 result = enumValues[value]; 147 return true; 148} 149 150template<class T> 151T FastConvertFromJSValue(const JSRef<JSVal>& jsValue) 152{ 153 T result; 154 if (!ConvertFromJSValue(jsValue, result)) { 155 LOGE("Failed to convert from JS value"); 156 } 157 return result; 158} 159 160template<class C, class V, class T, size_t N> 161void JSViewSetProperty(void (C::*setMethod)(V), int32_t param, const T (&enumValues)[N], T defValue) 162{ 163 auto component = AceType::DynamicCast<C>(ViewStackProcessor::GetInstance()->GetMainComponent()); 164 if (!component) { 165 LOGW("Failed to get '%{public}s' in view stack", AceType::TypeName<C>()); 166 return; 167 } 168 T value = defValue; 169 if (param >= 0 && static_cast<size_t>(param) < N) { 170 value = enumValues[param]; 171 } 172 ((*component).*setMethod)(value); 173} 174 175template<class C, class V, class T> 176void JSViewSetProperty(void (C::*setMethod)(V), T&& param) 177{ 178 auto component = AceType::DynamicCast<C>(ViewStackProcessor::GetInstance()->GetMainComponent()); 179 if (!component) { 180 LOGW("Failed to get '%{public}s' in view stack", AceType::TypeName<C>()); 181 return; 182 } 183 ((*component).*setMethod)(std::forward<T>(param)); 184} 185 186template<class C, class F> 187bool JSViewBindEvent( 188 void (C::*setMethod)(std::function<F>&&), const JSExecutionContext& context, const JSRef<JSVal>& jsValue) 189{ 190 if (!jsValue->IsFunction()) { 191 LOGW("Argument is not a function object"); 192 return false; 193 } 194 auto component = AceType::DynamicCast<C>(ViewStackProcessor::GetInstance()->GetMainComponent()); 195 if (!component) { 196 LOGW("Failed to get '%{public}s' in view stack", AceType::TypeName<C>()); 197 return false; 198 } 199 ((*component).*setMethod)(JsEventCallback<F>(context, JSRef<JSFunc>::Cast(jsValue))); 200 return true; 201} 202 203template<class C, class F> 204bool JSViewBindEvent(void (C::*setMethod)(std::function<F>&&), const JSCallbackInfo& args) 205{ 206 if (args.Length() < 1) { 207 LOGW("Must contain at least 1 argument"); 208 return false; 209 } 210 return JSViewBindEvent(setMethod, args.GetExecutionContext(), args[0]); 211} 212 213} // namespace OHOS::Ace::Framework 214