• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "frameworks/bridge/card_frontend/card_frontend.h"
17 
18 #include <memory>
19 #include <vector>
20 
21 #include "base/log/event_report.h"
22 #include "base/utils/utils.h"
23 #include "core/common/thread_checker.h"
24 #include "frameworks/bridge/common/utils/utils.h"
25 
26 namespace OHOS::Ace {
27 namespace {
28 
29 const char MANIFEST_JSON[] = "manifest.json";
30 const char FILE_TYPE_JSON[] = ".json";
31 
32 } // namespace
33 
~CardFrontend()34 CardFrontend::~CardFrontend()
35 {
36     LOG_DESTROY();
37 }
38 
Initialize(FrontendType type,const RefPtr<TaskExecutor> & taskExecutor)39 bool CardFrontend::Initialize(FrontendType type, const RefPtr<TaskExecutor>& taskExecutor)
40 {
41     type_ = type;
42     taskExecutor_ = taskExecutor;
43     delegate_ = AceType::MakeRefPtr<Framework::CardFrontendDelegate>();
44     manifestParser_ = AceType::MakeRefPtr<Framework::ManifestParser>();
45     return true;
46 }
47 
Destroy()48 void CardFrontend::Destroy()
49 {
50     CHECK_RUN_ON(JS);
51     LOGI("CardFrontend Destroy begin.");
52     parseJsCard_.Reset();
53     delegate_.Reset();
54     eventHandler_.Reset();
55     LOGI("CardFrontend Destroy end.");
56 }
57 
AttachPipelineContext(const RefPtr<PipelineBase> & context)58 void CardFrontend::AttachPipelineContext(const RefPtr<PipelineBase>& context)
59 {
60     auto pipelineContext = DynamicCast<PipelineContext>(context);
61     CHECK_NULL_VOID_NOLOG(delegate_);
62     CHECK_NULL_VOID_NOLOG(pipelineContext);
63     eventHandler_ = AceType::MakeRefPtr<CardEventHandler>(delegate_);
64     pipelineContext->RegisterEventHandler(eventHandler_);
65     holder_.Attach(context);
66     delegate_->GetJsAccessibilityManager()->SetPipelineContext(context);
67     delegate_->GetJsAccessibilityManager()->InitializeCallback();
68 }
69 
SetAssetManager(const RefPtr<AssetManager> & assetManager)70 void CardFrontend::SetAssetManager(const RefPtr<AssetManager>& assetManager)
71 {
72     assetManager_ = assetManager;
73 }
74 
ParseManifest() const75 void CardFrontend::ParseManifest() const
76 {
77     std::call_once(onceFlag_, [this]() {
78         std::string jsonContent;
79         if (!Framework::GetAssetContentImpl(assetManager_, MANIFEST_JSON, jsonContent)) {
80             LOGE("RunPage parse manifest.json failed");
81             EventReport::SendFormException(FormExcepType::RUN_PAGE_ERR);
82             return;
83         }
84         manifestParser_->Parse(jsonContent);
85     });
86 }
87 
RunPage(int32_t pageId,const std::string & url,const std::string & params)88 void CardFrontend::RunPage(int32_t pageId, const std::string& url, const std::string& params)
89 {
90 
91     std::string urlPath;
92     if (GetFormSrc().empty()) {
93         ParseManifest();
94         if (!url.empty()) {
95             urlPath = manifestParser_->GetRouter()->GetPagePath(url, FILE_TYPE_JSON);
96         }
97         if (urlPath.empty()) {
98             urlPath = manifestParser_->GetRouter()->GetEntry(FILE_TYPE_JSON);
99         }
100     } else {
101         urlPath = GetFormSrcPath(GetFormSrc(), FILE_TYPE_JSON);
102     }
103     if (urlPath.empty()) {
104         LOGE("fail to run page due to path url is empty");
105         EventReport::SendFormException(FormExcepType::RUN_PAGE_ERR);
106         return;
107     }
108     taskExecutor_->PostTask(
109         [weak = AceType::WeakClaim(this), urlPath, params] {
110             auto frontend = weak.Upgrade();
111             if (frontend) {
112                 frontend->LoadPage(urlPath, params);
113             }
114         },
115         TaskExecutor::TaskType::JS);
116 }
117 
GetFormSrcPath(const std::string & uri,const std::string & suffix) const118 std::string CardFrontend::GetFormSrcPath(const std::string& uri, const std::string& suffix) const
119 {
120     if (uri.empty()) {
121         LOGW("page uri is empty");
122         return "";
123     }
124     // the case uri is starts with "/" and "/" is the mainPage
125     if (uri.size() != 0) {
126         return uri + suffix;
127     }
128 
129     LOGE("can't find this page %{private}s path", uri.c_str());
130     return "";
131 }
132 
GetPage(int32_t pageId) const133 RefPtr<AcePage> CardFrontend::GetPage(int32_t pageId) const
134 {
135     CHECK_NULL_RETURN_NOLOG(delegate_, nullptr);
136     return delegate_->GetPage();
137 }
138 
GetWindowConfig()139 WindowConfig& CardFrontend::GetWindowConfig()
140 {
141     ParseManifest();
142     if (GetFormSrc().empty()) {
143         return manifestParser_->GetWindowConfig();
144     } else {
145         return GetCardWindowConfig();
146     }
147 }
148 
LoadPage(const std::string & urlPath,const std::string & params)149 void CardFrontend::LoadPage(const std::string& urlPath, const std::string& params)
150 {
151     CHECK_RUN_ON(JS);
152     CHECK_NULL_VOID_NOLOG(delegate_);
153     auto page = delegate_->CreatePage(0, urlPath);
154     page->SetPageParams(params);
155     page->SetFlushCallback([weak = WeakClaim(this)](const RefPtr<Framework::JsAcePage>& page) {
156         auto front = weak.Upgrade();
157         if (front) {
158             front->OnPageLoaded(page);
159         }
160     });
161 
162     std::string content;
163     if (!Framework::GetAssetContentImpl(assetManager_, urlPath, content)) {
164         LOGE("Failed to load page");
165         EventReport::SendFormException(FormExcepType::LOAD_PAGE_ERR);
166         return;
167     }
168     ParsePage(holder_.Get(), content, params, page);
169 }
170 
ParsePage(const RefPtr<PipelineBase> & context,const std::string & pageContent,const std::string & params,const RefPtr<Framework::JsAcePage> & page)171 void CardFrontend::ParsePage(const RefPtr<PipelineBase>& context, const std::string& pageContent,
172     const std::string& params, const RefPtr<Framework::JsAcePage>& page)
173 {
174     CHECK_RUN_ON(JS);
175     auto rootBody = Framework::ParseFileData(pageContent);
176     CHECK_NULL_VOID(rootBody);
177 
178     const auto& rootTemplate = rootBody->GetValue("template");
179     parseJsCard_ = AceType::MakeRefPtr<Framework::JsCardParser>(context, assetManager_, std::move(rootBody));
180     if (!parseJsCard_->Initialize()) {
181         LOGE("js card parser initialize fail");
182         return;
183     }
184     parseJsCard_->SetColorMode(colorMode_);
185     parseJsCard_->SetDensity(density_);
186     parseJsCard_->LoadImageInfo();
187     parseJsCard_->SetCardHapPath(cardHapPath_);
188     parseJsCard_->CreateDomNode(page, rootTemplate, -1);
189     parseJsCard_->ResetNodeId();
190     page->FlushCommands();
191     if (!params.empty()) {
192         parseJsCard_->UpdatePageData(params, page);
193     }
194 }
195 
OnPageLoaded(const RefPtr<Framework::JsAcePage> & page)196 void CardFrontend::OnPageLoaded(const RefPtr<Framework::JsAcePage>& page)
197 {
198     CHECK_RUN_ON(JS);
199     // Pop all JS command and execute them in UI thread.
200     auto jsCommands = std::make_shared<std::vector<RefPtr<Framework::JsCommand>>>();
201     page->PopAllCommands(*jsCommands);
202     page->SetPipelineContext(holder_.Get());
203     taskExecutor_->PostTask(
204         [weak = AceType::WeakClaim(this), page, jsCommands] {
205             auto frontend = weak.Upgrade();
206             CHECK_NULL_VOID_NOLOG(frontend);
207             // Flush all JS commands.
208             for (const auto& command : *jsCommands) {
209                 command->Execute(page);
210             }
211 
212             auto pipelineContext = AceType::DynamicCast<PipelineContext>(frontend->holder_.Get());
213             CHECK_NULL_VOID(pipelineContext);
214             auto minSdk = frontend->manifestParser_->GetMinPlatformVersion();
215             pipelineContext->SetMinPlatformVersion(minSdk);
216 
217             auto document = page->GetDomDocument();
218             if (frontend->pageLoaded_) {
219                 page->ClearShowCommand();
220                 std::vector<NodeId> dirtyNodes;
221                 page->PopAllDirtyNodes(dirtyNodes);
222                 if (dirtyNodes.empty()) {
223                     return;
224                 }
225                 auto rootNodeId = dirtyNodes.front();
226                 if (rootNodeId == DOM_ROOT_NODE_ID_BASE) {
227                     auto patchComponent = page->BuildPagePatch(rootNodeId);
228                     if (patchComponent) {
229                         pipelineContext->ScheduleUpdate(patchComponent);
230                     }
231                 }
232                 if (document) {
233                     // When a component is configured with "position: fixed", there is a proxy node in root tree
234                     // instead of the real composed node. So here updates the real composed node.
235                     for (int32_t nodeId : document->GetProxyRelatedNodes()) {
236                         auto patchComponent = page->BuildPagePatch(nodeId);
237                         if (patchComponent) {
238                             pipelineContext->ScheduleUpdate(patchComponent);
239                         }
240                     }
241                 }
242                 return;
243             }
244 
245             // Just clear all dirty nodes.
246             page->ClearAllDirtyNodes();
247             if (document) {
248                 document->HandleComponentPostBinding();
249             }
250             if (pipelineContext->GetAccessibilityManager()) {
251                 pipelineContext->GetAccessibilityManager()->HandleComponentPostBinding();
252             }
253             if (pipelineContext->CanPushPage()) {
254                 pipelineContext->PushPage(page->BuildPage(page->GetUrl()));
255                 frontend->pageLoaded_ = true;
256                 if (frontend->delegate_) {
257                     frontend->delegate_->GetJsAccessibilityManager()->SetRunningPage(page);
258                 }
259             }
260         },
261         TaskExecutor::TaskType::UI);
262 }
263 
UpdateData(const std::string & dataList)264 void CardFrontend::UpdateData(const std::string& dataList)
265 {
266     taskExecutor_->PostTask(
267         [weak = AceType::WeakClaim(this), dataList] {
268             auto frontend = weak.Upgrade();
269             if (frontend) {
270                 frontend->UpdatePageData(dataList);
271             }
272         },
273         TaskExecutor::TaskType::JS);
274 }
275 
UpdatePageData(const std::string & dataList)276 void CardFrontend::UpdatePageData(const std::string& dataList)
277 {
278     CHECK_RUN_ON(JS);
279     if (!delegate_ || !parseJsCard_) {
280         LOGE("the delegate or parseJsCard is null");
281         EventReport::SendFormException(FormExcepType::UPDATE_PAGE_ERR);
282         return;
283     }
284     parseJsCard_->UpdatePageData(dataList, delegate_->GetPage());
285 }
286 
SetColorMode(ColorMode colorMode)287 void CardFrontend::SetColorMode(ColorMode colorMode)
288 {
289     taskExecutor_->PostTask(
290         [weak = AceType::WeakClaim(this), colorMode]() {
291             auto frontend = weak.Upgrade();
292             if (frontend) {
293                 frontend->colorMode_ = colorMode;
294                 if (!frontend->delegate_ || !frontend->parseJsCard_) {
295                     LOGI("the delegate is null");
296                     return;
297                 }
298                 frontend->parseJsCard_->SetColorMode(frontend->colorMode_);
299                 frontend->OnMediaFeatureUpdate();
300             } else {
301                 LOGE("card frontend is nullptr");
302             }
303         },
304         TaskExecutor::TaskType::JS);
305 }
306 
RebuildAllPages()307 void CardFrontend::RebuildAllPages()
308 {
309     CHECK_NULL_VOID(delegate_);
310     auto page = delegate_->GetPage();
311     taskExecutor_->PostTask(
312         [weakPage = WeakPtr<Framework::JsAcePage>(page)] {
313             auto page = weakPage.Upgrade();
314             CHECK_NULL_VOID_NOLOG(page);
315             auto domDoc = page->GetDomDocument();
316             CHECK_NULL_VOID_NOLOG(domDoc);
317             auto rootNode = domDoc->GetDOMNodeById(domDoc->GetRootNodeId());
318             CHECK_NULL_VOID_NOLOG(rootNode);
319             rootNode->UpdateStyleWithChildren();
320         },
321         TaskExecutor::TaskType::UI);
322 }
323 
OnSurfaceChanged(int32_t width,int32_t height)324 void CardFrontend::OnSurfaceChanged(int32_t width, int32_t height)
325 {
326     taskExecutor_->PostTask(
327         [weak = AceType::WeakClaim(this), width, height] {
328             auto frontend = weak.Upgrade();
329             if (frontend) {
330                 frontend->HandleSurfaceChanged(width, height);
331             }
332         },
333         TaskExecutor::TaskType::JS);
334 }
335 
HandleSurfaceChanged(int32_t width,int32_t height)336 void CardFrontend::HandleSurfaceChanged(int32_t width, int32_t height)
337 {
338     CHECK_RUN_ON(JS);
339     CHECK_NULL_VOID(parseJsCard_);
340     parseJsCard_->OnSurfaceChanged(width, height);
341     OnMediaFeatureUpdate();
342 }
343 
OnMediaFeatureUpdate()344 void CardFrontend::OnMediaFeatureUpdate()
345 {
346     CHECK_RUN_ON(JS);
347     CHECK_NULL_VOID(delegate_);
348     CHECK_NULL_VOID(parseJsCard_);
349     parseJsCard_->UpdateStyle(delegate_->GetPage());
350 }
351 
352 } // namespace OHOS::Ace
353