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