1 /*
2 * Copyright (c) 2021 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/plugin_frontend/plugin_frontend_delegate.h"
17
18 #include <atomic>
19 #include <regex>
20 #include <string>
21
22 #include "base/log/ace_trace.h"
23 #include "base/log/event_report.h"
24 #include "base/resource/ace_res_config.h"
25 #include "base/thread/background_task_executor.h"
26 #include "base/utils/utils.h"
27 #include "core/common/ace_application_info.h"
28 #include "core/common/container.h"
29 #include "core/common/platform_bridge.h"
30 #include "core/common/thread_checker.h"
31 #include "core/components/dialog/dialog_component.h"
32 #include "core/components/toast/toast_component.h"
33 #include "frameworks/bridge/common/manifest/manifest_parser.h"
34 #include "frameworks/bridge/common/utils/utils.h"
35 #include "frameworks/bridge/js_frontend/js_ace_page.h"
36
37 namespace OHOS::Ace::Framework {
38 namespace {
39 constexpr uint8_t MIN_ROUT_COUNT = 2;
40 constexpr uint8_t JS_HEADER_OFFSET = 3;
41 constexpr int32_t INVALID_PAGE_ID = -1;
42 constexpr int32_t MAX_ROUTER_STACK = 32;
43 constexpr int32_t TOAST_TIME_MAX = 10000; // ms
44 constexpr int32_t TOAST_TIME_DEFAULT = 1500; // ms
45 constexpr int32_t MAX_PAGE_ID_SIZE = sizeof(uint64_t) * 8;
46 constexpr int32_t NANO_TO_MILLI = 1000000; // nanosecond to millisecond
47 constexpr int32_t TO_MILLI = 1000; // second to millisecond
48
49 const char MANIFEST_JSON[] = "manifest.json";
50 const char FILE_TYPE_JSON[] = ".json";
51 const char I18N_FOLDER[] = "i18n/";
52 const char RESOURCES_FOLDER[] = "resources/";
53 const char STYLES_FOLDER[] = "styles/";
54 const char I18N_FILE_SUFFIX[] = "/properties/string.json";
55 } // namespace
56
GenerateNextPageId()57 int32_t PluginFrontendDelegate::GenerateNextPageId()
58 {
59 for (int32_t idx = 0; idx < MAX_PAGE_ID_SIZE; ++idx) {
60 uint64_t bitMask = (1ULL << idx);
61 if ((bitMask & pageIdPool_.fetch_or(bitMask, std::memory_order_relaxed)) == 0) {
62 return idx;
63 }
64 }
65 return INVALID_PAGE_ID;
66 }
67
RecyclePageId(int32_t pageId)68 void PluginFrontendDelegate::RecyclePageId(int32_t pageId)
69 {
70 if (pageId < 0 || pageId >= MAX_PAGE_ID_SIZE) {
71 return;
72 }
73 uint64_t bitMask = (1ULL << pageId);
74 pageIdPool_.fetch_and(~bitMask, std::memory_order_relaxed);
75 }
76
PluginFrontendDelegate(const RefPtr<TaskExecutor> & taskExecutor,const LoadJsCallback & loadCallback,const JsMessageDispatcherSetterCallback & transferCallback,const EventCallback & asyncEventCallback,const EventCallback & syncEventCallback,const UpdatePageCallback & updatePageCallback,const ResetStagingPageCallback & resetLoadingPageCallback,const DestroyPageCallback & destroyPageCallback,const DestroyApplicationCallback & destroyApplicationCallback,const UpdateApplicationStateCallback & updateApplicationStateCallback,const TimerCallback & timerCallback,const MediaQueryCallback & mediaQueryCallback,const RequestAnimationCallback & requestAnimationCallback,const JsCallback & jsCallback,const OnWindowDisplayModeChangedCallBack & onWindowDisplayModeChangedCallBack,const OnConfigurationUpdatedCallBack & onConfigurationUpdatedCallBack,const OnSaveAbilityStateCallBack & onSaveAbilityStateCallBack,const OnRestoreAbilityStateCallBack & onRestoreAbilityStateCallBack,const OnNewWantCallBack & onNewWantCallBack,const OnActiveCallBack & onActiveCallBack,const OnInactiveCallBack & onInactiveCallBack,const OnMemoryLevelCallBack & onMemoryLevelCallBack,const OnStartContinuationCallBack & onStartContinuationCallBack,const OnCompleteContinuationCallBack & onCompleteContinuationCallBack,const OnRemoteTerminatedCallBack & onRemoteTerminatedCallBack,const OnSaveDataCallBack & onSaveDataCallBack,const OnRestoreDataCallBack & onRestoreDataCallBack)77 PluginFrontendDelegate::PluginFrontendDelegate(const RefPtr<TaskExecutor>& taskExecutor,
78 const LoadJsCallback& loadCallback, const JsMessageDispatcherSetterCallback& transferCallback,
79 const EventCallback& asyncEventCallback, const EventCallback& syncEventCallback,
80 const UpdatePageCallback& updatePageCallback, const ResetStagingPageCallback& resetLoadingPageCallback,
81 const DestroyPageCallback& destroyPageCallback, const DestroyApplicationCallback& destroyApplicationCallback,
82 const UpdateApplicationStateCallback& updateApplicationStateCallback,
83 const TimerCallback& timerCallback, const MediaQueryCallback& mediaQueryCallback,
84 const RequestAnimationCallback& requestAnimationCallback, const JsCallback& jsCallback,
85 const OnWindowDisplayModeChangedCallBack& onWindowDisplayModeChangedCallBack,
86 const OnConfigurationUpdatedCallBack& onConfigurationUpdatedCallBack,
87 const OnSaveAbilityStateCallBack& onSaveAbilityStateCallBack,
88 const OnRestoreAbilityStateCallBack& onRestoreAbilityStateCallBack,
89 const OnNewWantCallBack& onNewWantCallBack, const OnActiveCallBack& onActiveCallBack,
90 const OnInactiveCallBack& onInactiveCallBack, const OnMemoryLevelCallBack& onMemoryLevelCallBack,
91 const OnStartContinuationCallBack& onStartContinuationCallBack,
92 const OnCompleteContinuationCallBack& onCompleteContinuationCallBack,
93 const OnRemoteTerminatedCallBack& onRemoteTerminatedCallBack,
94 const OnSaveDataCallBack& onSaveDataCallBack,
95 const OnRestoreDataCallBack& onRestoreDataCallBack)
96 : loadJs_(loadCallback), dispatcherCallback_(transferCallback), asyncEvent_(asyncEventCallback),
97 syncEvent_(syncEventCallback), updatePage_(updatePageCallback), resetStagingPage_(resetLoadingPageCallback),
98 destroyPage_(destroyPageCallback), destroyApplication_(destroyApplicationCallback),
99 updateApplicationState_(updateApplicationStateCallback), timer_(timerCallback),
100 mediaQueryCallback_(mediaQueryCallback), requestAnimationCallback_(requestAnimationCallback),
101 jsCallback_(jsCallback), onWindowDisplayModeChanged_(onWindowDisplayModeChangedCallBack),
102 onConfigurationUpdated_(onConfigurationUpdatedCallBack),
103 onSaveAbilityState_(onSaveAbilityStateCallBack), onRestoreAbilityState_(onRestoreAbilityStateCallBack),
104 onNewWant_(onNewWantCallBack), onActive_(onActiveCallBack),
105 onInactive_(onInactiveCallBack), onMemoryLevel_(onMemoryLevelCallBack),
106 onStartContinuationCallBack_(onStartContinuationCallBack),
107 onCompleteContinuationCallBack_(onCompleteContinuationCallBack),
108 onRemoteTerminatedCallBack_(onRemoteTerminatedCallBack),
109 onSaveDataCallBack_(onSaveDataCallBack),
110 onRestoreDataCallBack_(onRestoreDataCallBack),
111 manifestParser_(AceType::MakeRefPtr<ManifestParser>()),
112 jsAccessibilityManager_(AccessibilityNodeManager::Create()),
113 mediaQueryInfo_(AceType::MakeRefPtr<MediaQueryInfo>()), taskExecutor_(taskExecutor)
114 {
115 }
116
~PluginFrontendDelegate()117 PluginFrontendDelegate::~PluginFrontendDelegate()
118 {
119 CHECK_RUN_ON(JS);
120 LOG_DESTROY();
121 }
122
GetMinPlatformVersion()123 int32_t PluginFrontendDelegate::GetMinPlatformVersion()
124 {
125 return manifestParser_->GetMinPlatformVersion();
126 }
127
RunPage(const std::string & url,const std::string & params)128 void PluginFrontendDelegate::RunPage(const std::string& url, const std::string& params)
129 {
130 ACE_SCOPED_TRACE("PluginFrontendDelegate::RunPage");
131 std::string jsonContent;
132 if (GetAssetContent(MANIFEST_JSON, jsonContent)) {
133 manifestParser_->Parse(jsonContent);
134 manifestParser_->Printer();
135 } else {
136 LOGE("RunPage parse manifest.json failed");
137 EventReport::SendPageRouterException(PageRouterExcepType::RUN_PAGE_ERR, url);
138 }
139
140 if (!url.empty()) {
141 mainPagePath_ = manifestParser_->GetRouter()->GetPagePath(url);
142 } else {
143 mainPagePath_ = manifestParser_->GetRouter()->GetEntry();
144 }
145 LoadPage(GenerateNextPageId(), PageTarget(mainPagePath_), false, params);
146 }
147
ChangeLocale(const std::string & language,const std::string & countryOrRegion)148 void PluginFrontendDelegate::ChangeLocale(const std::string& language, const std::string& countryOrRegion)
149 {
150 taskExecutor_->PostTask(
151 [language, countryOrRegion]() { AceApplicationInfo::GetInstance().ChangeLocale(language, countryOrRegion); },
152 TaskExecutor::TaskType::PLATFORM);
153 }
154
GetI18nData(std::unique_ptr<JsonValue> & json)155 void PluginFrontendDelegate::GetI18nData(std::unique_ptr<JsonValue>& json)
156 {
157 auto data = JsonUtil::CreateArray(true);
158 GetConfigurationCommon(I18N_FOLDER, data);
159 auto i18nData = JsonUtil::Create(true);
160 i18nData->Put("resources", data);
161 json->Put("i18n", i18nData);
162 }
163
GetResourceConfiguration(std::unique_ptr<JsonValue> & json)164 void PluginFrontendDelegate::GetResourceConfiguration(std::unique_ptr<JsonValue>& json)
165 {
166 auto data = JsonUtil::CreateArray(true);
167 GetConfigurationCommon(RESOURCES_FOLDER, data);
168 json->Put("resourcesConfiguration", data);
169 }
170
GetConfigurationCommon(const std::string & filePath,std::unique_ptr<JsonValue> & data)171 void PluginFrontendDelegate::GetConfigurationCommon(const std::string& filePath, std::unique_ptr<JsonValue>& data)
172 {
173 std::vector<std::string> files;
174 if (assetManager_) {
175 assetManager_->GetAssetList(filePath, files);
176 }
177
178 std::vector<std::string> fileNameList;
179 for (const auto& file : files) {
180 if (EndWith(file, FILE_TYPE_JSON) && !StartWith(file, STYLES_FOLDER)) {
181 fileNameList.emplace_back(file.substr(0, file.size() - (sizeof(FILE_TYPE_JSON) - 1)));
182 }
183 }
184
185 std::vector<std::string> priorityFileName;
186 if (filePath.compare(I18N_FOLDER) == 0) {
187 auto localeTag = AceApplicationInfo::GetInstance().GetLocaleTag();
188 priorityFileName = AceResConfig::GetLocaleFallback(localeTag, fileNameList);
189 } else {
190 priorityFileName = AceResConfig::GetResourceFallback(fileNameList);
191 }
192
193 for (const auto& fileName : priorityFileName) {
194 auto fileFullPath = filePath + fileName + std::string(FILE_TYPE_JSON);
195 std::string content;
196 if (GetAssetContent(fileFullPath, content)) {
197 auto fileData = ParseFileData(content);
198 if (fileData == nullptr) {
199 LOGW("parse %{private}s.json content failed", filePath.c_str());
200 } else {
201 data->Put(fileData);
202 }
203 }
204 }
205 }
206
LoadResourceConfiguration(std::map<std::string,std::string> & mediaResourceFileMap,std::unique_ptr<JsonValue> & currentResourceData)207 void PluginFrontendDelegate::LoadResourceConfiguration(std::map<std::string, std::string>& mediaResourceFileMap,
208 std::unique_ptr<JsonValue>& currentResourceData)
209 {
210 std::vector<std::string> files;
211 if (assetManager_) {
212 assetManager_->GetAssetList(RESOURCES_FOLDER, files);
213 }
214
215 std::set<std::string> resourceFolderName;
216 for (const auto& file : files) {
217 if (file.find_first_of("/") != std::string::npos) {
218 resourceFolderName.insert(file.substr(0, file.find_first_of("/")));
219 }
220 }
221
222 auto sortedResourceFolderPath = AceResConfig::GetDeclarativeResourceFallback(resourceFolderName);
223 for (const auto& folderName : sortedResourceFolderPath) {
224 auto fileFullPath = std::string(RESOURCES_FOLDER) + folderName + std::string(I18N_FILE_SUFFIX);
225 std::string content;
226 if (GetAssetContent(fileFullPath, content)) {
227 auto fileData = ParseFileData(content);
228 if (fileData != nullptr) {
229 currentResourceData->Put(fileData);
230 }
231 }
232 }
233
234 std::set<std::string> mediaFileName;
235 for (const auto& file : files) {
236 if (file.find_first_of("/") != std::string::npos) {
237 auto mediaPathName = file.substr(file.find_first_of("/"));
238 std::regex mediaPartten("^\\/media\\/\\w*(\\.jpg|\\.png|\\.gif|\\.svg|\\.webp|\\.bmp)$");
239 std::smatch result;
240 if (std::regex_match(mediaPathName, result, mediaPartten)) {
241 mediaFileName.insert(mediaPathName.substr(mediaPathName.find_first_of("/")));
242 }
243 }
244 }
245
246 auto currentResTag = AceResConfig::GetCurrentDeviceResTag();
247 auto currentResolutionTag = currentResTag.substr(currentResTag.find_last_of("-") + 1);
248 for (auto folderName : sortedResourceFolderPath) {
249 for (auto fileName : mediaFileName) {
250 if (mediaResourceFileMap.find(fileName) == mediaResourceFileMap.end()) {
251 continue;
252 }
253 auto fullFileName = folderName + fileName;
254 if (std::find(files.begin(), files.end(), fullFileName) != files.end()) {
255 mediaResourceFileMap.emplace(fileName.substr(fileName.find_last_of("/") + 1),
256 std::string(RESOURCES_FOLDER).append(fullFileName));
257 }
258 }
259 if (mediaResourceFileMap.size() == mediaFileName.size()) {
260 break;
261 }
262 }
263 }
264
OnJSCallback(const std::string & callbackId,const std::string & data)265 void PluginFrontendDelegate::OnJSCallback(const std::string& callbackId, const std::string& data)
266 {
267 taskExecutor_->PostTask(
268 [weak = AceType::WeakClaim(this), callbackId, args = std::move(data)] {
269 auto delegate = weak.Upgrade();
270 if (delegate) {
271 delegate->jsCallback_(callbackId, args);
272 }
273 },
274 TaskExecutor::TaskType::JS);
275 }
276
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher) const277 void PluginFrontendDelegate::SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) const
278 {
279 taskExecutor_->PostTask([dispatcherCallback = dispatcherCallback_, dispatcher] { dispatcherCallback(dispatcher); },
280 TaskExecutor::TaskType::JS);
281 }
282
TransferComponentResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data)283 void PluginFrontendDelegate::TransferComponentResponseData(int32_t callbackId, int32_t code,
284 std::vector<uint8_t>&& data)
285 {
286 auto pipelineContext = pipelineContextHolder_.Get();
287 WeakPtr<PipelineContext> contextWeak(pipelineContext);
288 taskExecutor_->PostTask(
289 [callbackId, data = std::move(data), contextWeak]() mutable {
290 auto context = contextWeak.Upgrade();
291 if (!context) {
292 LOGE("context is null");
293 } else if (!context->GetMessageBridge()) {
294 LOGE("messageBridge is null");
295 } else {
296 context->GetMessageBridge()->HandleCallback(callbackId, std::move(data));
297 }
298 },
299 TaskExecutor::TaskType::UI);
300 }
301
TransferJsResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const302 void PluginFrontendDelegate::TransferJsResponseData(
303 int32_t callbackId, int32_t code, std::vector<uint8_t>&& data) const
304 {
305 if (groupJsBridge_ && groupJsBridge_->ForwardToWorker(callbackId)) {
306 groupJsBridge_->TriggerModuleJsCallback(callbackId, code, std::move(data));
307 return;
308 }
309
310 taskExecutor_->PostTask(
311 [callbackId, code, data = std::move(data), groupJsBridge = groupJsBridge_]() mutable {
312 if (groupJsBridge) {
313 groupJsBridge->TriggerModuleJsCallback(callbackId, code, std::move(data));
314 }
315 },
316 TaskExecutor::TaskType::JS);
317 }
318
319 #if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
TransferJsResponseDataPreview(int32_t callbackId,int32_t code,ResponseData responseData) const320 void PluginFrontendDelegate::TransferJsResponseDataPreview(
321 int32_t callbackId, int32_t code, ResponseData responseData) const
322 {
323 taskExecutor_->PostTask(
324 [callbackId, code, responseData, groupJsBridge = groupJsBridge_]() mutable {
325 if (groupJsBridge) {
326 groupJsBridge->TriggerModuleJsCallbackPreview(callbackId, code, responseData);
327 }
328 },
329 TaskExecutor::TaskType::JS);
330 }
331 #endif
332
TransferJsPluginGetError(int32_t callbackId,int32_t errorCode,std::string && errorMessage) const333 void PluginFrontendDelegate::TransferJsPluginGetError(
334 int32_t callbackId, int32_t errorCode, std::string&& errorMessage) const
335 {
336 taskExecutor_->PostTask(
337 [callbackId, errorCode, errorMessage = std::move(errorMessage), groupJsBridge = groupJsBridge_]() mutable {
338 if (groupJsBridge) {
339 groupJsBridge->TriggerModulePluginGetErrorCallback(callbackId, errorCode, std::move(errorMessage));
340 }
341 },
342 TaskExecutor::TaskType::JS);
343 }
344
TransferJsEventData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const345 void PluginFrontendDelegate::TransferJsEventData(int32_t callbackId, int32_t code,
346 std::vector<uint8_t>&& data) const
347 {
348 taskExecutor_->PostTask(
349 [callbackId, code, data = std::move(data), groupJsBridge = groupJsBridge_]() mutable {
350 if (groupJsBridge) {
351 groupJsBridge->TriggerEventJsCallback(callbackId, code, std::move(data));
352 }
353 },
354 TaskExecutor::TaskType::JS);
355 }
356
LoadPluginJsCode(std::string && jsCode) const357 void PluginFrontendDelegate::LoadPluginJsCode(std::string&& jsCode) const
358 {
359 taskExecutor_->PostTask(
360 [jsCode = std::move(jsCode), groupJsBridge = groupJsBridge_]() mutable {
361 if (groupJsBridge) {
362 groupJsBridge->LoadPluginJsCode(std::move(jsCode));
363 }
364 },
365 TaskExecutor::TaskType::JS);
366 }
367
LoadPluginJsByteCode(std::vector<uint8_t> && jsCode,std::vector<int32_t> && jsCodeLen) const368 void PluginFrontendDelegate::LoadPluginJsByteCode(
369 std::vector<uint8_t>&& jsCode, std::vector<int32_t>&& jsCodeLen) const
370 {
371 if (groupJsBridge_ == nullptr) {
372 LOGE("groupJsBridge_ is nullptr");
373 return;
374 }
375 taskExecutor_->PostTask(
376 [jsCode = std::move(jsCode), jsCodeLen = std::move(jsCodeLen), groupJsBridge = groupJsBridge_]() mutable {
377 groupJsBridge->LoadPluginJsByteCode(std::move(jsCode), std::move(jsCodeLen));
378 },
379 TaskExecutor::TaskType::JS);
380 }
381
OnPageBackPress()382 bool PluginFrontendDelegate::OnPageBackPress()
383 {
384 auto result = false;
385 taskExecutor_->PostSyncTask(
386 [weak = AceType::WeakClaim(this), &result] {
387 auto delegate = weak.Upgrade();
388 if (!delegate) {
389 return;
390 }
391 auto pageId = delegate->GetRunningPageId();
392 auto page = delegate->GetPage(pageId);
393 if (page) {
394 result = page->FireDeclarativeOnBackPressCallback();
395 }
396 },
397 TaskExecutor::TaskType::JS);
398 return result;
399 }
400
NotifyAppStorage(const WeakPtr<Framework::JsEngine> & jsEngineWeak,const std::string & key,const std::string & value)401 void PluginFrontendDelegate::NotifyAppStorage(const WeakPtr<Framework::JsEngine>& jsEngineWeak,
402 const std::string& key, const std::string& value)
403 {
404 taskExecutor_->PostTask(
405 [jsEngineWeak, key, value] {
406 auto jsEngine = jsEngineWeak.Upgrade();
407 if (!jsEngine) {
408 return;
409 }
410 jsEngine->NotifyAppStorage(key, value);
411 },
412 TaskExecutor::TaskType::JS);
413 }
414
OnSuspended()415 void PluginFrontendDelegate::OnSuspended()
416 {
417 FireAsyncEvent("_root", std::string("\"viewsuspended\",null,null"), std::string(""));
418 }
419
OnBackGround()420 void PluginFrontendDelegate::OnBackGround()
421 {
422 taskExecutor_->PostTask(
423 [weak = AceType::WeakClaim(this)] {
424 auto delegate = weak.Upgrade();
425 if (!delegate) {
426 return;
427 }
428 delegate->OnPageHide();
429 },
430 TaskExecutor::TaskType::JS);
431 }
432
OnForground()433 void PluginFrontendDelegate::OnForground()
434 {
435 taskExecutor_->PostTask(
436 [weak = AceType::WeakClaim(this)] {
437 auto delegate = weak.Upgrade();
438 if (!delegate) {
439 return;
440 }
441 delegate->OnPageShow();
442 },
443 TaskExecutor::TaskType::JS);
444 }
445
OnConfigurationUpdated(const std::string & data)446 void PluginFrontendDelegate::OnConfigurationUpdated(const std::string& data)
447 {
448 taskExecutor_->PostSyncTask(
449 [onConfigurationUpdated = onConfigurationUpdated_, data] {
450 onConfigurationUpdated(data);
451 },
452 TaskExecutor::TaskType::JS);
453 }
454
OnStartContinuation()455 bool PluginFrontendDelegate::OnStartContinuation()
456 {
457 bool ret = false;
458 taskExecutor_->PostSyncTask(
459 [weak = AceType::WeakClaim(this), &ret] {
460 auto delegate = weak.Upgrade();
461 if (delegate && delegate->onStartContinuationCallBack_) {
462 ret = delegate->onStartContinuationCallBack_();
463 }
464 },
465 TaskExecutor::TaskType::JS);
466 return ret;
467 }
468
OnCompleteContinuation(int32_t code)469 void PluginFrontendDelegate::OnCompleteContinuation(int32_t code)
470 {
471 taskExecutor_->PostSyncTask(
472 [weak = AceType::WeakClaim(this), code] {
473 auto delegate = weak.Upgrade();
474 if (delegate && delegate->onCompleteContinuationCallBack_) {
475 delegate->onCompleteContinuationCallBack_(code);
476 }
477 },
478 TaskExecutor::TaskType::JS);
479 }
480
OnRemoteTerminated()481 void PluginFrontendDelegate::OnRemoteTerminated()
482 {
483 taskExecutor_->PostSyncTask(
484 [weak = AceType::WeakClaim(this)] {
485 auto delegate = weak.Upgrade();
486 if (delegate && delegate->onRemoteTerminatedCallBack_) {
487 delegate->onRemoteTerminatedCallBack_();
488 }
489 },
490 TaskExecutor::TaskType::JS);
491 }
492
OnSaveData(std::string & data)493 void PluginFrontendDelegate::OnSaveData(std::string& data)
494 {
495 std::string savedData;
496 taskExecutor_->PostSyncTask(
497 [weak = AceType::WeakClaim(this), &savedData] {
498 auto delegate = weak.Upgrade();
499 if (delegate && delegate->onSaveDataCallBack_) {
500 delegate->onSaveDataCallBack_(savedData);
501 }
502 },
503 TaskExecutor::TaskType::JS);
504 std::string pageUri = GetRunningPageUrl();
505 data = std::string("{\"url\":\"").append(pageUri).append("\",\"__remoteData\":").append(savedData).append("}");
506 }
507
OnRestoreData(const std::string & data)508 bool PluginFrontendDelegate::OnRestoreData(const std::string& data)
509 {
510 bool ret = false;
511 taskExecutor_->PostSyncTask(
512 [weak = AceType::WeakClaim(this), &data, &ret] {
513 auto delegate = weak.Upgrade();
514 if (delegate && delegate->onRestoreDataCallBack_) {
515 ret = delegate->onRestoreDataCallBack_(data);
516 }
517 },
518 TaskExecutor::TaskType::JS);
519 return ret;
520 }
521
OnMemoryLevel(const int32_t level)522 void PluginFrontendDelegate::OnMemoryLevel(const int32_t level)
523 {
524 taskExecutor_->PostTask(
525 [onMemoryLevel = onMemoryLevel_, level]() {
526 if (onMemoryLevel) {
527 onMemoryLevel(level);
528 }
529 },
530 TaskExecutor::TaskType::JS);
531 }
532
GetPluginsUsed(std::string & data)533 void PluginFrontendDelegate::GetPluginsUsed(std::string& data)
534 {
535 if (!GetAssetContentImpl(assetManager_, "module_collection.txt", data)) {
536 LOGW("read failed, will load all the system plugin");
537 data = "All";
538 }
539 }
540
OnActive()541 void PluginFrontendDelegate::OnActive()
542 {
543 taskExecutor_->PostTask(
544 [onActive = onActive_]() {
545 onActive();
546 },
547 TaskExecutor::TaskType::JS);
548 }
549
OnInactive()550 void PluginFrontendDelegate::OnInactive()
551 {
552 taskExecutor_->PostTask(
553 [onInactive = onInactive_]() {
554 onInactive();
555 },
556 TaskExecutor::TaskType::JS);
557 }
558
OnNewRequest(const std::string & data)559 void PluginFrontendDelegate::OnNewRequest(const std::string& data)
560 {
561 FireSyncEvent("_root", std::string("\"onNewRequest\","), data);
562 }
563
CallPopPage()564 void PluginFrontendDelegate::CallPopPage()
565 {
566 PopPage();
567 }
568
ResetStagingPage()569 void PluginFrontendDelegate::ResetStagingPage()
570 {
571 taskExecutor_->PostTask([resetStagingPage = resetStagingPage_] { resetStagingPage(); }, TaskExecutor::TaskType::JS);
572 }
573
OnApplicationDestroy(const std::string & packageName)574 void PluginFrontendDelegate::OnApplicationDestroy(const std::string& packageName)
575 {
576 taskExecutor_->PostSyncTask(
577 [destroyApplication = destroyApplication_, packageName] { destroyApplication(packageName); },
578 TaskExecutor::TaskType::JS);
579 }
580
UpdateApplicationState(const std::string & packageName,Frontend::State state)581 void PluginFrontendDelegate::UpdateApplicationState(const std::string& packageName, Frontend::State state)
582 {
583 taskExecutor_->PostTask(
584 [updateApplicationState = updateApplicationState_, packageName, state] {
585 updateApplicationState(packageName, state);
586 },
587 TaskExecutor::TaskType::JS);
588 }
589
OnWindowDisplayModeChanged(bool isShownInMultiWindow,const std::string & data)590 void PluginFrontendDelegate::OnWindowDisplayModeChanged(bool isShownInMultiWindow, const std::string& data)
591 {
592 taskExecutor_->PostTask(
593 [onWindowDisplayModeChanged = onWindowDisplayModeChanged_, isShownInMultiWindow, data] {
594 onWindowDisplayModeChanged(isShownInMultiWindow, data);
595 },
596 TaskExecutor::TaskType::JS);
597 }
598
OnSaveAbilityState(std::string & data)599 void PluginFrontendDelegate::OnSaveAbilityState(std::string& data)
600 {
601 taskExecutor_->PostSyncTask(
602 [onSaveAbilityState = onSaveAbilityState_, &data] {
603 onSaveAbilityState(data);
604 },
605 TaskExecutor::TaskType::JS);
606 }
607
OnRestoreAbilityState(const std::string & data)608 void PluginFrontendDelegate::OnRestoreAbilityState(const std::string& data)
609 {
610 taskExecutor_->PostTask(
611 [onRestoreAbilityState = onRestoreAbilityState_, data] {
612 onRestoreAbilityState(data);
613 },
614 TaskExecutor::TaskType::JS);
615 }
616
OnNewWant(const std::string & data)617 void PluginFrontendDelegate::OnNewWant(const std::string& data)
618 {
619 taskExecutor_->PostTask(
620 [onNewWant = onNewWant_, data] {
621 onNewWant(data);
622 },
623 TaskExecutor::TaskType::JS);
624 }
625
FireAsyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)626 void PluginFrontendDelegate::FireAsyncEvent(
627 const std::string& eventId, const std::string& param, const std::string& jsonArgs)
628 {
629 std::string args = param;
630 args.append(",null").append(",null"); // callback and dom changes
631 if (!jsonArgs.empty()) {
632 args.append(",").append(jsonArgs); // method args
633 }
634 taskExecutor_->PostTask(
635 [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
636 auto delegate = weak.Upgrade();
637 if (delegate) {
638 delegate->asyncEvent_(eventId, args);
639 }
640 },
641 TaskExecutor::TaskType::JS);
642 }
643
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)644 bool PluginFrontendDelegate::FireSyncEvent(
645 const std::string& eventId, const std::string& param, const std::string& jsonArgs)
646 {
647 std::string resultStr;
648 FireSyncEvent(eventId, param, jsonArgs, resultStr);
649 return (resultStr == "true");
650 }
651
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs,std::string & result)652 void PluginFrontendDelegate::FireSyncEvent(
653 const std::string& eventId, const std::string& param, const std::string& jsonArgs, std::string& result)
654 {
655 int32_t callbackId = callbackCnt_++;
656 std::string args = param;
657 args.append("{\"_callbackId\":\"").append(std::to_string(callbackId)).append("\"}").append(",null");
658 if (!jsonArgs.empty()) {
659 args.append(",").append(jsonArgs); // method args
660 }
661 taskExecutor_->PostSyncTask(
662 [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
663 auto delegate = weak.Upgrade();
664 if (delegate) {
665 delegate->syncEvent_(eventId, args);
666 }
667 },
668 TaskExecutor::TaskType::JS);
669
670 result = jsCallBackResult_[callbackId];
671 jsCallBackResult_.erase(callbackId);
672 }
673
FireAccessibilityEvent(const AccessibilityEvent & accessibilityEvent)674 void PluginFrontendDelegate::FireAccessibilityEvent(const AccessibilityEvent& accessibilityEvent)
675 {
676 jsAccessibilityManager_->SendAccessibilityAsyncEvent(accessibilityEvent);
677 }
678
InitializeAccessibilityCallback()679 void PluginFrontendDelegate::InitializeAccessibilityCallback()
680 {
681 jsAccessibilityManager_->InitializeCallback();
682 }
683
684 // Start FrontendDelegate overrides.
Push(const std::string & uri,const std::string & params)685 void PluginFrontendDelegate::Push(const std::string& uri, const std::string& params)
686 {
687 Push(PageTarget(uri), params);
688 }
689
Replace(const std::string & uri,const std::string & params)690 void PluginFrontendDelegate::Replace(const std::string& uri, const std::string& params)
691 {
692 Replace(PageTarget(uri), params);
693 }
694
Back(const std::string & uri,const std::string & params)695 void PluginFrontendDelegate::Back(const std::string& uri, const std::string& params)
696 {
697 BackWithTarget(PageTarget(uri), params);
698 }
699
Push(const PageTarget & target,const std::string & params)700 void PluginFrontendDelegate::Push(const PageTarget& target, const std::string& params)
701 {
702 if (target.url.empty()) {
703 LOGE("router.Push uri is empty");
704 return;
705 }
706 if (isRouteStackFull_) {
707 LOGE("the router stack has reached its max size, you can't push any more pages.");
708 EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, target.url);
709 return;
710 }
711
712 std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
713 if (!pagePath.empty()) {
714 LoadPage(GenerateNextPageId(), PageTarget(pagePath, target.container), false, params);
715 } else {
716 LOGW("[Engine Log] this uri not support in route push.");
717 }
718 }
719
Replace(const PageTarget & target,const std::string & params)720 void PluginFrontendDelegate::Replace(const PageTarget& target, const std::string& params)
721 {
722 if (target.url.empty()) {
723 LOGE("router.Replace uri is empty");
724 return;
725 }
726
727 std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
728 if (!pagePath.empty()) {
729 LoadReplacePage(GenerateNextPageId(), PageTarget(pagePath, target.container), params);
730 } else {
731 LOGW("[Engine Log] this uri not support in route replace.");
732 }
733 }
734
PostponePageTransition()735 void PluginFrontendDelegate::PostponePageTransition()
736 {
737 taskExecutor_->PostTask(
738 [weak = AceType::WeakClaim(this)] {
739 auto delegate = weak.Upgrade();
740 if (!delegate) {
741 return;
742 }
743 auto pipelineContext = delegate->pipelineContextHolder_.Get();
744 pipelineContext->PostponePageTransition();
745 },
746 TaskExecutor::TaskType::UI);
747 }
748
LaunchPageTransition()749 void PluginFrontendDelegate::LaunchPageTransition()
750 {
751 taskExecutor_->PostTask(
752 [weak = AceType::WeakClaim(this)] {
753 auto delegate = weak.Upgrade();
754 if (!delegate) {
755 return;
756 }
757 auto pipelineContext = delegate->pipelineContextHolder_.Get();
758 pipelineContext->LaunchPageTransition();
759 },
760 TaskExecutor::TaskType::UI);
761 }
762
BackWithTarget(const PageTarget & target,const std::string & params)763 void PluginFrontendDelegate::BackWithTarget(const PageTarget& target, const std::string& params)
764 {
765 if (target.url.empty()) {
766 {
767 std::lock_guard<std::mutex> lock(mutex_);
768 if (pageRouteStack_.size() > 1) {
769 pageId_ = pageRouteStack_[pageRouteStack_.size() - MIN_ROUT_COUNT].pageId;
770 }
771 if (!params.empty()) {
772 pageParamMap_[pageId_] = params;
773 }
774 }
775 PopPage();
776 } else {
777 std::string pagePath = manifestParser_->GetRouter()->GetPagePath(target.url);
778 if (!pagePath.empty()) {
779 pageId_ = GetPageIdByUrl(target.url);
780 if (!params.empty()) {
781 std::lock_guard<std::mutex> lock(mutex_);
782 pageParamMap_[pageId_] = params;
783 }
784 PopToPage(pagePath);
785 } else {
786 LOGW("[Engine Log] this uri not support in route Back.");
787 }
788 }
789 }
790
Clear()791 void PluginFrontendDelegate::Clear()
792 {
793 ClearInvisiblePages();
794 }
795
GetStackSize() const796 int32_t PluginFrontendDelegate::GetStackSize() const
797 {
798 std::lock_guard<std::mutex> lock(mutex_);
799 return static_cast<int32_t>(pageRouteStack_.size());
800 }
801
GetState(int32_t & index,std::string & name,std::string & path)802 void PluginFrontendDelegate::GetState(int32_t& index, std::string& name, std::string& path)
803 {
804 std::string url;
805 {
806 std::lock_guard<std::mutex> lock(mutex_);
807 if (pageRouteStack_.empty()) {
808 return;
809 }
810 index = static_cast<int32_t>(pageRouteStack_.size());
811 url = pageRouteStack_.back().url;
812 }
813 auto pos = url.rfind(".js");
814 if (pos == url.length() - JS_HEADER_OFFSET) {
815 url = url.substr(0, pos);
816 }
817 pos = url.rfind("/");
818 if (pos != std::string::npos) {
819 name = url.substr(pos + 1);
820 path = url.substr(0, pos + 1);
821 }
822 }
823
GetParams()824 std::string PluginFrontendDelegate::GetParams()
825 {
826 if (pageParamMap_.find(pageId_) != pageParamMap_.end()) {
827 return pageParamMap_.find(pageId_)->second;
828 } else {
829 return "";
830 }
831 }
832
TriggerPageUpdate(int32_t pageId,bool directExecute)833 void PluginFrontendDelegate::TriggerPageUpdate(int32_t pageId, bool directExecute)
834 {
835 auto page = GetPage(pageId);
836 if (!page) {
837 return;
838 }
839
840 auto jsPage = AceType::DynamicCast<Framework::JsAcePage>(page);
841 ACE_DCHECK(jsPage);
842
843 // Pop all JS command and execute them in UI thread.
844 auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
845 jsPage->PopAllCommands(*jsCommands);
846
847 auto pipelineContext = pipelineContextHolder_.Get();
848 WeakPtr<Framework::JsAcePage> jsPageWeak(jsPage);
849 WeakPtr<PipelineContext> contextWeak(pipelineContext);
850 auto updateTask = [jsPageWeak, contextWeak, jsCommands] {
851 ACE_SCOPED_TRACE("FlushUpdateCommands");
852 auto jsPage = jsPageWeak.Upgrade();
853 auto context = contextWeak.Upgrade();
854 if (!jsPage || !context) {
855 LOGE("Page update failed. page or context is null.");
856 EventReport::SendPageRouterException(PageRouterExcepType::UPDATE_PAGE_ERR);
857 return;
858 }
859 // Flush all JS commands.
860 for (const auto& command : *jsCommands) {
861 command->Execute(jsPage);
862 }
863 if (jsPage->GetDomDocument()) {
864 jsPage->GetDomDocument()->HandleComponentPostBinding();
865 }
866 auto accessibilityManager = context->GetAccessibilityManager();
867 if (accessibilityManager) {
868 accessibilityManager->HandleComponentPostBinding();
869 }
870
871 jsPage->ClearShowCommand();
872 std::vector<NodeId> dirtyNodes;
873 jsPage->PopAllDirtyNodes(dirtyNodes);
874 for (auto nodeId : dirtyNodes) {
875 auto patchComponent = jsPage->BuildPagePatch(nodeId);
876 if (patchComponent) {
877 context->ScheduleUpdate(patchComponent);
878 }
879 }
880 };
881
882 taskExecutor_->PostTask(
883 [updateTask, pipelineContext, directExecute]() {
884 pipelineContext->AddPageUpdateTask(std::move(updateTask), directExecute);
885 },
886 TaskExecutor::TaskType::UI);
887 }
888
PostJsTask(std::function<void ()> && task)889 void PluginFrontendDelegate::PostJsTask(std::function<void()>&& task)
890 {
891 taskExecutor_->PostTask(task, TaskExecutor::TaskType::JS);
892 }
893
RemoveVisibleChangeNode(NodeId id)894 void PluginFrontendDelegate::RemoveVisibleChangeNode(NodeId id)
895 {
896 LOGW("RemoveVisibleChangeNode: Not implemented yet.");
897 }
898
GetAppID() const899 const std::string& PluginFrontendDelegate::GetAppID() const
900 {
901 return manifestParser_->GetAppInfo()->GetAppID();
902 }
903
GetAppName() const904 const std::string& PluginFrontendDelegate::GetAppName() const
905 {
906 return manifestParser_->GetAppInfo()->GetAppName();
907 }
908
GetVersionName() const909 const std::string& PluginFrontendDelegate::GetVersionName() const
910 {
911 return manifestParser_->GetAppInfo()->GetVersionName();
912 }
913
GetVersionCode() const914 int32_t PluginFrontendDelegate::GetVersionCode() const
915 {
916 return manifestParser_->GetAppInfo()->GetVersionCode();
917 }
918
ShowToast(const std::string & message,int32_t duration,const std::string & bottom)919 void PluginFrontendDelegate::ShowToast(const std::string& message, int32_t duration, const std::string& bottom)
920 {
921 int32_t durationTime = std::clamp(duration, TOAST_TIME_DEFAULT, TOAST_TIME_MAX);
922 auto pipelineContext = pipelineContextHolder_.Get();
923 bool isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
924 taskExecutor_->PostTask(
925 [durationTime, message, bottom, isRightToLeft, context = pipelineContext] {
926 ToastComponent::GetInstance().Show(context, message, durationTime, bottom, isRightToLeft);
927 },
928 TaskExecutor::TaskType::UI);
929 }
930
ShowDialog(const std::string & title,const std::string & message,const std::vector<ButtonInfo> & buttons,bool autoCancel,std::function<void (int32_t,int32_t)> && callback,const std::set<std::string> & callbacks)931 void PluginFrontendDelegate::ShowDialog(const std::string& title, const std::string& message,
932 const std::vector<ButtonInfo>& buttons, bool autoCancel, std::function<void(int32_t, int32_t)>&& callback,
933 const std::set<std::string>& callbacks)
934 {
935 std::unordered_map<std::string, EventMarker> callbackMarkers;
936 if (callbacks.find(COMMON_SUCCESS) != callbacks.end()) {
937 auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
938 BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(
939 successEventMarker, [callback, taskExecutor = taskExecutor_](int32_t successType) {
940 taskExecutor->PostTask(
941 [callback, successType]() { callback(0, successType); }, TaskExecutor::TaskType::JS);
942 });
943 callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
944 }
945
946 if (callbacks.find(COMMON_CANCEL) != callbacks.end()) {
947 auto cancelEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
948 BackEndEventManager<void()>::GetInstance().BindBackendEvent(
949 cancelEventMarker, [callback, taskExecutor = taskExecutor_] {
950 taskExecutor->PostTask([callback]() { callback(1, 0); }, TaskExecutor::TaskType::JS);
951 });
952 callbackMarkers.emplace(COMMON_CANCEL, cancelEventMarker);
953 }
954
955 if (callbacks.find(COMMON_COMPLETE) != callbacks.end()) {
956 auto completeEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
957 BackEndEventManager<void()>::GetInstance().BindBackendEvent(
958 completeEventMarker, [callback, taskExecutor = taskExecutor_] {
959 taskExecutor->PostTask([callback]() { callback(MIN_ROUT_COUNT, 0); }, TaskExecutor::TaskType::JS);
960 });
961 callbackMarkers.emplace(COMMON_COMPLETE, completeEventMarker);
962 }
963
964 DialogProperties dialogProperties = {
965 .title = title,
966 .content = message,
967 .autoCancel = autoCancel,
968 .buttons = buttons,
969 .callbacks = std::move(callbackMarkers),
970 };
971 pipelineContextHolder_.Get()->ShowDialog(dialogProperties, AceApplicationInfo::GetInstance().IsRightToLeft());
972 }
973
974
GetBoundingRectData(NodeId nodeId)975 Rect PluginFrontendDelegate::GetBoundingRectData(NodeId nodeId)
976 {
977 Rect rect;
978 auto task = [context = pipelineContextHolder_.Get(), nodeId, &rect]() {
979 context->GetBoundingRectData(nodeId, rect);
980 };
981 PostSyncTaskToPage(task);
982 return rect;
983 }
984
GetInspector(NodeId nodeId)985 std::string PluginFrontendDelegate::GetInspector(NodeId nodeId)
986 {
987 std::string attrs;
988 auto task = [weak = WeakClaim(AceType::RawPtr(jsAccessibilityManager_)), nodeId, &attrs]() {
989 auto accessibilityNodeManager = weak.Upgrade();
990 if (accessibilityNodeManager) {
991 attrs = accessibilityNodeManager->GetInspectorNodeById(nodeId);
992 }
993 };
994 PostSyncTaskToPage(task);
995 return attrs;
996 }
997
SetCallBackResult(const std::string & callBackId,const std::string & result)998 void PluginFrontendDelegate::SetCallBackResult(const std::string& callBackId, const std::string& result)
999 {
1000 jsCallBackResult_.try_emplace(StringToInt(callBackId), result);
1001 }
1002
WaitTimer(const std::string & callbackId,const std::string & delay,bool isInterval,bool isFirst)1003 void PluginFrontendDelegate::WaitTimer(
1004 const std::string& callbackId, const std::string& delay, bool isInterval, bool isFirst)
1005 {
1006 if (!isFirst) {
1007 auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1008 // If not find the callbackId in map, means this timer already was removed,
1009 // no need create a new cancelableTimer again.
1010 if (timeoutTaskIter == timeoutTaskMap_.end()) {
1011 return;
1012 }
1013 }
1014
1015 int32_t delayTime = StringToInt(delay);
1016 // CancelableCallback class can only be executed once.
1017 CancelableCallback<void()> cancelableTimer;
1018 cancelableTimer.Reset([callbackId, delay, isInterval, call = timer_] { call(callbackId, delay, isInterval); });
1019 auto result = timeoutTaskMap_.try_emplace(callbackId, cancelableTimer);
1020 if (!result.second) {
1021 result.first->second = cancelableTimer;
1022 }
1023 taskExecutor_->PostDelayedTask(cancelableTimer, TaskExecutor::TaskType::JS, delayTime);
1024 }
1025
ClearTimer(const std::string & callbackId)1026 void PluginFrontendDelegate::ClearTimer(const std::string& callbackId)
1027 {
1028 auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1029 if (timeoutTaskIter != timeoutTaskMap_.end()) {
1030 timeoutTaskIter->second.Cancel();
1031 timeoutTaskMap_.erase(timeoutTaskIter);
1032 } else {
1033 LOGW("ClearTimer callbackId not found");
1034 }
1035 }
1036
PostSyncTaskToPage(std::function<void ()> && task)1037 void PluginFrontendDelegate::PostSyncTaskToPage(std::function<void()>&& task)
1038 {
1039 pipelineContextHolder_.Get(); // Wait until Pipeline Context is attached.
1040 taskExecutor_->PostSyncTask(task, TaskExecutor::TaskType::UI);
1041 }
1042
AddTaskObserver(std::function<void ()> && task)1043 void PluginFrontendDelegate::AddTaskObserver(std::function<void()>&& task)
1044 {
1045 taskExecutor_->AddTaskObserver(std::move(task));
1046 }
1047
RemoveTaskObserver()1048 void PluginFrontendDelegate::RemoveTaskObserver()
1049 {
1050 taskExecutor_->RemoveTaskObserver();
1051 }
1052
GetAssetContent(const std::string & url,std::string & content)1053 bool PluginFrontendDelegate::GetAssetContent(const std::string& url, std::string& content)
1054 {
1055 return GetAssetContentImpl(assetManager_, url, content);
1056 }
1057
GetAssetContent(const std::string & url,std::vector<uint8_t> & content)1058 bool PluginFrontendDelegate::GetAssetContent(const std::string& url, std::vector<uint8_t>& content)
1059 {
1060 return GetAssetContentImpl(assetManager_, url, content);
1061 }
1062
GetAssetPath(const std::string & url)1063 std::string PluginFrontendDelegate::GetAssetPath(const std::string& url)
1064 {
1065 return GetAssetPathImpl(assetManager_, url);
1066 }
1067
LoadPage(int32_t pageId,const PageTarget & target,bool isMainPage,const std::string & params)1068 void PluginFrontendDelegate::LoadPage(
1069 int32_t pageId, const PageTarget& target, bool isMainPage, const std::string& params)
1070 {
1071 {
1072 std::lock_guard<std::mutex> lock(mutex_);
1073 pageId_ = pageId;
1074 pageParamMap_[pageId] = params;
1075 }
1076 auto url = target.url;
1077 if (pageId == INVALID_PAGE_ID) {
1078 LOGE("PluginFrontendDelegate, invalid page id");
1079 EventReport::SendPageRouterException(PageRouterExcepType::LOAD_PAGE_ERR, url);
1080 return;
1081 }
1082 if (isStagingPageExist_) {
1083 LOGE("PluginFrontendDelegate, load page failed, waiting for current page loading finish.");
1084 RecyclePageId(pageId);
1085 return;
1086 }
1087 isStagingPageExist_ = true;
1088 auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1089 auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, target.container);
1090 page->SetPageParams(params);
1091 page->SetUsePluginComponent(true);
1092 page->SetPluginComponentJsonData(params);
1093 page->SetFlushCallback([weak = AceType::WeakClaim(this), isMainPage](const RefPtr<JsAcePage>& acePage) {
1094 auto delegate = weak.Upgrade();
1095 if (delegate && acePage) {
1096 delegate->FlushPageCommand(acePage, acePage->GetUrl(), isMainPage);
1097 }
1098 });
1099 LoadJS(page, url, isMainPage);
1100 }
1101
LoadJS(const RefPtr<Framework::JsAcePage> & page,const std::string & url,bool isMainPage)1102 void PluginFrontendDelegate::LoadJS(
1103 const RefPtr<Framework::JsAcePage>& page, const std::string& url, bool isMainPage)
1104 {
1105 taskExecutor_->PostSyncTask(
1106 [weak = AceType::WeakClaim(this), page, url, isMainPage] {
1107 auto delegate = weak.Upgrade();
1108 if (!delegate) {
1109 return;
1110 }
1111 delegate->loadJs_(url, page, isMainPage);
1112 page->FlushCommands();
1113 // just make sure the pipelineContext is created.
1114 auto pipeline = delegate->pipelineContextHolder_.Get();
1115 pipeline->SetMinPlatformVersion(delegate->GetMinPlatformVersion());
1116 delegate->taskExecutor_->PostTask(
1117 [weak, page] {
1118 auto delegate = weak.Upgrade();
1119 if (delegate && delegate->pipelineContextHolder_.Get()) {
1120 delegate->pipelineContextHolder_.Get()->FlushFocus();
1121 }
1122 if (page->GetDomDocument()) {
1123 page->GetDomDocument()->HandlePageLoadFinish();
1124 }
1125 },
1126 TaskExecutor::TaskType::UI);
1127 },
1128 TaskExecutor::TaskType::JS);
1129 }
1130
OnSurfaceChanged()1131 void PluginFrontendDelegate::OnSurfaceChanged()
1132 {
1133 if (mediaQueryInfo_->GetIsInit()) {
1134 mediaQueryInfo_->SetIsInit(false);
1135 }
1136 mediaQueryInfo_->EnsureListenerIdValid();
1137 OnMediaQueryUpdate();
1138 }
1139
OnMediaQueryUpdate()1140 void PluginFrontendDelegate::OnMediaQueryUpdate()
1141 {
1142 if (mediaQueryInfo_->GetIsInit()) {
1143 return;
1144 }
1145
1146 taskExecutor_->PostTask(
1147 [weak = AceType::WeakClaim(this)] {
1148 auto delegate = weak.Upgrade();
1149 if (!delegate) {
1150 return;
1151 }
1152 const auto& info = delegate->mediaQueryInfo_->GetMediaQueryInfo();
1153 // request css mediaquery
1154 std::string param("\"viewsizechanged\",");
1155 param.append(info);
1156 delegate->asyncEvent_("_root", param);
1157
1158 // request js mediaquery
1159 const auto& listenerId = delegate->mediaQueryInfo_->GetListenerId();
1160 delegate->mediaQueryCallback_(listenerId, info);
1161 delegate->mediaQueryInfo_->ResetListenerId();
1162 },
1163 TaskExecutor::TaskType::JS);
1164 }
1165
OnPageReady(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage)1166 void PluginFrontendDelegate::OnPageReady(
1167 const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage)
1168 {
1169 // Pop all JS command and execute them in UI thread.
1170 auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1171 page->PopAllCommands(*jsCommands);
1172
1173 auto pipelineContext = pipelineContextHolder_.Get();
1174 page->SetPipelineContext(pipelineContext);
1175 taskExecutor_->PostTask(
1176 [weak = AceType::WeakClaim(this), page, url, jsCommands, isMainPage] {
1177 auto delegate = weak.Upgrade();
1178 if (!delegate) {
1179 return;
1180 }
1181 auto pipelineContext = delegate->pipelineContextHolder_.Get();
1182 // Flush all JS commands.
1183 for (const auto& command : *jsCommands) {
1184 command->Execute(page);
1185 }
1186 // Just clear all dirty nodes.
1187 page->ClearAllDirtyNodes();
1188 if (page->GetDomDocument()) {
1189 page->GetDomDocument()->HandleComponentPostBinding();
1190 }
1191 if (pipelineContext->GetAccessibilityManager()) {
1192 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1193 }
1194 if (pipelineContext->CanPushPage()) {
1195 if (!isMainPage) {
1196 delegate->OnPageHide();
1197 }
1198 delegate->OnPrePageChange(page);
1199 pipelineContext->PushPage(page->BuildPage(url), page->GetStageElement());
1200 delegate->OnPushPageSuccess(page, url);
1201 delegate->SetCurrentPage(page->GetPageId());
1202 delegate->OnMediaQueryUpdate();
1203 } else {
1204 // This page has been loaded but become useless now, the corresponding js instance
1205 // must be destroyed to avoid memory leak.
1206 delegate->OnPageDestroy(page->GetPageId());
1207 delegate->ResetStagingPage();
1208 }
1209 delegate->isStagingPageExist_ = false;
1210 if (isMainPage) {
1211 delegate->OnPageShow();
1212 }
1213 },
1214 TaskExecutor::TaskType::UI);
1215 }
1216
OnPrePageChange(const RefPtr<JsAcePage> & page)1217 void PluginFrontendDelegate::OnPrePageChange(const RefPtr<JsAcePage>& page)
1218 {
1219 if (page && page->GetDomDocument() && jsAccessibilityManager_) {
1220 jsAccessibilityManager_->SetRootNodeId(page->GetDomDocument()->GetRootNodeId());
1221 }
1222 }
1223
FlushPageCommand(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage)1224 void PluginFrontendDelegate::FlushPageCommand(
1225 const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage)
1226 {
1227 if (!page) {
1228 return;
1229 }
1230 if (page->FragmentCount() == 1) {
1231 OnPageReady(page, url, isMainPage);
1232 } else {
1233 TriggerPageUpdate(page->GetPageId());
1234 }
1235 }
1236
AddPageLocked(const RefPtr<JsAcePage> & page)1237 void PluginFrontendDelegate::AddPageLocked(const RefPtr<JsAcePage>& page)
1238 {
1239 auto result = pageMap_.try_emplace(page->GetPageId(), page);
1240 if (!result.second) {
1241 LOGW("the page has already in the map");
1242 }
1243 }
1244
SetCurrentPage(int32_t pageId)1245 void PluginFrontendDelegate::SetCurrentPage(int32_t pageId)
1246 {
1247 auto page = GetPage(pageId);
1248 if (page != nullptr) {
1249 jsAccessibilityManager_->SetVersion(AccessibilityVersion::JS_DECLARATIVE_VERSION);
1250 jsAccessibilityManager_->SetRunningPage(page);
1251 taskExecutor_->PostTask([updatePage = updatePage_, page] { updatePage(page); }, TaskExecutor::TaskType::JS);
1252 } else {
1253 LOGE("PluginFrontendDelegate SetCurrentPage page is null.");
1254 }
1255 }
1256
OnPushPageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1257 void PluginFrontendDelegate::OnPushPageSuccess(
1258 const RefPtr<JsAcePage>& page, const std::string& url)
1259 {
1260 std::lock_guard<std::mutex> lock(mutex_);
1261 AddPageLocked(page);
1262 pageRouteStack_.emplace_back(PageInfo { page->GetPageId(), url});
1263 if (pageRouteStack_.size() >= MAX_ROUTER_STACK) {
1264 isRouteStackFull_ = true;
1265 EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, page->GetUrl());
1266 }
1267 }
1268
OnPopToPageSuccess(const std::string & url)1269 void PluginFrontendDelegate::OnPopToPageSuccess(const std::string& url)
1270 {
1271 std::lock_guard<std::mutex> lock(mutex_);
1272 while (!pageRouteStack_.empty()) {
1273 if (pageRouteStack_.back().url == url) {
1274 break;
1275 }
1276 OnPageDestroy(pageRouteStack_.back().pageId);
1277 pageMap_.erase(pageRouteStack_.back().pageId);
1278 pageParamMap_.erase(pageRouteStack_.back().pageId);
1279 pageRouteStack_.pop_back();
1280 }
1281
1282 if (isRouteStackFull_) {
1283 isRouteStackFull_ = false;
1284 }
1285 }
1286
PopToPage(const std::string & url)1287 void PluginFrontendDelegate::PopToPage(const std::string& url)
1288 {
1289 taskExecutor_->PostTask(
1290 [weak = AceType::WeakClaim(this), url] {
1291 auto delegate = weak.Upgrade();
1292 if (!delegate) {
1293 return;
1294 }
1295 auto pageId = delegate->GetPageIdByUrl(url);
1296 if (pageId == INVALID_PAGE_ID) {
1297 return;
1298 }
1299 auto pipelineContext = delegate->pipelineContextHolder_.Get();
1300 if (!pipelineContext->CanPopPage()) {
1301 delegate->ResetStagingPage();
1302 return;
1303 }
1304 delegate->OnPageHide();
1305 pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1306 delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1307 [weak, url, pageId](
1308 const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1309 auto delegate = weak.Upgrade();
1310 if (delegate) {
1311 delegate->PopToPageTransitionListener(event, url, pageId);
1312 }
1313 });
1314 pipelineContext->PopToPage(pageId);
1315 },
1316 TaskExecutor::TaskType::UI);
1317 }
1318
PopToPageTransitionListener(const TransitionEvent & event,const std::string & url,int32_t pageId)1319 void PluginFrontendDelegate::PopToPageTransitionListener(
1320 const TransitionEvent& event, const std::string& url, int32_t pageId)
1321 {
1322 if (event == TransitionEvent::POP_END) {
1323 OnPopToPageSuccess(url);
1324 SetCurrentPage(pageId);
1325 OnPageShow();
1326 OnMediaQueryUpdate();
1327 }
1328 }
1329
OnPopPageSuccess()1330 int32_t PluginFrontendDelegate::OnPopPageSuccess()
1331 {
1332 std::lock_guard<std::mutex> lock(mutex_);
1333 pageMap_.erase(pageRouteStack_.back().pageId);
1334 pageParamMap_.erase(pageRouteStack_.back().pageId);
1335 pageRouteStack_.pop_back();
1336 if (isRouteStackFull_) {
1337 isRouteStackFull_ = false;
1338 }
1339 if (!pageRouteStack_.empty()) {
1340 return pageRouteStack_.back().pageId;
1341 }
1342 return INVALID_PAGE_ID;
1343 }
1344
PopPage()1345 void PluginFrontendDelegate::PopPage()
1346 {
1347 taskExecutor_->PostTask(
1348 [weak = AceType::WeakClaim(this)] {
1349 auto delegate = weak.Upgrade();
1350 if (!delegate) {
1351 return;
1352 }
1353 auto pipelineContext = delegate->pipelineContextHolder_.Get();
1354 if (delegate->GetStackSize() == 1) {
1355 if (delegate->disallowPopLastPage_) {
1356 LOGW("Not allow back because this is the last page!");
1357 return;
1358 }
1359 delegate->OnPageHide();
1360 delegate->OnPageDestroy(delegate->GetRunningPageId());
1361 delegate->OnPopPageSuccess();
1362 pipelineContext->Finish();
1363 return;
1364 }
1365 if (!pipelineContext->CanPopPage()) {
1366 delegate->ResetStagingPage();
1367 return;
1368 }
1369 delegate->OnPageHide();
1370 pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1371 delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1372 [weak, destroyPageId = delegate->GetRunningPageId()](
1373 const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1374 auto delegate = weak.Upgrade();
1375 if (delegate) {
1376 delegate->PopPageTransitionListener(event, destroyPageId);
1377 }
1378 });
1379 pipelineContext->PopPage();
1380 },
1381 TaskExecutor::TaskType::UI);
1382 }
1383
PopPageTransitionListener(const TransitionEvent & event,int32_t destroyPageId)1384 void PluginFrontendDelegate::PopPageTransitionListener(
1385 const TransitionEvent& event, int32_t destroyPageId)
1386 {
1387 if (event == TransitionEvent::POP_END) {
1388 OnPageDestroy(destroyPageId);
1389 auto pageId = OnPopPageSuccess();
1390 SetCurrentPage(pageId);
1391 OnPageShow();
1392 OnMediaQueryUpdate();
1393 }
1394 }
1395
OnClearInvisiblePagesSuccess()1396 int32_t PluginFrontendDelegate::OnClearInvisiblePagesSuccess()
1397 {
1398 std::lock_guard<std::mutex> lock(mutex_);
1399 PageInfo pageInfo = std::move(pageRouteStack_.back());
1400 pageRouteStack_.pop_back();
1401 for (const auto& info : pageRouteStack_) {
1402 OnPageDestroy(info.pageId);
1403 pageMap_.erase(info.pageId);
1404 pageParamMap_.erase(info.pageId);
1405 }
1406 pageRouteStack_.clear();
1407 int32_t resPageId = pageInfo.pageId;
1408 pageRouteStack_.emplace_back(std::move(pageInfo));
1409 if (isRouteStackFull_) {
1410 isRouteStackFull_ = false;
1411 }
1412 return resPageId;
1413 }
1414
ClearInvisiblePages()1415 void PluginFrontendDelegate::ClearInvisiblePages()
1416 {
1417 taskExecutor_->PostTask(
1418 [weak = AceType::WeakClaim(this)] {
1419 auto delegate = weak.Upgrade();
1420 if (!delegate) {
1421 return;
1422 }
1423 auto pipelineContext = delegate->pipelineContextHolder_.Get();
1424 if (pipelineContext->ClearInvisiblePages()) {
1425 auto pageId = delegate->OnClearInvisiblePagesSuccess();
1426 delegate->SetCurrentPage(pageId);
1427 }
1428 },
1429 TaskExecutor::TaskType::UI);
1430 }
1431
OnReplacePageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1432 void PluginFrontendDelegate::OnReplacePageSuccess(
1433 const RefPtr<JsAcePage>& page, const std::string& url)
1434 {
1435 if (!page) {
1436 return;
1437 }
1438 std::lock_guard<std::mutex> lock(mutex_);
1439 AddPageLocked(page);
1440 if (!pageRouteStack_.empty()) {
1441 pageMap_.erase(pageRouteStack_.back().pageId);
1442 pageParamMap_.erase(pageRouteStack_.back().pageId);
1443 pageRouteStack_.pop_back();
1444 }
1445 pageRouteStack_.emplace_back(PageInfo { page->GetPageId(), url});
1446 }
1447
ReplacePage(const RefPtr<JsAcePage> & page,const std::string & url)1448 void PluginFrontendDelegate::ReplacePage(
1449 const RefPtr<JsAcePage>& page, const std::string& url)
1450 {
1451 // Pop all JS command and execute them in UI thread.
1452 auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1453 page->PopAllCommands(*jsCommands);
1454
1455 auto pipelineContext = pipelineContextHolder_.Get();
1456 page->SetPipelineContext(pipelineContext);
1457 taskExecutor_->PostTask(
1458 [weak = AceType::WeakClaim(this), page, url, jsCommands] {
1459 auto delegate = weak.Upgrade();
1460 if (!delegate) {
1461 return;
1462 }
1463 auto pipelineContext = delegate->pipelineContextHolder_.Get();
1464 // Flush all JS commands.
1465 for (const auto& command : *jsCommands) {
1466 command->Execute(page);
1467 }
1468 // Just clear all dirty nodes.
1469 page->ClearAllDirtyNodes();
1470 page->GetDomDocument()->HandleComponentPostBinding();
1471 if (pipelineContext->GetAccessibilityManager()) {
1472 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1473 }
1474 if (pipelineContext->CanReplacePage()) {
1475 delegate->OnPageHide();
1476 delegate->OnPageDestroy(delegate->GetRunningPageId());
1477 delegate->OnPrePageChange(page);
1478 pipelineContext->ReplacePage(page->BuildPage(url), page->GetStageElement());
1479 delegate->OnReplacePageSuccess(page, url);
1480 delegate->SetCurrentPage(page->GetPageId());
1481 delegate->OnMediaQueryUpdate();
1482 } else {
1483 // This page has been loaded but become useless now, the corresponding js instance
1484 // must be destroyed to avoid memory leak.
1485 delegate->OnPageDestroy(page->GetPageId());
1486 delegate->ResetStagingPage();
1487 }
1488 delegate->isStagingPageExist_ = false;
1489 },
1490 TaskExecutor::TaskType::UI);
1491 }
1492
LoadReplacePage(int32_t pageId,const PageTarget & target,const std::string & params)1493 void PluginFrontendDelegate::LoadReplacePage(int32_t pageId, const PageTarget& target, const std::string& params)
1494 {
1495 {
1496 std::lock_guard<std::mutex> lock(mutex_);
1497 pageId_ = pageId;
1498 pageParamMap_[pageId] = params;
1499 }
1500 auto url = target.url;
1501 if (pageId == INVALID_PAGE_ID) {
1502 LOGE("PluginFrontendDelegate, invalid page id");
1503 EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1504 return;
1505 }
1506 if (isStagingPageExist_) {
1507 LOGE("PluginFrontendDelegate, replace page failed, waiting for current page loading finish.");
1508 EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1509 return;
1510 }
1511 isStagingPageExist_ = true;
1512 auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1513 auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, target.url, target.container);
1514 page->SetPageParams(params);
1515 taskExecutor_->PostTask(
1516 [page, url, weak = AceType::WeakClaim(this)] {
1517 auto delegate = weak.Upgrade();
1518 if (delegate) {
1519 delegate->loadJs_(url, page, false);
1520 delegate->ReplacePage(page, url);
1521 }
1522 },
1523 TaskExecutor::TaskType::JS);
1524 }
1525
SetColorMode(ColorMode colorMode)1526 void PluginFrontendDelegate::SetColorMode(ColorMode colorMode)
1527 {
1528 OnMediaQueryUpdate();
1529 }
1530
RebuildAllPages()1531 void PluginFrontendDelegate::RebuildAllPages()
1532 {
1533 std::unordered_map<int32_t, RefPtr<JsAcePage>> pages;
1534 {
1535 std::lock_guard<std::mutex> lock(mutex_);
1536 pages.insert(pageMap_.begin(), pageMap_.end());
1537 }
1538 for (const auto& [pageId, page] : pages) {
1539 page->FireDeclarativeOnPageRefreshCallback();
1540 TriggerPageUpdate(page->GetPageId(), true);
1541 }
1542 }
1543
OnPageShow()1544 void PluginFrontendDelegate::OnPageShow()
1545 {
1546 auto pageId = GetRunningPageId();
1547 auto page = GetPage(pageId);
1548 if (page) {
1549 page->FireDeclarativeOnPageAppearCallback();
1550 }
1551 FireAsyncEvent("_root", std::string("\"viewappear\",null,null"), std::string(""));
1552 }
1553
OnPageHide()1554 void PluginFrontendDelegate::OnPageHide()
1555 {
1556 auto pageId = GetRunningPageId();
1557 auto page = GetPage(pageId);
1558 if (page) {
1559 page->FireDeclarativeOnPageDisAppearCallback();
1560 }
1561 FireAsyncEvent("_root", std::string("\"viewdisappear\",null,null"), std::string(""));
1562 }
1563
OnPageDestroy(int32_t pageId)1564 void PluginFrontendDelegate::OnPageDestroy(int32_t pageId)
1565 {
1566 taskExecutor_->PostTask(
1567 [weak = AceType::WeakClaim(this), pageId] {
1568 auto delegate = weak.Upgrade();
1569 if (delegate) {
1570 delegate->destroyPage_(pageId);
1571 delegate->RecyclePageId(pageId);
1572 }
1573 },
1574 TaskExecutor::TaskType::JS);
1575 }
1576
GetRunningPageId() const1577 int32_t PluginFrontendDelegate::GetRunningPageId() const
1578 {
1579 std::lock_guard<std::mutex> lock(mutex_);
1580 if (pageRouteStack_.empty()) {
1581 return INVALID_PAGE_ID;
1582 }
1583 return pageRouteStack_.back().pageId;
1584 }
1585
GetRunningPageUrl() const1586 std::string PluginFrontendDelegate::GetRunningPageUrl() const
1587 {
1588 std::lock_guard<std::mutex> lock(mutex_);
1589 if (pageRouteStack_.empty()) {
1590 return std::string();
1591 }
1592 const auto& pageUrl = pageRouteStack_.back().url;
1593 auto pos = pageUrl.rfind(".js");
1594 if (pos == pageUrl.length() - JS_HEADER_OFFSET) {
1595 return pageUrl.substr(0, pos);
1596 }
1597 return pageUrl;
1598 }
1599
GetPageIdByUrl(const std::string & url)1600 int32_t PluginFrontendDelegate::GetPageIdByUrl(const std::string& url)
1601 {
1602 std::lock_guard<std::mutex> lock(mutex_);
1603 auto pageIter = std::find_if(std::rbegin(pageRouteStack_), std::rend(pageRouteStack_),
1604 [&url](const PageInfo& pageRoute) { return url == pageRoute.url; });
1605 if (pageIter != std::rend(pageRouteStack_)) {
1606 LOGW("GetPageIdByUrl pageId=%{private}d url=%{private}s", pageIter->pageId, url.c_str());
1607 return pageIter->pageId;
1608 }
1609 return INVALID_PAGE_ID;
1610 }
1611
GetPage(int32_t pageId) const1612 RefPtr<JsAcePage> PluginFrontendDelegate::GetPage(int32_t pageId) const
1613 {
1614 std::lock_guard<std::mutex> lock(mutex_);
1615 auto itPage = pageMap_.find(pageId);
1616 if (itPage == pageMap_.end()) {
1617 LOGE("the page is not in the map");
1618 return nullptr;
1619 }
1620 return itPage->second;
1621 }
1622
RegisterFont(const std::string & familyName,const std::string & familySrc)1623 void PluginFrontendDelegate::RegisterFont(const std::string& familyName, const std::string& familySrc)
1624 {
1625 pipelineContextHolder_.Get()->RegisterFont(familyName, familySrc);
1626 }
1627
HandleImage(const std::string & src,std::function<void (bool,int32_t,int32_t)> && callback)1628 void PluginFrontendDelegate::HandleImage(
1629 const std::string& src, std::function<void(bool, int32_t, int32_t)>&& callback)
1630 {
1631 if (src.empty() || !callback) {
1632 return;
1633 }
1634 auto loadCallback = [jsCallback = std::move(callback), taskExecutor = taskExecutor_](
1635 bool success, int32_t width, int32_t height) {
1636 taskExecutor->PostTask(
1637 [callback = std::move(jsCallback), success, width, height] { callback(success, width, height); },
1638 TaskExecutor::TaskType::JS);
1639 };
1640 pipelineContextHolder_.Get()->TryLoadImageInfo(src, std::move(loadCallback));
1641 }
1642
PushJsCallbackToRenderNode(NodeId id,double ratio,std::function<void (bool,double)> && callback)1643 void PluginFrontendDelegate::PushJsCallbackToRenderNode(NodeId id, double ratio,
1644 std::function<void(bool, double)>&& callback)
1645 {
1646 LOGW("Not implement in declarative frontend.");
1647 }
1648
RequestAnimationFrame(const std::string & callbackId)1649 void PluginFrontendDelegate::RequestAnimationFrame(const std::string& callbackId)
1650 {
1651 CancelableCallback<void()> cancelableTask;
1652 cancelableTask.Reset([callbackId, call = requestAnimationCallback_, weak = AceType::WeakClaim(this)] {
1653 auto delegate = weak.Upgrade();
1654 if (delegate && call) {
1655 call(callbackId, delegate->GetSystemRealTime());
1656 }
1657 });
1658 animationFrameTaskMap_.try_emplace(callbackId, cancelableTask);
1659 animationFrameTaskIds_.emplace(callbackId);
1660 }
1661
GetSystemRealTime()1662 uint64_t PluginFrontendDelegate::GetSystemRealTime()
1663 {
1664 struct timespec ts;
1665 clock_gettime(CLOCK_REALTIME, &ts);
1666 return ts.tv_sec * TO_MILLI + ts.tv_nsec / NANO_TO_MILLI;
1667 }
1668
CancelAnimationFrame(const std::string & callbackId)1669 void PluginFrontendDelegate::CancelAnimationFrame(const std::string& callbackId)
1670 {
1671 auto animationTaskIter = animationFrameTaskMap_.find(callbackId);
1672 if (animationTaskIter != animationFrameTaskMap_.end()) {
1673 animationTaskIter->second.Cancel();
1674 animationFrameTaskMap_.erase(animationTaskIter);
1675 } else {
1676 LOGW("cancelAnimationFrame callbackId not found");
1677 }
1678 }
1679
FlushAnimationTasks()1680 void PluginFrontendDelegate::FlushAnimationTasks()
1681 {
1682 while (!animationFrameTaskIds_.empty()) {
1683 const auto& callbackId = animationFrameTaskIds_.front();
1684 if (!callbackId.empty()) {
1685 auto taskIter = animationFrameTaskMap_.find(callbackId);
1686 if (taskIter != animationFrameTaskMap_.end()) {
1687 taskExecutor_->PostTask(taskIter->second, TaskExecutor::TaskType::JS);
1688 }
1689 }
1690 animationFrameTaskIds_.pop();
1691 }
1692 }
1693
GetAnimationJsTask()1694 SingleTaskExecutor PluginFrontendDelegate::GetAnimationJsTask()
1695 {
1696 return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::JS);
1697 }
1698
GetUiTask()1699 SingleTaskExecutor PluginFrontendDelegate::GetUiTask()
1700 {
1701 return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::UI);
1702 }
1703
AttachPipelineContext(const RefPtr<PipelineContext> & context)1704 void PluginFrontendDelegate::AttachPipelineContext(const RefPtr<PipelineContext>& context)
1705 {
1706 context->SetOnPageShow([weak = AceType::WeakClaim(this)] {
1707 auto delegate = weak.Upgrade();
1708 if (delegate) {
1709 delegate->OnPageShow();
1710 }
1711 });
1712 context->SetAnimationCallback([weak = AceType::WeakClaim(this)] {
1713 auto delegate = weak.Upgrade();
1714 if (delegate) {
1715 delegate->FlushAnimationTasks();
1716 }
1717 });
1718 pipelineContextHolder_.Attach(context);
1719 jsAccessibilityManager_->SetPipelineContext(context);
1720 jsAccessibilityManager_->InitializeCallback();
1721 }
1722
GetPipelineContext()1723 RefPtr<PipelineContext> PluginFrontendDelegate::GetPipelineContext()
1724 {
1725 return pipelineContextHolder_.Get();
1726 }
1727 } // namespace OHOS::Ace::Framework
1728