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