1 /*
2  * Copyright (c) 2021-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 #ifndef FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_VIEW_STACK_PROCESSOR_H
17 #define FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_VIEW_STACK_PROCESSOR_H
18 
19 #include <memory>
20 #include <stack>
21 #include <unordered_map>
22 #include <vector>
23 
24 #include "core/accessibility/accessibility_node.h"
25 #include "core/components/common/properties/animation_option.h"
26 #include "core/components/grid_layout/grid_layout_component.h"
27 #include "core/pipeline/base/component.h"
28 #include "frameworks/core/components/box/box_component.h"
29 #include "frameworks/core/components/checkable/radio_group_component.h"
30 #include "frameworks/core/components/coverage/coverage_component.h"
31 #include "frameworks/core/components/display/display_component.h"
32 #include "frameworks/core/components/flex/flex_item_component.h"
33 #include "frameworks/core/components/focusable/focusable_component.h"
34 #include "frameworks/core/components/gesture_listener/gesture_component.h"
35 #include "frameworks/core/components/gesture_listener/gesture_listener_component.h"
36 #include "frameworks/core/components/menu/menu_component.h"
37 #include "frameworks/core/components/mouse_listener/mouse_listener_component.h"
38 #include "frameworks/core/components/navigation_bar/navigation_container_component.h"
39 #include "frameworks/core/components/page_transition/page_transition_component.h"
40 #include "frameworks/core/components/scroll/scroll_component.h"
41 #include "frameworks/core/components/stepper/stepper_item_component.h"
42 #ifndef WEARABLE_PRODUCT
43 #include "frameworks/core/components/popup/popup_component_v2.h"
44 #endif
45 #include "core/pipeline/base/element_register.h"
46 #include "frameworks/core/components/positioned/positioned_component.h"
47 #include "frameworks/core/components/shared_transition/shared_transition_component.h"
48 #include "frameworks/core/components/touch_listener/touch_listener_component.h"
49 #include "frameworks/core/components/transform/transform_component.h"
50 #include "frameworks/core/components_v2/inspector/inspector_composed_component.h"
51 
52 namespace OHOS::Ace::Framework {
53     using JsPageRadioGroups = std::unordered_map<std::string, RadioGroupComponent<std::string>>;
54     using JsPageCheckboxGroups = std::unordered_map<std::string, RefPtr<CheckboxComponent>>;
55 
56 class ViewStackProcessor final {
57 public:
58     using SaveComponentEvent = std::function<void(std::unordered_map<std::string, RefPtr<Component>>)>;
59     friend class ScopedViewStackProcessor;
60 
61     ACE_FORCE_EXPORT static ViewStackProcessor* GetInstance();
62     ~ViewStackProcessor() = default;
63     // possible wrapping components
64     RefPtr<FlexItemComponent> GetFlexItemComponent();
65     RefPtr<StepperItemComponent> GetStepperItemComponent();
66     RefPtr<DisplayComponent> GetStepperDisplayComponent();
67     RefPtr<ScrollComponent> GetStepperScrollComponent();
68     RefPtr<BoxComponent> GetBoxComponent();
69     RefPtr<Component> GetMainComponent() const;
70     RefPtr<DisplayComponent> GetDisplayComponent();
71     bool HasDisplayComponent() const;
72     RefPtr<TransformComponent> GetTransformComponent();
73     RefPtr<TouchListenerComponent> GetTouchListenerComponent();
74     bool HasTouchListenerComponent() const;
75     RefPtr<MouseListenerComponent> GetMouseListenerComponent();
76     RefPtr<GestureListenerComponent> GetClickGestureListenerComponent();
77     bool HasClickGestureListenerComponent() const;
78     RefPtr<GestureListenerComponent> GetPanGestureListenerComponent();
79     RefPtr<FocusableComponent> GetFocusableComponent(bool createIfNotExist = true);
80     RefPtr<SharedTransitionComponent> GetSharedTransitionComponent();
81     RefPtr<GestureComponent> GetGestureComponent();
82     RefPtr<PositionedComponent> GetPositionedComponent();
83     RefPtr<ComposedComponent> GetRootComponent(const std::string& id = "", const std::string& name = "");
84     RefPtr<PageTransitionComponent> GetPageTransitionComponent();
85     RefPtr<CoverageComponent> GetCoverageComponent();
86     void ClearPageTransitionComponent();
87     RefPtr<MenuComponent> GetMenuComponent(bool createNewComponent = true);
88 #ifndef WEARABLE_PRODUCT
89     RefPtr<PopupComponentV2> GetPopupComponent(bool createNewComponent = true);
90 #endif
91 
92     // create wrappingComponentsMap and the component to map and then Push
93     // the map to the stack.
94     // use flag: isCustomView to avoid creating redundant Components.
95     void Push(const RefPtr<Component>& component, bool isCustomView = false);
96 
97     // special versions of Push and Pop for JSGrid
98     // maintains a stack of GridLayoutComponent
99     // to be accessed when creating JSGridItems
PushGrid(const RefPtr<GridLayoutComponent> & gridComponent)100     void PushGrid(const RefPtr<GridLayoutComponent>& gridComponent)
101     {
102         gridStack_.push(gridComponent);
103         Push(gridComponent);
104     }
105 
PopGrid()106     void PopGrid()
107     {
108         if (!gridStack_.empty()) {
109             gridStack_.pop();
110         }
111         Pop();
112     }
113 
GetTopGrid()114     RefPtr<GridLayoutComponent> GetTopGrid() const
115     {
116         if (gridStack_.empty()) {
117             return nullptr;
118         }
119         return gridStack_.top();
120     }
121 
122     // Push special tabs component for tabs, tabContent.
PushTabs(const RefPtr<Component> & component)123     void PushTabs(const RefPtr<Component>& component)
124     {
125         tabsStack_.push(component);
126     }
127 
PopTabs()128     void PopTabs()
129     {
130         tabsStack_.pop();
131     }
132 
GetTopTabs()133     RefPtr<Component> GetTopTabs() const
134     {
135         if (tabsStack_.empty()) {
136             return nullptr;
137         }
138         return tabsStack_.top();
139     }
140 
141     // Wrap the components map for the stack top and then pop the stack.
142     // Add the wrappedcomponent has child of the new stack top's main component.
143     void Pop();
144 
145     // pop the last container
146     void PopContainer();
147 
148     // End of Render function, create component tree.
Finish()149     RefPtr<Component> Finish()
150     {
151         return FinishReturnMain().first;
152     }
153 
154     // return mainComponent ... outmostWrappingComponent
155     // local Component to Element updates will be performed on these any any Component in-between
156     // returns the same cComponent twice if no wrapping Components.
157     std::pair<RefPtr<Component>, RefPtr<Component>> FinishReturnMain();
158 
Size()159     int32_t Size() const
160     {
161         return static_cast<int32_t>(componentsStack_.size());
162     }
163 
164     // Set key to be used for next custom component on the stack
165     void PushKey(const std::string& key);
166 
167     // Returns a key for the CustomComponent if it has been pushed to the stack. Default is ""
168     std::string GetKey();
169 
170     // Takes care of the viewId wrt to foreach
171     std::string ProcessViewId(const std::string& viewId);
172 
173     // Clear the key pushed to the stack
174     void PopKey();
175 
176     // Sets the implicit animation option. All the views use the same option.
177     void SetImplicitAnimationOption(const AnimationOption& option);
178 
179     // Returns implicit animation option.
180     const AnimationOption& GetImplicitAnimationOption() const;
181 
182     void SetZIndex(RefPtr<Component>& component);
183     bool ShouldPopImmediately();
184 
185     void SetIsPercentSize(RefPtr<Component>& component);
186     std::shared_ptr<JsPageRadioGroups> GetRadioGroupComponent();
187     std::shared_ptr<JsPageCheckboxGroups> GetCheckboxGroupComponent();
188 
189     RefPtr<Component> GetNewComponent();
190     RefPtr<V2::InspectorComposedComponent> GetInspectorComposedComponent() const;
191 
SetVisualState(VisualState state)192     void SetVisualState(VisualState state)
193     {
194         visualState_ = state;
195     }
196 
GetVisualState()197     VisualState GetVisualState()
198     {
199         return visualState_;
200     }
201 
IsVisualStateSet()202     bool IsVisualStateSet()
203     {
204         return visualState_ != VisualState::NOTSET;
205     }
206 
ClearVisualState()207     void ClearVisualState()
208     {
209         visualState_ = VisualState::NOTSET;
210     }
211 
ClearStack()212     void ClearStack()
213     {
214         auto emptyStack = std::stack<std::unordered_map<std::string, RefPtr<Component>>>();
215         componentsStack_.swap(emptyStack);
216     }
217 
218     /**
219      * start 'get' access recording
220      * account all get access to given elmtId
221      * next component creation will claim the given elmtId
222      * see ClaimElementId()
223      */
StartGetAccessRecordingFor(int32_t elmtId)224     void StartGetAccessRecordingFor(int32_t elmtId)
225     {
226         accountGetAccessToElmtId_ = elmtId;
227         reservedElementId_ = elmtId;
228     }
229 
230     /**
231      * Use reserved elementId for given component
232      * sets the reserved lemntId to none
233      */
234     void ClaimElementId(const RefPtr<Component>& component);
235 
ClaimElementId()236     int32_t ClaimElementId()
237     {
238         ACE_DCHECK(
239             (reservedElementId_ != ElementRegister::UndefinedElementId) && "No reserved elmtId, internal error!");
240         const auto result = reservedElementId_;
241         reservedElementId_ = ElementRegister::UndefinedElementId;
242         return result;
243     }
244 
245     /**
246      * get the elmtId to which all get access should be accounted
247      * ElementRegister::UndefinedElementId; means no get access recording enabled
248      */
GetElmtIdToAccountFor()249     ElementIdType GetElmtIdToAccountFor()
250     {
251         return accountGetAccessToElmtId_;
252     }
SetElmtIdToAccountFor(ElementIdType elmtId)253     void SetElmtIdToAccountFor(ElementIdType elmtId)
254     {
255         accountGetAccessToElmtId_ = elmtId;
256     }
257 
258     /**
259      * inverse of StartGetAccessRecordingFor
260      */
StopGetAccessRecording()261     void StopGetAccessRecording()
262     {
263         accountGetAccessToElmtId_ = ElementRegister::UndefinedElementId;
264         // normally already set like this, but just in case
265         reservedElementId_ = ElementRegister::UndefinedElementId;
266     }
267     RefPtr<ComposedComponent> CreateInspectorWrapper(const std::string& inspectorTag);
268 
GetAndPushFrameNode(const std::string & tag,int32_t elmtId)269     void GetAndPushFrameNode(const std::string& tag, int32_t elmtId)
270     {
271         LOGW("NON NG ViewStackProcessor GetAndPushFrameNode()");
272         // FrameNode is not available in NON-NG pipeline.
273     }
274 
275 private:
276     ViewStackProcessor();
277 
278 #ifdef ACE_DEBUG
279     // Dump view stack comtent
280     void DumpStack();
281 #endif
282 
283     // Go through the wrappingComponentsMap and wrap the components
284     // should be done before pushing to the stack.
285     // returns pair(outmost wrapping Component, main Component)
286     std::pair<RefPtr<Component>, RefPtr<Component>> WrapComponents();
287 
288     // Update position and enabled status
289     void UpdateTopComponentProps(const RefPtr<Component>& component);
290 
291     void CreateInspectorComposedComponent(const std::string& inspectorTag);
292     void CreateScoringComponent(const std::string& tag);
293     RefPtr<Component> GetScoringComponent() const;
294 
295     // Singleton instance
296     static thread_local std::unique_ptr<ViewStackProcessor> instance;
297 
298     // stack
299     std::stack<std::unordered_map<std::string, RefPtr<Component>>> componentsStack_;
300     std::shared_ptr<JsPageRadioGroups> radioGroups_;
301     std::shared_ptr<JsPageCheckboxGroups> checkboxGroups_;
302     // stack for tabs component.
303     std::stack<RefPtr<Component>> tabsStack_;
304 
305     // stack for Grid component.
306     std::stack<RefPtr<GridLayoutComponent>> gridStack_;
307 
308     RefPtr<PageTransitionComponent> pageTransitionComponent_;
309 
310     std::string viewKey_;
311     std::stack<size_t> keyStack_;
312 
313     RefPtr<AccessibilityManager> accessibilityManager_;
314     std::stack<int32_t> parentIdStack_;
315 
316     AnimationOption implicitAnimationOption_;
317     VisualState visualState_ = VisualState::NOTSET;
318 
319     bool isScoringEnable_ = false;
320 
321     // elmtId reserved for next component creation
322     ElementIdType reservedElementId_ = ElementRegister::UndefinedElementId;
323 
324     // elmtId to accouunt get access to
325     ElementIdType accountGetAccessToElmtId_ = ElementRegister::UndefinedElementId;
326 
327     ACE_DISALLOW_COPY_AND_MOVE(ViewStackProcessor);
328 };
329 
330 class ScopedViewStackProcessor final {
331 public:
332     ScopedViewStackProcessor();
333     ~ScopedViewStackProcessor();
334 
335 private:
336     std::unique_ptr<ViewStackProcessor> instance_;
337 
338     ACE_DISALLOW_COPY_AND_MOVE(ScopedViewStackProcessor);
339 };
340 
341 } // namespace OHOS::Ace::Framework
342 #endif // FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_VIEW_STACK_PROCESSOR_H
343