1 /*
2 * Copyright (c) 2021-2022 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/js_frontend/engine/jsi/jsi_xcomponent_bridge.h"
17
18 #include "frameworks/bridge/js_frontend/engine/jsi/ark_js_value.h"
19 #include "frameworks/core/common/ace_view.h"
20
21 namespace OHOS::Ace::Framework {
JsiXComponentBridge()22 JsiXComponentBridge::JsiXComponentBridge()
23 {
24 nativeXcomponentImpl_ = AceType::MakeRefPtr<NativeXComponentImpl>();
25 nativeXComponent_ = new OH_NativeXComponent(AceType::RawPtr(nativeXcomponentImpl_));
26 }
27
~JsiXComponentBridge()28 JsiXComponentBridge::~JsiXComponentBridge()
29 {
30 if (nativeXComponent_) {
31 delete nativeXComponent_;
32 nativeXComponent_ = nullptr;
33 }
34 // render context must be release on js thread.
35 auto currentContainer = Container::Current();
36 if (currentContainer) {
37 auto taskExecutor = currentContainer->GetTaskExecutor();
38 if (taskExecutor) {
39 taskExecutor->PostTask([renderContext = std::move(renderContext_)]() mutable { renderContext.reset(); },
40 TaskExecutor::TaskType::JS, "ArkUIXComponentRenderContextRelease");
41 }
42 }
43 }
44
HandleContext(const shared_ptr<JsRuntime> & runtime,NodeId id,const std::string & args)45 void JsiXComponentBridge::HandleContext(const shared_ptr<JsRuntime>& runtime, NodeId id, const std::string& args)
46 {
47 if (hasPluginLoaded_) {
48 return;
49 }
50
51 if (!runtime) {
52 LOGE("Runtime is null");
53 return;
54 }
55
56 auto engineInstance = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
57 auto page = engineInstance->GetRunningPage();
58 if (!page) {
59 LOGE("JsiXComponentBridge page is null.");
60 return;
61 }
62 auto domXcomponent = AceType::DynamicCast<DOMXComponent>(page->GetDomDocument()->GetDOMNodeById(id));
63 if (!domXcomponent) {
64 LOGE("JsiXComponentBridge domXcomponent is null.");
65 return;
66 }
67 auto xcomponent = AceType::DynamicCast<XComponentComponent>(domXcomponent->GetSpecializedComponent());
68 if (!xcomponent) {
69 LOGE("JsiXComponentBridge xcomponent is null.");
70 return;
71 }
72
73 auto container = Container::Current();
74 if (!container) {
75 LOGE("JsiXComponentBridge Current container null");
76 return;
77 }
78 auto nativeView = container->GetAceView();
79 if (!nativeView) {
80 LOGE("JsiXComponentBridge nativeView null");
81 return;
82 }
83
84 void* nativeWindow = nullptr;
85 #ifdef OHOS_STANDARD_SYSTEM
86 nativeWindow = const_cast<void*>(xcomponent->GetNativeWindow());
87 #else
88 auto textureId = static_cast<int64_t>(xcomponent->GetTextureId());
89 nativeWindow = const_cast<void*>(nativeView->GetNativeWindowById(textureId));
90 #endif
91 if (!nativeWindow) {
92 LOGE("JsiXComponentBridge::HandleJsContext nativeWindow invalid");
93 return;
94 }
95 nativeXcomponentImpl_->SetSurface(nativeWindow);
96 nativeXcomponentImpl_->SetXComponentId(xcomponent->GetId());
97
98 auto nativeEngine = static_cast<ArkNativeEngine*>(engineInstance->GetNativeEngine());
99 if (!nativeEngine) {
100 LOGE("NativeEngine is null");
101 return;
102 }
103
104 auto arkObjectRef = nativeEngine->LoadModuleByName(xcomponent->GetLibraryName(), true,
105 args, OH_NATIVE_XCOMPONENT_OBJ,
106 reinterpret_cast<void*>(nativeXComponent_));
107
108 shared_ptr<ArkJSRuntime> pandaRuntime = std::static_pointer_cast<ArkJSRuntime>(runtime);
109 if (arkObjectRef.IsEmpty() || pandaRuntime->HasPendingException()) {
110 LOGE("LoadModuleByName failed.");
111 return;
112 }
113 renderContext_ = runtime->NewObject();
114 auto renderContext = std::static_pointer_cast<ArkJSValue>(renderContext_);
115 LocalScope scope(pandaRuntime->GetEcmaVm());
116 Local<ObjectRef> obj = arkObjectRef->ToObject(pandaRuntime->GetEcmaVm());
117 if (obj.IsEmpty() || pandaRuntime->HasPendingException()) {
118 LOGE("Get local object failed.");
119 renderContext_.reset();
120 return;
121 }
122 renderContext->SetValue(pandaRuntime, obj);
123
124 auto task = [weak = WeakClaim(this), xcomponent]() {
125 auto pool = xcomponent->GetTaskPool();
126 if (!pool) {
127 return;
128 }
129 auto bridge = weak.Upgrade();
130 if (bridge) {
131 pool->NativeXComponentInit(
132 bridge->nativeXComponent_,
133 AceType::WeakClaim(AceType::RawPtr(bridge->nativeXcomponentImpl_)));
134 }
135 };
136
137 auto delegate = engineInstance->GetFrontendDelegate();
138 if (!delegate) {
139 LOGE("Delegate is null");
140 return;
141 }
142 delegate->PostSyncTaskToPage(task, "ArkUIXComponentNativeInit");
143
144 hasPluginLoaded_ = true;
145 return;
146 }
147
JsGetXComponentSurfaceId(const shared_ptr<JsRuntime> & runtime,NodeId nodeId)148 shared_ptr<JsValue> JsiXComponentBridge::JsGetXComponentSurfaceId(const shared_ptr<JsRuntime>& runtime, NodeId nodeId)
149 {
150 if (!runtime) {
151 LOGE("JsGetXComponentSurfaceId failed. runtime is null.");
152 return nullptr;
153 }
154 auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
155 if (!engine) {
156 LOGE("JsGetXComponentSurfaceId failed. engine is null.");
157 return runtime->NewUndefined();
158 }
159 auto page = engine->GetRunningPage();
160 if (!page) {
161 LOGE("JsGetXComponentSurfaceId failed. page is null.");
162 return runtime->NewUndefined();
163 }
164 std::string surfaceId = "";
165 auto task = [nodeId, page, &surfaceId]() {
166 auto domDoc = page->GetDomDocument();
167 if (!domDoc) {
168 return;
169 }
170 auto domXComponent = AceType::DynamicCast<DOMXComponent>(domDoc->GetDOMNodeById(nodeId));
171 if (!domXComponent) {
172 return;
173 }
174 surfaceId = domXComponent->GetSurfaceId();
175 };
176 auto delegate = engine->GetFrontendDelegate();
177 if (!delegate) {
178 LOGE("JsGetXComponentSurfaceId failed. delegate is null.");
179 return runtime->NewUndefined();
180 }
181 delegate->PostSyncTaskToPage(task, "ArkUIXComponentGetSurfaceId");
182 return runtime->NewString(surfaceId);
183 }
184
JsSetXComponentSurfaceSize(const shared_ptr<JsRuntime> & runtime,const std::string & arguments,NodeId nodeId)185 void JsiXComponentBridge::JsSetXComponentSurfaceSize(
186 const shared_ptr<JsRuntime>& runtime, const std::string& arguments, NodeId nodeId)
187 {
188 if (!runtime) {
189 LOGE("JsSetXComponentSurfaceSize failed. runtime is null.");
190 return;
191 }
192 auto engine = static_cast<JsiEngineInstance*>(runtime->GetEmbedderData());
193 if (!engine) {
194 LOGE("JsSetXComponentSurfaceSize failed. engine is null.");
195 return;
196 }
197 auto page = engine->GetRunningPage();
198 if (!page) {
199 LOGE("JsSetXComponentSurfaceSize failed. page is null.");
200 return;
201 }
202 auto task = [nodeId, page, arguments]() {
203 auto domDoc = page->GetDomDocument();
204 if (!domDoc) {
205 return;
206 }
207 auto domXComponent = AceType::DynamicCast<DOMXComponent>(domDoc->GetDOMNodeById(nodeId));
208 if (!domXComponent) {
209 return;
210 }
211
212 std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(arguments);
213 if (!argsValue || !argsValue->IsArray() || argsValue->GetArraySize() < 1) {
214 LOGE("JsSetXComponentSurfaceSize failed. parse args error");
215 return;
216 }
217 std::unique_ptr<JsonValue> surfaceSizePara = argsValue->GetArrayItem(0);
218 uint32_t surfaceWidth = surfaceSizePara->GetUInt("surfaceWidth", 0);
219 uint32_t surfaceHeight = surfaceSizePara->GetUInt("surfaceHeight", 0);
220 domXComponent->SetSurfaceSize(surfaceWidth, surfaceHeight);
221 };
222 auto delegate = engine->GetFrontendDelegate();
223 if (!delegate) {
224 LOGE("JsSetXComponentSurfaceSize failed. delegate is null.");
225 return;
226 }
227 delegate->PostSyncTaskToPage(task, "ArkUIXComponentSetSurfaceSize");
228 }
229 } // namespace OHOS::Ace::Framework