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