• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 UI_MODEL_H
17 #define UI_MODEL_H
18 
19 #include <vector>
20 #include <sstream>
21 #include "common_utilities_hpp.h"
22 #include "frontend_api_handler.h"
23 #include "json.hpp"
24 
25 namespace OHOS::uitest {
26     /**Enumerates the supported UiComponent attributes.*/
27     enum UiAttr : uint8_t {
28         ACCESSIBILITY_ID,
29         ID,
30         TEXT,
31         KEY,
32         TYPE,
33         BOUNDS,
34         ENABLED,
35         FOCUSED,
36         SELECTED,
37         CLICKABLE,
38         LONG_CLICKABLE,
39         SCROLLABLE,
40         CHECKABLE,
41         CHECKED,
42         // inner used attributes
43         HIERARCHY,
44         HASHCODE,
45         BOUNDSCENTER,
46         HOST_WINDOW_ID,
47     };
48 
49     /**Supported UiComponent attribute names. Ordered by <code>UiAttr</code> definition.*/
50     constexpr std::string_view ATTR_NAMES[] = {
51         "accessibilityId", // ACCESSIBILITY_ID
52         "id",            // ID
53         "text",          // TEXT
54         "key",           // KEY
55         "type",          // TYPE
56         "bounds",        // BOUNDS
57         "enabled",       // ENABLED
58         "focused",       // FOCUSED
59         "selected",      // SELECTED
60         "clickable",     // CLICKABLE
61         "longClickable", // LONG_CLICKABLE
62         "scrollable",    // SCROLLABLE
63         "checkable",     // CHECKABLE
64         "checked",       // CHECKED
65         "hierarchy",     // HIERARCHY
66         "hashcode",      // HASHCODE
67         "boundsCenter",  // BOUNDSCENTER
68         "hostWindowId",  // HOST_WINDOW_ID
69     };
70 
71     struct Point {
PointPoint72         Point() : px_(0), py_(0) {};
PointPoint73         Point(int32_t px, int32_t py) : px_(px), py_(py) {};
74         int32_t px_;
75         int32_t py_;
76     };
77 
78     /**Represents a reasonable rectangle area.*/
79     struct Rect {
RectRect80         Rect(int32_t left, int32_t right, int32_t top, int32_t bottom)
81             : left_(left), right_(right), top_(top), bottom_(bottom)
82         {
83             DCHECK(right_ >= left_ && bottom_ >= top_);
84         };
85 
86         int32_t left_;
87         int32_t right_;
88         int32_t top_;
89         int32_t bottom_;
90 
GetCenterXRect91         FORCE_INLINE int32_t GetCenterX() const
92         {
93             return (left_ + right_) / TWO;
94         }
95 
GetCenterYRect96         FORCE_INLINE int32_t GetCenterY() const
97         {
98             return (top_ + bottom_) / TWO;
99         }
100 
GetWidthRect101         FORCE_INLINE int32_t GetWidth() const
102         {
103             return right_ - left_;
104         }
105 
GetHeightRect106         FORCE_INLINE int32_t GetHeight() const
107         {
108             return bottom_ - top_;
109         }
110     };
111 
112     /**Algorithm of rectangle.*/
113     class RectAlgorithm {
114     public:
115         FORCE_INLINE static bool CheckEqual(const Rect &ra, const Rect &rb);
116         FORCE_INLINE static bool CheckIntersectant(const Rect &ra, const Rect &rb);
117         FORCE_INLINE static bool IsInnerPoint(const Rect &rect, const Point &point);
118         FORCE_INLINE static bool IsPointOnEdge(const Rect &rect, const Point &point);
119         static bool ComputeIntersection(const Rect &ra, const Rect &rb, Rect &result);
120         static bool ComputeMaxVisibleRegion(const Rect &rect, const std::vector<Rect> &overlays, Rect &out);
121     };
122 
CheckEqual(const Rect & ra,const Rect & rb)123     FORCE_INLINE bool RectAlgorithm::CheckEqual(const Rect &ra, const Rect &rb)
124     {
125         return ra.left_ == rb.left_ && ra.right_ == rb.right_ && ra.top_ == rb.top_ && ra.bottom_ == rb.bottom_;
126     }
127 
CheckIntersectant(const Rect & ra,const Rect & rb)128     FORCE_INLINE bool RectAlgorithm::CheckIntersectant(const Rect &ra, const Rect &rb)
129     {
130         if (ra.left_ >= rb.right_ || ra.right_ <= rb.left_) {
131             return false;
132         }
133         if (ra.top_ >= rb.bottom_ || ra.bottom_ <= rb.top_) {
134             return false;
135         }
136         return true;
137     }
138 
IsInnerPoint(const Rect & rect,const Point & point)139     FORCE_INLINE bool RectAlgorithm::IsInnerPoint(const Rect &rect, const Point& point)
140     {
141         if (point.px_ <= rect.left_ || point.px_ >= rect.right_
142             || point.py_ <= rect.top_ || point.py_ >= rect.bottom_) {
143             return false;
144         }
145         return true;
146     }
147 
IsPointOnEdge(const Rect & rect,const Point & point)148     FORCE_INLINE bool RectAlgorithm::IsPointOnEdge(const Rect &rect, const Point& point)
149     {
150         if ((point.px_ == rect.left_ || point.px_ == rect.right_)
151             && point.py_ >= rect.top_ && point.py_ <= rect.bottom_) {
152             return true;
153         }
154         if ((point.py_ == rect.top_ || point.py_ == rect.bottom_)
155             && point.px_ >= rect.left_ && point.px_ <= rect.right_) {
156             return true;
157         }
158         return false;
159     }
160 
161     class Widget : public BackendClass {
162     public:
163         // disable default constructor, copy constructor and assignment operator
Widget(std::string_view hierarchy)164         explicit Widget(std::string_view hierarchy) : hierarchy_(hierarchy)
165         {
166             attributes_.insert(std::make_pair(ATTR_NAMES[UiAttr::HIERARCHY], hierarchy));
167         };
168 
~Widget()169         ~Widget() override {}
170 
GetFrontendClassDef()171         const FrontEndClassDef &GetFrontendClassDef() const override
172         {
173             return COMPONENT_DEF;
174         }
175 
176         bool HasAttr(std::string_view name) const;
177 
178         std::string GetAttr(std::string_view name, std::string_view defaultVal) const;
179 
GetBounds()180         Rect GetBounds() const
181         {
182             return bounds_;
183         }
184 
GetHierarchy()185         std::string GetHierarchy() const
186         {
187             return hierarchy_;
188         }
189 
190         void SetAttr(std::string_view name, std::string_view value);
191 
192         void SetHostTreeId(std::string_view tid);
193 
194         std::string GetHostTreeId() const;
195 
196         void SetBounds(const Rect &bounds);
197 
198         std::string ToStr() const;
199 
200         std::unique_ptr<Widget> Clone(std::string_view hostTreeId, std::string_view hierarchy) const;
201 
202         std::map<std::string, std::string> GetAttrMap() const;
203 
204     private:
205         const std::string hierarchy_;
206         std::string hostTreeId_;
207         std::map<std::string, std::string> attributes_;
208         Rect bounds_ = {0, 0, 0, 0};
209     };
210 
211     // ensure Widget is movable, since we need to move a constructed Widget object into WidgetTree
212     static_assert(std::is_move_constructible<Widget>::value, "Widget need to be movable");
213 
214     class WidgetVisitor {
215     public:
216         virtual void Visit(const Widget &widget) = 0;
217     };
218 
219     class WidgetTree {
220     public:
221         WidgetTree() = delete;
222 
~WidgetTree()223         ~WidgetTree() {}
224 
WidgetTree(std::string name)225         explicit WidgetTree(std::string name) : name_(std::move(name)), identifier_(GenerateTreeId()) {}
226 
227         /**
228          * Construct tree nodes from the given dom data.
229          *
230          * @param dom: the dom json data.
231          * @param amendBounds: if or not amend widget bounds and visibility.
232          * */
233         void ConstructFromDom(const nlohmann::json &dom, bool amendBounds);
234 
235         /**
236          * Marshal tree nodes hierarchy into the given dom data.
237          *
238          * @param dom: the dom json data.
239          * */
240         void MarshalIntoDom(nlohmann::json &dom) const;
241 
242         void DfsTraverse(WidgetVisitor &visitor) const;
243 
244         void DfsTraverseFronts(WidgetVisitor &visitor, const Widget &pivot) const;
245 
246         void DfsTraverseRears(WidgetVisitor &visitor, const Widget &pivot) const;
247 
248         void DfsTraverseDescendants(WidgetVisitor &visitor, const Widget &root) const;
249 
250         /**
251          * Get the root widget node.
252          *
253          * @return the root widget node, or <code>nullptr</code> if the tree is empty or not constructed.
254          * */
255         const Widget *GetRootWidget() const;
256 
257         /**
258          * Get the parent widget node of the given widget
259          *
260          * @param widget: the child widget.
261          * @returns the parent widget pointer, <code>nullptr</code> if the given node it's the root node.
262          * */
263         const Widget *GetParentWidget(const Widget &widget) const;
264 
265         /**
266          * Get the child widget node of the given widget at the given index.
267          *
268          * @param widget: the parent widget.
269          * @param index: the child widget index, <b>starts from 0</b>.
270          * @returns the child widget pointer, or <code>nullptr</code> if there's no such child.
271          * */
272         const Widget *GetChildWidget(const Widget &widget, uint32_t index) const;
273 
274         /**Check if the given widget node hierarchy is the root node hierarchy.*/
275         static bool IsRootWidgetHierarchy(std::string_view hierarchy);
276 
277         /**
278          * Merge several tree into one tree.
279          *
280          * @param from: the subtrees to merge, should be sorted by z-order and the top one be at first.
281          * @param to: the root tree to merge into.
282          * */
283         static void MergeTrees(const std::vector<std::unique_ptr<WidgetTree>> &from, WidgetTree &to);
284 
285     private:
286         const std::string name_;
287         const std::string identifier_;
288         bool widgetsConstructed_ = false;
289         // widget-hierarchy VS widget-ptr
290         std::map<std::string, Widget> widgetMap_;
291         // widget-hierarchies, dfs order
292         std::vector<std::string> widgetHierarchyIdDfsOrder_;
293 
294         /**
295          * Get WidgetTree by hierarchy,return <code>nullptr</code> if no such widget exist.
296          * */
297         const Widget *GetWidgetByHierarchy(std::string_view hierarchy) const;
298 
299         /**Check if the given widget is in this tree.*/
300         inline bool CheckIsMyNode(const Widget &widget) const;
301 
302         /**Generated an unique tree-identifier.*/
303         static std::string GenerateTreeId();
304     };
305 
306     /**Enumerates the supported UiComponent attributes.*/
307     enum WindowMode : uint8_t { UNKNOWN, FULLSCREEN, SPLIT_PRIMARY, SPLIT_SECONDARY, FLOATING, PIP };
308 
309     // Represents a UI window on screen.
310     class Window : public BackendClass {
311     public:
Window(int32_t id)312         explicit Window(int32_t id) : id_(id) {};
313 
~Window()314         ~Window() override {}
315 
GetFrontendClassDef()316         const FrontEndClassDef &GetFrontendClassDef() const override
317         {
318             return UI_WINDOW_DEF;
319         }
320         // plain properties, make them public for easy access
321         int32_t id_ = 0;
322         std::string bundleName_ = "";
323         std::string title_ = "";
324         bool focused_ = false;
325         bool actived_ = false;
326         bool decoratorEnabled_ = false;
327         Rect bounds_ = {0, 0, 0, 0};
328         WindowMode mode_ = UNKNOWN;
329     };
330 } // namespace OHOS::uitest
331 
332 #endif