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 16 #include <algorithm> 17 #include "ui_model.h" 18 19 namespace OHOS::uitest { 20 using namespace std; 21 ComputeIntersection(const Rect & ra,const Rect & rb,Rect & result)22 bool RectAlgorithm::ComputeIntersection(const Rect &ra, const Rect &rb, Rect &result) 23 { 24 if (ra.left_ >= rb.right_ || ra.right_ <= rb.left_) { 25 return false; 26 } 27 if (ra.top_ >= rb.bottom_ || ra.bottom_ <= rb.top_) { 28 return false; 29 } 30 array<int32_t, INDEX_FOUR> px = {ra.left_, ra.right_, rb.left_, rb.right_}; 31 array<int32_t, INDEX_FOUR> py = {ra.top_, ra.bottom_, rb.top_, rb.bottom_}; 32 sort(px.begin(), px.end()); 33 sort(py.begin(), py.end()); 34 result = {px[INDEX_ONE], px[INDEX_TWO], py[INDEX_ONE], py[INDEX_TWO]}; 35 return true; 36 } 37 38 /** Use static data buffers instead of dynamic-containers to ensure performance.*/ 39 static constexpr size_t MAX_OVERLAYS = 64; 40 static constexpr size_t MAX_COORDS = (MAX_OVERLAYS + 1) << 1; 41 static constexpr size_t MAX_POINTS = MAX_COORDS * MAX_COORDS; 42 static int32_t g_XCoords[MAX_COORDS]; 43 static int32_t g_YCoords[MAX_COORDS]; 44 static Point g_Points[MAX_POINTS]; 45 static size_t g_XCount = 0; 46 static size_t g_YCount = 0; 47 static size_t g_PCount = 0; 48 CollectGridLineCoords(const Rect & rect,const Rect & overlay)49 static void CollectGridLineCoords(const Rect& rect, const Rect& overlay) 50 { 51 bool contained = false; 52 if (overlay.left_ >= rect.left_ && overlay.left_ <= rect.right_) { 53 for (size_t idx = 0; idx < g_XCount; idx++) { 54 if (overlay.left_ == g_XCoords[idx]) { 55 contained = true; 56 break; 57 } 58 } 59 if (!contained) { 60 g_XCoords[g_XCount++] = overlay.left_; 61 } 62 } 63 64 contained = false; 65 if (overlay.right_ >= rect.left_ && overlay.right_ <= rect.right_) { 66 for (size_t idx = 0; idx < g_XCount; idx++) { 67 if (overlay.right_ == g_XCoords[idx]) { 68 contained = true; 69 break; 70 } 71 } 72 if (!contained) { 73 g_XCoords[g_XCount++] = overlay.right_; 74 } 75 } 76 77 contained = false; 78 if (overlay.top_ >= rect.top_ && overlay.top_ <= rect.bottom_) { 79 for (size_t idx = 0; idx < g_YCount; idx++) { 80 if (overlay.top_ == g_YCoords[idx]) { 81 contained = true; 82 break; 83 } 84 } 85 if (!contained) { 86 g_YCoords[g_YCount++] = overlay.top_; 87 } 88 } 89 90 contained = false; 91 if (overlay.bottom_ >= rect.top_ && overlay.bottom_ <= rect.bottom_) { 92 for (size_t idx = 0; idx < g_YCount; idx++) { 93 if (overlay.bottom_ == g_YCoords[idx]) { 94 contained = true; 95 break; 96 } 97 } 98 if (!contained) { 99 g_YCoords[g_YCount++] = overlay.bottom_; 100 } 101 } 102 } 103 CollectGridPoint(int32_t px,int32_t py,const Rect & rect,const vector<Rect> & overlays)104 static void CollectGridPoint(int32_t px, int32_t py, const Rect& rect, const vector<Rect>& overlays) 105 { 106 const auto point = Point(px, py); 107 const bool onRectEdge = RectAlgorithm::IsPointOnEdge(rect, point); 108 if (!onRectEdge && !RectAlgorithm::IsInnerPoint(rect, point)) { 109 return; // point must be on or in the rect 110 } 111 bool onOverlyEdge = false; 112 for (const auto& overlay : overlays) { 113 if (RectAlgorithm::IsInnerPoint(overlay, point)) { 114 return; // point is in at least one of the overlays, discard 115 } 116 if (!onRectEdge && !onOverlyEdge) { 117 onOverlyEdge = RectAlgorithm::IsPointOnEdge(overlay, point); 118 } 119 } 120 if (onRectEdge || onOverlyEdge) { 121 g_Points[g_PCount++] = point; 122 } 123 } 124 FindMaxVisibleRegion(const vector<Rect> & overlays,Rect & out)125 static void FindMaxVisibleRegion(const vector<Rect>& overlays, Rect& out) 126 { 127 // sort grid points and use double-pointer traversing, to resuce time-complexity 128 sort(g_Points, g_Points + g_PCount, [](const Point& pa, const Point& pb) { 129 return pa.px_ == pb.px_ ? pa.py_ < pb.py_ : pa.px_ < pb.px_; 130 }); 131 out = Rect(0, 0, 0, 0); 132 for (size_t idx0 = 0; idx0 < g_PCount; idx0++) { 133 for (size_t idx1 = g_PCount - 1; idx1 > idx0; idx1--) { 134 const auto width = g_Points[idx1].px_ - g_Points[idx0].px_; 135 const auto height = g_Points[idx1].py_ - g_Points[idx0].py_; 136 if (width <= 0) { 137 break; // x is strictly ascending ordered 138 } 139 if (width * height <= out.GetWidth() * out.GetHeight()) { 140 continue; // discard smaller region 141 } 142 auto intersect = false; 143 const auto area = Rect(g_Points[idx0].px_, g_Points[idx1].px_, g_Points[idx0].py_, g_Points[idx1].py_); 144 for (auto& overlay : overlays) { 145 if (RectAlgorithm::CheckIntersectant(overlay, area)) { 146 intersect = true; // region is intersected with some overlays, discard 147 break; 148 } 149 } 150 if (!intersect) { 151 out = area; 152 } 153 } 154 } 155 } 156 ComputeMaxVisibleRegion(const Rect & rect,const vector<Rect> & overlays,Rect & out)157 bool RectAlgorithm::ComputeMaxVisibleRegion(const Rect& rect, const vector<Rect>& overlays, Rect& out) 158 { 159 vector<Rect> filteredOverlays; 160 for (auto& overlay : overlays) { 161 if (!RectAlgorithm::CheckIntersectant(rect, overlay)) { 162 continue; // no intersection, invalid overlay 163 } 164 auto intersection = Rect(0, 0, 0, 0); 165 const auto intersected = RectAlgorithm::ComputeIntersection(rect, overlay, intersection); 166 if (intersected && RectAlgorithm::CheckEqual(rect, intersection)) { 167 out = Rect(0, 0, 0, 0); 168 return false; // fully covered, no visible region 169 } 170 filteredOverlays.emplace_back(overlay); 171 } 172 if (filteredOverlays.empty()) { 173 out = rect; 174 return true; // not covered 175 } 176 g_XCount = 0; 177 g_YCount = 0; 178 g_PCount = 0; 179 CollectGridLineCoords(rect, rect); 180 for (auto& overlay : filteredOverlays) { 181 CollectGridLineCoords(rect, overlay); 182 } 183 for (size_t xIdx = 0; xIdx < g_XCount; xIdx++) { 184 for (size_t yIdx = 0; yIdx < g_YCount; yIdx++) { 185 CollectGridPoint(g_XCoords[xIdx], g_YCoords[yIdx], rect, filteredOverlays); 186 } 187 } 188 FindMaxVisibleRegion(filteredOverlays, out); 189 return out.GetHeight() > 0 && out.GetWidth() > 0; 190 } 191 } // namespace OHOS::uitest 192