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