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