1 /*
2  * Copyright (c) 2023-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 #include <common/rs_occlusion_region_helper.h>
16 
17 namespace OHOS {
18 namespace Rosen {
19 namespace Occlusion {
20 
Insert(const Rect & r)21 void Assembler::Insert(const Rect&r)
22 {
23     if (rectsRow_.size() > 0) {
24         if (cur_->top_ != r.top_) {                 // current rect r is not in same row of current span
25             FlushVerticalSpan();                    // current span will be cleared
26         } else if (cur_->right_ == r.left_) {      // merge rect in horizon (X) direction
27             cur_->right_ = r.right_;
28             return;
29         }
30     }
31     rectsRow_.push_back(r);
32     cur_ = rectsRow_.begin() + static_cast<long>(rectsRow_.size() - 1);
33 }
34 
FlushVerticalSpan()35 void Assembler::FlushVerticalSpan()
36 {
37     if (rectsRow_.size() == 0) {
38         return;
39     }
40     if (CurrentSpanCanMerge()) {
41         MergeSpanVertically();
42     } else {
43         bound_.left_ = std::min(rectsRow_[0].left_, bound_.left_);
44         bound_.right_ = std::max(rectsRow_[rectsRow_.size() - 1].right_, bound_.right_);
45         storage_.insert(storage_.end(), rectsRow_.begin(), rectsRow_.end());
46         end_ = (storage_.begin() + static_cast<long>(storage_.size()));
47         lastRectRowBegin_ = end_ - static_cast<long>(rectsRow_.size());
48     }
49     rectsRow_.clear();
50 }
51 
CurrentSpanCanMerge() const52 bool Assembler::CurrentSpanCanMerge() const
53 {
54     bool merge = false;
55     if (end_ - lastRectRowBegin_ == static_cast<long>(rectsRow_.size())) {
56         std::vector<Rect>::const_iterator curRowPtr = rectsRow_.cbegin();
57         std::vector<Rect>::const_iterator lastRowPtr = lastRectRowBegin_;
58         if (curRowPtr->top_ != lastRowPtr->bottom_) {
59             return false;
60         }
61         merge = true;
62         while (lastRowPtr != end_) {
63             if ((curRowPtr->left_ != lastRowPtr->left_) ||
64                 (curRowPtr->right_ != lastRowPtr->right_)) {
65                 merge = false;
66                 break;
67             }
68             ++curRowPtr;
69             ++lastRowPtr;
70         }
71     }
72     return merge;
73 }
74 
MergeSpanVertically()75 void Assembler::MergeSpanVertically()
76 {
77     if (rectsRow_.size() == 0) {
78         return;
79     }
80     const int bottom = rectsRow_[0].bottom_;
81     std::vector<Rect>::iterator r = lastRectRowBegin_;
82     while (r != end_) {
83         r->bottom_ = bottom;
84         ++r;
85     }
86 }
87 
~Assembler()88 Assembler::~Assembler()
89 {
90     if (storage_.size()) {
91         bound_.top_ = storage_[0].top_;
92         bound_.bottom_ = storage_[storage_.size() - 1].bottom_;
93     }
94 }
95 
GetEdgeRelation(int & head,int & tail,bool & moreLhs,bool & moreRhs)96 inline RectType Looper::GetEdgeRelation(int &head, int &tail,
97     bool &moreLhs, bool &moreRhs)
98 {
99     RectType relationship;
100     moreLhs = false;
101     moreRhs = false;
102     if (lhsStart_ < rhsStart_) {
103         relationship = RectType::LHS_ONLY;
104         head = lhsStart_;
105         if (lhsEnd_ <= rhsStart_) {
106             tail = lhsEnd_;
107             moreLhs = true;
108         } else {
109             lhsStart_ = rhsStart_;
110             tail = rhsStart_;
111         }
112     } else if (rhsStart_ < lhsStart_) {
113         relationship = RectType::RHS_ONLY;
114         head = rhsStart_;
115         if (rhsEnd_ <= lhsStart_) {
116             tail = rhsEnd_;
117             moreRhs = true;
118         } else {
119             rhsStart_ = lhsStart_;
120             tail = lhsStart_;
121         }
122     } else {
123         relationship = RectType::LHS_RHS_BOTH;
124         head = lhsStart_;
125         if (lhsEnd_ <= rhsEnd_) {
126             tail = rhsStart_ = lhsEnd_;
127             moreLhs = true;
128         }
129         if (rhsEnd_ <= lhsEnd_) {
130             tail = lhsStart_ = rhsEnd_;
131             moreRhs = true;
132         }
133     }
134     return relationship;
135 }
136 
NextScanline(int & curTop,int & curBottom)137 RectType OuterLooper::NextScanline(int &curTop, int &curBottom)
138 {
139     bool moreLhs;
140     bool moreRhs;
141     RectType relationships = Looper::GetEdgeRelation(curTop, curBottom, moreLhs, moreRhs);
142     MoveScanline(moreLhs, moreRhs);
143     return relationships;
144 }
145 
MoveScanline(bool moreLhs,bool moreRhs)146 inline void OuterLooper::MoveScanline(bool moreLhs, bool moreRhs)
147 {
148     if (moreLhs) {
149         MoveScanline(lhs_, lhsStart_, lhsEnd_);
150     }
151     if (moreRhs) {
152         MoveScanline(rhs_, rhsStart_, rhsEnd_);
153     }
154     return;
155 }
156 
MoveScanline(RectsPtr & r,int & top,int & bottom)157 void OuterLooper::MoveScanline(RectsPtr &r, int &top, int &bottom)
158 {
159     auto rect = r.rects_;
160     auto count = r.count_;
161     auto rectEnd = rect + static_cast<long>(count);
162     int curTop = rect->top_;
163     while (rect != rectEnd && rect->top_ == curTop) {
164         ++rect;
165         --count;
166     }
167     if (rect != rectEnd) {
168         top = rect->top_;
169         bottom = rect->bottom_;
170     } else {
171         top = INT_MAX;
172         bottom = INT_MAX;
173     }
174     r.rects_ = rect;
175     r.count_ = count;
176     return;
177 }
178 
Init(RectType relationship)179 void InnerLooper::Init(RectType relationship)
180 {
181     if (relationship == RectType::LHS_ONLY) {
182         if (lhs_.count_) {
183             lhsStart_ = lhs_.rects_->left_;
184             lhsEnd_ = lhs_.rects_->right_;
185         }
186         rhsStart_ = INT_MAX;
187         rhsEnd_ = INT_MAX;
188     } else if (relationship == RectType::RHS_ONLY) {
189         if (rhs_.count_) {
190             rhsStart_ = rhs_.rects_->left_;
191             rhsEnd_ = rhs_.rects_->right_;
192         }
193         lhsStart_ = INT_MAX;
194         lhsEnd_ = INT_MAX;
195     } else {
196         if (lhs_.count_) {
197             lhsStart_ = lhs_.rects_->left_;
198             lhsEnd_ = lhs_.rects_->right_;
199         }
200         if (rhs_.count_) {
201             rhsStart_ = rhs_.rects_->left_;
202             rhsEnd_ = rhs_.rects_->right_;
203         }
204     }
205 }
206 
NextRect(int & curLeft,int & curRight)207 RectType InnerLooper::NextRect(int &curLeft, int &curRight)
208 {
209     bool moreLhs;
210     bool moreRhs;
211     RectType rectType = GetEdgeRelation(curLeft, curRight, moreLhs, moreRhs);
212     MoveRect(moreLhs, moreRhs);
213     return rectType;
214 }
215 
MoveRect(bool moreLhs,bool moreRhs)216 inline void InnerLooper::MoveRect(bool moreLhs, bool moreRhs)
217 {
218     if (moreLhs) {
219         MoveRect(lhs_, lhsStart_, lhsEnd_);
220     }
221     if (moreRhs) {
222         MoveRect(rhs_, rhsStart_, rhsEnd_);
223     }
224     return;
225 }
226 
MoveRect(RectsPtr & r,int & left,int & right)227 void InnerLooper::MoveRect(RectsPtr &r, int &left, int &right)
228 {
229     if (r.count_) {
230         int curTop = r.rects_->top_;
231         ++r.rects_;
232         r.count_--;
233         if (r.count_ > 0 && r.rects_->top_ == curTop) {
234             left = r.rects_->left_;
235             right = r.rects_->right_;
236         } else {
237             left = INT_MAX;
238             right = INT_MAX;
239         }
240     }
241 }
242 
243 } // namespace Occlusion
244 } // namespace Rosen
245 } // namespace OHOS