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