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 using namespace nlohmann; 28 const std::string ROOT_HIERARCHY = "ROOT"; 29 /**Enumerates the supported string value match rules.*/ 30 enum ValueMatchPattern : uint8_t { EQ, CONTAINS, STARTS_WITH, ENDS_WITH }; 31 32 /**Enumerates the supported UiComponent attributes.*/ 33 enum UiAttr : uint8_t { 34 ACCESSIBILITY_ID, 35 ID, 36 TEXT, 37 KEY, 38 DESCRIPTION, 39 TYPE, 40 BOUNDS, 41 ENABLED, 42 FOCUSED, 43 SELECTED, 44 CLICKABLE, 45 LONG_CLICKABLE, 46 SCROLLABLE, 47 CHECKABLE, 48 CHECKED, 49 HOST_WINDOW_ID, 50 ORIGBOUNDS, 51 ZINDEX, 52 OPACITY, 53 BACKGROUNDCOLOR, 54 BACKGROUNDIMAGE, 55 BLUR, 56 HITTESTBEHAVIOR, 57 // inner used attributes 58 HIERARCHY, 59 HASHCODE, 60 BOUNDSCENTER, 61 VISIBLE, 62 ABILITYNAME, 63 BUNDLENAME, 64 PAGEPATH, 65 DUMMY_ATTRNAME_SELECTION, 66 HINT, 67 MAX, // mark the max length 68 }; 69 70 /**Supported UiComponent attribute names. Ordered by <code>UiAttr</code> definition.*/ 71 constexpr std::string_view ATTR_NAMES[] = { 72 "accessibilityId", // ACCESSIBILITY_ID 73 "id", // ID 74 "text", // TEXT 75 "key", // KEY 76 "description", // DESCRIPTION 77 "type", // TYPE 78 "bounds", // BOUNDS 79 "enabled", // ENABLED 80 "focused", // FOCUSED 81 "selected", // SELECTED 82 "clickable", // CLICKABLE 83 "longClickable", // LONG_CLICKABLE 84 "scrollable", // SCROLLABLE 85 "checkable", // CHECKABLE 86 "checked", // CHECKED 87 "hostWindowId", // HOST_WINDOW_ID 88 "origBounds", // ORIGBOUNDS 89 "zIndex", // ZINDEX 90 "opacity", //OPACITY 91 "backgroundColor", // BACKGROUNDCOLOR 92 "backgroundImage", // BACKGROUNDIMAGE 93 "blur", //BLUR 94 "hitTestBehavior", // HITTESTBEHAVIOR 95 "hierarchy", // HIERARCHY 96 "hashcode", // HASHCODE 97 "boundsCenter", // BOUNDSCENTER 98 "visible", // VISIBLE 99 "abilityName", // ABILITYNAME 100 "bundleName", // BUNDLENAME 101 "pagePath", // PAGEPATH 102 "dummyAttrnameSelection", // DUMMY_ATTRNAME_SELECTION 103 "hint", // HINT 104 }; 105 106 const std::set<std::string> CONTAINER_TYPE = { 107 "List", "Grid", "WaterFlow", "GridCol", "GridRow", "Scroll", "Flex", 108 "ListItemGroup", "Swiper", "DecorBar", "_Common_", "TabContent", "WindowScene"}; 109 struct Point { PointPoint110 Point() : px_(0), py_(0){}; PointPoint111 Point(int32_t px, int32_t py) : px_(px), py_(py){}; 112 int32_t px_; 113 int32_t py_; 114 }; 115 116 /**Represents a reasonable rectangle area.*/ 117 struct Rect { RectRect118 Rect(int32_t left, int32_t right, int32_t top, int32_t bottom) 119 : left_(left), right_(right), top_(top), bottom_(bottom) 120 { 121 DCHECK(right_ >= left_ && bottom_ >= top_); 122 }; RectRect123 Rect() 124 { 125 left_ = 0; 126 right_ = 0; 127 top_ = 0; 128 bottom_ = 0; 129 }; 130 int32_t left_; 131 int32_t right_; 132 int32_t top_; 133 int32_t bottom_; 134 GetCenterXRect135 FORCE_INLINE int32_t GetCenterX() const 136 { 137 return (left_ + right_) / TWO; 138 } 139 GetCenterYRect140 FORCE_INLINE int32_t GetCenterY() const 141 { 142 return (top_ + bottom_) / TWO; 143 } 144 GetWidthRect145 FORCE_INLINE int32_t GetWidth() const 146 { 147 return right_ - left_; 148 } 149 GetHeightRect150 FORCE_INLINE int32_t GetHeight() const 151 { 152 return bottom_ - top_; 153 } 154 DescribeRect155 std::string Describe() const 156 { 157 std::stringstream ss; 158 ss << "Rect {left:" << left_ << ",right:" << right_ << ",top:" << top_ << ",bottom:" << bottom_ << "}"; 159 return ss.str(); 160 } 161 }; 162 163 struct WidgetMatchModel { WidgetMatchModelWidgetMatchModel164 WidgetMatchModel(UiAttr name, string value, ValueMatchPattern matchPattern) 165 : attrName(name), attrValue(value), pattern(matchPattern) 166 { 167 } WidgetMatchModelWidgetMatchModel168 WidgetMatchModel() {} DescribeWidgetMatchModel169 std::string Describe() const 170 { 171 stringstream ss; 172 ss << "{"; 173 ss << "attrName:" << ATTR_NAMES[attrName].data() << "; value:" << attrValue 174 << "; Pattern:" << to_string(pattern); 175 ss << "}"; 176 return ss.str(); 177 } 178 UiAttr attrName; 179 string attrValue; 180 ValueMatchPattern pattern; 181 }; 182 183 /**Algorithm of rectangle.*/ 184 class RectAlgorithm { 185 public: 186 FORCE_INLINE static bool CheckEqual(const Rect &ra, const Rect &rb); 187 FORCE_INLINE static bool CheckIntersectant(const Rect &ra, const Rect &rb); 188 FORCE_INLINE static bool IsInnerPoint(const Rect &rect, const Point &point); 189 FORCE_INLINE static bool IsPointOnEdge(const Rect &rect, const Point &point); 190 static bool ComputeIntersection(const Rect &ra, const Rect &rb, Rect &result); 191 static bool ComputeMaxVisibleRegion(const Rect &rect, const std::vector<Rect> &overlays, Rect &out); 192 }; 193 CheckEqual(const Rect & ra,const Rect & rb)194 FORCE_INLINE bool RectAlgorithm::CheckEqual(const Rect &ra, const Rect &rb) 195 { 196 return ra.left_ == rb.left_ && ra.right_ == rb.right_ && ra.top_ == rb.top_ && ra.bottom_ == rb.bottom_; 197 } 198 CheckIntersectant(const Rect & ra,const Rect & rb)199 FORCE_INLINE bool RectAlgorithm::CheckIntersectant(const Rect &ra, const Rect &rb) 200 { 201 if (ra.left_ >= rb.right_ || ra.right_ <= rb.left_) { 202 return false; 203 } 204 if (ra.top_ >= rb.bottom_ || ra.bottom_ <= rb.top_) { 205 return false; 206 } 207 return true; 208 } 209 IsInnerPoint(const Rect & rect,const Point & point)210 FORCE_INLINE bool RectAlgorithm::IsInnerPoint(const Rect &rect, const Point& point) 211 { 212 if (point.px_ <= rect.left_ || point.px_ >= rect.right_ 213 || point.py_ <= rect.top_ || point.py_ >= rect.bottom_) { 214 return false; 215 } 216 return true; 217 } 218 IsPointOnEdge(const Rect & rect,const Point & point)219 FORCE_INLINE bool RectAlgorithm::IsPointOnEdge(const Rect &rect, const Point& point) 220 { 221 if ((point.px_ == rect.left_ || point.px_ == rect.right_) 222 && point.py_ >= rect.top_ && point.py_ <= rect.bottom_) { 223 return true; 224 } 225 if ((point.py_ == rect.top_ || point.py_ == rect.bottom_) 226 && point.px_ >= rect.left_ && point.px_ <= rect.right_) { 227 return true; 228 } 229 return false; 230 } 231 232 class Widget : public BackendClass { 233 public: 234 // disable default constructor, copy constructor and assignment operator Widget(std::string_view hierarchy)235 explicit Widget(std::string_view hierarchy) : hierarchy_(hierarchy) 236 { 237 attributeVec_[UiAttr::HIERARCHY] = hierarchy; 238 }; 239 ~Widget()240 ~Widget() override {} 241 GetFrontendClassDef()242 const FrontEndClassDef &GetFrontendClassDef() const override 243 { 244 return COMPONENT_DEF; 245 } 246 GetBounds()247 Rect GetBounds() const 248 { 249 return bounds_; 250 } 251 GetHierarchy()252 std::string GetHierarchy() const 253 { 254 return hierarchy_; 255 } 256 257 void SetBounds(const Rect &bounds); 258 259 std::string ToStr() const; 260 261 std::unique_ptr<Widget> Clone(std::string_view hierarchy) const; 262 263 std::vector<std::string> GetAttrVec() const; 264 IsVisible()265 bool IsVisible() const 266 { 267 return GetAttr(UiAttr::VISIBLE) == "true"; 268 } 269 270 void SetAttr(UiAttr attrId, string value); 271 272 std::string GetAttr(UiAttr attrId) const; 273 274 bool MatchAttr(const WidgetMatchModel& matchModel) const; 275 276 void SetHierarchy(const std::string& hierarch); 277 278 void WrapperWidgetToJson(nlohmann::json& out); 279 private: 280 std::string hierarchy_; 281 std::vector<string> attributeVec_ = std::vector<string>(UiAttr::MAX + 1); 282 Rect bounds_ = {0, 0, 0, 0}; 283 }; 284 285 // ensure Widget is movable, since we need to move a constructed Widget object into WidgetTree 286 static_assert(std::is_move_constructible<Widget>::value, "Widget need to be movable"); 287 288 /**Enumerates the supported UiComponent attributes.*/ 289 enum WindowMode : uint8_t { UNKNOWN, FULLSCREEN, SPLIT_PRIMARY, SPLIT_SECONDARY, FLOATING, PIP }; 290 291 // Represents a UI window on screen. 292 class Window : public BackendClass { 293 public: Window(int32_t id)294 explicit Window(int32_t id) : id_(id) {}; 295 ~Window()296 ~Window() override {} 297 GetFrontendClassDef()298 const FrontEndClassDef &GetFrontendClassDef() const override 299 { 300 return UI_WINDOW_DEF; 301 } 302 303 // plain properties, make them public for easy access 304 int32_t id_ = 0; 305 int32_t windowLayer_ = 0; 306 std::string bundleName_ = ""; 307 std::string title_ = ""; 308 bool focused_ = false; 309 bool actived_ = false; 310 bool decoratorEnabled_ = false; 311 Rect bounds_ = {0, 0, 0, 0}; 312 Rect visibleBounds_ = {0, 0, 0, 0}; 313 std::vector<Rect> invisibleBoundsVec_; 314 std::string abilityName_ = ""; 315 std::string pagePath_ = ""; 316 WindowMode mode_ = UNKNOWN; 317 }; 318 319 class DumpHandler { 320 public: 321 static void AddExtraAttrs(nlohmann::json &root, const map<int32_t, string_view> &elementTrees, size_t index); 322 static void DumpWindowInfoToJson(vector<Widget> &allWidget, nlohmann::json &root); 323 }; 324 325 class WidgetHierarchyBuilder { 326 public: 327 static string Build(string_view parentWidgetHierarchy, uint32_t childIndex); 328 329 static string GetParentWidgetHierarchy(string_view hierarchy); 330 331 static string GetChildHierarchy(string_view hierarchy, uint32_t childIndex); 332 333 private: 334 static constexpr auto HIERARCHY_SEPARATOR = ","; 335 }; 336 } // namespace OHOS::uitest 337 338 #endif