1 /*
2  * Copyright (c) 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 #ifndef OHOS_ROSEN_WM_OCCLUSION_REGION_H
16 #define OHOS_ROSEN_WM_OCCLUSION_REGION_H
17 
18 #include <refbase.h>
19 #include <algorithm>
20 #include <iostream>
21 #include <vector>
22 #include <string>
23 
24 namespace OHOS::Rosen::WmOcclusion {
25 class Rect {
26 public:
27     int left_ = 0;
28     int top_ = 0;
29     int right_ = 0;
30     int bottom_ = 0;
31     static Rect _s_empty_rect_;
32     static Rect _s_invalid_rect_;
33 
Rect()34     Rect() : left_(0), top_(0), right_(0), bottom_(0) {}
Rect(int l,int t,int r,int b)35     Rect(int l, int t, int r, int b) : left_(l), top_(t), right_(r), bottom_(b) {}
36 
GetRectInfo()37     std::string GetRectInfo() const
38     {
39         return std::string("[" +
40             std::to_string(left_) + ", " +
41             std::to_string(top_) + ", " +
42             std::to_string(right_ - left_) + ", " +
43             std::to_string(bottom_ - top_) + "]");
44     }
45 
IsEmpty()46     bool IsEmpty() const
47     {
48         return left_ >= right_ || top_ >= bottom_;
49     }
50 };
51 
52 std::ostream& operator<<(std::ostream& os, const Rect& r);
53 
54 /*
55     Event: Used for record a rect edge in/out event
56     y_: rect edge Y value
57     type: OPEN/CLOSE: lhs rect in/out; VOID_OPEN/VOID_CLOSE: rhs rect in/out
58 */
59 class Event {
60 public:
61     // Use different value to differentiate lhs and rhs ranges.
62     enum Type { OPEN = 1, CLOSE = -1, VOID_OPEN = 2, VOID_CLOSE = -2 };
63     int y_ = 0;
64     Type type_ = Type::OPEN;
65     int left_ = 0;
66     int right_ = 0;
67 
Event(int y,Type type,int l,int r)68     Event(int y, Type type, int l, int r) : y_(y), type_(type), left_(l), right_(r) {}
69 };
70 
71 bool EventSortByY(const Event& e1, const Event& e2);
72 
73 class Range {
74 public:
75     int start_ = 0;
76     int end_ = 0;
Range(int start,int end)77     Range(int start, int end) : start_(start), end_(end) {}
78     bool operator==(const Range& r)
79     {
80         return start_ == r.start_ && end_ == r.end_;
81     }
82 };
83 
84 class Node {
85 public:
86     int start_ = 0;
87     int end_ = 0;
88     int mid_ = 0;
89     Node* left_ = nullptr;
90     Node* right_ = nullptr;
91     int positive_count_ = 0; // used for counting current lhs ranges
92     int negative_count_ = 0; // used for counting current rhs ranges
93 
Node(int s,int e)94     Node(int s, int e) : start_(s), end_(e), mid_((s + e) >> 1) {}
~Node()95     ~Node()
96     {
97         if (right_ != nullptr) {
98             delete right_;
99             right_ = nullptr;
100         }
101         if (left_ != nullptr) {
102             delete left_;
103             left_ = nullptr;
104         }
105     }
106 
IsLeaf()107     inline bool IsLeaf()
108     {
109         return left_ == nullptr && right_ == nullptr;
110     }
111 
112     // push current node [start, end] into range result, merge last range if possible
PushRange(std::vector<Range> & res)113     inline void PushRange(std::vector<Range>& res)
114     {
115         if (res.size() > 0 && start_ == res[res.size() - 1].end_) {
116             // merge range with previous range if their end and start share same point
117             res[res.size() - 1].end_ = end_;
118         } else {
119             res.emplace_back(Range { start_, end_ });
120         }
121     }
122 
123     // update segment tree
124     void Update(int updateStart, int updateEnd, Event::Type type);
125     // get ranges where positive_count_ or negtive_count_ is positive
126     void GetOrRange(std::vector<Range>& res, bool isParentNodePos, bool isParentNodeNeg);
127     // get ranges where positive_count_ and negtive_count_ are both positive
128     void GetAndRange(std::vector<Range>& res, bool isParentNodePos, bool isParentNodeNeg);
129     // get ranges where positive_count_ is positive and negtive_count_ not
130     void GetSubRange(std::vector<Range>& res, bool isParentNodePos, bool isParentNodeNeg);
131     // get ranges where either positive_count_ and negtive_count_ are both positive
132     void GetXOrRange(std::vector<Range>& res, bool isParentNodePos, bool isParentNodeNeg);
133 };
134 
135 class Region {
136 public:
137     enum OP {
138         // bit index 0: lhs
139         // bit index 1: lhs & rhs
140         // bit index 2: rhs
141         AND = 2, // 010
142         OR  = 7, // 111
143         XOR = 5, // 101
144         SUB = 1  // 001
145     };
146 
147     Region() = default;
Region(Rect & rect)148     explicit Region(Rect& rect)
149     {
150         rects_.push_back(rect);
151         bound_ = Rect { rect };
152     }
153 
Region(const Region & region)154     Region(const Region& region) : rects_(region.rects_), bound_(region.bound_) {}
155     Region& operator=(const Region& region)
156     {
157         rects_ = region.rects_;
158         bound_ = region.bound_;
159         return *this;
160     }
~Region()161     ~Region() {}
162 
GetRegionRects()163     std::vector<Rect>& GetRegionRects()
164     {
165         return rects_;
166     }
167 
GetRegionRects()168     std::vector<Rect> GetRegionRects() const
169     {
170         return rects_;
171     }
172 
IsEmpty()173     bool IsEmpty() const
174     {
175         return rects_.size() == 0;
176     }
177 
GetSize()178     int GetSize() const
179     {
180         return rects_.size();
181     }
182 
GetBoundRef()183     Rect& GetBoundRef()
184     {
185         return bound_;
186     }
187 
GetBound()188     Rect GetBound() const
189     {
190         return bound_;
191     }
192 
GetRegionInfo()193     std::string GetRegionInfo() const
194     {
195         std::string info = "{ Region Size " + std::to_string(rects_.size()) + ": ";
196         for (auto& rect : rects_) {
197             info.append(rect.GetRectInfo());
198         }
199         info.append(" }");
200         return info;
201     }
202 
Size()203     inline size_t Size() const
204     {
205         return rects_.size();
206     }
207 
CBegin()208     inline std::vector<Rect>::const_iterator CBegin() const
209     {
210         return rects_.cbegin();
211     }
212 
Begin()213     inline std::vector<Rect>::iterator Begin()
214     {
215         return rects_.begin();
216     }
217 
CEnd()218     inline std::vector<Rect>::const_iterator CEnd() const
219     {
220         return rects_.cend();
221     }
222 
End()223     inline std::vector<Rect>::const_iterator End()
224     {
225         return rects_.end();
226     }
227 
228     /* core Region logic operation function, the return region's rects is guaranteed no-intersection
229         (rect in rects_ do not intersect with each other)
230     */
231     void RegionOp(Region& r1, Region& r2, Region& res, Region::OP op);
232     void RegionOpLocal(Region& r1, Region& r2, Region& res, Region::OP op);
233     // bound of all region rects
234     void MakeBound();
235 
236     // return merge region
237     Region Or(Region& r);
238     // return intersection region
239     Region And(Region& r);
240     // return region belongs to Region(lhs) but not Region(rhs)
241     Region Sub(Region& r);
242     // return merge region subtract intersection region
243     Region Xor(Region& r);
244 
245     Region& OperationSelf(Region& r, Region::OP op);
246     // replace region with or result
247     Region& OrSelf(Region& r);
248     // replace region with and result
249     Region& AndSelf(Region& r);
250     // replace region with sub result
251     Region& SubSelf(Region& r);
252     // replace region with xor result
253     Region& XOrSelf(Region& r);
254 
255 private:
256     class Rects {
257     public:
258         int preY = 0;
259         int curY = 0;
260         std::vector<Rect> preRects;
261         std::vector<Rect> curRects;
262     };
263     // update tmp rects and region according to current ranges
264     void UpdateRects(Rects& r, std::vector<Range>& ranges, std::vector<int>& indexAt, Region& res);
265     // get ranges from segmentTree node according to logical operation type
266     void getRange(std::vector<Range>& ranges, Node& node, OP op);
267 
268 private:
269     std::vector<Rect> rects_;
270     Rect bound_;
271     static bool _s_so_loaded_;
272 };
273 std::ostream& operator<<(std::ostream& os, const Region& r);
274 } // namespace OHOS::Rosen::Occlusion
275 #endif // OHOS_ROSEN_WM_OCCLUSION_REGION_H