1 /*
2  * Copyright (c) 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 "bridge/declarative_frontend/jsview/js_embedded_component.h"
17 
18 #include <cstdint>
19 #include <functional>
20 #include <string>
21 
22 #include "base/log/ace_scoring_log.h"
23 #include "base/log/log_wrapper.h"
24 #include "base/memory/ace_type.h"
25 #include "base/thread/task_executor.h"
26 #include "base/utils/utils.h"
27 #include "bridge/common/utils/engine_helper.h"
28 #include "bridge/declarative_frontend/engine/js_converter.h"
29 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
30 #include "bridge/declarative_frontend/engine/js_types.h"
31 #include "bridge/declarative_frontend/engine/jsi/jsi_ref.h"
32 #include "bridge/declarative_frontend/engine/jsi/jsi_types.h"
33 #include "bridge/declarative_frontend/jsview/js_ui_extension.h"
34 #include "bridge/declarative_frontend/jsview/js_utils.h"
35 #include "bridge/js_frontend/engine/jsi/js_value.h"
36 #include "core/common/container.h"
37 #include "core/common/container_scope.h"
38 #include "core/components_ng/pattern/ui_extension/session_wrapper.h"
39 #include "core/components_ng/pattern/ui_extension/ui_extension_model.h"
40 #include "core/components_ng/pattern/ui_extension/ui_extension_model_ng.h"
41 #include "frameworks/core/components_ng/base/view_abstract_model.h"
42 
43 namespace OHOS::Ace::Framework {
44 const CalcDimension EMBEDDED_COMPONENT_MIN_WIDTH(10.0f, DimensionUnit::VP);
45 const CalcDimension EMBEDDED_COMPONENT_MIN_HEIGHT(10.0f, DimensionUnit::VP);
46 
JSBind(BindingTarget globalObj)47 void JSEmbeddedComponent::JSBind(BindingTarget globalObj)
48 {
49     JSClass<JSEmbeddedComponent>::Declare("EmbeddedComponent");
50     MethodOptions opt = MethodOptions::NONE;
51     JSClass<JSEmbeddedComponent>::StaticMethod("create", &JSEmbeddedComponent::Create, opt);
52     JSClass<JSEmbeddedComponent>::StaticMethod("onTerminated", &JSEmbeddedComponent::OnTerminated);
53     JSClass<JSEmbeddedComponent>::StaticMethod("onError", &JSEmbeddedComponent::OnError);
54     JSClass<JSEmbeddedComponent>::StaticMethod("width", &JSEmbeddedComponent::JsWidth);
55     JSClass<JSEmbeddedComponent>::StaticMethod("height", &JSEmbeddedComponent::JsHeight);
56     JSClass<JSEmbeddedComponent>::StaticMethod("constraintSize", &JSEmbeddedComponent::JsConstraintSize);
57     JSClass<JSEmbeddedComponent>::StaticMethod("aspectRatio", &JSEmbeddedComponent::JsAspectRatio);
58     JSClass<JSEmbeddedComponent>::StaticMethod("layoutWeight", &JSEmbeddedComponent::JsLayoutWeight);
59     JSClass<JSEmbeddedComponent>::StaticMethod("flexBasis", &JSEmbeddedComponent::JsFlexBasis);
60     JSClass<JSEmbeddedComponent>::StaticMethod("flexGrow", &JSEmbeddedComponent::JsFlexGrow);
61     JSClass<JSEmbeddedComponent>::StaticMethod("flexShrink", &JSEmbeddedComponent::JsFlexShrink);
62     JSClass<JSEmbeddedComponent>::StaticMethod("opacity", &JSEmbeddedComponent::JsOpacity);
63     JSClass<JSEmbeddedComponent>::InheritAndBind<JSViewAbstract>(globalObj);
64 }
65 
Create(const JSCallbackInfo & info)66 void JSEmbeddedComponent::Create(const JSCallbackInfo& info)
67 {
68     if (info.Length() < 1 || !info[0]->IsObject()) {
69         return;
70     }
71     auto wantObj = JSRef<JSObject>::Cast(info[0]);
72     RefPtr<OHOS::Ace::WantWrap> want = CreateWantWrapFromNapiValue(wantObj);
73 
74     NG::SessionType sessionType = NG::SessionType::EMBEDDED_UI_EXTENSION;
75     if (info.Length() > 1 && info[1]->IsNumber()) {
76         sessionType = static_cast<NG::SessionType>(info[1]->ToNumber<int32_t>());
77     }
78 
79     UIExtensionModel::GetInstance()->Create(want, sessionType);
80     ViewAbstractModel::GetInstance()->SetWidth(EMBEDDED_COMPONENT_MIN_WIDTH);
81     ViewAbstractModel::GetInstance()->SetHeight(EMBEDDED_COMPONENT_MIN_HEIGHT);
82     ViewAbstractModel::GetInstance()->SetMinWidth(EMBEDDED_COMPONENT_MIN_WIDTH);
83     ViewAbstractModel::GetInstance()->SetMinHeight(EMBEDDED_COMPONENT_MIN_HEIGHT);
84 }
85 
OnTerminated(const JSCallbackInfo & info)86 void JSEmbeddedComponent::OnTerminated(const JSCallbackInfo& info)
87 {
88     if (!info[0]->IsFunction()) {
89         return;
90     }
91     auto frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
92     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
93     auto instanceId = ContainerScope::CurrentId();
94     auto onTerminated = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), instanceId, node = frameNode](
95                             int32_t code, const RefPtr<WantWrap>& wantWrap) {
96         ContainerScope scope(instanceId);
97         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
98         ACE_SCORING_EVENT("EmbeddedComponent.onTerminated");
99         auto pipelineContext = PipelineContext::GetCurrentContext();
100         CHECK_NULL_VOID(pipelineContext);
101         pipelineContext->UpdateCurrentActiveNode(node);
102         auto engine = EngineHelper::GetCurrentEngine();
103         CHECK_NULL_VOID(engine);
104         NativeEngine* nativeEngine = engine->GetNativeEngine();
105         CHECK_NULL_VOID(nativeEngine);
106         JSRef<JSObject> obj = JSRef<JSObject>::New();
107         obj->SetProperty<int32_t>("code", code);
108         if (wantWrap) {
109             auto nativeWant =
110                 WantWrap::ConvertToNativeValue(wantWrap->GetWant(), reinterpret_cast<napi_env>(nativeEngine));
111             auto wantJSVal = JsConverter::ConvertNapiValueToJsVal(nativeWant);
112             obj->SetPropertyObject("want", wantJSVal);
113         }
114         auto returnValue = JSRef<JSVal>::Cast(obj);
115         func->ExecuteJS(1, &returnValue);
116     };
117     UIExtensionModel::GetInstance()->SetOnTerminated(std::move(onTerminated));
118 }
119 
OnError(const JSCallbackInfo & info)120 void JSEmbeddedComponent::OnError(const JSCallbackInfo& info)
121 {
122     if (!info[0]->IsFunction()) {
123         return;
124     }
125     auto frameNode = AceType::Claim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
126     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
127     auto instanceId = ContainerScope::CurrentId();
128     auto onError = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), instanceId, node = frameNode](
129                        int32_t code, const std::string& name, const std::string& message) {
130         ContainerScope scope(instanceId);
131         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
132         ACE_SCORING_EVENT("EmbeddedComponent.onError");
133         auto pipelineContext = PipelineContext::GetCurrentContext();
134         CHECK_NULL_VOID(pipelineContext);
135         pipelineContext->UpdateCurrentActiveNode(node);
136         JSRef<JSObject> obj = JSRef<JSObject>::New();
137         obj->SetProperty<int32_t>("code", code);
138         obj->SetProperty<std::string>("name", name);
139         obj->SetProperty<std::string>("message", message);
140         auto returnValue = JSRef<JSVal>::Cast(obj);
141         func->ExecuteJS(FUNC_ARGC_1, &returnValue);
142     };
143     UIExtensionModel::GetInstance()->SetOnError(std::move(onError));
144 }
145 
JsWidth(const JSCallbackInfo & info)146 void JSEmbeddedComponent::JsWidth(const JSCallbackInfo& info)
147 {
148     if (info[0]->IsUndefined()) {
149         return;
150     }
151 
152     CalcDimension value;
153     if (JSViewAbstract::ParseJsDimensionVpNG(info[0], value)) {
154         ViewAbstractModel::GetInstance()->SetWidth(value);
155     }
156 }
157 
JsHeight(const JSCallbackInfo & info)158 void JSEmbeddedComponent::JsHeight(const JSCallbackInfo& info)
159 {
160     if (info[0]->IsUndefined()) {
161         return;
162     }
163 
164     CalcDimension value;
165     if (JSViewAbstract::ParseJsDimensionVpNG(info[0], value)) {
166         ViewAbstractModel::GetInstance()->SetHeight(value);
167     }
168 }
169 } // namespace OHOS::Ace::Framework
170