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