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