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