• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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/components_ng/syntax/if_else_node.h"
17 
18 #include "core/components_ng/base/frame_node.h"
19 #include "core/pipeline/base/element_register.h"
20 
21 namespace OHOS::Ace::NG {
22 
GetOrCreateIfElseNode(int32_t nodeId)23 RefPtr<IfElseNode> IfElseNode::GetOrCreateIfElseNode(int32_t nodeId)
24 {
25     auto node = ElementRegister::GetInstance()->GetSpecificItemById<IfElseNode>(nodeId);
26     if (node) {
27         return node;
28     }
29     node = MakeRefPtr<IfElseNode>(nodeId);
30     ElementRegister::GetInstance()->AddUINode(node);
31     return node;
32 }
33 
34 /* how if else works
35  * the transpiler generated JS code is like this(simplified, but main points shown)
36  * this.observeComponentCreation(..., () => {
37  * If.create();
38  * if (condition1) {
39  *    this.ifElseBranchUpdateFunction(compilerGeneratedUniqueConstBranchId, () =>
40  *          code for children first render
41  *    })
42  * } else if (condition2) {
43  *    this.ifElseBranchUpdateFunction(compilerGeneratedUniqueConstBranchId, () =>
44  *          code for children first render
45  *    })
46  * } else {
47  *    // else added by the transpiler
48  *    If.setBranchId(compilerGeneratedUniqueConstBranchId)
49  * }
50  * If.pop()
51  * - if re-renders whenever one of the variables used in 'condition' during last render has changed.
52  *      - the dependent variables can change from one render of if to the next, depending if 'condition1' and
53  *        'condition2' bind to different variables.
54  *      - If can re-render, but the branch does not change, e.g. if 'condition1' is (this.i > 20)
55  *        then If will re-render whenever i changes.
56  * - eDSL to JS traspiler generates a unique id for each branch of the code inside.
57  *   Thereby the framework can detect that the branch has actually changed.
58  *   In this case ViewPU.ifElseBranchUpdateFunction will call IfElseNode::SetBranchId to upate
59  *   and it will execute the 2nd parameter lambda function to re-generate the children.
60  * - In case of if without else, or if ... else if ... , eDSL to JS traspiler generates
61  *   an extra else clause in which to set the branchId (calls IfElseNode::SetBranchId)
62  * - IfElseNode::FlushUpdateAndMarkDirty is called upon If.Pop()
63  */
SetBranchId(int32_t value,std::list<int32_t> & removedElmtId,std::list<int32_t> & reservedElmtId)64 void IfElseNode::SetBranchId(int32_t value, std::list<int32_t>& removedElmtId, std::list<int32_t>& reservedElmtId)
65 {
66     branchIdChanged_ = (branchId_ != value);
67     TAG_LOGD(AceLogTag::ACE_IF, "IfElse(%{public}d).SetBranchId branchIdChanged_: %{public}d",
68         GetId(), branchIdChanged_);
69     if (branchIdChanged_) {
70         // collect elmtIds of all children and their children up to CustomNode object
71         // these will be removed, but possibly with a delay if their is an animation
72         // list of elmtIds is sent back to calling TS ViewPU.ifElseBranchUpdateFunction()
73         Clean(false, true, branchId_);
74         CollectCleanedChildren(GetChildren(), removedElmtId, reservedElmtId, true);
75         branchId_ = value;
76     }
77 }
78 
FlushUpdateAndMarkDirty()79 void IfElseNode::FlushUpdateAndMarkDirty()
80 {
81     if (branchIdChanged_) {
82         auto parent = GetParent();
83         int64_t accessibilityId = GetAccessibilityId();
84         if (parent) {
85             parent->NotifyChange(0, 0, accessibilityId, NotificationType::START_CHANGE_POSITION);
86         }
87         // mark parent dirty to flush measure.
88         MarkNeedFrameFlushDirty(PROPERTY_UPDATE_BY_CHILD_REQUEST);
89     }
90     branchIdChanged_ = false;
91 }
92 
TryRetake(const std::string & id)93 bool IfElseNode::TryRetake(const std::string& id)
94 {
95     auto node = GetDisappearingChildById(id, branchId_);
96     if (node) {
97         ACE_SCOPED_TRACE("IfElse TryRetake validate.");
98         node->SetJSViewActive(true);
99         AddChild(node);
100         // for geometryTransition, let all reused children call UpdateGeometryTransition.
101         LayoutProperty::UpdateAllGeometryTransition(node);
102         CollectRetakenNodes(node);
103         return true;
104     }
105     return false;
106 }
107 
CollectRetakenNodes(const RefPtr<UINode> & node)108 void IfElseNode::CollectRetakenNodes(const RefPtr<UINode>& node)
109 {
110     retakenElmtIds_.emplace_back(node->GetId());
111     if (GetTag() != V2::JS_VIEW_ETS_TAG) {
112         for (auto const& child : node->GetChildren()) {
113             CollectRetakenNodes(child);
114         }
115     }
116 }
117 
GetRetakenElmtIds(std::list<int32_t> & retakenElmtIds)118 bool IfElseNode::GetRetakenElmtIds(std::list<int32_t>& retakenElmtIds)
119 {
120     if (retakenElmtIds_.size() == 0) {
121         return false;
122     }
123     retakenElmtIds.splice(retakenElmtIds.end(), retakenElmtIds_);
124     return true;
125 }
126 
127 } // namespace OHOS::Ace::NG
128