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