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 "core/pipeline/base/composed_element.h"
17
18 #include "base/log/dump_log.h"
19 #include "core/common/container.h"
20 #include "core/components/page/page_element.h"
21
22 namespace OHOS::Ace {
23
ComposedElement(const ComposeId & id)24 ComposedElement::ComposedElement(const ComposeId& id) : id_(id)
25 {
26 type_ = COMPOSED_ELEMENT;
27 }
28
Detached()29 void ComposedElement::Detached()
30 {
31 auto context = context_.Upgrade();
32 if (addedToMap_ && context) {
33 context->RemoveComposedElement(id_, AceType::Claim(this));
34 addedToMap_ = false;
35 }
36 }
37
Deactivate()38 void ComposedElement::Deactivate()
39 {
40 Detached();
41 UmountRender();
42 }
43
UmountRender()44 void ComposedElement::UmountRender()
45 {
46 for (const auto& child : children_) {
47 child->UmountRender();
48 }
49 }
50
PerformBuild()51 void ComposedElement::PerformBuild()
52 {
53 auto context = context_.Upgrade();
54 if (!context) {
55 LOGW("Invalid pipeline stop building");
56 return;
57 }
58
59 if (!addedToMap_) {
60 context->AddComposedElement(id_, AceType::Claim(this));
61 addedToMap_ = true;
62 }
63
64 auto component = HasRenderFunction() ? CallRenderFunction(component_) : BuildChild();
65
66 if (!component && Container::IsCurrentUsePartialUpdate()) {
67 // partial update re-render code path calls JSView::MakeElementUpdatesToCompleteRerender
68 // this function returns no component, ComposedElement does not require update
69 return;
70 }
71
72 auto child = children_.empty() ? nullptr : children_.front();
73 auto composedComponent = AceType::DynamicCast<ComposedComponent>(component_);
74 if (composedComponent) {
75 auto composedChild = composedComponent->GetChild();
76 if (HasRenderFunction() && composedComponent->GetNeedReserveChild()) {
77 auto flexItem = AceType::DynamicCast<SoleChildComponent>(composedChild);
78 if (flexItem) {
79 flexItem->SetChild(component);
80 UpdateChild(child, flexItem);
81 return;
82 }
83 }
84 }
85
86 UpdateChild(child, component);
87 }
88
Update()89 void ComposedElement::Update()
90 {
91 const RefPtr<ComposedComponent> compose = AceType::DynamicCast<ComposedComponent>(component_);
92 if (compose != nullptr) {
93 name_ = compose->GetName();
94 SetElementId(compose->GetElementId());
95 if (id_ != compose->GetId()) {
96 auto context = context_.Upgrade();
97 if (addedToMap_ && context != nullptr) {
98 context->RemoveComposedElement(id_, AceType::Claim(this));
99 context->AddComposedElement(compose->GetId(), AceType::Claim(this));
100 }
101 id_ = compose->GetId();
102 }
103 compose->ClearNeedUpdate();
104 }
105 if (HasPageTransitionFunction()) {
106 auto pageElement = GetPageElement();
107 if (pageElement) {
108 pageElement->SetPageTransitionFunction(std::move(pageTransitionFunction_));
109 }
110 }
111 }
112
BuildChild()113 RefPtr<Component> ComposedElement::BuildChild()
114 {
115 RefPtr<ComposedComponent> compose = AceType::DynamicCast<ComposedComponent>(component_);
116 if (compose != nullptr) {
117 return compose->GetChild();
118 }
119 return nullptr;
120 }
121
Apply(const RefPtr<Element> & child)122 void ComposedElement::Apply(const RefPtr<Element>& child)
123 {
124 if (!child) {
125 LOGE("Element child is null");
126 return;
127 }
128
129 if (!applyFunction_) {
130 LOGE("No apply function");
131 return;
132 }
133
134 if (child->GetType() == RENDER_ELEMENT) {
135 // Directly attach the RenderNode if child is RenderElement.
136 applyFunction_(AceType::DynamicCast<RenderElement>(child));
137 } else if (child->GetType() == COMPOSED_ELEMENT) {
138 // If child is ComposedElement, just set apply function.
139 RefPtr<ComposedElement> composeChild = AceType::DynamicCast<ComposedElement>(child);
140 if (composeChild) {
141 composeChild->ApplyComposed(applyFunction_);
142 }
143 }
144 }
145
ApplyChildren()146 void ComposedElement::ApplyChildren()
147 {
148 for (const auto& child : children_) {
149 Apply(child);
150 }
151 }
152
Dump()153 void ComposedElement::Dump()
154 {
155 DumpLog::GetInstance().AddDesc("name:" + name_);
156 DumpLog::GetInstance().AddDesc("id:" + id_);
157 }
158
CanUpdate(const RefPtr<Component> & newComponent)159 bool ComposedElement::CanUpdate(const RefPtr<Component>& newComponent)
160 {
161 auto compose = AceType::DynamicCast<ComposedComponent>(newComponent);
162 if (!compose) {
163 return false;
164 }
165 if (compose->GetId() == id_) {
166 return true;
167 }
168
169 // For declarative, IDs MUST equal
170 auto context = context_.Upgrade();
171 if (context && context->GetIsDeclarative()) {
172 return false;
173 }
174
175 if (children_.empty()) {
176 return true;
177 }
178 auto childComponent = compose->GetChild();
179 if (!childComponent) {
180 return true;
181 }
182 return children_.front()->CanUpdate(childComponent);
183 }
184
NeedUpdateWithComponent(const RefPtr<Component> & newComponent)185 bool ComposedElement::NeedUpdateWithComponent(const RefPtr<Component>& newComponent)
186 {
187 auto component = AceType::DynamicCast<ComposedComponent>(newComponent);
188 if (component) {
189 auto newId = component->GetId();
190 if (newId.empty()) {
191 return true;
192 }
193
194 if (component->NeedUpdate()) {
195 return true;
196 }
197
198 auto context = context_.Upgrade();
199 if (context && context->GetIsDeclarative()) {
200 return newId == id_;
201 } else {
202 return newId != id_;
203 }
204 }
205 return true;
206 }
207
UnregisterForPartialUpdates()208 void ComposedElement::UnregisterForPartialUpdates()
209 {
210 if (HasRemoveFunction()) {
211 CallRemoveFunction();
212 }
213
214 Element::UnregisterForPartialUpdates();
215 }
216
UpdateChild(const RefPtr<Element> & child,const RefPtr<Component> & newComponent)217 RefPtr<Element> ComposedElement::UpdateChild(const RefPtr<Element>& child, const RefPtr<Component>& newComponent)
218 {
219 auto context = context_.Upgrade();
220 if (!context) {
221 LOGW("Invalid pipeline stop updating");
222 return nullptr;
223 }
224
225 RefPtr<Element> newChild;
226 if (context->GetIsDeclarative()) {
227 newChild = UpdateChildWithSlot(child, newComponent, DEFAULT_ELEMENT_SLOT, GetRenderSlot());
228 } else {
229 newChild = UpdateChildWithSlot(child, newComponent, DEFAULT_ELEMENT_SLOT, DEFAULT_RENDER_SLOT);
230 }
231 countRenderNode_ = newChild ? newChild->CountRenderNode() : 0;
232 return newChild;
233 }
234
235 } // namespace OHOS::Ace
236