• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 "frameworks/bridge/declarative_frontend/jsview/js_xcomponent_controller.h"
17 
18 #include "interfaces/inner_api/ace/ai/image_analyzer.h"
19 #include "js_utils.h"
20 
21 #include "base/error/error_code.h"
22 #include "base/memory/referenced.h"
23 #include "base/utils/linear_map.h"
24 #include "base/utils/utils.h"
25 #include "bridge/common/utils/engine_helper.h"
26 #include "bridge/declarative_frontend/engine/js_converter.h"
27 #include "core/components/xcomponent/xcomponent_controller_impl.h"
28 #include "core/components_ng/pattern/xcomponent/xcomponent_controller_ng.h"
29 #include "frameworks/bridge/declarative_frontend/jsview/js_view_common_def.h"
30 
31 namespace OHOS::Ace::Framework {
OHOS_ACE_GetXComponentController(void * jsController,void * controller)32 extern "C" ACE_FORCE_EXPORT void OHOS_ACE_GetXComponentController(void* jsController, void* controller)
33 {
34     auto* jsXComponentController = static_cast<Framework::JSXComponentController*>(jsController);
35     if (!jsXComponentController) {
36         return;
37     }
38     auto xComponentController = reinterpret_cast<std::shared_ptr<InnerXComponentController>*>(controller);
39     if (!xComponentController) {
40         return;
41     }
42     *xComponentController = jsXComponentController->GetController();
43 }
44 
45 struct XComponentAsyncCxt {
46     napi_env env = nullptr;
47     napi_deferred deferred = nullptr;
48 };
49 namespace {
ParseSurfaceRectParam(const JSRef<JSVal> & jsValue,CalcDimension & result)50 bool ParseSurfaceRectParam(const JSRef<JSVal>& jsValue, CalcDimension& result)
51 {
52     if (!jsValue->IsNumber()) {
53         return false;
54     }
55     result = CalcDimension(jsValue->ToNumber<double>(), DimensionUnit::PX);
56     return true;
57 }
58 
CreateErrorValue(napi_env env,int32_t errCode,const std::string & errMsg="")59 napi_value CreateErrorValue(napi_env env, int32_t errCode, const std::string& errMsg = "")
60 {
61     napi_value code = nullptr;
62     std::string codeStr = std::to_string(errCode);
63     napi_create_string_utf8(env, codeStr.c_str(), codeStr.length(), &code);
64     napi_value msg = nullptr;
65     napi_create_string_utf8(env, errMsg.c_str(), errMsg.length(), &msg);
66     napi_value error = nullptr;
67     napi_create_error(env, code, msg, &error);
68     return error;
69 }
70 
HandleDeferred(const shared_ptr<XComponentAsyncCxt> & asyncCtx,ImageAnalyzerState state)71 void HandleDeferred(const shared_ptr<XComponentAsyncCxt>& asyncCtx, ImageAnalyzerState state)
72 {
73     auto env = asyncCtx->env;
74     CHECK_NULL_VOID(env);
75     auto deferred = asyncCtx->deferred;
76     CHECK_NULL_VOID(deferred);
77 
78     napi_handle_scope scope = nullptr;
79     auto status = napi_open_handle_scope(env, &scope);
80     if (status != napi_ok) {
81         return;
82     }
83 
84     napi_value result = nullptr;
85     switch (state) {
86         case ImageAnalyzerState::UNSUPPORTED:
87             result = CreateErrorValue(env, ERROR_CODE_AI_ANALYSIS_UNSUPPORTED);
88             napi_reject_deferred(env, deferred, result);
89             break;
90         case ImageAnalyzerState::ONGOING:
91             result = CreateErrorValue(env, ERROR_CODE_AI_ANALYSIS_IS_ONGOING);
92             napi_reject_deferred(env, deferred, result);
93             break;
94         case ImageAnalyzerState::STOPPED:
95             result = CreateErrorValue(env, ERROR_CODE_AI_ANALYSIS_IS_STOPPED);
96             napi_reject_deferred(env, deferred, result);
97             break;
98         case ImageAnalyzerState::FINISHED:
99             napi_get_null(env, &result);
100             napi_resolve_deferred(env, deferred, result);
101             break;
102         default:
103             break;
104     }
105     napi_close_handle_scope(env, scope);
106 }
107 
ReturnPromise(const JSCallbackInfo & info,napi_value result)108 void ReturnPromise(const JSCallbackInfo& info, napi_value result)
109 {
110     CHECK_NULL_VOID(result);
111     auto jsPromise = JsConverter::ConvertNapiValueToJsVal(result);
112     if (!jsPromise->IsObject()) {
113         return;
114     }
115     info.SetReturnValue(JSRef<JSObject>::Cast(jsPromise));
116 }
117 } // namespace
JSBind(BindingTarget globalObj)118 void JSXComponentController::JSBind(BindingTarget globalObj)
119 {
120     JSClass<JSXComponentController>::Declare("XComponentController");
121     JSClass<JSXComponentController>::CustomMethod("getXComponentSurfaceId", &JSXComponentController::GetSurfaceId);
122     JSClass<JSXComponentController>::CustomMethod(
123         "getXComponentContext", &JSXComponentController::GetXComponentContext);
124     JSClass<JSXComponentController>::CustomMethod(
125         "setXComponentSurfaceSize", &JSXComponentController::SetSurfaceConfig);
126     JSClass<JSXComponentController>::CustomMethod(
127         "getXComponentSurfaceRect", &JSXComponentController::GetXComponentSurfaceRect);
128     JSClass<JSXComponentController>::CustomMethod(
129         "setXComponentSurfaceRect", &JSXComponentController::SetXComponentSurfaceRect);
130     JSClass<JSXComponentController>::CustomMethod("startImageAnalyzer", &JSXComponentController::StartImageAnalyzer);
131     JSClass<JSXComponentController>::CustomMethod("stopImageAnalyzer", &JSXComponentController::StopImageAnalyzer);
132     JSClass<JSXComponentController>::CustomMethod(
133         "setXComponentSurfaceRotation", &JSXComponentController::SetXComponentSurfaceRotation);
134     JSClass<JSXComponentController>::CustomMethod(
135         "getXComponentSurfaceRotation", &JSXComponentController::GetXComponentSurfaceRotation);
136     JSClass<JSXComponentController>::Bind(
137         globalObj, JSXComponentController::Constructor, JSXComponentController::Destructor);
138 }
139 
Constructor(const JSCallbackInfo & args)140 void JSXComponentController::Constructor(const JSCallbackInfo& args)
141 {
142     auto xcomponentController = Referenced::MakeRefPtr<JSXComponentController>();
143     xcomponentController->IncRefCount();
144     std::shared_ptr<InnerXComponentController> controller;
145 #ifdef NG_BUILD
146     controller = std::make_shared<NG::XComponentControllerNG>();
147 #else
148     if (Container::IsCurrentUseNewPipeline()) {
149         controller = std::make_shared<NG::XComponentControllerNG>();
150     } else {
151         controller = std::make_shared<XComponentControllerImpl>();
152     }
153 #endif
154     xcomponentController->SetController(controller);
155     args.SetReturnValue(Referenced::RawPtr(xcomponentController));
156 }
157 
Destructor(JSXComponentController * xcomponentController)158 void JSXComponentController::Destructor(JSXComponentController* xcomponentController)
159 {
160     if (xcomponentController) {
161         xcomponentController->DecRefCount();
162     }
163 }
164 
GetSurfaceId(const JSCallbackInfo & args)165 void JSXComponentController::GetSurfaceId(const JSCallbackInfo& args)
166 {
167     if (xcomponentController_) {
168         auto surfaceId = xcomponentController_->GetSurfaceId();
169         auto returnValue = JSVal(ToJSValue(surfaceId));
170         auto returnPtr = JSRef<JSVal>::Make(returnValue);
171         TAG_LOGI(AceLogTag::ACE_XCOMPONENT, "Controller GetSurfaceId:%{public}s", surfaceId.c_str());
172         args.SetReturnValue(returnPtr);
173     }
174 }
175 
SetSurfaceConfig(const JSCallbackInfo & args)176 void JSXComponentController::SetSurfaceConfig(const JSCallbackInfo& args)
177 {
178     if (args.Length() < 1 || !args[0]->IsObject()) {
179         LOGW("Invalid params");
180         return;
181     }
182 
183     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
184     uint32_t surfaceWidth;
185     uint32_t surfaceHeight;
186     if (!ConvertFromJSValue(obj->GetProperty("surfaceWidth"), surfaceWidth) ||
187         !ConvertFromJSValue(obj->GetProperty("surfaceHeight"), surfaceHeight)) {
188         LOGW("Failed to parse param 'surfaceWidth' or 'surfaceHeight'");
189         return;
190     }
191 
192     if (xcomponentController_) {
193         xcomponentController_->ConfigSurface(surfaceWidth, surfaceHeight);
194     }
195 }
196 
GetXComponentSurfaceRect(const JSCallbackInfo & args)197 void JSXComponentController::GetXComponentSurfaceRect(const JSCallbackInfo& args)
198 {
199     if (!xcomponentController_) {
200         return;
201     }
202     auto retObj = JSRef<JSObject>::New();
203     float offsetX = 0.0f;
204     float offsetY = 0.0f;
205     float width = 0.0f;
206     float height = 0.0f;
207     xcomponentController_->GetSurfaceOffset(offsetX, offsetY);
208     xcomponentController_->GetSurfaceSize(width, height);
209     retObj->SetProperty("offsetX", offsetX);
210     retObj->SetProperty("offsetY", offsetY);
211     retObj->SetProperty("surfaceWidth", width);
212     retObj->SetProperty("surfaceHeight", height);
213     args.SetReturnValue(retObj);
214 }
215 
SetXComponentSurfaceRect(const JSCallbackInfo & args)216 void JSXComponentController::SetXComponentSurfaceRect(const JSCallbackInfo& args)
217 {
218     if (args.Length() < 1 || !args[0]->IsObject()) {
219         return;
220     }
221     if (!xcomponentController_) {
222         return;
223     }
224 
225     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
226     auto jsSurfaceWidth = obj->GetProperty("surfaceWidth");
227     CalcDimension surfaceWidth;
228     if (!ParseSurfaceRectParam(jsSurfaceWidth, surfaceWidth) || !surfaceWidth.IsValid()) {
229         return;
230     }
231     auto jsSurfaceHeight = obj->GetProperty("surfaceHeight");
232     CalcDimension surfaceHeight;
233     if (!ParseSurfaceRectParam(jsSurfaceHeight, surfaceHeight) || !surfaceHeight.IsValid()) {
234         return;
235     }
236     xcomponentController_->SetIdealSurfaceWidth(static_cast<float>(surfaceWidth.ConvertToPx()));
237     xcomponentController_->SetIdealSurfaceHeight(static_cast<float>(surfaceHeight.ConvertToPx()));
238 
239     auto jsOffsetX = obj->GetProperty("offsetX");
240     CalcDimension offsetX;
241     if (ParseSurfaceRectParam(jsOffsetX, offsetX)) {
242         xcomponentController_->SetIdealSurfaceOffsetX(static_cast<float>(offsetX.ConvertToPx()));
243     } else {
244         xcomponentController_->ClearIdealSurfaceOffset(true);
245     }
246     auto jsOffsetY = obj->GetProperty("offsetY");
247     CalcDimension offsetY;
248     if (ParseSurfaceRectParam(jsOffsetY, offsetY)) {
249         xcomponentController_->SetIdealSurfaceOffsetY(static_cast<float>(offsetY.ConvertToPx()));
250     } else {
251         xcomponentController_->ClearIdealSurfaceOffset(false);
252     }
253 
254     xcomponentController_->UpdateSurfaceBounds();
255 }
256 
StartImageAnalyzer(const JSCallbackInfo & args)257 void JSXComponentController::StartImageAnalyzer(const JSCallbackInfo& args)
258 {
259     ContainerScope scope(instanceId_);
260     auto engine = EngineHelper::GetCurrentEngine();
261     CHECK_NULL_VOID(engine);
262     NativeEngine* nativeEngine = engine->GetNativeEngine();
263     auto env = reinterpret_cast<napi_env>(nativeEngine);
264 
265     auto asyncCtx = std::make_shared<XComponentAsyncCxt>();
266     asyncCtx->env = env;
267     napi_value promise = nullptr;
268     napi_create_promise(env, &asyncCtx->deferred, &promise);
269     if (args.Length() < 1 || !args[0]->IsObject()) {
270         ReturnPromise(args, promise);
271         return;
272     }
273 
274     ScopeRAII scopeRaii(env);
275     panda::Local<JsiValue> value = args[0].Get().GetLocalHandle();
276     JSValueWrapper valueWrapper = value;
277     napi_value configNativeValue = nativeEngine->ValueToNapiValue(valueWrapper);
278     if (isImageAnalyzing_) {
279         napi_value result = CreateErrorValue(env, ERROR_CODE_AI_ANALYSIS_IS_ONGOING);
280         napi_reject_deferred(env, asyncCtx->deferred, result);
281         ReturnPromise(args, promise);
282         return;
283     }
284 
285     OnAnalyzedCallback onAnalyzed_ = [asyncCtx, weakCtx = WeakClaim(this)](ImageAnalyzerState state) {
286         CHECK_NULL_VOID(asyncCtx);
287         HandleDeferred(asyncCtx, state);
288         auto ctx = weakCtx.Upgrade();
289         CHECK_NULL_VOID(ctx);
290         ctx->isImageAnalyzing_ = false;
291     };
292     isImageAnalyzing_ = true;
293     CHECK_NULL_VOID(xcomponentController_);
294     xcomponentController_->StartImageAnalyzer(configNativeValue, onAnalyzed_);
295     ReturnPromise(args, promise);
296 }
297 
StopImageAnalyzer(const JSCallbackInfo & args)298 void JSXComponentController::StopImageAnalyzer(const JSCallbackInfo& args)
299 {
300     ContainerScope scope(instanceId_);
301     CHECK_NULL_VOID(xcomponentController_);
302     xcomponentController_->StopImageAnalyzer();
303 }
304 
SetXComponentSurfaceRotation(const JSCallbackInfo & args)305 void JSXComponentController::SetXComponentSurfaceRotation(const JSCallbackInfo& args)
306 {
307     if (!args[0]->IsObject()) {
308         return;
309     }
310 
311     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
312     bool lock = false;
313     ConvertFromJSValue(obj->GetProperty("lock"), lock);
314     CHECK_NULL_VOID(xcomponentController_);
315     xcomponentController_->SetSurfaceRotation(lock);
316 }
317 
GetXComponentSurfaceRotation(const JSCallbackInfo & args)318 void JSXComponentController::GetXComponentSurfaceRotation(const JSCallbackInfo& args)
319 {
320     auto retObj = JSRef<JSObject>::New();
321     CHECK_NULL_VOID(xcomponentController_);
322     bool lock = xcomponentController_->GetSurfaceRotation();
323     retObj->SetProperty("lock", lock);
324     args.SetReturnValue(retObj);
325 }
326 } // namespace OHOS::Ace::Framework
327