• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "bridge/declarative_frontend/jsview/models/view_partial_update_model_impl.h"
17 
18 #include "base/memory/ace_type.h"
19 #include "base/utils/utils.h"
20 #include "bridge/declarative_frontend/view_stack_processor.h"
21 #include "core/components/grid_layout/grid_layout_item_element.h"
22 #include "core/components/ifelse/if_else_element.h"
23 #include "core/components_ng/base/view_full_update_model.h"
24 #include "core/components_v2/common/element_proxy.h"
25 #include "core/pipeline/base/component.h"
26 
27 namespace OHOS::Ace::Framework {
28 
CreateNode(NodeInfoPU && info)29 RefPtr<AceType> ViewPartialUpdateModelImpl::CreateNode(NodeInfoPU&& info)
30 {
31     ACE_SCOPED_TRACE("JSViewPartialUpdate::CreateSpecializedComponent");
32     // create component, return new something, need to set proper ID
33 
34     const auto reservedElementId = ViewStackProcessor::GetInstance()->ClaimElementId();
35     LOGD("Creating ComposedComponent with claimed elmtId %{public}d.", reservedElementId);
36     const std::string key = std::to_string(reservedElementId);
37     auto composedComponent = AceType::MakeRefPtr<ComposedComponent>(key, "view");
38     composedComponent->SetElementId(reservedElementId);
39     auto isStatic = info.isStatic;
40     if (info.updateViewIdFunc) {
41         info.updateViewIdFunc(key);
42     }
43 
44     auto renderFunction = [renderFunc = std::move(info.renderFunc), updateFunc = std::move(info.updateFunc)](
45                               const RefPtr<Component>& component) -> RefPtr<Component> {
46         auto node = renderFunc ? renderFunc() : nullptr;
47         if (updateFunc) {
48             updateFunc();
49         }
50         return AceType::DynamicCast<Component>(node);
51     };
52 
53     auto elementFunction = [renderFunction = std::move(renderFunction), nodeInfo = std::move(info)](
54                                const RefPtr<ComposedElement>& element) mutable {
55         if (nodeInfo.appearFunc) {
56             nodeInfo.appearFunc();
57         }
58         if (nodeInfo.updateNodeFunc) {
59             nodeInfo.updateNodeFunc(element);
60         }
61 
62         // add render function callback to element. when the element rebuilds due
63         // to state update it will call this callback to get the new child component.
64         if (element) {
65             element->SetRenderFunction(std::move(renderFunction));
66             element->SetRemoveFunction(std::move(nodeInfo.removeFunc));
67             if (nodeInfo.pageTransitionFunc) {
68                 auto pageTransitionFunction = [transitionFunc =
69                                                       std::move(nodeInfo.pageTransitionFunc)]() -> RefPtr<Component> {
70                     transitionFunc();
71                     auto pageTransitionComponent = ViewStackProcessor::GetInstance()->GetPageTransitionComponent();
72                     ViewStackProcessor::GetInstance()->ClearPageTransitionComponent();
73                     return pageTransitionComponent;
74                 };
75                 element->SetPageTransitionFunction(std::move(pageTransitionFunction));
76             }
77         }
78     };
79 
80     composedComponent->SetElementFunction(std::move(elementFunction));
81 
82     if (isStatic) {
83         LOGD("will mark composedComponent as static");
84         composedComponent->SetStatic();
85     }
86 
87     return composedComponent;
88 }
89 
MarkNeedUpdate(const WeakPtr<AceType> & node)90 bool ViewPartialUpdateModelImpl::MarkNeedUpdate(const WeakPtr<AceType>& node)
91 {
92     ACE_SCOPED_TRACE("JSView::MarkNeedUpdate");
93     auto weakElement = AceType::DynamicCast<ComposedElement>(node);
94     if (weakElement.Invalid()) {
95         LOGE("Invalid Element weak ref, internal error");
96         return false;
97     }
98     auto element = weakElement.Upgrade();
99     if (element) {
100         LOGD("Element %{public}d MarkDirty", element->GetElementId());
101         element->MarkDirty();
102     }
103     return true;
104 }
105 
FlushUpdateTask(const UpdateTask & task)106 void ViewPartialUpdateModelImpl::FlushUpdateTask(const UpdateTask& task)
107 {
108     const int32_t elmtId = std::get<0>(task);
109     const RefPtr<Component> outmostWrappingComponent = AceType::DynamicCast<Component>(std::get<1>(task)); // stop at
110     const RefPtr<Component> mainComponent = AceType::DynamicCast<Component>(std::get<2>(task));            // has elmtId
111 
112     ACE_DCHECK(mainComponent != nullptr);
113     ACE_DCHECK(elmtId != ElementRegister::UndefinedElementId);
114 
115     RefPtr<Element> element = ElementRegister::GetInstance()->GetElementById(elmtId);
116     if (element != nullptr) {
117         LOGD("Searching for localized update for %{public}s elmtId: %{public}d ...", AceType::TypeName(element),
118             element->GetElementId());
119         // special case, because new IfElement will be created
120         if (AceType::DynamicCast<IfElseElement>(element) != nullptr) {
121             IfElseElement::ComponentToElementLocalizedUpdate(mainComponent, element);
122         } else if (AceType::DynamicCast<GridLayoutItemElement>(element) != nullptr) {
123             // VSP::Finish returns swapped compared to reg
124             AceType::DynamicCast<SoleChildElement>(element)->LocalizedUpdateWithItemComponent(
125                 mainComponent, outmostWrappingComponent);
126         } else {
127             element->LocalizedUpdateWithComponent(mainComponent, outmostWrappingComponent);
128         }
129         return;
130     }
131 
132     auto elementProxy = ElementRegister::GetInstance()->GetElementProxyById(elmtId);
133     if (elementProxy != nullptr) {
134         elementProxy->LocalizedUpdate(mainComponent, outmostWrappingComponent);
135         return;
136     }
137 
138     LOGE("No suitable Element/ElementProxy with elmtId %{public}d found to update from %{public}s,"
139          " elmtId exists in ElementRegister "
140          "'%{public}s'.",
141         elmtId, (mainComponent ? AceType::TypeName(mainComponent) : "no Component error"),
142         (ElementRegister::GetInstance()->Exists(elmtId) ? "exists" : "missing"));
143 }
144 
FinishUpdate(const WeakPtr<AceType> & viewNode,int32_t id,std::function<void (const UpdateTask &)> && emplaceTaskFunc)145 void ViewPartialUpdateModelImpl::FinishUpdate(
146     const WeakPtr<AceType>& viewNode, int32_t id, std::function<void(const UpdateTask&)>&& emplaceTaskFunc)
147 {
148     auto componentsPair = ViewStackProcessor::GetInstance()->FinishReturnMain();
149     if ((componentsPair.first == nullptr) || (componentsPair.second == nullptr)) {
150         LOGE("outmost wrapping component is null");
151         return;
152     }
153     // chk main component componentsPair.second elmtId
154     ACE_DCHECK(componentsPair.second->GetElementId() == id);
155 
156     LOGD("Obtained %{public}s from ViewStackProcessor, to-be update Element has elmtId %{public}d. Adding to "
157          "List of Component -> Element updates on next FlushBuild",
158         AceType::TypeName(componentsPair.second), id);
159 
160     // push the result of the update function with elmtId added on the list of pending updates, triple:
161     // 0: elmtId
162     // 1: outmost wrapping Component (most keep reference until localized updates done to avoid smart pointer auto
163     // deletion!) 2: main Component
164     if (emplaceTaskFunc) {
165         emplaceTaskFunc(std::make_tuple(id, componentsPair.first, componentsPair.second));
166     }
167 
168     // FlushBuild on UI thread side
169     // will call MakeElementUpdatesToCompleteRerender
170     auto element = AceType::DynamicCast<ComposedElement>(viewNode.Upgrade());
171     if (element) {
172         element->MarkDirty();
173     } else {
174         LOGE("Internal error, element is is null");
175     }
176 }
177 
178 } // namespace OHOS::Ace::Framework
179