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