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