1 /* 2 * Copyright (c) 2022-2023 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 #ifndef RENDER_SERVICE_BASE_CORE_COMMON_RS_OCCLUSION_REGION_H 16 #define RENDER_SERVICE_BASE_CORE_COMMON_RS_OCCLUSION_REGION_H 17 18 #include <algorithm> 19 #include <iostream> 20 #include <vector> 21 #include <string> 22 23 #include "rs_rect.h" 24 #include "common/rs_macros.h" 25 #include "platform/common/rs_log.h" 26 27 namespace OHOS { 28 namespace Rosen { 29 namespace Occlusion { 30 31 constexpr int MAX_REGION_VALUE = 1000000; // normal region value should not exceed 1000000 32 constexpr int MIN_REGION_VALUE = -1000000; // normal region value should not less than -1000000 33 class Rect { 34 public: 35 // assumption: left-top is [0,0] 36 int left_ = 0; 37 int top_ = 0; 38 int right_ = 0; 39 int bottom_ = 0; 40 static Rect _s_empty_rect_; 41 static Rect _s_invalid_rect_; 42 Rect()43 Rect() : left_(0), top_(0), right_(0), bottom_(0) {} 44 Rect(int l, int t, int r, int b, bool checkValue = true) 45 { 46 left_ = l; 47 top_ = t; 48 right_ = r; 49 bottom_ = b; 50 if (checkValue && (IsEmpty() || CheckIfHasAbnormalValue())) { 51 SetEmpty(); 52 } 53 } 54 55 Rect(const RectI& r, bool checkValue = true) 56 { 57 left_ = r.left_; 58 top_ = r.top_; 59 right_ = r.GetRight(); 60 bottom_ = r.GetBottom(); 61 if (checkValue && (IsEmpty() || CheckIfHasAbnormalValue())) { 62 SetEmpty(); 63 } 64 } 65 SetEmpty()66 void SetEmpty() 67 { 68 left_ = 0; 69 top_ = 0; 70 right_ = 0; 71 bottom_ = 0; 72 } 73 CheckIfHasAbnormalValue()74 bool CheckIfHasAbnormalValue() 75 { 76 bool hasAbnormalValue = false; 77 if (left_ < MIN_REGION_VALUE || left_ > MAX_REGION_VALUE) { 78 hasAbnormalValue = true; 79 } 80 if (top_ < MIN_REGION_VALUE || top_ > MAX_REGION_VALUE) { 81 hasAbnormalValue = true; 82 } 83 if (right_ < MIN_REGION_VALUE || right_ > MAX_REGION_VALUE) { 84 hasAbnormalValue = true; 85 } 86 if (bottom_ < MIN_REGION_VALUE || bottom_ > MAX_REGION_VALUE) { 87 hasAbnormalValue = true; 88 } 89 if (hasAbnormalValue) { 90 RS_LOGE("Occlusion::Rect initialized with invalid value, [%{public}d, %{public}d, %{public}d, %{public}d], \ 91 should in range [%{public}d, %{public}d]", 92 left_, top_, right_, bottom_, MIN_REGION_VALUE, MAX_REGION_VALUE); 93 } 94 return hasAbnormalValue; 95 } 96 IsEmpty()97 bool IsEmpty() const 98 { 99 return left_ >= right_ || top_ >= bottom_; 100 } 101 102 bool operator==(const Rect& r) const 103 { 104 return left_ == r.left_ && top_ == r.top_ && right_ == r.right_ && bottom_ == r.bottom_; 105 } 106 107 bool operator!=(const Rect& r) const 108 { 109 return !(*this == r); 110 } 111 Intersect(const Rect & rect)112 Rect Intersect(const Rect& rect) const 113 { 114 int left = std::max(left_, rect.left_); 115 int top = std::max(top_, rect.top_); 116 int right = std::min(right_, rect.right_); 117 int bottom = std::min(bottom_, rect.bottom_); 118 if ((right - left <= 0) || (bottom - top <= 0)) { 119 return Rect(0, 0, 0, 0); 120 } else { 121 return Rect(left, top, right, bottom); 122 } 123 } 124 IsIntersect(const Rect & rect)125 bool IsIntersect(const Rect& rect) const 126 { 127 int left = std::max(left_, rect.left_); 128 int top = std::max(top_, rect.top_); 129 int right = std::min(right_, rect.right_); 130 int bottom = std::min(bottom_, rect.bottom_); 131 return (right - left > 0) && (bottom - top > 0); 132 } 133 GetRectInfo()134 std::string GetRectInfo() const 135 { 136 return std::string("[" + 137 std::to_string(left_) + ", " + 138 std::to_string(top_) + ", " + 139 std::to_string(right_ - left_) + ", " + 140 std::to_string(bottom_ - top_) + "]"); 141 } 142 ToRectI()143 RectI ToRectI() const 144 { 145 return RectI{left_, top_, right_ - left_, bottom_ - top_}; 146 } 147 148 int Area() const; 149 int IntersectArea(const Rect& r) const; 150 }; 151 152 std::ostream& operator<<(std::ostream& os, const Rect& r); 153 154 /* 155 Event: Used for record a rect edge in/out event 156 y_: rect edge Y value 157 type: OPEN/CLOSE: lhs rect in/out; VOID_OPEN/VOID_CLOSE: rhs rect in/out 158 */ 159 class Event { 160 public: 161 // Use different value to differentiate lhs and rhs ranges 162 enum Type { OPEN = 1, CLOSE = -1, VOID_OPEN = 2, VOID_CLOSE = -2 }; 163 int y_ = 0; 164 Type type_ = Type::OPEN; 165 int left_ = 0; 166 int right_ = 0; 167 Event(int y,Type type,int l,int r)168 Event(int y, Type type, int l, int r) : y_(y), type_(type), left_(l), right_(r) {} 169 }; 170 bool EventSortByY(const Event& e1, const Event& e2); 171 172 class Range { 173 public: 174 int start_ = 0; 175 int end_ = 0; Range(int s,int e)176 Range(int s, int e) : start_(s), end_(e) {} 177 bool operator==(const Range& r) 178 { 179 return start_ == r.start_ && end_ == r.end_; 180 } 181 }; 182 183 class Node { 184 public: 185 int start_ = 0; 186 int end_ = 0; 187 int mid_ = 0; 188 int positive_count_ = 0; // used for counting current lhs ranges 189 int negative_count_ = 0; // used for counting current rhs ranges 190 Node* left_ = nullptr; 191 Node* right_ = nullptr; 192 Node(int s,int e)193 Node(int s, int e) : start_(s), end_(e), mid_((s + e) >> 1) {} ~Node()194 ~Node() 195 { 196 if (left_ != nullptr) { 197 delete left_; 198 left_ = nullptr; 199 } 200 if (right_ != nullptr) { 201 delete right_; 202 right_ = nullptr; 203 } 204 } 205 206 // push current node [start, end] into range result, merge last range if possible PushRange(std::vector<Range> & res)207 inline void PushRange(std::vector<Range>& res) 208 { 209 if (res.size() > 0 && start_ == res[res.size() - 1].end_) { 210 // merge range with previous range if their end and start share same point 211 res[res.size() - 1].end_ = end_; 212 } else { 213 res.emplace_back(Range { start_, end_ }); 214 } 215 } 216 IsLeaf()217 inline bool IsLeaf() 218 { 219 return left_ == nullptr && right_ == nullptr; 220 } 221 222 // update segment tree 223 void Update(int updateStart, int updateEnd, Event::Type type); 224 // get ranges where positive_count_ and negtive_count_ are both positive 225 void GetAndRange(std::vector<Range>& res, bool isParentNodePos, bool isParentNodeNeg); 226 // get ranges where positive_count_ or negtive_count_ is positive 227 void GetOrRange(std::vector<Range>& res, bool isParentNodePos, bool isParentNodeNeg); 228 // get ranges where either positive_count_ and negtive_count_ are both positive 229 void GetXOrRange(std::vector<Range>& res, bool isParentNodePos, bool isParentNodeNeg); 230 // get ranges where positive_count_ is positive and negtive_count_ not 231 void GetSubRange(std::vector<Range>& res, bool isParentNodePos, bool isParentNodeNeg); 232 }; 233 234 class RSB_EXPORT Region { 235 public: 236 enum OP { 237 // bit index 0: lhs 238 // bit index 1: lhs & rhs 239 // bit index 2: rhs 240 AND = 2, // 010 241 OR = 7, // 111 242 XOR = 5, // 101 243 SUB = 1 // 001 244 }; 245 246 Region() = default; Region(Rect r)247 Region(Rect r) 248 { 249 rects_.push_back(r); 250 bound_ = Rect { r }; 251 } 252 Region(const Region & reg)253 Region(const Region& reg) : rects_(reg.rects_), bound_(reg.bound_) {} ~Region()254 ~Region() {} 255 GetRegionRectsRef()256 std::vector<Rect>& GetRegionRectsRef() 257 { 258 return rects_; 259 } 260 GetRegionRects()261 const std::vector<Rect>& GetRegionRects() const 262 { 263 return rects_; 264 } GetSize()265 int GetSize() const 266 { 267 return rects_.size(); 268 } GetBound()269 Rect GetBound() const 270 { 271 return bound_; 272 } GetBoundRef()273 Rect& GetBoundRef() 274 { 275 return bound_; 276 } IsEmpty()277 bool IsEmpty() const 278 { 279 return rects_.size() == 0 || bound_.IsEmpty(); 280 } GetRegionInfo()281 std::string GetRegionInfo() const 282 { 283 std::string info; 284 if (IsEmpty()) { 285 info = "Region [Empty]"; 286 } else { 287 info = "Region " + std::to_string(rects_.size()) + ": "; 288 for (auto& r : rects_) { 289 info.append(r.GetRectInfo()); 290 } 291 } 292 return info; 293 } 294 CBegin()295 inline std::vector<Rect>::const_iterator CBegin() const 296 { 297 return rects_.cbegin(); 298 } CEnd()299 inline std::vector<Rect>::const_iterator CEnd() const 300 { 301 return rects_.cend(); 302 } Begin()303 inline std::vector<Rect>::iterator Begin() 304 { 305 return rects_.begin(); 306 } End()307 inline std::vector<Rect>::const_iterator End() 308 { 309 return rects_.end(); 310 } Size()311 inline size_t Size() const 312 { 313 return rects_.size(); 314 } 315 316 // bound of all region rects 317 void MakeBound(); 318 IsIntersectWith(const Rect & r)319 bool IsIntersectWith(const Rect& r) const 320 { 321 for (const Rect& rect : rects_) { 322 if (rect.IsIntersect(r)) { 323 return true; 324 } 325 } 326 return false; 327 } 328 329 /* core Region logic operation function, the return region's rects is guaranteed no-intersection 330 (rect in rects_ do not intersect with each other) 331 */ 332 void RegionOp(Region& r1, Region& r2, Region& res, Region::OP op); 333 void RegionOpLocal(Region& r1, Region& r2, Region& res, Region::OP op); 334 void RegionOpAccelate(Region& r1, Region& r2, Region& res, Region::OP op); 335 336 Region& OperationSelf(Region& r, Region::OP op); 337 // replace region with and result 338 Region& AndSelf(Region& r); 339 // replace region with or result 340 Region& OrSelf(Region& r); 341 // replace region with xor result 342 Region& XOrSelf(Region& r); 343 // replace region with sub result 344 Region& SubSelf(Region& r); 345 346 // return intersection region 347 Region And(Region& r); 348 // return merge region 349 Region Or(Region& r); 350 // return merge region subtract intersection region 351 Region Xor(Region& r); 352 // return region belongs to Region(lhs) but not Region(rhs) 353 Region Sub(Region& r); 354 355 // get current region's area, return the sum of the areas of all rectangles (as they are not intersect each other) 356 int Area() const; 357 // return the area of the region where the current region intersects the rectangle 358 int IntersectArea(const Rect& r) const; 359 360 private: 361 class Rects { 362 public: 363 std::vector<Rect> preRects; 364 std::vector<Rect> curRects; 365 int preY = 0; 366 int curY = 0; 367 }; 368 // get ranges from segmentTree node according to logical operation type 369 void getRange(std::vector<Range>& ranges, Node& node, OP op); 370 // update tmp rects and region according to current ranges 371 void UpdateRects(Rects& r, std::vector<Range>& ranges, std::vector<int>& indexAt, Region& res); 372 373 private: 374 std::vector<Rect> rects_; 375 Rect bound_; 376 static bool _s_so_loaded_; 377 }; 378 std::ostream& operator<<(std::ostream& os, const Region& r); 379 } // namespace Occlusion 380 } // namespace Rosen 381 } // namespace OHOS 382 #endif // RENDER_SERVICE_BASE_CORE_COMMON_RS_OCCLUSION_REGION_H