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 16#include "display_cutout_controller.h" 17#include <screen_manager/screen_types.h> 18#include "display_manager_service_inner.h" 19#include "dm_common.h" 20 21namespace OHOS { 22namespace Rosen { 23namespace { 24constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "DisplayCutoutController"}; 25const uint32_t NO_WATERFALL_DISPLAY_COMPRESSION_SIZE = 0; 26} 27 28bool DisplayCutoutController::isWaterfallDisplay_ = false; 29bool DisplayCutoutController::isWaterfallAreaCompressionEnableWhenHorizontal_ = false; 30uint32_t DisplayCutoutController::waterfallAreaCompressionSizeWhenHorizontal_ = 0; 31 32void DisplayCutoutController::SetBuiltInDisplayCutoutSvgPath(const std::string& svgPath) 33{ 34 SetCutoutSvgPath(0, svgPath); 35} 36 37void DisplayCutoutController::SetIsWaterfallDisplay(bool isWaterfallDisplay) 38{ 39 WLOGFI("Set isWaterfallDisplay: %{public}u", isWaterfallDisplay); 40 isWaterfallDisplay_ = isWaterfallDisplay; 41} 42 43bool DisplayCutoutController::IsWaterfallDisplay() 44{ 45 return isWaterfallDisplay_; 46} 47 48void DisplayCutoutController::SetCurvedScreenBoundary(std::vector<int> curvedScreenBoundary) 49{ 50 while (curvedScreenBoundary.size() < 4) { // 4 directions. 51 curvedScreenBoundary.emplace_back(0); 52 } 53 WLOGFI("Set curvedScreenBoundary"); 54 curvedScreenBoundary_ = curvedScreenBoundary; 55} 56 57void DisplayCutoutController::SetCutoutSvgPath(DisplayId displayId, const std::string& svgPath) 58{ 59 WLOGFI("Set SvgPath: %{public}s", svgPath.c_str()); 60 if (svgPaths_.count(displayId) == 1) { 61 svgPaths_[displayId].emplace_back(svgPath); 62 } else { 63 std::vector<std::string> pathVec; 64 pathVec.emplace_back(svgPath); 65 svgPaths_[displayId] = pathVec; 66 } 67 DMRect boundingRect = CalcCutoutBoundingRect(svgPath); 68 if (boundingRects_.count(displayId) == 1) { 69 boundingRects_[displayId].emplace_back(boundingRect); 70 } else { 71 std::vector<DMRect> rectVec; 72 rectVec.emplace_back(boundingRect); 73 boundingRects_[displayId] = rectVec; 74 } 75} 76 77sptr<CutoutInfo> DisplayCutoutController::GetCutoutInfo(DisplayId displayId) 78{ 79 WLOGFD("Get Cutout Info"); 80 std::vector<DMRect> boundingRects; 81 WaterfallDisplayAreaRects waterfallDisplayAreaRects; 82 if (boundingRects_.count(displayId) == 1) { 83 TransferBoundingRectsByRotation(displayId, boundingRects); 84 } 85 if (displayId == DisplayManagerServiceInner::GetInstance().GetDefaultDisplayId()) { 86 CalcBuiltInDisplayWaterfallRects(); 87 waterfallDisplayAreaRects = waterfallDisplayAreaRects_; 88 } 89 sptr<CutoutInfo> cutoutInfo(new CutoutInfo(boundingRects, waterfallDisplayAreaRects)); 90 return cutoutInfo; 91} 92 93void DisplayCutoutController::CheckBoundingRectsBoundary(DisplayId displayId, std::vector<DMRect>& boundingRects) 94{ 95 sptr<SupportedScreenModes> modes = 96 DisplayManagerServiceInner::GetInstance().GetScreenModesByDisplayId(displayId); 97 if (modes == nullptr) { 98 WLOGFE("DisplayId is invalid"); 99 return; 100 } 101 uint32_t displayHeight = modes->height_; 102 uint32_t displayWidth = modes->width_; 103 for (auto iter = boundingRects.begin(); iter != boundingRects.end();) { 104 DMRect boundingRect = *iter; 105 if (boundingRect.posX_ < 0 || boundingRect.posY_ < 0 || 106 static_cast<int32_t>(boundingRect.width_) + boundingRect.posX_ > static_cast<int32_t>(displayWidth) || 107 static_cast<int32_t>(boundingRect.height_) + boundingRect.posY_ > static_cast<int32_t>(displayHeight) || 108 boundingRect.width_ > displayWidth || boundingRect.height_ > displayHeight || 109 boundingRect.IsUninitializedRect()) { 110 WLOGFE("boundingRect boundary is invalid"); 111 iter = boundingRects.erase(iter); 112 } else { 113 iter++; 114 } 115 } 116} 117 118DMRect DisplayCutoutController::CalcCutoutBoundingRect(std::string svgPath) 119{ 120 DMRect emptyRect = {0, 0, 0, 0}; 121 SkPath skCutoutSvgPath; 122 if (!SkParsePath::FromSVGString(svgPath.c_str(), &skCutoutSvgPath)) { 123 WLOGFE("Parse svg string path failed."); 124 return emptyRect; 125 } 126 SkRect skRect = skCutoutSvgPath.computeTightBounds(); 127 if (skRect.isEmpty()) { 128 WLOGFW("Get empty skRect"); 129 return emptyRect; 130 } 131 SkIRect skiRect = skRect.roundOut(); 132 if (skiRect.isEmpty()) { 133 WLOGFW("Get empty skiRect"); 134 return emptyRect; 135 } 136 int32_t left = static_cast<int32_t>(skiRect.left()); 137 int32_t top = static_cast<int32_t>(skiRect.top()); 138 uint32_t width = static_cast<uint32_t>(skiRect.width()); 139 uint32_t height = static_cast<uint32_t>(skiRect.height()); 140 WLOGFI("calc rect from path,[%{public}d, %{public}d, %{public}u, %{public}u]", left, top, width, height); 141 DMRect cutoutMinOuterRect = {.posX_ = left, .posY_ = top, .width_ = width, .height_ = height}; 142 return cutoutMinOuterRect; 143} 144 145void DisplayCutoutController::CalcBuiltInDisplayWaterfallRects() 146{ 147 WaterfallDisplayAreaRects emptyRects = {}; 148 if (!isWaterfallDisplay_) { 149 WLOGFI("not waterfall display"); 150 waterfallDisplayAreaRects_ = emptyRects; 151 return; 152 } 153 if (curvedScreenBoundary_.empty()) { 154 WLOGFI("curved screen boundary is empty"); 155 waterfallDisplayAreaRects_ = emptyRects; 156 return; 157 } 158 uint32_t left = static_cast<uint32_t>(curvedScreenBoundary_[0]); 159 uint32_t top = static_cast<uint32_t>(curvedScreenBoundary_[1]); 160 uint32_t right = static_cast<uint32_t>(curvedScreenBoundary_[2]); 161 uint32_t bottom = static_cast<uint32_t>(curvedScreenBoundary_[3]); 162 if (left == 0 && top == 0 && right == 0 && bottom == 0) { 163 waterfallDisplayAreaRects_ = emptyRects; 164 return; 165 } 166 sptr<SupportedScreenModes> modes = 167 DisplayManagerServiceInner::GetInstance().GetScreenModesByDisplayId( 168 DisplayManagerServiceInner::GetInstance().GetDefaultDisplayId()); 169 if (!modes) { 170 WLOGE("support screen modes get failed"); 171 waterfallDisplayAreaRects_ = emptyRects; 172 return; 173 } 174 uint32_t displayHeight = modes->height_; 175 uint32_t displayWidth = modes->width_; 176 177 if ((left > displayWidth / 2) || (right > displayWidth / 2) || // invalid if more than 1/2 width 178 (top > displayHeight / 2) || (bottom > displayHeight / 2)) { // invalid if more than 1/2 height 179 WLOGFE("Curved screen boundary data is not valid."); 180 waterfallDisplayAreaRects_ = emptyRects; 181 return; 182 } 183 CalcBuiltInDisplayWaterfallRectsByRotation( 184 DisplayManagerServiceInner::GetInstance().GetDefaultDisplay()->GetRotation(), 185 displayHeight, displayWidth); 186} 187 188void DisplayCutoutController::CalcBuiltInDisplayWaterfallRectsByRotation( 189 Rotation rotation, uint32_t displayHeight, uint32_t displayWidth) 190{ 191 uint32_t left = static_cast<uint32_t>(curvedScreenBoundary_[0]); 192 uint32_t top = static_cast<uint32_t>(curvedScreenBoundary_[1]); 193 uint32_t right = static_cast<uint32_t>(curvedScreenBoundary_[2]); 194 uint32_t bottom = static_cast<uint32_t>(curvedScreenBoundary_[3]); 195 switch (rotation) { 196 case Rotation::ROTATION_0: { 197 DMRect leftRect = CreateWaterfallRect(0, 0, left, displayHeight); 198 DMRect topRect = CreateWaterfallRect(0, 0, displayWidth, top); 199 DMRect rightRect = CreateWaterfallRect(displayWidth - right, 0, right, displayHeight); 200 DMRect bottomRect = CreateWaterfallRect(0, displayHeight - bottom, displayWidth, bottom); 201 waterfallDisplayAreaRects_ = WaterfallDisplayAreaRects {leftRect, topRect, rightRect, bottomRect}; 202 return; 203 } 204 case Rotation::ROTATION_90: { 205 DMRect leftRect = CreateWaterfallRect(0, 0, bottom, displayWidth); 206 DMRect topRect = CreateWaterfallRect(0, 0, displayHeight, left); 207 DMRect rightRect = CreateWaterfallRect(displayHeight - top, 0, top, displayWidth); 208 DMRect bottomRect = CreateWaterfallRect(0, displayWidth - right, displayHeight, right); 209 waterfallDisplayAreaRects_ = WaterfallDisplayAreaRects {leftRect, topRect, rightRect, bottomRect}; 210 return; 211 } 212 case Rotation::ROTATION_180: { 213 DMRect leftRect = CreateWaterfallRect(0, 0, right, displayHeight); 214 DMRect topRect = CreateWaterfallRect(0, 0, bottom, displayWidth); 215 DMRect rightRect = CreateWaterfallRect(displayWidth - left, 0, left, displayHeight); 216 DMRect bottomRect = CreateWaterfallRect(0, displayHeight - top, displayWidth, top); 217 waterfallDisplayAreaRects_ = WaterfallDisplayAreaRects {leftRect, topRect, rightRect, bottomRect}; 218 return; 219 } 220 case Rotation::ROTATION_270: { 221 DMRect leftRect = CreateWaterfallRect(0, 0, top, displayWidth); 222 DMRect topRect = CreateWaterfallRect(0, 0, displayHeight, right); 223 DMRect rightRect = CreateWaterfallRect(displayHeight - bottom, 0, bottom, displayWidth); 224 DMRect bottomRect = CreateWaterfallRect(0, displayWidth - left, displayHeight, left); 225 waterfallDisplayAreaRects_ = WaterfallDisplayAreaRects {leftRect, topRect, rightRect, bottomRect}; 226 return; 227 } 228 default: { 229 } 230 } 231} 232 233void DisplayCutoutController::TransferBoundingRectsByRotation(DisplayId displayId, std::vector<DMRect>& boundingRects) 234{ 235 std::vector<DMRect> resultVec; 236 if (boundingRects_.count(displayId) == 0) { 237 boundingRects = resultVec; 238 return; 239 } 240 std::vector<DMRect> displayBoundingRects = boundingRects_[displayId]; 241 if (displayBoundingRects.empty()) { 242 boundingRects = resultVec; 243 return; 244 } 245 sptr<DisplayInfo> displayInfo = DisplayManagerServiceInner::GetInstance().GetDisplayById(displayId); 246 if (!displayInfo) { 247 WLOGFE("display invaild"); 248 return; 249 } 250 Rotation currentRotation = displayInfo->GetRotation(); 251 CheckBoundingRectsBoundary(displayId, displayBoundingRects); 252 if (currentRotation == Rotation::ROTATION_0) { 253 boundingRects = displayBoundingRects; 254 return; 255 } 256 sptr<SupportedScreenModes> modes = 257 DisplayManagerServiceInner::GetInstance().GetScreenModesByDisplayId(displayId); 258 if (!modes) { 259 WLOGE("support screen modes get failed"); 260 return; 261 } 262 uint32_t displayHeight = modes->height_; 263 uint32_t displayWidth = modes->width_; 264 265 switch (currentRotation) { 266 case Rotation::ROTATION_90: { 267 CurrentRotation90(resultVec, displayBoundingRects, displayHeight); 268 break; 269 } 270 case Rotation::ROTATION_180: { 271 CurrentRotation180(resultVec, displayBoundingRects, displayHeight, displayWidth); 272 break; 273 } 274 case Rotation::ROTATION_270: { 275 for (DMRect rect : displayBoundingRects) { 276 resultVec.emplace_back(DMRect {rect.posY_, displayWidth - rect.posX_ - rect.width_, 277 rect.height_, rect.width_}); 278 } 279 break; 280 } 281 default: { 282 } 283 } 284 boundingRects = resultVec; 285} 286 287void DisplayCutoutController::CurrentRotation90(std::vector<DMRect> resultVec, 288 std::vector<DMRect> displayBoundingRects, uint32_t displayHeight) 289{ 290 for (DMRect rect : displayBoundingRects) { 291 resultVec.emplace_back(DMRect {.posX_ = displayHeight - rect.posY_ - rect.height_, 292 .posY_ = rect.posX_, .width_ = rect.height_, .height_ = rect.width_}); 293 } 294} 295 296void DisplayCutoutController::CurrentRotation180(std::vector<DMRect> resultVec, 297 std::vector<DMRect> displayBoundingRects, uint32_t displayHeight, uint32_t displayWidth) 298{ 299 for (DMRect rect : displayBoundingRects) { 300 resultVec.emplace_back(DMRect {displayWidth - rect.posX_ - rect.width_, 301 displayHeight - rect.posY_ - rect.height_, rect.width_, rect.height_}); 302 } 303} 304 305DMRect DisplayCutoutController::CreateWaterfallRect(uint32_t left, uint32_t top, uint32_t width, uint32_t height) 306{ 307 if (width == 0 || height == 0) { 308 return DMRect {0, 0, 0, 0}; 309 } 310 return DMRect {left, top, width, height}; 311} 312 313void DisplayCutoutController::SetWaterfallAreaCompressionEnableWhenHorzontal(bool isEnable) 314{ 315 isWaterfallAreaCompressionEnableWhenHorizontal_ = isEnable; 316} 317 318void DisplayCutoutController::SetWaterfallAreaCompressionSizeWhenHorizontal(uint32_t size) 319{ 320 waterfallAreaCompressionSizeWhenHorizontal_ = size; 321} 322 323bool DisplayCutoutController::IsWaterfallAreaCompressionEnableWhenHorizontal() 324{ 325 return isWaterfallDisplay_ && isWaterfallAreaCompressionEnableWhenHorizontal_; 326} 327 328uint32_t DisplayCutoutController::GetWaterfallAreaCompressionSizeWhenHorizontal() 329{ 330 if (!isWaterfallDisplay_ || !isWaterfallAreaCompressionEnableWhenHorizontal_) { 331 WLOGFW("Not waterfall display or not enable waterfall compression"); 332 return NO_WATERFALL_DISPLAY_COMPRESSION_SIZE; 333 } 334 return waterfallAreaCompressionSizeWhenHorizontal_; 335} 336} // Rosen 337} // OHOS 338