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 "frameworks/base/utils/string_utils.h" 17#include "frameworks/bridge/js_frontend/engine/jsi/ark_js_runtime.h" 18#include "frameworks/bridge/declarative_frontend/engine/jsi/jsi_ref.h" 19#include "frameworks/bridge/declarative_frontend/engine/jsi/jsi_types.h" 20 21namespace OHOS::Ace::Framework { 22 23template<typename T> 24JsiType<T>::JsiType(panda::Local<T> val) 25{ 26 if (!val.IsEmpty()) { 27 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 28 handle_ = panda::CopyableGlobal(runtime->GetEcmaVm(), val); 29 } 30} 31 32template<typename T> 33JsiType<T>::JsiType(const EcmaVM *vm, panda::Local<T> val) 34{ 35 if (!val.IsEmpty()) { 36 handle_ = panda::CopyableGlobal(vm, val); 37 } 38} 39 40template<typename T> 41template<typename S> 42JsiType<T>::JsiType(panda::Local<S> val) 43{ 44 if (!val.IsEmpty()) { 45 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 46 handle_ = panda::CopyableGlobal(runtime->GetEcmaVm(), val); 47 } 48} 49 50template<typename T> 51JsiType<T>::JsiType(const panda::CopyableGlobal<T>& other) : handle_(other) 52{ 53} 54 55template<typename T> 56JsiType<T>::JsiType(const JsiType<T>& rhs) : handle_(rhs.handle_) 57{ 58} 59 60template<typename T> 61JsiType<T>::JsiType(JsiType<T>&& rhs) : handle_(std::move(rhs.handle_)) 62{ 63} 64 65template<typename T> 66JsiType<T>& JsiType<T>::operator=(const JsiType<T>& rhs) 67{ 68 handle_ = rhs.handle_; 69 return *this; 70} 71 72template<typename T> 73JsiType<T>& JsiType<T>::operator=(JsiType<T>&& rhs) 74{ 75 handle_ = std::move(rhs.handle_); 76 return *this; 77} 78 79template<typename T> 80void JsiType<T>::SetWeakCallback(void *ref, panda::WeakRefClearCallBack callback) 81{ 82 if (!handle_.IsEmpty()) { 83 handle_.SetWeakCallback(ref, callback, nullptr); 84 } 85} 86 87template<typename T> 88const EcmaVM* JsiType<T>::GetEcmaVM() const 89{ 90 return handle_.GetEcmaVM(); 91} 92 93template<typename T> 94const panda::CopyableGlobal<T>& JsiType<T>::GetHandle() const 95{ 96 return handle_; 97} 98 99template<typename T> 100panda::Local<T> JsiType<T>::GetLocalHandle() const 101{ 102 return handle_.ToLocal(); 103} 104 105template<typename T> 106bool JsiType<T>::IsEmpty() const 107{ 108 return handle_.IsEmpty(); 109} 110 111template<typename T> 112bool JsiType<T>::IsWeak() const 113{ 114 return handle_.IsWeak(); 115} 116 117template<typename T> 118void JsiType<T>::Reset() 119{ 120 handle_.Reset(); 121} 122 123template<typename T> 124const panda::CopyableGlobal<T>& JsiType<T>::operator->() const 125{ 126 return handle_; 127} 128 129template<typename T> 130JsiType<T>::operator panda::CopyableGlobal<T>() const 131{ 132 return handle_; 133} 134 135template<typename T> 136template<class... Args> 137JsiType<T> JsiType<T>::New(Args&&... args) 138{ 139 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 140 return JsiType<T>(T::New(runtime->GetEcmaVm(), std::forward<Args>(args)...)); 141} 142 143template<typename T> 144T JsiValue::ToNumber() const 145{ 146 return JsiValueConvertor::fromJsiValue<T>(GetEcmaVM(), GetLocalHandle()); 147} 148 149template<typename T> 150T* JsiObject::Unwrap() const 151{ 152 if (GetHandle()->GetNativePointerFieldCount(GetEcmaVM()) < 1) { 153 return nullptr; 154 } 155 return static_cast<T*>(GetHandle()->GetNativePointerField(GetEcmaVM(), INSTANCE)); 156} 157 158template<typename T> 159void JsiObject::Wrap(T* data) const 160{ 161 GetHandle()->SetNativePointerField(GetEcmaVM(), INSTANCE, static_cast<void*>(data)); 162} 163 164template<typename T> 165void JsiObject::SetProperty(const char* prop, T value) const 166{ 167 auto stringRef = panda::StringRef::NewFromUtf8(GetEcmaVM(), prop); 168 GetHandle()->Set(GetEcmaVM(), stringRef, JsiValueConvertor::toJsiValueWithVM<T>(GetEcmaVM(), value)); 169} 170 171template<typename T> 172void JsiObject::SetProperty(int32_t propertyIndex, T value) const 173{ 174 Local<StringRef> stringRef = panda::ExternalStringCache::GetCachedString(GetEcmaVM(), propertyIndex); 175 GetHandle()->Set(GetEcmaVM(), stringRef, JsiValueConvertor::toJsiValueWithVM<T>(GetEcmaVM(), value)); 176} 177 178template<typename T> 179T JsiObject::GetPropertyValue(const char* prop, T defaultValue) const 180{ 181 static_assert(!std::is_const_v<T> && !std::is_reference_v<T>, 182 "Cannot convert value to reference or cv-qualified types!"); 183 184 const EcmaVM* vm = GetEcmaVM(); 185 Local<StringRef> stringRef = panda::StringRef::NewFromUtf8(vm, prop); 186 Local<JSValueRef> valueRef = GetHandle()->Get(vm, stringRef); 187 if constexpr (std::is_same<T, bool>::value) { 188 return valueRef->IsBoolean() ? valueRef->BooleaValue(vm) : defaultValue; 189 } else if constexpr (std::is_arithmetic<T>::value) { 190 return valueRef->IsNumber() ? JsiValueConvertor::fromJsiValue<T>(vm, valueRef) : defaultValue; 191 } else if constexpr (std::is_same_v<T, std::string>) { 192 return valueRef->IsString(vm) ? valueRef->ToString(vm)->ToString(vm) : defaultValue; 193 } else { 194 LOGW("Get property value failed."); 195 } 196 return defaultValue; 197} 198 199template<typename T> 200T JsiObject::GetPropertyValue(int32_t propertyIndex, T defaultValue) const 201{ 202 static_assert(!std::is_const_v<T> && !std::is_reference_v<T>, 203 "Cannot convert value to reference or cv-qualified types!"); 204 205 const EcmaVM* vm = GetEcmaVM(); 206 Local<StringRef> stringRef = panda::ExternalStringCache::GetCachedString(vm, propertyIndex); 207 Local<JSValueRef> valueRef = GetHandle()->Get(vm, stringRef); 208 if constexpr (std::is_same<T, bool>::value) { 209 return valueRef->IsBoolean() ? valueRef->BooleaValue(vm) : defaultValue; 210 } else if constexpr (std::is_arithmetic<T>::value) { 211 return valueRef->IsNumber() ? JsiValueConvertor::fromJsiValue<T>(vm, valueRef) : defaultValue; 212 } else if constexpr (std::is_same_v<T, std::string>) { 213 return valueRef->IsString(vm) ? valueRef->ToString(vm)->ToString(vm) : defaultValue; 214 } else { 215 LOGW("Get property value failed."); 216 } 217 return defaultValue; 218} 219 220template<typename T> 221void JsiCallbackInfo::SetReturnValue(T* instance) const 222{ 223 retVal_ = instance; 224} 225 226template<typename T> 227void JsiCallbackInfo::SetReturnValue(JsiRef<T> val) const 228{ 229 retVal_ = panda::CopyableGlobal<panda::JSValueRef>(val.Get().GetHandle()); 230} 231 232template<typename T> 233T* JsiCallbackInfo::UnwrapArg(size_t index) const 234{ 235 auto arg = info_->GetCallArgRef(index); 236 if (arg.IsEmpty() || !arg->IsObject(info_->GetVM())) { 237 return nullptr; 238 } 239 return static_cast<T*>(arg->ToEcmaObject(info_->GetVM())->GetNativePointerField(info_->GetVM(), 0)); 240} 241 242template<typename... Args> 243void JsiException::Throw(const char* format, Args... args) 244{ 245 const std::string str = StringUtils::FormatString(format, args...); 246 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 247 auto vm = runtime->GetEcmaVm(); 248 panda::JSNApi::ThrowException(vm, panda::Exception::Error(vm, panda::StringRef::NewFromUtf8(vm, str.c_str()))); 249} 250 251template<typename... Args> 252void JsiException::Throw(int32_t code, const char* format, Args... args) 253{ 254 const std::string str = StringUtils::FormatString(format, args...); 255 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 256 auto vm = runtime->GetEcmaVm(); 257 LocalScope scope(vm); 258 Local<JSValueRef> error(JSValueRef::Undefined(vm)); 259 error = panda::Exception::Error(vm, StringRef::NewFromUtf8(vm, str.c_str())); 260 Local<JSValueRef> codeKey = StringRef::NewFromUtf8(vm, "code"); 261 Local<JSValueRef> codeValue = StringRef::NewFromUtf8(vm, std::to_string(code).c_str()); 262 Local<ObjectRef> errorObj(error); 263 errorObj->Set(vm, codeKey, codeValue); 264 panda::JSNApi::ThrowException(vm, error); 265} 266 267template<typename... Args> 268void JsiException::ThrowRangeError(const char* format, Args... args) 269{ 270 const std::string str = StringUtils::FormatString(format, args...); 271 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 272 auto vm = runtime->GetEcmaVm(); 273 panda::JSNApi::ThrowException(vm, panda::Exception::RangeError(vm, panda::StringRef::NewFromUtf8(vm, str.c_str()))); 274} 275 276template<typename... Args> 277void JsiException::ThrowReferenceError(const char* format, Args... args) 278{ 279 const std::string str = StringUtils::FormatString(format, args...); 280 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 281 auto vm = runtime->GetEcmaVm(); 282 panda::JSNApi::ThrowException( 283 vm, panda::Exception::ReferenceError(vm, panda::StringRef::NewFromUtf8(vm, str.c_str()))); 284} 285 286template<typename... Args> 287void JsiException::ThrowSyntaxError(const char* format, Args... args) 288{ 289 const std::string str = StringUtils::FormatString(format, args...); 290 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 291 auto vm = runtime->GetEcmaVm(); 292 panda::JSNApi::ThrowException( 293 vm, panda::Exception::SyntaxError(vm, panda::StringRef::NewFromUtf8(vm, str.c_str()))); 294} 295 296template<typename... Args> 297void JsiException::ThrowTypeError(const char* format, Args... args) 298{ 299 const std::string str = StringUtils::FormatString(format, args...); 300 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 301 auto vm = runtime->GetEcmaVm(); 302 panda::JSNApi::ThrowException(vm, panda::Exception::TypeError(vm, panda::StringRef::NewFromUtf8(vm, str.c_str()))); 303} 304 305template<typename... Args> 306void JsiException::ThrowEvalError(const char* format, Args... args) 307{ 308 const std::string str = StringUtils::FormatString(format, args...); 309 auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime()); 310 auto vm = runtime->GetEcmaVm(); 311 panda::JSNApi::ThrowException(vm, panda::Exception::EvalError(vm, panda::StringRef::NewFromUtf8(vm, str.c_str()))); 312} 313} // namespace OHOS::Ace::Framework 314