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