• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "frameworks/bridge/js_frontend/frontend_delegate_impl.h"
17 
18 #include <atomic>
19 #include <regex>
20 #include <string>
21 
22 #include "base/i18n/localization.h"
23 #include "base/log/ace_trace.h"
24 #include "base/log/event_report.h"
25 #include "base/resource/ace_res_config.h"
26 #include "base/thread/background_task_executor.h"
27 #include "base/utils/utils.h"
28 #include "base/utils/measure_util.h"
29 #include "core/common/ace_application_info.h"
30 #include "core/common/platform_bridge.h"
31 #include "core/common/thread_checker.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 
40 constexpr int32_t INVALID_PAGE_ID = -1;
41 constexpr int32_t MAX_ROUTER_STACK = 32;
42 constexpr int32_t TOAST_TIME_MAX = 10000;    // ms
43 constexpr int32_t TOAST_TIME_DEFAULT = 1500; // ms
44 constexpr int32_t MAX_PAGE_ID_SIZE = sizeof(uint64_t) * 8;
45 constexpr int32_t NANO_TO_MILLI = 1000000; // nanosecond to millisecond
46 constexpr int32_t TO_MILLI = 1000;         // second to millisecond
47 constexpr int32_t COMPATIBLE_VERSION = 7;
48 constexpr int32_t WEB_FEATURE_VERSION = 6;
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/i18n.json";
56 
57 } // namespace
58 
GenerateNextPageId()59 int32_t FrontendDelegateImpl::GenerateNextPageId()
60 {
61     for (int32_t idx = 0; idx < MAX_PAGE_ID_SIZE; ++idx) {
62         uint64_t bitMask = (1ULL << idx);
63         if ((bitMask & pageIdPool_.fetch_or(bitMask, std::memory_order_relaxed)) == 0) {
64             return idx;
65         }
66     }
67     return INVALID_PAGE_ID;
68 }
69 
RecyclePageId(int32_t pageId)70 void FrontendDelegateImpl::RecyclePageId(int32_t pageId)
71 {
72     if (pageId < 0 && pageId >= MAX_PAGE_ID_SIZE) {
73         return;
74     }
75     uint64_t bitMask = (1ULL << pageId);
76     pageIdPool_.fetch_and(~bitMask, std::memory_order_relaxed);
77 }
78 
FrontendDelegateImpl(const FrontendDelegateImplBuilder & builder)79 FrontendDelegateImpl::FrontendDelegateImpl(const FrontendDelegateImplBuilder& builder)
80     : loadJs_(builder.loadCallback), dispatcherCallback_(builder.transferCallback),
81       asyncEvent_(builder.asyncEventCallback), syncEvent_(builder.syncEventCallback),
82       externalEvent_(builder.externalEventCallback),
83       updatePage_(builder.updatePageCallback), resetStagingPage_(builder.resetStagingPageCallback),
84       destroyPage_(builder.destroyPageCallback), destroyApplication_(builder.destroyApplicationCallback),
85       updateApplicationState_(builder.updateApplicationStateCallback),
86       onStartContinuationCallBack_(builder.onStartContinuationCallBack),
87       onCompleteContinuationCallBack_(builder.onCompleteContinuationCallBack),
88       onRemoteTerminatedCallBack_(builder.onRemoteTerminatedCallBack),
89       onSaveDataCallBack_(builder.onSaveDataCallBack),
90       onRestoreDataCallBack_(builder.onRestoreDataCallBack),
91       timer_(builder.timerCallback), mediaQueryCallback_(builder.mediaQueryCallback),
92       requestAnimationCallback_(builder.requestAnimationCallback), jsCallback_(builder.jsCallback),
93       manifestParser_(AceType::MakeRefPtr<ManifestParser>()),
94       jsAccessibilityManager_(AccessibilityNodeManager::Create()),
95       mediaQueryInfo_(AceType::MakeRefPtr<MediaQueryInfo>()), taskExecutor_(builder.taskExecutor),
96       callNativeHandler_(builder.callNativeHandler)
97 {}
98 
~FrontendDelegateImpl()99 FrontendDelegateImpl::~FrontendDelegateImpl()
100 {
101     CHECK_RUN_ON(JS);
102     LOG_DESTROY();
103 }
104 
ParseManifest()105 void FrontendDelegateImpl::ParseManifest()
106 {
107     std::call_once(onceFlag_, [weak = AceType::WeakClaim(this)]() {
108         std::string jsonContent;
109         auto delegate = weak.Upgrade();
110         if (delegate) {
111             if (!delegate->GetAssetContent(MANIFEST_JSON, jsonContent)) {
112                 LOGE("RunPage parse manifest.json failed");
113                 EventReport::SendFormException(FormExcepType::RUN_PAGE_ERR);
114                 return;
115             }
116             delegate->manifestParser_->Parse(jsonContent);
117             auto task = [delegate]() {
118                 delegate->pipelineContextHolder_.Get(); // Wait until Pipeline Context is attached.
119                 delegate->manifestParser_->GetAppInfo()->ParseI18nJsonInfo();
120             };
121             delegate->taskExecutor_->PostTask(task, TaskExecutor::TaskType::JS);
122         }
123     });
124 }
125 
RunPage(const std::string & url,const std::string & params)126 void FrontendDelegateImpl::RunPage(const std::string& url, const std::string& params)
127 {
128     ACE_SCOPED_TRACE("FrontendDelegateImpl::RunPage");
129 
130     auto routerBackCallback = [weak = WeakClaim(this)](const std::string& urlPath) {
131         auto delegate = weak.Upgrade();
132         if (!delegate) {
133             return false;
134         }
135         delegate->Push(urlPath, "");
136         return true;
137     };
138     DelegateClient::GetInstance().RegisterRouterPushCallback(routerBackCallback);
139 
140     auto getWebPageUrlCallback = [weak = WeakClaim(this)](std::string& pageUrl, int32_t& pageId) {
141         auto delegate = weak.Upgrade();
142         if (!delegate) {
143             return false;
144         }
145         pageUrl = delegate->GetRunningPageUrl();
146         pageId = delegate->GetRunningPageId();
147         return true;
148     };
149     DelegateClient::GetInstance().RegisterGetWebPageUrlCallback(getWebPageUrlCallback);
150 
151     auto isPagePathInvalidCallback = [weak = WeakClaim(this)](bool& isPageEmpty) {
152         auto delegate = weak.Upgrade();
153         if (!delegate) {
154             return false;
155         }
156         isPageEmpty = delegate->GetPagePathInvalidFlag();
157         return true;
158     };
159     DelegateClient::GetInstance().RegisterIsPagePathInvalidCallback(isPagePathInvalidCallback);
160 
161     LOGD("FrontendDelegateImpl RunPage url=%{private}s", url.c_str());
162     ParseManifest();
163     if (!url.empty()) {
164         mainPagePath_ = manifestParser_->GetRouter()->GetPagePath(url);
165         if (mainPagePath_.empty()) {
166             mainPagePath_ = manifestParser_->GetRouter()->GetEntry();
167         }
168     } else {
169         mainPagePath_ = manifestParser_->GetRouter()->GetEntry();
170     }
171     LoadPage(GenerateNextPageId(), mainPagePath_, true, params);
172 }
173 
ChangeLocale(const std::string & language,const std::string & countryOrRegion)174 void FrontendDelegateImpl::ChangeLocale(const std::string& language, const std::string& countryOrRegion)
175 {
176     LOGD("JsFrontend ChangeLocale");
177     taskExecutor_->PostTask(
178         [language, countryOrRegion]() { AceApplicationInfo::GetInstance().ChangeLocale(language, countryOrRegion); },
179         TaskExecutor::TaskType::PLATFORM);
180 }
181 
GetI18nData(std::unique_ptr<JsonValue> & json)182 void FrontendDelegateImpl::GetI18nData(std::unique_ptr<JsonValue>& json)
183 {
184     auto data = JsonUtil::CreateArray(true);
185     GetConfigurationCommon(I18N_FOLDER, data);
186     auto i18nData = JsonUtil::Create(true);
187     i18nData->Put("resources", data);
188     json->Put("i18n", i18nData);
189 }
190 
GetResourceConfiguration(std::unique_ptr<JsonValue> & json)191 void FrontendDelegateImpl::GetResourceConfiguration(std::unique_ptr<JsonValue>& json)
192 {
193     auto data = JsonUtil::CreateArray(true);
194     GetConfigurationCommon(RESOURCES_FOLDER, data);
195     json->Put("resourcesConfiguration", data);
196 }
197 
GetConfigurationCommon(const std::string & filePath,std::unique_ptr<JsonValue> & data)198 void FrontendDelegateImpl::GetConfigurationCommon(const std::string& filePath, std::unique_ptr<JsonValue>& data)
199 {
200     std::vector<std::string> files;
201     if (assetManager_) {
202         assetManager_->GetAssetList(filePath, files);
203     }
204 
205     std::vector<std::string> fileNameList;
206     for (const auto& file : files) {
207         if (EndWith(file, FILE_TYPE_JSON) && !StartWith(file, STYLES_FOLDER)) {
208             std::string tmp = file.substr(0, file.size() - (sizeof(FILE_TYPE_JSON) - 1));
209             size_t pos = tmp.find_last_of("/");
210             pos = (pos == std::string::npos) ? 0 : (pos + 1);
211             fileNameList.emplace_back(tmp.substr(pos, tmp.size() - pos));
212         }
213     }
214 
215     std::vector<std::string> priorityFileName;
216     if (filePath.compare(I18N_FOLDER) == 0) {
217         auto localeTag = AceApplicationInfo::GetInstance().GetLocaleTag();
218         priorityFileName = AceResConfig::GetLocaleFallback(localeTag, fileNameList);
219     } else {
220         priorityFileName = AceResConfig::GetResourceFallback(fileNameList);
221     }
222 
223     for (const auto& fileName : priorityFileName) {
224         auto fileFullPath = filePath + fileName + std::string(FILE_TYPE_JSON);
225         std::string content;
226         if (GetAssetContent(fileFullPath, content)) {
227             auto fileData = ParseFileData(content);
228             if (fileData == nullptr) {
229                 LOGW("parse %{private}s.json i18n content failed", filePath.c_str());
230             } else {
231                 data->Put(fileData);
232             }
233         }
234     }
235 }
236 
OnJsCallback(const std::string & callbackId,const std::string & data)237 void FrontendDelegateImpl::OnJsCallback(const std::string& callbackId, const std::string& data)
238 {
239     taskExecutor_->PostTask(
240         [weak = AceType::WeakClaim(this), callbackId, args = std::move(data)] {
241             auto delegate = weak.Upgrade();
242             if (delegate) {
243                 delegate->jsCallback_(callbackId, args);
244             }
245         },
246         TaskExecutor::TaskType::JS);
247 }
248 
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher) const249 void FrontendDelegateImpl::SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) const
250 {
251     LOGD("JsFrontend SetJsMessageDispatcher");
252     taskExecutor_->PostTask([dispatcherCallback = dispatcherCallback_, dispatcher] { dispatcherCallback(dispatcher); },
253         TaskExecutor::TaskType::JS);
254 }
255 
TransferComponentResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data)256 void FrontendDelegateImpl::TransferComponentResponseData(int32_t callbackId, int32_t code, std::vector<uint8_t>&& data)
257 {
258     LOGD("JsFrontend TransferComponentResponseData");
259     WeakPtr<PipelineBase> contextWeak(pipelineContextHolder_.Get());
260     taskExecutor_->PostTask(
261         [callbackId, data = std::move(data), contextWeak]() mutable {
262             auto context = contextWeak.Upgrade();
263             if (!context) {
264                 LOGE("context is null");
265             } else if (!context->GetMessageBridge()) {
266                 LOGE("messageBridge is null");
267             } else {
268                 context->GetMessageBridge()->HandleCallback(callbackId, std::move(data));
269             }
270         },
271         TaskExecutor::TaskType::UI);
272 }
273 
TransferJsResponseData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const274 void FrontendDelegateImpl::TransferJsResponseData(int32_t callbackId, int32_t code, std::vector<uint8_t>&& data) const
275 {
276     LOGD("JsFrontend TransferJsResponseData");
277     auto weak = AceType::WeakClaim(AceType::RawPtr(groupJsBridge_));
278     taskExecutor_->PostTask([callbackId, code, data = std::move(data), weak]() mutable {
279         auto groupJsBridge = weak.Upgrade();
280         if (groupJsBridge) {
281             groupJsBridge->TriggerModuleJsCallback(callbackId, code, std::move(data));
282         }
283     }, TaskExecutor::TaskType::JS);
284 }
285 
286 #if defined(PREVIEW)
TransferJsResponseDataPreview(int32_t callbackId,int32_t code,ResponseData responseData) const287 void FrontendDelegateImpl::TransferJsResponseDataPreview(
288     int32_t callbackId, int32_t code, ResponseData responseData) const
289 {
290     LOGI("JsFrontend TransferJsResponseDataPreview");
291     auto weak = AceType::WeakClaim(AceType::RawPtr(groupJsBridge_));
292     taskExecutor_->PostTask([callbackId, code, responseData, weak]() mutable {
293         auto groupJsBridge = weak.Upgrade();
294         if (groupJsBridge) {
295             groupJsBridge->TriggerModuleJsCallbackPreview(callbackId, code, responseData);
296         }
297     }, TaskExecutor::TaskType::JS);
298 }
299 #endif
300 
TransferJsPluginGetError(int32_t callbackId,int32_t errorCode,std::string && errorMessage) const301 void FrontendDelegateImpl::TransferJsPluginGetError(
302     int32_t callbackId, int32_t errorCode, std::string&& errorMessage) const
303 {
304     LOGD("JsFrontend TransferJsPluginGetError");
305     auto weak = AceType::WeakClaim(AceType::RawPtr(groupJsBridge_));
306     taskExecutor_->PostTask([callbackId, errorCode, errorMessage = std::move(errorMessage), weak]() mutable {
307         auto groupJsBridge = weak.Upgrade();
308         if (groupJsBridge) {
309             groupJsBridge->TriggerModulePluginGetErrorCallback(callbackId, errorCode, std::move(errorMessage));
310         }
311     }, TaskExecutor::TaskType::JS);
312 }
313 
TransferJsEventData(int32_t callbackId,int32_t code,std::vector<uint8_t> && data) const314 void FrontendDelegateImpl::TransferJsEventData(int32_t callbackId, int32_t code, std::vector<uint8_t>&& data) const
315 {
316     auto weak = AceType::WeakClaim(AceType::RawPtr(groupJsBridge_));
317     taskExecutor_->PostTask([callbackId, code, data = std::move(data), weak]() mutable {
318         auto groupJsBridge = weak.Upgrade();
319         if (groupJsBridge) {
320             groupJsBridge->TriggerEventJsCallback(callbackId, code, std::move(data));
321         }
322     }, TaskExecutor::TaskType::JS);
323 }
324 
LoadPluginJsCode(std::string && jsCode) const325 void FrontendDelegateImpl::LoadPluginJsCode(std::string&& jsCode) const
326 {
327     auto weak = AceType::WeakClaim(AceType::RawPtr(groupJsBridge_));
328     taskExecutor_->PostTask([jsCode = std::move(jsCode), weak]() mutable {
329         auto groupJsBridge = weak.Upgrade();
330         if (groupJsBridge) {
331             groupJsBridge->LoadPluginJsCode(std::move(jsCode));
332         }
333     }, TaskExecutor::TaskType::JS);
334 }
335 
LoadPluginJsByteCode(std::vector<uint8_t> && jsCode,std::vector<int32_t> && jsCodeLen) const336 void FrontendDelegateImpl::LoadPluginJsByteCode(std::vector<uint8_t>&& jsCode, std::vector<int32_t>&& jsCodeLen) const
337 {
338     LOGD("JsFrontend LoadPluginJsByteCode");
339     auto weak = AceType::WeakClaim(AceType::RawPtr(groupJsBridge_));
340     taskExecutor_->PostTask([jsCode = std::move(jsCode), jsCodeLen = std::move(jsCodeLen), weak]() mutable {
341         auto groupJsBridge = weak.Upgrade();
342         if (groupJsBridge) {
343             groupJsBridge->LoadPluginJsByteCode(std::move(jsCode), std::move(jsCodeLen));
344         }
345     }, TaskExecutor::TaskType::JS);
346 }
347 
OnPageBackPress()348 bool FrontendDelegateImpl::OnPageBackPress()
349 {
350     bool result = FireSyncEvent("_root", std::string("\"clickbackitem\","), std::string(""));
351     LOGD("OnPageBackPress: jsframework callback result: %{public}d", result);
352     return result;
353 }
354 
OnActive()355 void FrontendDelegateImpl::OnActive()
356 {
357     LOGD("JsFrontend onActive");
358     FireAsyncEvent("_root", std::string("\"viewactive\",null,null"), std::string(""));
359 }
360 
OnInactive()361 void FrontendDelegateImpl::OnInactive()
362 {
363     LOGD("JsFrontend OnInactive");
364     FireAsyncEvent("_root", std::string("\"viewinactive\",null,null"), std::string(""));
365     FireAsyncEvent("_root", std::string("\"viewsuspended\",null,null"), std::string(""));
366 }
367 
OnBackGround()368 void FrontendDelegateImpl::OnBackGround()
369 {
370     OnPageHide();
371 }
372 
OnForeground()373 void FrontendDelegateImpl::OnForeground()
374 {
375     // first page show will be called by push page successfully
376     if (!isFirstNotifyShow_) {
377         OnPageShow();
378     }
379     isFirstNotifyShow_ = false;
380 }
381 
OnStartContinuation()382 bool FrontendDelegateImpl::OnStartContinuation()
383 {
384     bool ret = false;
385     taskExecutor_->PostSyncTask([weak = AceType::WeakClaim(this), &ret] {
386         auto delegate = weak.Upgrade();
387         if (delegate && delegate->onStartContinuationCallBack_) {
388             ret = delegate->onStartContinuationCallBack_();
389         }
390     }, TaskExecutor::TaskType::JS);
391     if (!ret) {
392         ret = FireSyncEvent("_root", std::string("\"onStartContinuation\","), std::string(""));
393     }
394     return ret;
395 }
396 
OnCompleteContinuation(int32_t code)397 void FrontendDelegateImpl::OnCompleteContinuation(int32_t code)
398 {
399     taskExecutor_->PostSyncTask([weak = AceType::WeakClaim(this), code] {
400         auto delegate = weak.Upgrade();
401         if (delegate && delegate->onCompleteContinuationCallBack_) {
402             delegate->onCompleteContinuationCallBack_(code);
403         }
404     }, TaskExecutor::TaskType::JS);
405     FireSyncEvent("_root", std::string("\"onCompleteContinuation\","), std::to_string(code));
406 }
407 
OnRemoteTerminated()408 void FrontendDelegateImpl::OnRemoteTerminated()
409 {
410     taskExecutor_->PostSyncTask([weak = AceType::WeakClaim(this)] {
411         auto delegate = weak.Upgrade();
412         if (delegate && delegate->onRemoteTerminatedCallBack_) {
413             delegate->onRemoteTerminatedCallBack_();
414         }
415     }, TaskExecutor::TaskType::JS);
416 }
417 
OnSaveData(std::string & data)418 void FrontendDelegateImpl::OnSaveData(std::string& data)
419 {
420     std::string savedData;
421     taskExecutor_->PostSyncTask([weak = AceType::WeakClaim(this), &savedData] {
422         auto delegate = weak.Upgrade();
423         if (delegate && delegate->onSaveDataCallBack_) {
424             delegate->onSaveDataCallBack_(savedData);
425         }
426     }, TaskExecutor::TaskType::JS);
427     if (savedData.empty()) {
428         FireSyncEvent("_root", std::string("\"onSaveData\","), std::string(""), savedData);
429     }
430     std::string pageUri = GetRunningPageUrl();
431     data = std::string("{\"url\":\"").append(pageUri).append("\",\"__remoteData\":").append(savedData).append("}");
432 }
433 
OnRestoreData(const std::string & data)434 bool FrontendDelegateImpl::OnRestoreData(const std::string& data)
435 {
436     bool ret = false;
437     taskExecutor_->PostSyncTask([weak = AceType::WeakClaim(this), &data, &ret] {
438         auto delegate = weak.Upgrade();
439         if (delegate && delegate->onRestoreDataCallBack_) {
440             ret = delegate->onRestoreDataCallBack_(data);
441         }
442     }, TaskExecutor::TaskType::JS);
443     FireSyncEvent("_root", std::string("\"onSaveData\","), data);
444     return ret;
445 }
446 
OnNewRequest(const std::string & data)447 void FrontendDelegateImpl::OnNewRequest(const std::string& data)
448 {
449     FireSyncEvent("_root", std::string("\"onNewRequest\","), data);
450 }
451 
CallPopPage()452 void FrontendDelegateImpl::CallPopPage()
453 {
454     std::lock_guard<std::mutex> lock(mutex_);
455     auto& currentPage = pageRouteStack_.back();
456     if (!pageRouteStack_.empty() && currentPage.alertCallback) {
457         backUri_ = "";
458         taskExecutor_->PostTask(
459             [context = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get()),
460                 dialogProperties = pageRouteStack_.back().dialogProperties,
461                 isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft()]() {
462                 if (context) {
463                     context->ShowDialog(dialogProperties, isRightToLeft);
464                 }
465             },
466             TaskExecutor::TaskType::UI);
467     } else {
468         PopPage();
469     }
470 }
471 
ResetStagingPage()472 void FrontendDelegateImpl::ResetStagingPage()
473 {
474     taskExecutor_->PostTask([resetStagingPage = resetStagingPage_] { resetStagingPage(); }, TaskExecutor::TaskType::JS);
475 }
476 
OnApplicationDestroy(const std::string & packageName)477 void FrontendDelegateImpl::OnApplicationDestroy(const std::string& packageName)
478 {
479     taskExecutor_->PostSyncTask(
480         [destroyApplication = destroyApplication_, packageName] { destroyApplication(packageName); },
481         TaskExecutor::TaskType::JS);
482 }
483 
OnApplicationUpdateState(const std::string & packageName,Frontend::State state)484 void FrontendDelegateImpl::OnApplicationUpdateState(const std::string& packageName, Frontend::State state)
485 {
486     taskExecutor_->PostSyncTask(
487         [updateApplication = updateApplicationState_, packageName, state] { updateApplication(packageName, state); },
488         TaskExecutor::TaskType::JS);
489 }
490 
FireAsyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)491 void FrontendDelegateImpl::FireAsyncEvent(
492     const std::string& eventId, const std::string& param, const std::string& jsonArgs)
493 {
494     LOGD("FireAsyncEvent eventId: %{public}s", eventId.c_str());
495     std::string args = param;
496     args.append(",null").append(",null"); // callback and dom changes
497     if (!jsonArgs.empty()) {
498         args.append(",").append(jsonArgs); // method args
499     }
500     taskExecutor_->PostTask(
501         [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
502             auto delegate = weak.Upgrade();
503             if (delegate) {
504                 delegate->asyncEvent_(eventId, args);
505             }
506         },
507         TaskExecutor::TaskType::JS);
508 }
509 
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs)510 bool FrontendDelegateImpl::FireSyncEvent(
511     const std::string& eventId, const std::string& param, const std::string& jsonArgs)
512 {
513     std::string resultStr;
514     FireSyncEvent(eventId, param, jsonArgs, resultStr);
515     return (resultStr == "true");
516 }
517 
FireSyncEvent(const std::string & eventId,const std::string & param,const std::string & jsonArgs,std::string & result)518 void FrontendDelegateImpl::FireSyncEvent(
519     const std::string& eventId, const std::string& param, const std::string& jsonArgs, std::string& result)
520 {
521     int32_t callbackId = callbackCnt_++;
522     std::string args = param;
523     args.append("{\"_callbackId\":\"").append(std::to_string(callbackId)).append("\"}").append(",null");
524     if (!jsonArgs.empty()) {
525         args.append(",").append(jsonArgs); // method args
526     }
527     taskExecutor_->PostSyncTask(
528         [weak = AceType::WeakClaim(this), eventId, args = std::move(args)] {
529             auto delegate = weak.Upgrade();
530             if (delegate) {
531                 delegate->syncEvent_(eventId, args);
532             }
533         },
534         TaskExecutor::TaskType::JS);
535 
536     result = jsCallBackResult_[callbackId];
537     LOGD("FireSyncEvent eventId: %{public}s, callbackId: %{public}d", eventId.c_str(), callbackId);
538     jsCallBackResult_.erase(callbackId);
539 }
540 
FireExternalEvent(const std::string & eventId,const std::string & componentId,const uint32_t nodeId,const bool isDestroy)541 void FrontendDelegateImpl::FireExternalEvent(
542     const std::string& eventId, const std::string& componentId, const uint32_t nodeId, const bool isDestroy)
543 {
544     taskExecutor_->PostSyncTask(
545         [weak = AceType::WeakClaim(this), componentId, nodeId, isDestroy] {
546             auto delegate = weak.Upgrade();
547             if (delegate) {
548                 delegate->externalEvent_(componentId, nodeId, isDestroy);
549             }
550         },
551         TaskExecutor::TaskType::JS);
552 }
553 
FireAccessibilityEvent(const AccessibilityEvent & accessibilityEvent)554 void FrontendDelegateImpl::FireAccessibilityEvent(const AccessibilityEvent& accessibilityEvent)
555 {
556     jsAccessibilityManager_->SendAccessibilityAsyncEvent(accessibilityEvent);
557 }
558 
InitializeAccessibilityCallback()559 void FrontendDelegateImpl::InitializeAccessibilityCallback()
560 {
561     jsAccessibilityManager_->InitializeCallback();
562 }
563 
564 // Start FrontendDelegate overrides.
Push(const std::string & uri,const std::string & params)565 void FrontendDelegateImpl::Push(const std::string& uri, const std::string& params)
566 {
567     Push(uri, params, nullptr);
568 }
569 
PushWithCallback(const std::string & uri,const std::string & params,const std::function<void (const std::string &,int32_t)> & errorCallback,uint32_t routerMode)570 void FrontendDelegateImpl::PushWithCallback(const std::string& uri, const std::string& params,
571     const std::function<void(const std::string&, int32_t)>& errorCallback, uint32_t routerMode)
572 {
573     Push(uri, params, errorCallback);
574 }
575 
Push(const std::string & uri,const std::string & params,const std::function<void (const std::string &,int32_t)> & errorCallback)576 void FrontendDelegateImpl::Push(const std::string& uri, const std::string& params,
577     const std::function<void(const std::string&, int32_t)>& errorCallback)
578 {
579     if (uri.empty()) {
580         LOGE("router.Push uri is empty");
581         return;
582     }
583     if (isRouteStackFull_) {
584         LOGE("the router stack has reached its max size, you can't push any more pages.");
585         EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, uri);
586         if (errorCallback != nullptr) {
587             errorCallback("The pages are pushed too much.", ERROR_CODE_PAGE_STACK_FULL);
588         }
589         return;
590     }
591     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(uri);
592     LOGD("router.Push pagePath = %{private}s", pagePath.c_str());
593     if (!pagePath.empty()) {
594         isPagePathInvalid_ = true;
595         LoadPage(GenerateNextPageId(), pagePath, false, params);
596         if (errorCallback != nullptr) {
597             errorCallback("", ERROR_CODE_NO_ERROR);
598         }
599     } else {
600         isPagePathInvalid_ = false;
601         LOGW("[Engine Log] this uri not support in route push.");
602         if (errorCallback != nullptr) {
603             errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR);
604         }
605     }
606 
607     if (taskExecutor_) {
608         taskExecutor_->PostTask(
609             [context = pipelineContextHolder_.Get(), isPagePathInvalid = isPagePathInvalid_]() {
610                 if (context) {
611                     context->NotifyIsPagePathInvalidDismiss(isPagePathInvalid);
612                 }
613             },
614             TaskExecutor::TaskType::UI);
615     }
616 }
617 
Replace(const std::string & uri,const std::string & params)618 void FrontendDelegateImpl::Replace(const std::string& uri, const std::string& params)
619 {
620     Replace(uri, params, nullptr);
621 }
622 
ReplaceWithCallback(const std::string & uri,const std::string & params,const std::function<void (const std::string &,int32_t)> & errorCallback,uint32_t routerMode)623 void FrontendDelegateImpl::ReplaceWithCallback(const std::string& uri, const std::string& params,
624     const std::function<void(const std::string&, int32_t)>& errorCallback, uint32_t routerMode)
625 {
626     Push(uri, params, errorCallback);
627 }
628 
Replace(const std::string & uri,const std::string & params,const std::function<void (const std::string &,int32_t)> & errorCallback)629 void FrontendDelegateImpl::Replace(const std::string& uri, const std::string& params,
630     const std::function<void(const std::string&, int32_t)>& errorCallback)
631 {
632     if (uri.empty()) {
633         LOGE("router.Replace uri is empty");
634         return;
635     }
636 
637     std::string pagePath = manifestParser_->GetRouter()->GetPagePath(uri);
638     LOGD("router.Replace pagePath = %{private}s", pagePath.c_str());
639     if (!pagePath.empty()) {
640         LoadReplacePage(GenerateNextPageId(), pagePath, params);
641         if (errorCallback != nullptr) {
642             errorCallback("", ERROR_CODE_NO_ERROR);
643         }
644     } else {
645         LOGW("[Engine Log] this uri not support in route replace.");
646         if (errorCallback != nullptr) {
647             errorCallback("The uri of router is not exist.", ERROR_CODE_URI_ERROR_LITE);
648         }
649     }
650 }
651 
Back(const std::string & uri,const std::string & params)652 void FrontendDelegateImpl::Back(const std::string& uri, const std::string& params)
653 {
654     auto pipelineContext = pipelineContextHolder_.Get();
655     {
656         std::lock_guard<std::mutex> lock(mutex_);
657         auto& currentPage = pageRouteStack_.back();
658         if (!pageRouteStack_.empty() && currentPage.alertCallback) {
659             backUri_ = uri;
660             backParam_ = params;
661             taskExecutor_->PostTask(
662                 [context = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get()),
663                     dialogProperties = pageRouteStack_.back().dialogProperties,
664                     isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft()]() {
665                     if (context) {
666                         context->ShowDialog(dialogProperties, isRightToLeft);
667                     }
668                 },
669                 TaskExecutor::TaskType::UI);
670             return;
671         }
672     }
673     BackImplement(uri, params);
674 }
675 
BackImplement(const std::string & uri,const std::string & params)676 void FrontendDelegateImpl::BackImplement(const std::string& uri, const std::string& params)
677 {
678     LOGD("router.Back path = %{private}s", uri.c_str());
679     if (uri.empty()) {
680         PopPage();
681     } else {
682         std::string pagePath = manifestParser_->GetRouter()->GetPagePath(uri);
683         pageId_ = GetPageIdByUrl(pagePath);
684         LOGD("router.Back pagePath = %{private}s", pagePath.c_str());
685         if (!pagePath.empty()) {
686             if (!params.empty()) {
687                 std::lock_guard<std::mutex> lock(mutex_);
688                 pageParamMap_[pageId_] = params;
689             }
690             PopToPage(pagePath);
691         } else {
692             LOGW("[Engine Log] this uri not support in route Back.");
693         }
694     }
695 
696     taskExecutor_->PostTask(
697         [context = pipelineContextHolder_.Get()]() {
698             if (context) {
699                 context->NotifyRouterBackDismiss();
700             }
701         },
702         TaskExecutor::TaskType::UI);
703 }
704 
PostponePageTransition()705 void FrontendDelegateImpl::PostponePageTransition()
706 {
707     std::lock_guard<std::mutex> lock(mutex_);
708     taskExecutor_->PostTask(
709         [context = pipelineContextHolder_.Get()]() {
710             if (context) {
711                 context->PostponePageTransition();
712             }
713         },
714         TaskExecutor::TaskType::UI);
715 }
716 
LaunchPageTransition()717 void FrontendDelegateImpl::LaunchPageTransition()
718 {
719     std::lock_guard<std::mutex> lock(mutex_);
720     taskExecutor_->PostTask(
721         [context = pipelineContextHolder_.Get()]() {
722             if (context) {
723                 context->LaunchPageTransition();
724             }
725         },
726         TaskExecutor::TaskType::UI);
727 }
728 
Clear()729 void FrontendDelegateImpl::Clear()
730 {
731     ClearInvisiblePages();
732 }
733 
GetStackSize() const734 int32_t FrontendDelegateImpl::GetStackSize() const
735 {
736     std::lock_guard<std::mutex> lock(mutex_);
737     return static_cast<int32_t>(pageRouteStack_.size());
738 }
739 
GetState(int32_t & index,std::string & name,std::string & path)740 void FrontendDelegateImpl::GetState(int32_t& index, std::string& name, std::string& path)
741 {
742     std::string url;
743     {
744         std::lock_guard<std::mutex> lock(mutex_);
745         if (pageRouteStack_.empty()) {
746             return;
747         }
748         index = static_cast<int32_t>(pageRouteStack_.size());
749         url = pageRouteStack_.back().url;
750     }
751     auto pos = url.rfind(".js");
752     if (pos == url.length() - 3) {
753         url = url.substr(0, pos);
754     }
755     pos = url.rfind("/");
756     if (pos != std::string::npos) {
757         name = url.substr(pos + 1);
758         path = url.substr(0, pos + 1);
759     }
760 }
761 
GetComponentsCount()762 size_t FrontendDelegateImpl::GetComponentsCount()
763 {
764     std::lock_guard<std::mutex> lock(mutex_);
765     if (pageRouteStack_.empty()) {
766         return 0;
767     }
768     auto itPage = pageMap_.find(pageRouteStack_.back().pageId);
769     if (itPage == pageMap_.end()) {
770         return 0;
771     }
772     auto domDoc = itPage->second->GetDomDocument();
773     if (!domDoc) {
774         return 0;
775     }
776     return domDoc->GetComponentsCount();
777 }
778 
GetParams()779 std::string FrontendDelegateImpl::GetParams()
780 {
781     if (pageParamMap_.find(pageId_) != pageParamMap_.end()) {
782         return pageParamMap_.find(pageId_)->second;
783     } else {
784         return "";
785     }
786 }
787 
TriggerPageUpdate(int32_t pageId,bool directExecute)788 void FrontendDelegateImpl::TriggerPageUpdate(int32_t pageId, bool directExecute)
789 {
790     auto page = GetPage(pageId);
791     if (!page) {
792         return;
793     }
794 
795     auto jsPage = AceType::DynamicCast<Framework::JsAcePage>(page);
796     ACE_DCHECK(jsPage);
797 
798     // Pop all JS command and execute them in UI thread.
799     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
800     jsPage->PopAllCommands(*jsCommands);
801 
802     auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
803     WeakPtr<Framework::JsAcePage> jsPageWeak(jsPage);
804     WeakPtr<PipelineContext> contextWeak(pipelineContext);
805     auto updateTask = [weak = AceType::WeakClaim(this), jsPageWeak, contextWeak, jsCommands] {
806         ACE_SCOPED_TRACE("FlushUpdateCommands");
807         auto delegate = weak.Upgrade();
808         auto jsPage = jsPageWeak.Upgrade();
809         auto context = contextWeak.Upgrade();
810         if (!delegate || !jsPage || !context) {
811             LOGE("Page update failed. page or context is null.");
812             EventReport::SendPageRouterException(PageRouterExcepType::UPDATE_PAGE_ERR);
813             return;
814         }
815         bool useLiteStyle = delegate->GetMinPlatformVersion() < COMPATIBLE_VERSION && delegate->IsUseLiteStyle();
816         context->SetUseLiteStyle(useLiteStyle);
817         jsPage->SetUseLiteStyle(useLiteStyle);
818         jsPage->SetUseBoxWrap(delegate->GetMinPlatformVersion() >= WEB_FEATURE_VERSION);
819         // Flush all JS commands.
820         for (const auto& command : *jsCommands) {
821             command->Execute(jsPage);
822         }
823         if (jsPage->GetDomDocument()) {
824             jsPage->GetDomDocument()->HandleComponentPostBinding();
825         }
826         auto accessibilityManager = context->GetAccessibilityManager();
827         if (accessibilityManager) {
828             accessibilityManager->HandleComponentPostBinding();
829         }
830 
831         jsPage->ClearShowCommand();
832         std::vector<NodeId> dirtyNodes;
833         jsPage->PopAllDirtyNodes(dirtyNodes);
834         for (auto nodeId : dirtyNodes) {
835             auto patchComponent = jsPage->BuildPagePatch(nodeId);
836             if (patchComponent) {
837                 context->ScheduleUpdate(patchComponent);
838             }
839         }
840     };
841     auto weakContext = AceType::WeakClaim(AceType::RawPtr(pipelineContext));
842     taskExecutor_->PostTask([updateTask, weakContext, directExecute]() {
843         auto pipelineContext = weakContext.Upgrade();
844         if (pipelineContext) {
845             pipelineContext->AddPageUpdateTask(std::move(updateTask), directExecute);
846         }
847     }, TaskExecutor::TaskType::UI);
848 }
849 
PostJsTask(std::function<void ()> && task)850 void FrontendDelegateImpl::PostJsTask(std::function<void()>&& task)
851 {
852     taskExecutor_->PostTask(task, TaskExecutor::TaskType::JS);
853 }
854 
PostUITask(std::function<void ()> && task)855 void FrontendDelegateImpl::PostUITask(std::function<void()>&& task)
856 {
857     taskExecutor_->PostTask(task, TaskExecutor::TaskType::UI);
858 }
859 
RemoveVisibleChangeNode(NodeId id)860 void FrontendDelegateImpl::RemoveVisibleChangeNode(NodeId id)
861 {
862     auto task = [nodeId = id, pipeline = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get())]() {
863         if (pipeline) {
864             pipeline->RemoveVisibleChangeNode(nodeId);
865         }
866     };
867     taskExecutor_->PostTask(task, TaskExecutor::TaskType::UI);
868 }
869 
GetAppID() const870 const std::string& FrontendDelegateImpl::GetAppID() const
871 {
872     return manifestParser_->GetAppInfo()->GetAppID();
873 }
874 
GetAppName() const875 const std::string& FrontendDelegateImpl::GetAppName() const
876 {
877     return manifestParser_->GetAppInfo()->GetAppName();
878 }
879 
GetVersionName() const880 const std::string& FrontendDelegateImpl::GetVersionName() const
881 {
882     return manifestParser_->GetAppInfo()->GetVersionName();
883 }
884 
GetVersionCode() const885 int32_t FrontendDelegateImpl::GetVersionCode() const
886 {
887     return manifestParser_->GetAppInfo()->GetVersionCode();
888 }
889 
GetWindowConfig()890 WindowConfig& FrontendDelegateImpl::GetWindowConfig()
891 {
892     ParseManifest();
893     return manifestParser_->GetWindowConfig();
894 }
895 
GetMinPlatformVersion()896 int32_t FrontendDelegateImpl::GetMinPlatformVersion()
897 {
898     ParseManifest();
899     return manifestParser_->GetMinPlatformVersion();
900 }
901 
IsUseLiteStyle()902 bool FrontendDelegateImpl::IsUseLiteStyle()
903 {
904     ParseManifest();
905     return manifestParser_->IsUseLiteStyle();
906 }
907 
IsWebFeature()908 bool FrontendDelegateImpl::IsWebFeature()
909 {
910     ParseManifest();
911     return manifestParser_->IsWebFeature();
912 }
913 
MeasureText(const MeasureContext & context)914 double FrontendDelegateImpl::MeasureText(const MeasureContext& context)
915 {
916     LOGD("FrontendDelegateImpl MeasureTxt.");
917     return MeasureUtil::MeasureText(context);
918 }
919 
MeasureTextSize(const MeasureContext & context)920 Size FrontendDelegateImpl::MeasureTextSize(const MeasureContext& context)
921 {
922     LOGD("FrontendDelegateImpl MeasureTxtSize.");
923     return MeasureUtil::MeasureTextSize(context);
924 }
925 
926 
ShowToast(const std::string & message,int32_t duration,const std::string & bottom)927 void FrontendDelegateImpl::ShowToast(const std::string& message, int32_t duration, const std::string& bottom)
928 {
929     LOGD("FrontendDelegateImpl ShowToast.");
930     int32_t durationTime = std::clamp(duration, TOAST_TIME_DEFAULT, TOAST_TIME_MAX);
931     auto pipelineContext = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
932     bool isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft();
933     auto weak = AceType::WeakClaim(AceType::RawPtr(pipelineContext));
934     taskExecutor_->PostTask([durationTime, message, bottom, isRightToLeft, weak] {
935         ToastComponent::GetInstance().Show(weak.Upgrade(), message, durationTime, bottom, isRightToLeft);
936     }, TaskExecutor::TaskType::UI);
937 }
938 
GetBoundingRectData(NodeId nodeId)939 Rect FrontendDelegateImpl::GetBoundingRectData(NodeId nodeId)
940 {
941     Rect rect;
942     auto task = [context = pipelineContextHolder_.Get(), nodeId, &rect]() {
943         context->GetBoundingRectData(nodeId, rect);
944     };
945     PostSyncTaskToPage(task);
946     return rect;
947 }
948 
GetInspector(NodeId nodeId)949 std::string FrontendDelegateImpl::GetInspector(NodeId nodeId)
950 {
951     std::string attrs;
952     auto task = [weak = WeakClaim(AceType::RawPtr(jsAccessibilityManager_)), nodeId, &attrs]() {
953         auto accessibilityNodeManager = weak.Upgrade();
954         if (accessibilityNodeManager) {
955             attrs = accessibilityNodeManager->GetInspectorNodeById(nodeId);
956         }
957     };
958     PostSyncTaskToPage(task);
959     return attrs;
960 }
961 
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)962 void FrontendDelegateImpl::ShowDialog(const std::string& title, const std::string& message,
963     const std::vector<ButtonInfo>& buttons, bool autoCancel, std::function<void(int32_t, int32_t)>&& callback,
964     const std::set<std::string>& callbacks)
965 {
966     if (!taskExecutor_) {
967         LOGE("task executor is null.");
968         return;
969     }
970 
971     std::unordered_map<std::string, EventMarker> callbackMarkers;
972     if (callbacks.find(COMMON_SUCCESS) != callbacks.end()) {
973         auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
974         BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(
975             successEventMarker, [callback, taskExecutor = taskExecutor_](int32_t successType) {
976                 taskExecutor->PostTask(
977                     [callback, successType]() { callback(0, successType); }, TaskExecutor::TaskType::JS);
978             });
979         callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
980     }
981 
982     if (callbacks.find(COMMON_CANCEL) != callbacks.end()) {
983         auto cancelEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
984         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
985             cancelEventMarker, [callback, taskExecutor = taskExecutor_] {
986                 taskExecutor->PostTask([callback]() { callback(1, 0); }, TaskExecutor::TaskType::JS);
987             });
988         callbackMarkers.emplace(COMMON_CANCEL, cancelEventMarker);
989     }
990 
991     if (callbacks.find(COMMON_COMPLETE) != callbacks.end()) {
992         auto completeEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
993         BackEndEventManager<void()>::GetInstance().BindBackendEvent(
994             completeEventMarker, [callback, taskExecutor = taskExecutor_] {
995                 taskExecutor->PostTask([callback]() { callback(2, 0); }, TaskExecutor::TaskType::JS);
996             });
997         callbackMarkers.emplace(COMMON_COMPLETE, completeEventMarker);
998     }
999 
1000     DialogProperties dialogProperties = {
1001         .title = title,
1002         .content = message,
1003         .autoCancel = autoCancel,
1004         .buttons = buttons,
1005         .callbacks = std::move(callbackMarkers),
1006     };
1007     WeakPtr<PipelineContext> weak = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
1008     taskExecutor_->PostTask(
1009         [weak, dialogProperties, isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft()]() {
1010             auto context = weak.Upgrade();
1011             if (context) {
1012                 context->ShowDialog(dialogProperties, isRightToLeft);
1013             }
1014         },
1015         TaskExecutor::TaskType::UI);
1016 }
1017 
ShowActionMenu(const std::string & title,const std::vector<ButtonInfo> & button,std::function<void (int32_t,int32_t)> && callback)1018 void FrontendDelegateImpl::ShowActionMenu(const std::string& title,
1019     const std::vector<ButtonInfo>& button, std::function<void(int32_t, int32_t)>&& callback)
1020 {
1021     if (!taskExecutor_) {
1022         LOGE("task executor is null.");
1023         return;
1024     }
1025 
1026     std::unordered_map<std::string, EventMarker> callbackMarkers;
1027 
1028     auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
1029     BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(
1030         successEventMarker, [callback, number = button.size(), taskExecutor = taskExecutor_](int32_t successType) {
1031             taskExecutor->PostTask(
1032                 [callback, number, successType]() {
1033                     // if callback index is larger than button's number, cancel button is selected
1034                     if (static_cast<size_t>(successType) == number) {
1035                         callback(1, 0);
1036                     } else {
1037                         callback(0, successType);
1038                     }
1039                 },
1040                 TaskExecutor::TaskType::JS);
1041         });
1042     callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
1043 
1044     auto cancelEventMarker = BackEndEventManager<void()>::GetInstance().GetAvailableMarker();
1045     BackEndEventManager<void()>::GetInstance().BindBackendEvent(
1046         cancelEventMarker, [callback, taskExecutor = taskExecutor_] {
1047             taskExecutor->PostTask([callback]() { callback(1, 0); }, TaskExecutor::TaskType::JS);
1048         });
1049     callbackMarkers.emplace(COMMON_CANCEL, cancelEventMarker);
1050 
1051     DialogProperties dialogProperties = {
1052         .title = title,
1053         .autoCancel = true,
1054         .isMenu = true,
1055         .buttons = button,
1056         .callbacks = std::move(callbackMarkers),
1057     };
1058     ButtonInfo buttonInfo = {
1059         .text = Localization::GetInstance()->GetEntryLetters("common.cancel"),
1060         .textColor = "#000000"
1061     };
1062     dialogProperties.buttons.emplace_back(buttonInfo);
1063     WeakPtr<PipelineContext> weak = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get());
1064     taskExecutor_->PostTask(
1065         [weak, dialogProperties, isRightToLeft = AceApplicationInfo::GetInstance().IsRightToLeft()]() {
1066             auto context = weak.Upgrade();
1067             if (context) {
1068                 context->ShowDialog(dialogProperties, isRightToLeft);
1069             }
1070         },
1071         TaskExecutor::TaskType::UI);
1072 }
1073 
EnableAlertBeforeBackPage(const std::string & message,std::function<void (int32_t)> && callback)1074 void FrontendDelegateImpl::EnableAlertBeforeBackPage(
1075     const std::string& message, std::function<void(int32_t)>&& callback)
1076 {
1077     if (!taskExecutor_) {
1078         LOGE("task executor is null.");
1079         return;
1080     }
1081 
1082     std::unordered_map<std::string, EventMarker> callbackMarkers;
1083     auto pipelineContext = pipelineContextHolder_.Get();
1084     auto successEventMarker = BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker();
1085     BackEndEventManager<void(int32_t)>::GetInstance().BindBackendEvent(successEventMarker,
1086         [weak = AceType::WeakClaim(this), callback, taskExecutor = taskExecutor_](int32_t successType) {
1087             taskExecutor->PostTask(
1088                 [weak, callback, successType]() {
1089                     callback(successType);
1090                     if (!successType) {
1091                         LOGI("dialog choose cancel button, can not back");
1092                         return;
1093                     }
1094                     auto delegate = weak.Upgrade();
1095                     if (!delegate) {
1096                         return;
1097                     }
1098                     delegate->BackImplement(delegate->backUri_, delegate->backParam_);
1099                 },
1100                 TaskExecutor::TaskType::JS);
1101         });
1102     callbackMarkers.emplace(COMMON_SUCCESS, successEventMarker);
1103 
1104     std::lock_guard<std::mutex> lock(mutex_);
1105     if (pageRouteStack_.empty()) {
1106         LOGE("page stack is null.");
1107         return;
1108     }
1109 
1110     auto& currentPage = pageRouteStack_.back();
1111     ClearAlertCallback(currentPage);
1112     currentPage.dialogProperties = {
1113         .content = message,
1114         .autoCancel = false,
1115         .buttons = { { .text = Localization::GetInstance()->GetEntryLetters("common.cancel"), .textColor = "" },
1116             { .text = Localization::GetInstance()->GetEntryLetters("common.ok"), .textColor = "" } },
1117         .callbacks = std::move(callbackMarkers),
1118     };
1119 }
1120 
DisableAlertBeforeBackPage()1121 void FrontendDelegateImpl::DisableAlertBeforeBackPage()
1122 {
1123     std::lock_guard<std::mutex> lock(mutex_);
1124     if (pageRouteStack_.empty()) {
1125         LOGE("page stack is null.");
1126         return;
1127     }
1128     auto& currentPage = pageRouteStack_.back();
1129     ClearAlertCallback(currentPage);
1130 }
1131 
SetCallBackResult(const std::string & callBackId,const std::string & result)1132 void FrontendDelegateImpl::SetCallBackResult(const std::string& callBackId, const std::string& result)
1133 {
1134     jsCallBackResult_.try_emplace(StringToInt(callBackId), result);
1135 }
1136 
WaitTimer(const std::string & callbackId,const std::string & delay,bool isInterval,bool isFirst)1137 void FrontendDelegateImpl::WaitTimer(
1138     const std::string& callbackId, const std::string& delay, bool isInterval, bool isFirst)
1139 {
1140     if (!isFirst) {
1141         auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1142         // If not find the callbackId in map, means this timer already was removed,
1143         // no need create a new cancelableTimer again.
1144         if (timeoutTaskIter == timeoutTaskMap_.end()) {
1145             return;
1146         }
1147     }
1148 
1149     int32_t delayTime = StringToInt(delay);
1150     // CancelableCallback class can only be executed once.
1151     CancelableCallback<void()> cancelableTimer;
1152     cancelableTimer.Reset([callbackId, delay, isInterval, call = timer_] { call(callbackId, delay, isInterval); });
1153     auto result = timeoutTaskMap_.try_emplace(callbackId, cancelableTimer);
1154     if (!result.second) {
1155         result.first->second = cancelableTimer;
1156     }
1157     taskExecutor_->PostDelayedTask(cancelableTimer, TaskExecutor::TaskType::JS, delayTime);
1158 }
1159 
ClearTimer(const std::string & callbackId)1160 void FrontendDelegateImpl::ClearTimer(const std::string& callbackId)
1161 {
1162     auto timeoutTaskIter = timeoutTaskMap_.find(callbackId);
1163     if (timeoutTaskIter != timeoutTaskMap_.end()) {
1164         timeoutTaskIter->second.Cancel();
1165         timeoutTaskMap_.erase(timeoutTaskIter);
1166     } else {
1167         LOGW("ClearTimer callbackId not found");
1168     }
1169 }
1170 
PostSyncTaskToPage(std::function<void ()> && task)1171 void FrontendDelegateImpl::PostSyncTaskToPage(std::function<void()>&& task)
1172 {
1173     pipelineContextHolder_.Get(); // Wait until Pipeline Context is attached.
1174     TriggerPageUpdate(GetRunningPageId(), true);
1175     taskExecutor_->PostSyncTask(task, TaskExecutor::TaskType::UI);
1176 }
1177 
AddTaskObserver(std::function<void ()> && task)1178 void FrontendDelegateImpl::AddTaskObserver(std::function<void()>&& task)
1179 {
1180     taskExecutor_->AddTaskObserver(std::move(task));
1181 }
1182 
RemoveTaskObserver()1183 void FrontendDelegateImpl::RemoveTaskObserver()
1184 {
1185     taskExecutor_->RemoveTaskObserver();
1186 }
1187 
GetAssetContent(const std::string & url,std::string & content)1188 bool FrontendDelegateImpl::GetAssetContent(const std::string& url, std::string& content)
1189 {
1190     return GetAssetContentImpl(assetManager_, url, content);
1191 }
1192 
GetAssetContent(const std::string & url,std::vector<uint8_t> & content)1193 bool FrontendDelegateImpl::GetAssetContent(const std::string& url, std::vector<uint8_t>& content)
1194 {
1195     return GetAssetContentImpl(assetManager_, url, content);
1196 }
1197 
GetAssetPath(const std::string & url)1198 std::string FrontendDelegateImpl::GetAssetPath(const std::string& url)
1199 {
1200     return GetAssetPathImpl(assetManager_, url);
1201 }
1202 
LoadPage(int32_t pageId,const std::string & url,bool isMainPage,const std::string & params)1203 void FrontendDelegateImpl::LoadPage(int32_t pageId, const std::string& url, bool isMainPage, const std::string& params)
1204 {
1205     LOGD("FrontendDelegateImpl LoadPage[%{private}d]: %{private}s.", pageId, url.c_str());
1206     {
1207         std::lock_guard<std::mutex> lock(mutex_);
1208         pageId_ = pageId;
1209         pageParamMap_[pageId] = params;
1210     }
1211     if (pageId == INVALID_PAGE_ID) {
1212         LOGE("FrontendDelegateImpl, invalid page id");
1213         EventReport::SendPageRouterException(PageRouterExcepType::LOAD_PAGE_ERR, url);
1214         return;
1215     }
1216     if (isStagingPageExist_) {
1217         LOGE("FrontendDelegateImpl, load page failed, waiting for current page loading finish.");
1218         RecyclePageId(pageId);
1219         return;
1220     }
1221     isStagingPageExist_ = true;
1222     auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1223     auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, url);
1224     page->SetPageParams(params);
1225     page->SetFlushCallback([weak = AceType::WeakClaim(this), isMainPage](const RefPtr<JsAcePage>& acePage) {
1226         auto delegate = weak.Upgrade();
1227         if (delegate && acePage) {
1228             delegate->FlushPageCommand(acePage, acePage->GetUrl(), isMainPage);
1229         }
1230     });
1231     taskExecutor_->PostTask(
1232         [weak = AceType::WeakClaim(this), page, url, isMainPage] {
1233             auto delegate = weak.Upgrade();
1234             if (!delegate) {
1235                 LOGE("the delegate context is nullptr");
1236                 return;
1237             }
1238             delegate->loadJs_(url, page, isMainPage);
1239             page->FlushCommands();
1240             // just make sure the pipelineContext is created.
1241             auto pipelineContext = delegate->pipelineContextHolder_.Get();
1242             if (!pipelineContext) {
1243                 LOGE("the pipeline context is nullptr");
1244                 return;
1245             }
1246             if (delegate->GetMinPlatformVersion() > 0) {
1247                 pipelineContext->SetMinPlatformVersion(delegate->GetMinPlatformVersion());
1248             }
1249             delegate->taskExecutor_->PostTask(
1250                 [weak, page] {
1251                     auto delegate = weak.Upgrade();
1252                     if (delegate && delegate->pipelineContextHolder_.Get()) {
1253                         auto context = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1254                         if (context) {
1255                             context->FlushFocus();
1256                         }
1257                     }
1258                     if (page->GetDomDocument()) {
1259                         page->GetDomDocument()->HandlePageLoadFinish();
1260                     }
1261                 },
1262                 TaskExecutor::TaskType::UI);
1263         },
1264         TaskExecutor::TaskType::JS);
1265 }
1266 
OnSurfaceChanged()1267 void FrontendDelegateImpl::OnSurfaceChanged()
1268 {
1269     if (mediaQueryInfo_->GetIsInit()) {
1270         mediaQueryInfo_->SetIsInit(false);
1271     }
1272     mediaQueryInfo_->EnsureListenerIdValid();
1273     OnMediaQueryUpdate();
1274 }
1275 
OnLayoutCompleted(const std::string & componentId)1276 void FrontendDelegateImpl::OnLayoutCompleted(const std::string& componentId) {}
1277 
OnDrawCompleted(const std::string & componentId)1278 void FrontendDelegateImpl::OnDrawCompleted(const std::string& componentId) {}
1279 
OnMediaQueryUpdate(bool isSynchronous)1280 void FrontendDelegateImpl::OnMediaQueryUpdate(bool isSynchronous)
1281 {
1282     if (mediaQueryInfo_->GetIsInit()) {
1283         return;
1284     }
1285 
1286     taskExecutor_->PostTask(
1287         [weak = AceType::WeakClaim(this)] {
1288             auto delegate = weak.Upgrade();
1289             if (!delegate) {
1290                 return;
1291             }
1292             const auto& info = delegate->mediaQueryInfo_->GetMediaQueryInfo();
1293             // request css mediaquery
1294             std::string param("\"viewsizechanged\",");
1295             param.append(info);
1296             delegate->asyncEvent_("_root", param);
1297 
1298             // request js mediaquery
1299             const auto& listenerId = delegate->mediaQueryInfo_->GetListenerId();
1300             delegate->mediaQueryCallback_(listenerId, info);
1301             delegate->mediaQueryInfo_->ResetListenerId();
1302         },
1303         TaskExecutor::TaskType::JS);
1304 }
1305 
OnPageReady(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage)1306 void FrontendDelegateImpl::OnPageReady(const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage)
1307 {
1308     LOGI("OnPageReady url = %{private}s", url.c_str());
1309     // Pop all JS command and execute them in UI thread.
1310     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1311     page->PopAllCommands(*jsCommands);
1312 
1313     auto pipelineContext = pipelineContextHolder_.Get();
1314     page->SetPipelineContext(pipelineContext);
1315     taskExecutor_->PostTask(
1316         [weak = AceType::WeakClaim(this), page, url, jsCommands, isMainPage] {
1317             auto delegate = weak.Upgrade();
1318             if (!delegate) {
1319                 return;
1320             }
1321             delegate->SetCurrentReadyPage(page);
1322             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1323             CHECK_NULL_VOID(pipelineContext);
1324             bool useLiteStyle = delegate->GetMinPlatformVersion() < COMPATIBLE_VERSION && delegate->IsUseLiteStyle();
1325             pipelineContext->SetUseLiteStyle(useLiteStyle);
1326             page->SetUseLiteStyle(useLiteStyle);
1327             page->SetUseBoxWrap(delegate->GetMinPlatformVersion() >= WEB_FEATURE_VERSION);
1328             // Flush all JS commands.
1329             for (const auto& command : *jsCommands) {
1330                 command->Execute(page);
1331             }
1332             // Just clear all dirty nodes.
1333             page->ClearAllDirtyNodes();
1334             if (page->GetDomDocument()) {
1335                 page->GetDomDocument()->HandleComponentPostBinding();
1336             }
1337             if (pipelineContext->GetAccessibilityManager()) {
1338                 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1339             }
1340             if (pipelineContext->CanPushPage()) {
1341                 if (!isMainPage) {
1342                     delegate->OnPageHide();
1343                 }
1344                 pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1345                 delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1346                     [weak, page](
1347                         const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1348                         auto delegate = weak.Upgrade();
1349                         if (delegate) {
1350                             delegate->PushPageTransitionListener(event, page);
1351                         }
1352                     });
1353                 pipelineContext->PushPage(page->BuildPage(url));
1354                 delegate->OnPushPageSuccess(page, url);
1355                 delegate->SetCurrentPage(page->GetPageId());
1356                 delegate->OnMediaQueryUpdate();
1357             } else {
1358                 // This page has been loaded but become useless now, the corresponding js instance
1359                 // must be destroyed to avoid memory leak.
1360                 delegate->OnPageDestroy(page->GetPageId());
1361                 delegate->ResetStagingPage();
1362             }
1363             delegate->isStagingPageExist_ = false;
1364         },
1365         TaskExecutor::TaskType::UI);
1366 }
1367 
PushPageTransitionListener(const TransitionEvent & event,const RefPtr<JsAcePage> & page)1368 void FrontendDelegateImpl::PushPageTransitionListener(
1369     const TransitionEvent& event, const RefPtr<JsAcePage>& page)
1370 {
1371     if (event == TransitionEvent::PUSH_END) {
1372         OnPageShow();
1373     }
1374 }
1375 
FlushPageCommand(const RefPtr<JsAcePage> & page,const std::string & url,bool isMainPage)1376 void FrontendDelegateImpl::FlushPageCommand(const RefPtr<JsAcePage>& page, const std::string& url, bool isMainPage)
1377 {
1378     if (!page) {
1379         return;
1380     }
1381     LOGI("FlushPageCommand FragmentCount(%{public}d)", page->FragmentCount());
1382     if (page->FragmentCount() == 1) {
1383         OnPageReady(page, url, isMainPage);
1384     } else {
1385         TriggerPageUpdate(page->GetPageId());
1386     }
1387 }
1388 
AddPageLocked(const RefPtr<JsAcePage> & page)1389 void FrontendDelegateImpl::AddPageLocked(const RefPtr<JsAcePage>& page)
1390 {
1391     auto result = pageMap_.try_emplace(page->GetPageId(), page);
1392     if (!result.second) {
1393         LOGW("the page has already in the map");
1394     }
1395 }
1396 
SetCurrentPage(int32_t pageId)1397 void FrontendDelegateImpl::SetCurrentPage(int32_t pageId)
1398 {
1399     LOGD("FrontendDelegateImpl SetCurrentPage pageId=%{private}d", pageId);
1400     auto page = GetPage(pageId);
1401     if (page != nullptr) {
1402         jsAccessibilityManager_->SetRunningPage(page);
1403         taskExecutor_->PostTask([updatePage = updatePage_, page] { updatePage(page); }, TaskExecutor::TaskType::JS);
1404     } else {
1405         LOGE("FrontendDelegateImpl SetCurrentPage page is null.");
1406     }
1407 }
1408 
OnPushPageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1409 void FrontendDelegateImpl::OnPushPageSuccess(const RefPtr<JsAcePage>& page, const std::string& url)
1410 {
1411     std::lock_guard<std::mutex> lock(mutex_);
1412     AddPageLocked(page);
1413     pageRouteStack_.emplace_back(PageInfo { page->GetPageId(), url });
1414     if (pageRouteStack_.size() >= MAX_ROUTER_STACK) {
1415         isRouteStackFull_ = true;
1416         EventReport::SendPageRouterException(PageRouterExcepType::PAGE_STACK_OVERFLOW_ERR, page->GetUrl());
1417     }
1418     auto pipelineContext = pipelineContextHolder_.Get();
1419     if (pipelineContext) {
1420         pipelineContext->onRouterChange(url);
1421         pipelineContext->NotifyPopPageSuccessDismiss(url, pageRouteStack_.back().pageId);
1422     }
1423     LOGI("OnPushPageSuccess size=%{private}zu,pageId=%{private}d,url=%{private}s", pageRouteStack_.size(),
1424         pageRouteStack_.back().pageId, pageRouteStack_.back().url.c_str());
1425 }
1426 
OnPopToPageSuccess(const std::string & url)1427 void FrontendDelegateImpl::OnPopToPageSuccess(const std::string& url)
1428 {
1429     std::lock_guard<std::mutex> lock(mutex_);
1430     while (!pageRouteStack_.empty()) {
1431         if (pageRouteStack_.back().url == url) {
1432             break;
1433         }
1434         OnPageDestroy(pageRouteStack_.back().pageId);
1435         pageMap_.erase(pageRouteStack_.back().pageId);
1436         pageParamMap_.erase(pageRouteStack_.back().pageId);
1437         ClearAlertCallback(pageRouteStack_.back());
1438         pageRouteStack_.pop_back();
1439     }
1440     if (isRouteStackFull_) {
1441         isRouteStackFull_ = false;
1442     }
1443     auto pipelineContext = pipelineContextHolder_.Get();
1444     if (pipelineContext) {
1445         pipelineContext->onRouterChange(url);
1446         pipelineContext->NotifyPopPageSuccessDismiss(url, pageRouteStack_.back().pageId);
1447     }
1448 }
1449 
PopToPage(const std::string & url)1450 void FrontendDelegateImpl::PopToPage(const std::string& url)
1451 {
1452     LOGD("FrontendDelegateImpl PopToPage url = %{private}s", url.c_str());
1453     taskExecutor_->PostTask(
1454         [weak = AceType::WeakClaim(this), url] {
1455             auto delegate = weak.Upgrade();
1456             if (!delegate) {
1457                 return;
1458             }
1459             auto pageId = delegate->GetPageIdByUrl(url);
1460             if (pageId == INVALID_PAGE_ID) {
1461                 return;
1462             }
1463             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1464             CHECK_NULL_VOID(pipelineContext);
1465             if (!pipelineContext->CanPopPage()) {
1466                 delegate->ResetStagingPage();
1467                 return;
1468             }
1469             delegate->OnPageHide();
1470             pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1471             delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1472                 [weak, url, pageId](
1473                     const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1474                     auto delegate = weak.Upgrade();
1475                     if (delegate) {
1476                         delegate->PopToPageTransitionListener(event, url, pageId);
1477                     }
1478                 });
1479             pipelineContext->PopToPage(pageId);
1480         },
1481         TaskExecutor::TaskType::UI);
1482 }
1483 
PopToPageTransitionListener(const TransitionEvent & event,const std::string & url,int32_t pageId)1484 void FrontendDelegateImpl::PopToPageTransitionListener(
1485     const TransitionEvent& event, const std::string& url, int32_t pageId)
1486 {
1487     if (event == TransitionEvent::POP_END) {
1488         OnPopToPageSuccess(url);
1489         SetCurrentPage(pageId);
1490         OnPageShow();
1491         OnMediaQueryUpdate();
1492     }
1493 }
1494 
OnPopPageSuccess()1495 int32_t FrontendDelegateImpl::OnPopPageSuccess()
1496 {
1497     std::lock_guard<std::mutex> lock(mutex_);
1498     pageMap_.erase(pageRouteStack_.back().pageId);
1499     pageParamMap_.erase(pageRouteStack_.back().pageId);
1500     ClearAlertCallback(pageRouteStack_.back());
1501     pageRouteStack_.pop_back();
1502     if (isRouteStackFull_) {
1503         isRouteStackFull_ = false;
1504     }
1505     if (!pageRouteStack_.empty()) {
1506         auto context = pipelineContextHolder_.Get();
1507         if (context) {
1508             context->NotifyPopPageSuccessDismiss(pageRouteStack_.back().url, pageRouteStack_.back().pageId);
1509             context->onRouterChange(pageRouteStack_.back().url);
1510         }
1511 
1512         return pageRouteStack_.back().pageId;
1513     }
1514     return INVALID_PAGE_ID;
1515 }
1516 
PopPage()1517 void FrontendDelegateImpl::PopPage()
1518 {
1519     taskExecutor_->PostTask(
1520         [weak = AceType::WeakClaim(this)] {
1521             auto delegate = weak.Upgrade();
1522             if (!delegate) {
1523                 return;
1524             }
1525             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1526             CHECK_NULL_VOID(pipelineContext);
1527             if (delegate->GetStackSize() == 1) {
1528                 if (delegate->disallowPopLastPage_) {
1529                     LOGW("Not allow back because this is the last page!");
1530                     return;
1531                 }
1532                 delegate->OnPageHide();
1533                 delegate->OnPageDestroy(delegate->GetRunningPageId());
1534                 delegate->OnPopPageSuccess();
1535                 pipelineContext->Finish();
1536                 return;
1537             }
1538             if (!pipelineContext->CanPopPage()) {
1539                 delegate->ResetStagingPage();
1540                 return;
1541             }
1542             delegate->OnPageHide();
1543             pipelineContext->RemovePageTransitionListener(delegate->pageTransitionListenerId_);
1544             delegate->pageTransitionListenerId_ = pipelineContext->AddPageTransitionListener(
1545                 [weak, destroyPageId = delegate->GetRunningPageId()](
1546                     const TransitionEvent& event, const WeakPtr<PageElement>& in, const WeakPtr<PageElement>& out) {
1547                     auto delegate = weak.Upgrade();
1548                     if (delegate) {
1549                         delegate->PopPageTransitionListener(event, destroyPageId);
1550                     }
1551                 });
1552             pipelineContext->PopPage();
1553         },
1554         TaskExecutor::TaskType::UI);
1555 }
1556 
PopPageTransitionListener(const TransitionEvent & event,int32_t destroyPageId)1557 void FrontendDelegateImpl::PopPageTransitionListener(const TransitionEvent& event, int32_t destroyPageId)
1558 {
1559     if (event == TransitionEvent::POP_END) {
1560         OnPageDestroy(destroyPageId);
1561         auto pageId = OnPopPageSuccess();
1562         SetCurrentPage(pageId);
1563         OnPageShow();
1564         OnMediaQueryUpdate();
1565     }
1566 }
1567 
OnClearInvisiblePagesSuccess()1568 int32_t FrontendDelegateImpl::OnClearInvisiblePagesSuccess()
1569 {
1570     std::lock_guard<std::mutex> lock(mutex_);
1571     PageInfo pageInfo = std::move(pageRouteStack_.back());
1572     pageRouteStack_.pop_back();
1573     for (const auto& info : pageRouteStack_) {
1574         ClearAlertCallback(info);
1575         OnPageDestroy(info.pageId);
1576         pageMap_.erase(info.pageId);
1577         pageParamMap_.erase(info.pageId);
1578     }
1579     pageRouteStack_.clear();
1580     int32_t resPageId = pageInfo.pageId;
1581     pageRouteStack_.emplace_back(std::move(pageInfo));
1582     if (isRouteStackFull_) {
1583         isRouteStackFull_ = false;
1584     }
1585     return resPageId;
1586 }
1587 
ClearInvisiblePages()1588 void FrontendDelegateImpl::ClearInvisiblePages()
1589 {
1590     std::lock_guard<std::mutex> lock(mutex_);
1591     // Execute invisible pages' OnJsEngineDestroy to release JsValue
1592     for (auto pageRouteIter = pageRouteStack_.cbegin(); pageRouteIter != pageRouteStack_.cend() - 1; ++pageRouteIter) {
1593         const auto& info = *pageRouteIter;
1594         auto iter = pageMap_.find(info.pageId);
1595         if (iter != pageMap_.end()) {
1596             auto page = iter->second;
1597             if (page) {
1598                 page->OnJsEngineDestroy();
1599             }
1600         }
1601     }
1602 
1603     taskExecutor_->PostTask(
1604         [weak = AceType::WeakClaim(this)] {
1605             auto delegate = weak.Upgrade();
1606             if (!delegate) {
1607                 return;
1608             }
1609             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1610             CHECK_NULL_VOID(pipelineContext);
1611             if (pipelineContext->ClearInvisiblePages()) {
1612                 auto pageId = delegate->OnClearInvisiblePagesSuccess();
1613                 delegate->SetCurrentPage(pageId);
1614             }
1615         },
1616         TaskExecutor::TaskType::UI);
1617 }
1618 
OnReplacePageSuccess(const RefPtr<JsAcePage> & page,const std::string & url)1619 void FrontendDelegateImpl::OnReplacePageSuccess(const RefPtr<JsAcePage>& page, const std::string& url)
1620 {
1621     if (!page) {
1622         return;
1623     }
1624     std::lock_guard<std::mutex> lock(mutex_);
1625     AddPageLocked(page);
1626     if (!pageRouteStack_.empty()) {
1627         pageMap_.erase(pageRouteStack_.back().pageId);
1628         pageParamMap_.erase(pageRouteStack_.back().pageId);
1629         ClearAlertCallback(pageRouteStack_.back());
1630         pageRouteStack_.pop_back();
1631     }
1632     pageRouteStack_.emplace_back(PageInfo { page->GetPageId(), url });
1633     auto pipelineContext = pipelineContextHolder_.Get();
1634     if (pipelineContext) {
1635         pipelineContext->onRouterChange(url);
1636         pipelineContext->NotifyPopPageSuccessDismiss(url, pageRouteStack_.back().pageId);
1637     }
1638 }
1639 
ReplacePage(const RefPtr<JsAcePage> & page,const std::string & url)1640 void FrontendDelegateImpl::ReplacePage(const RefPtr<JsAcePage>& page, const std::string& url)
1641 {
1642     LOGI("ReplacePage url = %{private}s", url.c_str());
1643     // Pop all JS command and execute them in UI thread.
1644     auto jsCommands = std::make_shared<std::vector<RefPtr<JsCommand>>>();
1645     page->PopAllCommands(*jsCommands);
1646 
1647     auto pipelineContext = pipelineContextHolder_.Get();
1648     page->SetPipelineContext(pipelineContext);
1649     taskExecutor_->PostTask(
1650         [weak = AceType::WeakClaim(this), page, url, jsCommands] {
1651             auto delegate = weak.Upgrade();
1652             if (!delegate) {
1653                 return;
1654             }
1655             delegate->SetCurrentReadyPage(page);
1656             auto pipelineContext = AceType::DynamicCast<PipelineContext>(delegate->pipelineContextHolder_.Get());
1657             CHECK_NULL_VOID(pipelineContext);
1658             bool useLiteStyle = delegate->GetMinPlatformVersion() < COMPATIBLE_VERSION && delegate->IsUseLiteStyle();
1659             pipelineContext->SetUseLiteStyle(useLiteStyle);
1660             page->SetUseLiteStyle(useLiteStyle);
1661             page->SetUseBoxWrap(delegate->GetMinPlatformVersion() >= WEB_FEATURE_VERSION);
1662             // Flush all JS commands.
1663             for (const auto& command : *jsCommands) {
1664                 command->Execute(page);
1665             }
1666             // Just clear all dirty nodes.
1667             page->ClearAllDirtyNodes();
1668             page->GetDomDocument()->HandleComponentPostBinding();
1669             if (pipelineContext->GetAccessibilityManager()) {
1670                 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
1671             }
1672             if (pipelineContext->CanReplacePage()) {
1673                 delegate->OnPageHide();
1674                 delegate->OnPageDestroy(delegate->GetRunningPageId());
1675                 pipelineContext->ReplacePage(page->BuildPage(url));
1676                 delegate->OnReplacePageSuccess(page, url);
1677                 delegate->SetCurrentPage(page->GetPageId());
1678                 delegate->OnPageShow();
1679                 delegate->OnMediaQueryUpdate();
1680             } else {
1681                 // This page has been loaded but become useless now, the corresponding js instance
1682                 // must be destroyed to avoid memory leak.
1683                 delegate->OnPageDestroy(page->GetPageId());
1684                 delegate->ResetStagingPage();
1685             }
1686             delegate->isStagingPageExist_ = false;
1687         },
1688         TaskExecutor::TaskType::UI);
1689 }
1690 
LoadReplacePage(int32_t pageId,const std::string & url,const std::string & params)1691 void FrontendDelegateImpl::LoadReplacePage(int32_t pageId, const std::string& url, const std::string& params)
1692 {
1693     LOGD("FrontendDelegateImpl LoadReplacePage[%{private}d]: %{private}s.", pageId, url.c_str());
1694     {
1695         std::lock_guard<std::mutex> lock(mutex_);
1696         pageId_ = pageId;
1697         pageParamMap_[pageId] = params;
1698     }
1699     if (pageId == INVALID_PAGE_ID) {
1700         LOGE("FrontendDelegateImpl, invalid page id");
1701         EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1702         return;
1703     }
1704     if (isStagingPageExist_) {
1705         LOGE("FrontendDelegateImpl, replace page failed, waiting for current page loading finish.");
1706         EventReport::SendPageRouterException(PageRouterExcepType::REPLACE_PAGE_ERR, url);
1707         return;
1708     }
1709     isStagingPageExist_ = true;
1710     auto document = AceType::MakeRefPtr<DOMDocument>(pageId);
1711     auto page = AceType::MakeRefPtr<JsAcePage>(pageId, document, url);
1712     page->SetPageParams(params);
1713     taskExecutor_->PostTask(
1714         [page, url, weak = AceType::WeakClaim(this)] {
1715             auto delegate = weak.Upgrade();
1716             if (delegate) {
1717                 delegate->loadJs_(url, page, false);
1718                 delegate->ReplacePage(page, url);
1719             }
1720         },
1721         TaskExecutor::TaskType::JS);
1722 }
1723 
RebuildAllPages()1724 void FrontendDelegateImpl::RebuildAllPages()
1725 {
1726     std::unordered_map<int32_t, RefPtr<JsAcePage>> pages;
1727     {
1728         std::lock_guard<std::mutex> lock(mutex_);
1729         pages.insert(pageMap_.begin(), pageMap_.end());
1730     }
1731     for (const auto& [pageId, page] : pages) {
1732         taskExecutor_->PostTask(
1733             [weakPage = WeakPtr<JsAcePage>(page)] {
1734                 auto page = weakPage.Upgrade();
1735                 if (!page) {
1736                     return;
1737                 }
1738                 auto domDoc = page->GetDomDocument();
1739                 if (!domDoc) {
1740                     return;
1741                 }
1742                 auto rootNode = domDoc->GetDOMNodeById(domDoc->GetRootNodeId());
1743                 if (!rootNode) {
1744                     return;
1745                 }
1746                 rootNode->UpdateStyleWithChildren();
1747             },
1748             TaskExecutor::TaskType::UI);
1749     }
1750 }
1751 
OnPageShow()1752 void FrontendDelegateImpl::OnPageShow()
1753 {
1754     FireAsyncEvent("_root", std::string("\"viewappear\",null,null"), std::string(""));
1755 }
1756 
OnPageHide()1757 void FrontendDelegateImpl::OnPageHide()
1758 {
1759     FireAsyncEvent("_root", std::string("\"viewdisappear\",null,null"), std::string(""));
1760 }
1761 
OnConfigurationUpdated(const std::string & configurationData)1762 void FrontendDelegateImpl::OnConfigurationUpdated(const std::string& configurationData)
1763 {
1764     FireSyncEvent("_root", std::string("\"onConfigurationUpdated\","), configurationData);
1765 }
1766 
ClearAlertCallback(PageInfo pageInfo)1767 void FrontendDelegateImpl::ClearAlertCallback(PageInfo pageInfo)
1768 {
1769     if (pageInfo.alertCallback) {
1770         // notify to clear js reference
1771         pageInfo.alertCallback(static_cast<int32_t>(AlertState::RECOVERY));
1772         pageInfo.alertCallback = nullptr;
1773     }
1774 }
1775 
OnPageDestroy(int32_t pageId)1776 void FrontendDelegateImpl::OnPageDestroy(int32_t pageId)
1777 {
1778     taskExecutor_->PostTask(
1779         [weak = AceType::WeakClaim(this), pageId] {
1780             auto delegate = weak.Upgrade();
1781             if (delegate) {
1782                 auto iter = delegate->pageMap_.find(pageId);
1783                 if (iter != delegate->pageMap_.end()) {
1784                     auto page = iter->second;
1785                     if (page) {
1786                         page->OnJsEngineDestroy();
1787                     }
1788                 }
1789                 delegate->destroyPage_(pageId);
1790                 delegate->RecyclePageId(pageId);
1791             }
1792         },
1793         TaskExecutor::TaskType::JS);
1794 }
1795 
GetRunningPageId() const1796 int32_t FrontendDelegateImpl::GetRunningPageId() const
1797 {
1798     std::lock_guard<std::mutex> lock(mutex_);
1799     if (pageRouteStack_.empty()) {
1800         return INVALID_PAGE_ID;
1801     }
1802     return pageRouteStack_.back().pageId;
1803 }
1804 
GetRunningPageUrl() const1805 std::string FrontendDelegateImpl::GetRunningPageUrl() const
1806 {
1807     std::lock_guard<std::mutex> lock(mutex_);
1808     if (pageRouteStack_.empty()) {
1809         return std::string();
1810     }
1811     const auto& pageUrl = pageRouteStack_.back().url;
1812     auto pos = pageUrl.rfind(".js");
1813     if (pos == pageUrl.length() - 3) {
1814         return pageUrl.substr(0, pos);
1815     }
1816     return pageUrl;
1817 }
1818 
GetPageIdByUrl(const std::string & url)1819 int32_t FrontendDelegateImpl::GetPageIdByUrl(const std::string& url)
1820 {
1821     std::lock_guard<std::mutex> lock(mutex_);
1822     auto pageIter = std::find_if(std::rbegin(pageRouteStack_), std::rend(pageRouteStack_),
1823         [&url](const PageInfo& pageRoute) { return url == pageRoute.url; });
1824     if (pageIter != std::rend(pageRouteStack_)) {
1825         LOGD("GetPageIdByUrl pageId=%{private}d url=%{private}s", pageIter->pageId, url.c_str());
1826         return pageIter->pageId;
1827     }
1828     return INVALID_PAGE_ID;
1829 }
1830 
GetPage(int32_t pageId) const1831 RefPtr<JsAcePage> FrontendDelegateImpl::GetPage(int32_t pageId) const
1832 {
1833     std::lock_guard<std::mutex> lock(mutex_);
1834     auto itPage = pageMap_.find(pageId);
1835     if (itPage == pageMap_.end()) {
1836         LOGE("the page is not in the map");
1837         return nullptr;
1838     }
1839     return itPage->second;
1840 }
1841 
RegisterFont(const std::string & familyName,const std::string & familySrc)1842 void FrontendDelegateImpl::RegisterFont(const std::string& familyName, const std::string& familySrc)
1843 {
1844     pipelineContextHolder_.Get()->RegisterFont(familyName, familySrc);
1845 }
1846 
GetSystemFontList(std::vector<std::string> & fontList)1847 void FrontendDelegateImpl::GetSystemFontList(std::vector<std::string>& fontList)
1848 {
1849     pipelineContextHolder_.Get()->GetSystemFontList(fontList);
1850 }
1851 
GetSystemFont(const std::string & fontName,FontInfo & fontInfo)1852 bool FrontendDelegateImpl::GetSystemFont(const std::string& fontName, FontInfo& fontInfo)
1853 {
1854     return pipelineContextHolder_.Get()->GetSystemFont(fontName, fontInfo);
1855 }
1856 
HandleImage(const std::string & src,std::function<void (bool,int32_t,int32_t)> && callback)1857 void FrontendDelegateImpl::HandleImage(const std::string& src, std::function<void(bool, int32_t, int32_t)>&& callback)
1858 {
1859     if (src.empty() || !callback) {
1860         return;
1861     }
1862     auto loadCallback = [jsCallback = std::move(callback), taskExecutor = taskExecutor_](
1863                             bool success, int32_t width, int32_t height) {
1864         taskExecutor->PostTask(
1865             [callback = std::move(jsCallback), success, width, height] { callback(success, width, height); },
1866             TaskExecutor::TaskType::JS);
1867     };
1868     pipelineContextHolder_.Get()->TryLoadImageInfo(src, std::move(loadCallback));
1869 }
1870 
RequestAnimationFrame(const std::string & callbackId)1871 void FrontendDelegateImpl::RequestAnimationFrame(const std::string& callbackId)
1872 {
1873     CancelableCallback<void()> cancelableTask;
1874     cancelableTask.Reset([callbackId, call = requestAnimationCallback_, weak = AceType::WeakClaim(this)] {
1875         auto delegate = weak.Upgrade();
1876         if (delegate && call) {
1877             call(callbackId, delegate->GetSystemRealTime());
1878         }
1879     });
1880     animationFrameTaskMap_.try_emplace(callbackId, cancelableTask);
1881     animationFrameTaskIds_.emplace(callbackId);
1882 }
1883 
GetSystemRealTime()1884 uint64_t FrontendDelegateImpl::GetSystemRealTime()
1885 {
1886     struct timespec ts;
1887     clock_gettime(CLOCK_REALTIME, &ts);
1888     return ts.tv_sec * TO_MILLI + ts.tv_nsec / NANO_TO_MILLI;
1889 }
1890 
CancelAnimationFrame(const std::string & callbackId)1891 void FrontendDelegateImpl::CancelAnimationFrame(const std::string& callbackId)
1892 {
1893     auto animationTaskIter = animationFrameTaskMap_.find(callbackId);
1894     if (animationTaskIter != animationFrameTaskMap_.end()) {
1895         animationTaskIter->second.Cancel();
1896         animationFrameTaskMap_.erase(animationTaskIter);
1897     } else {
1898         LOGW("cancelAnimationFrame callbackId not found");
1899     }
1900 }
1901 
FlushAnimationTasks()1902 void FrontendDelegateImpl::FlushAnimationTasks()
1903 {
1904     while (!animationFrameTaskIds_.empty()) {
1905         const auto& callbackId = animationFrameTaskIds_.front();
1906         if (!callbackId.empty()) {
1907             auto taskIter = animationFrameTaskMap_.find(callbackId);
1908             if (taskIter != animationFrameTaskMap_.end()) {
1909                 taskExecutor_->PostTask(taskIter->second, TaskExecutor::TaskType::JS);
1910             }
1911         }
1912         animationFrameTaskIds_.pop();
1913     }
1914 
1915     auto pageId = GetRunningPageId();
1916     auto page = GetPage(pageId);
1917     if (!page) {
1918         return;
1919     }
1920     auto jsPage = AceType::DynamicCast<Framework::JsAcePage>(page);
1921     if (jsPage && jsPage->GetCommandSize() > 0) {
1922         TriggerPageUpdate(pageId);
1923     }
1924 }
1925 
GetAnimationJsTask()1926 SingleTaskExecutor FrontendDelegateImpl::GetAnimationJsTask()
1927 {
1928     return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::JS);
1929 }
1930 
GetUiTask()1931 SingleTaskExecutor FrontendDelegateImpl::GetUiTask()
1932 {
1933     return SingleTaskExecutor::Make(taskExecutor_, TaskExecutor::TaskType::UI);
1934 }
1935 
AttachPipelineContext(const RefPtr<PipelineBase> & context)1936 void FrontendDelegateImpl::AttachPipelineContext(const RefPtr<PipelineBase>& context)
1937 {
1938     context->SetOnPageShow([weak = AceType::WeakClaim(this)] {
1939         auto delegate = weak.Upgrade();
1940         if (delegate) {
1941             delegate->OnPageShow();
1942         }
1943     });
1944     context->SetAnimationCallback([weak = AceType::WeakClaim(this)] {
1945         auto delegate = weak.Upgrade();
1946         if (delegate) {
1947             delegate->FlushAnimationTasks();
1948         }
1949     });
1950     pipelineContextHolder_.Attach(context);
1951     jsAccessibilityManager_->SetPipelineContext(context);
1952     jsAccessibilityManager_->InitializeCallback();
1953 }
1954 
GetPipelineContext()1955 RefPtr<PipelineBase> FrontendDelegateImpl::GetPipelineContext()
1956 {
1957     return pipelineContextHolder_.Get();
1958 }
1959 
SetColorMode(ColorMode colorMode)1960 void FrontendDelegateImpl::SetColorMode(ColorMode colorMode)
1961 {
1962     mediaQueryInfo_->EnsureListenerIdValid();
1963     OnMediaQueryUpdate();
1964 }
1965 
LoadResourceConfiguration(std::map<std::string,std::string> & mediaResourceFileMap,std::unique_ptr<JsonValue> & currentResourceData)1966 void FrontendDelegateImpl::LoadResourceConfiguration(std::map<std::string, std::string>& mediaResourceFileMap,
1967     std::unique_ptr<JsonValue>& currentResourceData)
1968 {
1969     std::vector<std::string> files;
1970     if (assetManager_) {
1971         assetManager_->GetAssetList(RESOURCES_FOLDER, files);
1972     }
1973 
1974     std::set<std::string> resourceFolderName;
1975     for (const auto& file : files) {
1976         resourceFolderName.insert(file.substr(0, file.find_first_of("/")));
1977     }
1978 
1979     std::vector<std::string> sortedResourceFolderPath =
1980         AceResConfig::GetDeclarativeResourceFallback(resourceFolderName);
1981     for (const auto& folderName : sortedResourceFolderPath) {
1982         auto fileFullPath = std::string(RESOURCES_FOLDER) + folderName + std::string(I18N_FILE_SUFFIX);
1983         std::string content;
1984         if (GetAssetContent(fileFullPath, content)) {
1985             auto fileData = ParseFileData(content);
1986             if (fileData == nullptr) {
1987                 LOGW("parse %{private}s i18n content failed", fileFullPath.c_str());
1988             } else {
1989                 currentResourceData->Put(fileData);
1990             }
1991         }
1992     }
1993 
1994     std::set<std::string> mediaFileName;
1995     for (const auto& file : files) {
1996         auto mediaPathName = file.substr(file.find_first_of("/"));
1997         std::regex mediaPattern("^\\/media\\/\\w*(\\.jpg|\\.png|\\.gif|\\.svg|\\.webp|\\.bmp)$");
1998         std::smatch result;
1999         if (std::regex_match(mediaPathName, result, mediaPattern)) {
2000             mediaFileName.insert(mediaPathName.substr(mediaPathName.find_first_of("/")));
2001         }
2002     }
2003 
2004     auto currentResTag = AceResConfig::GetCurrentDeviceResTag();
2005     auto currentResolutionTag = currentResTag.substr(currentResTag.find_last_of("-") + 1);
2006     for (auto folderName : sortedResourceFolderPath) {
2007         for (auto fileName : mediaFileName) {
2008             if (mediaResourceFileMap.find(fileName) != mediaResourceFileMap.end()) {
2009                 continue;
2010             }
2011             auto fullFileName = folderName + fileName;
2012             if (std::find(files.begin(), files.end(), fullFileName) != files.end()) {
2013                 mediaResourceFileMap.emplace(fileName.substr(fileName.find_last_of("/") + 1),
2014                     std::string(RESOURCES_FOLDER).append(fullFileName));
2015             }
2016         }
2017         if (mediaResourceFileMap.size() == mediaFileName.size()) {
2018             break;
2019         }
2020     }
2021 }
2022 
PushJsCallbackToRenderNode(NodeId id,double ratio,std::function<void (bool,double)> && callback)2023 void FrontendDelegateImpl::PushJsCallbackToRenderNode(NodeId id, double ratio,
2024     std::function<void(bool, double)>&& callback)
2025 {
2026     auto visibleCallback = [jsCallback = std::move(callback), executor = taskExecutor_] (bool visible, double ratio) {
2027         executor->PostTask([task = std::move(jsCallback), visible, ratio] {
2028             if (task) {
2029                 task(visible, ratio);
2030             }
2031         }, TaskExecutor::TaskType::JS);
2032     };
2033     auto uiPushTask = [id, ratio, visibleCallback,
2034                           pipeline = AceType::DynamicCast<PipelineContext>(pipelineContextHolder_.Get())]() {
2035         if (pipeline) {
2036             pipeline->PushVisibleCallback(id, ratio, visibleCallback);
2037         }
2038     };
2039     taskExecutor_->PostTask(uiPushTask, TaskExecutor::TaskType::UI);
2040 }
2041 
CallNativeHandler(const std::string & event,const std::string & params)2042 void FrontendDelegateImpl::CallNativeHandler(const std::string& event, const std::string& params)
2043 {
2044     if (callNativeHandler_ != nullptr) {
2045         callNativeHandler_(event, params);
2046     }
2047 }
2048 
2049 } // namespace OHOS::Ace::Framework
2050