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