1 /*
2 * Copyright (c) 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 "rs_round_corner_display.h"
17 #include <SkImage.h>
18 #include <SkData.h>
19 #include <SkStream.h>
20 #include <SkMatrix.h>
21 #include <SkCanvas.h>
22 #include <mutex>
23 #include "platform/common/rs_system_properties.h"
24 #include "common/rs_optional_trace.h"
25 #include "common/rs_singleton.h"
26 #include "rs_sub_thread_rcd.h"
27
28 namespace OHOS {
29 namespace Rosen {
RoundCornerDisplay()30 RoundCornerDisplay::RoundCornerDisplay()
31 {
32 RS_LOGD("[%{public}s] Created \n", __func__);
33 Init();
34 }
35
~RoundCornerDisplay()36 RoundCornerDisplay::~RoundCornerDisplay()
37 {
38 RS_LOGD("[%{public}s] Destroy \n", __func__);
39 }
40
Init()41 bool RoundCornerDisplay::Init()
42 {
43 LoadConfigFile();
44 SeletedLcdModel(rs_rcd::ATTR_DEFAULT);
45 LoadImgsbyResolution(displayWidth_, displayHeight_);
46 isRcdEnable_ = RSSystemProperties::GetRSScreenRoundCornerEnable();
47 RS_LOGD("[%{public}s] RoundCornerDisplay init \n", __func__);
48 return true;
49 }
50
SeletedLcdModel(const char * lcdModelName)51 bool RoundCornerDisplay::SeletedLcdModel(const char* lcdModelName)
52 {
53 auto& rcdCfg = RSSingleton<rs_rcd::RCDConfig>::GetInstance();
54 lcdModel_ = rcdCfg.GetLcdModel(lcdModelName);
55 if (lcdModel_ == nullptr) {
56 RS_LOGD("[%{public}s] No lcdModel found in config file with name %{public}s \n", __func__, lcdModelName);
57 return false;
58 }
59 supportTopSurface_ = lcdModel_->surfaceConfig.topSurface.support;
60 supportBottomSurface_ = lcdModel_->surfaceConfig.bottomSurface.support;
61 supportHardware_ = lcdModel_->hardwareConfig.hardwareComposer.support;
62 RS_LOGI("[%{public}s] Selected model: %{public}s, supported: top->%{public}d, bottom->%{public}d,"
63 "hardware->%{public}d \n", __func__, lcdModelName, static_cast<int>(supportTopSurface_),
64 static_cast<int>(supportBottomSurface_), static_cast<int>(supportHardware_));
65 return true;
66 }
67
LoadConfigFile()68 bool RoundCornerDisplay::LoadConfigFile()
69 {
70 RS_LOGD("[%{public}s] LoadConfigFile \n", __func__);
71 auto& rcdCfg = RSSingleton<rs_rcd::RCDConfig>::GetInstance();
72 return rcdCfg.Load(rs_rcd::PATH_CONFIG_FILE);
73 }
74
75 #ifndef USE_ROSEN_DRAWING
LoadImg(const char * path,sk_sp<SkImage> & img)76 bool RoundCornerDisplay::LoadImg(const char* path, sk_sp<SkImage>& img)
77 {
78 std::string filePath = std::string(rs_rcd::PATH_CONFIG_DIR) + "/" + path;
79 RS_LOGD("[%{public}s] Read Img(%{public}s) \n", __func__, filePath.c_str());
80 sk_sp<SkData> skData = SkData::MakeFromFileName(filePath.c_str());
81 if (skData == nullptr) {
82 RS_LOGE("[%{public}s] Open picture file failed! \n", __func__);
83 return false;
84 }
85 img = SkImage::MakeFromEncoded(skData);
86 if (img == nullptr) {
87 RS_LOGE("[%{public}s] Decode picture file failed! \n", __func__);
88 return false;
89 }
90 return true;
91 }
92
DecodeBitmap(sk_sp<SkImage> image,SkBitmap & bitmap)93 bool RoundCornerDisplay::DecodeBitmap(sk_sp<SkImage> image, SkBitmap &bitmap)
94 {
95 if (image == nullptr) {
96 RS_LOGE("[%{public}s] No image found \n", __func__);
97 return false;
98 }
99 if (!image->asLegacyBitmap(&bitmap, SkImage::kRO_LegacyBitmapMode)) {
100 RS_LOGE("[%{public}s] Create bitmap from skImage failed \n", __func__);
101 return false;
102 }
103 return true;
104 }
105 #else
LoadImg(const char * path,std::shared_ptr<Drawing::Image> & img)106 bool RoundCornerDisplay::LoadImg(const char* path, std::shared_ptr<Drawing::Image>& img)
107 {
108 std::string filePath = std::string(rs_rcd::PATH_CONFIG_DIR) + "/" + path;
109 RS_LOGD("[%{public}s] Read Img(%{public}s) \n", __func__, filePath.c_str());
110 std::shared_ptr<Drawing::Data> drData = Drawing::Data::MakeFromFileName(filePath.c_str());
111 if (drData == nullptr) {
112 RS_LOGE("[%{public}s] Open picture file failed! \n", __func__);
113 return false;
114 }
115 img = std::make_shared<Drawing::Image>();
116 if (!img->MakeFromEncoded(drData)) {
117 img = nullptr;
118 RS_LOGE("[%{public}s] Decode picture file failed! \n", __func__);
119 return false;
120 }
121 return true;
122 }
123
DecodeBitmap(std::shared_ptr<Drawing::Image> image,Drawing::Bitmap & bitmap)124 bool RoundCornerDisplay::DecodeBitmap(std::shared_ptr<Drawing::Image> image, Drawing::Bitmap &bitmap)
125 {
126 if (image == nullptr) {
127 RS_LOGE("[%{public}s] No image found \n", __func__);
128 return false;
129 }
130 if (!image->AsLegacyBitmap(bitmap)) {
131 RS_LOGE("[%{public}s] Create bitmap from drImage failed \n", __func__);
132 return false;
133 }
134 return true;
135 }
136 #endif
137
SetHardwareLayerSize()138 bool RoundCornerDisplay::SetHardwareLayerSize()
139 {
140 if (hardInfo_.topLayer == nullptr) {
141 RS_LOGE("[%{public}s] No topLayer found in hardInfo \n", __func__);
142 return false;
143 }
144 if (hardInfo_.bottomLayer == nullptr) {
145 RS_LOGE("[%{public}s] No bottomLayer found in hardInfo \n", __func__);
146 return false;
147 }
148 hardInfo_.topLayer->layerWidth = displayWidth_;
149 hardInfo_.topLayer->layerHeight = displayHeight_;
150 hardInfo_.bottomLayer->layerWidth = displayWidth_;
151 hardInfo_.bottomLayer->layerHeight = displayHeight_;
152 return true;
153 }
154
GetTopSurfaceSource()155 bool RoundCornerDisplay::GetTopSurfaceSource()
156 {
157 if (rog_ == nullptr) {
158 RS_LOGE("[%{public}s] No rog found in config file \n", __func__);
159 return false;
160 }
161 rs_rcd::RCDConfig::PrintParseRog(rog_);
162
163 if (rog_->portraitMap.count(rs_rcd::NODE_PORTRAIT) < 1) {
164 RS_LOGE("[%{public}s] PORTRAIT layerUp do not configured \n", __func__);
165 return false;
166 }
167 LoadImg(rog_->portraitMap[rs_rcd::NODE_PORTRAIT].layerUp.fileName.c_str(), imgTopPortrait_);
168
169 if (rog_->landscapeMap.count(rs_rcd::NODE_LANDSCAPE) < 1) {
170 RS_LOGE("[%{public}s] LANDSACPE layerUp do not configured \n", __func__);
171 return false;
172 }
173 LoadImg(rog_->landscapeMap[rs_rcd::NODE_LANDSCAPE].layerUp.fileName.c_str(), imgTopLadsOrit_);
174
175 if (rog_->portraitMap.count(rs_rcd::NODE_PORTRAIT) < 1) {
176 RS_LOGE("[%{public}s] PORTRAIT layerHide do not configured \n", __func__);
177 return false;
178 }
179 LoadImg(rog_->portraitMap[rs_rcd::NODE_PORTRAIT].layerHide.fileName.c_str(), imgTopHidden_);
180 if (supportHardware_) {
181 DecodeBitmap(imgTopPortrait_, bitmapTopPortrait_);
182 DecodeBitmap(imgTopLadsOrit_, bitmapTopLadsOrit_);
183 DecodeBitmap(imgTopHidden_, bitmapTopHidden_);
184 }
185 return true;
186 }
187
GetBottomSurfaceSource()188 bool RoundCornerDisplay::GetBottomSurfaceSource()
189 {
190 if (rog_ == nullptr) {
191 RS_LOGE("[%{public}s] No rog found in config file \n", __func__);
192 return false;
193 }
194 if (rog_->portraitMap.count(rs_rcd::NODE_PORTRAIT) < 1) {
195 RS_LOGE("[%{public}s] PORTRAIT layerDown do not configured \n", __func__);
196 return false;
197 }
198 LoadImg(rog_->portraitMap[rs_rcd::NODE_PORTRAIT].layerDown.fileName.c_str(), imgBottomPortrait_);
199 if (supportHardware_) {
200 DecodeBitmap(imgBottomPortrait_, bitmapBottomPortrait_);
201 }
202 return true;
203 }
204
LoadImgsbyResolution(uint32_t width,uint32_t height)205 bool RoundCornerDisplay::LoadImgsbyResolution(uint32_t width, uint32_t height)
206 {
207 std::lock_guard<std::mutex> lock(resourceMut_);
208
209 if (lcdModel_ == nullptr) {
210 RS_LOGD("[%{public}s] No lcdModel selected in config file \n", __func__);
211 return false;
212 }
213 rog_ = lcdModel_->GetRog(width, height);
214 if (rog_ == nullptr) {
215 RS_LOGE("[%{public}s] Can't find resolution (%{public}u x %{public}u) in config file \n",
216 __func__, width, height);
217 return false;
218 }
219 RS_LOGD("[%{public}s] Get rog resolution (%{public}u x %{public}u) in config file \n", __func__, width, height);
220 if (supportTopSurface_) {
221 if (!GetTopSurfaceSource()) {
222 RS_LOGE("[%{public}s] Top surface support configured, but resources if missing! \n", __func__);
223 return false;
224 }
225 }
226 if (supportBottomSurface_) {
227 if (!GetBottomSurfaceSource()) {
228 RS_LOGE("[%{public}s] Bottom surface support configured, but resources if missing! \n", __func__);
229 return false;
230 }
231 }
232 return true;
233 }
234
UpdateDisplayParameter(uint32_t width,uint32_t height)235 void RoundCornerDisplay::UpdateDisplayParameter(uint32_t width, uint32_t height)
236 {
237 std::lock_guard<std::mutex> lock(resourceMut_);
238 if (width == displayWidth_ && height == displayHeight_) {
239 RS_LOGD("[%{public}s] DisplayParameter do not change \n", __func__);
240 return;
241 }
242 RS_LOGD("[%{public}s] displayWidth_ updated from %{public}u -> %{public}u,"
243 "displayHeight_ updated from %{public}u -> %{public}u \n", __func__,
244 displayWidth_, width, displayHeight_, height);
245 // the width, height do not use reference,which is local var
246 RSSingleton<RSSubThreadRCD>::GetInstance().PostTask([this, width, height]() {
247 bool isOk = LoadImgsbyResolution(width, height);
248 if (isOk) {
249 std::lock_guard<std::mutex> lock(resourceMut_);
250 updateFlag_["display"] = isOk;
251 displayWidth_ = width;
252 displayHeight_ = height;
253 }
254 });
255 }
256
UpdateNotchStatus(int status)257 void RoundCornerDisplay::UpdateNotchStatus(int status)
258 {
259 std::lock_guard<std::mutex> lock(resourceMut_);
260 // Update surface when surface status changed
261 if (status < 0 || status > 1) {
262 RS_LOGE("[%{public}s] notchStatus won't be over 1 or below 0 \n", __func__);
263 return;
264 }
265 if (notchStatus_ == status) {
266 RS_LOGD("[%{public}s] NotchStatus do not change \n", __func__);
267 return;
268 }
269 RS_LOGD("[%{public}s] notchStatus change from %{public}d to %{public}d \n", __func__, notchStatus_, status);
270 notchStatus_ = status;
271 updateFlag_["notch"] = true;
272 }
273
UpdateOrientationStatus(ScreenRotation orientation)274 void RoundCornerDisplay::UpdateOrientationStatus(ScreenRotation orientation)
275 {
276 std::lock_guard<std::mutex> lock(resourceMut_);
277 if (orientation == curOrientation_) {
278 RS_LOGD("[%{public}s] OrientationStatus do not change \n", __func__);
279 return;
280 }
281 lastOrientation_ = curOrientation_;
282 curOrientation_ = orientation;
283 RS_LOGD("[%{public}s] curOrientation_ = %{public}d, lastOrientation_ = %{public}d \n",
284 __func__, curOrientation_, lastOrientation_);
285 updateFlag_["orientation"] = true;
286 }
287
UpdateParameter(std::map<std::string,bool> & updateFlag)288 void RoundCornerDisplay::UpdateParameter(std::map<std::string, bool>& updateFlag)
289 {
290 hardInfo_.resourceChanged = false;
291 for (auto item = updateFlag.begin(); item != updateFlag.end(); item++) {
292 if (item->second == true) {
293 resourceChanged = true;
294 item->second = false; // reset
295 }
296 }
297 if (resourceChanged) {
298 RcdChooseTopResourceType();
299 RcdChooseRSResource();
300 if (supportHardware_) {
301 RcdChooseHardwareResource();
302 SetHardwareLayerSize();
303 }
304 hardInfo_.resourceChanged = resourceChanged; // output
305 resourceChanged = false; // reset
306 } else {
307 RS_LOGD("[%{public}s] Status is not changed \n", __func__);
308 }
309 }
310
311 // Choose the approriate resource type according to orientation and notch status
RcdChooseTopResourceType()312 void RoundCornerDisplay::RcdChooseTopResourceType()
313 {
314 RS_LOGD("[%{public}s] Choose surface \n", __func__);
315 RS_LOGD("[%{public}s] curOrientation is %{public}d \n", __func__, curOrientation_);
316 RS_LOGD("[%{public}s] notchStatus is %{public}d \n", __func__, notchStatus_);
317 switch (curOrientation_) {
318 case ScreenRotation::ROTATION_0:
319 case ScreenRotation::ROTATION_180:
320 if (notchStatus_ == WINDOW_NOTCH_HIDDEN) {
321 RS_LOGD("prepare TOP_HIDDEN show resource \n");
322 showResourceType_ = TOP_HIDDEN;
323 } else {
324 RS_LOGD("prepare TOP_PORTRAIT show resource \n");
325 showResourceType_ = TOP_PORTRAIT;
326 }
327 break;
328 case ScreenRotation::ROTATION_90:
329 case ScreenRotation::ROTATION_270:
330 if (notchStatus_ == WINDOW_NOTCH_HIDDEN) {
331 RS_LOGD("prepare TOP_LADS_ORIT show resource \n");
332 showResourceType_ = TOP_LADS_ORIT;
333 } else {
334 RS_LOGD("prepare TOP_PORTRAIT show resource \n");
335 showResourceType_ = TOP_PORTRAIT;
336 }
337 break;
338 default:
339 RS_LOGD("Unknow orientation, use default type \n");
340 showResourceType_ = TOP_PORTRAIT;
341 break;
342 }
343 }
344
RcdChooseRSResource()345 void RoundCornerDisplay::RcdChooseRSResource()
346 {
347 switch (showResourceType_) {
348 case TOP_PORTRAIT:
349 curTop_ = imgTopPortrait_;
350 RS_LOGD("prepare imgTopPortrait_ resource \n");
351 break;
352 case TOP_HIDDEN:
353 curTop_ = imgTopHidden_;
354 RS_LOGD("prepare imgTopHidden_ resource \n");
355 break;
356 case TOP_LADS_ORIT:
357 curTop_ = imgTopLadsOrit_;
358 RS_LOGD("prepare imgTopLadsOrit_ resource \n");
359 break;
360 default:
361 RS_LOGE("[%{public}s] No showResourceType found with type %{public}d \n", __func__, showResourceType_);
362 break;
363 }
364 curBottom_ = imgBottomPortrait_;
365 }
366
RcdChooseHardwareResource()367 void RoundCornerDisplay::RcdChooseHardwareResource()
368 {
369 if (rog_ == nullptr) {
370 RS_LOGE("[%{public}s] No rog info \n", __func__);
371 return;
372 }
373 switch (showResourceType_) {
374 case TOP_PORTRAIT:
375 if (rog_->portraitMap.count(rs_rcd::NODE_PORTRAIT) < 1) {
376 RS_LOGE("[%{public}s] PORTRAIT layerHide do not configured \n", __func__);
377 break;
378 }
379 hardInfo_.topLayer = &rog_->portraitMap[rs_rcd::NODE_PORTRAIT].layerUp;
380 hardInfo_.topLayer->curBitmap = &bitmapTopPortrait_;
381 break;
382 case TOP_HIDDEN:
383 if (rog_->portraitMap.count(rs_rcd::NODE_PORTRAIT) < 1) {
384 RS_LOGE("[%{public}s] PORTRAIT layerHide do not configured \n", __func__);
385 break;
386 }
387 hardInfo_.topLayer = &rog_->portraitMap[rs_rcd::NODE_PORTRAIT].layerHide;
388 hardInfo_.topLayer->curBitmap = &bitmapTopHidden_;
389 break;
390 case TOP_LADS_ORIT:
391 if (rog_->landscapeMap.count(rs_rcd::NODE_LANDSCAPE) < 1) {
392 RS_LOGE("[%{public}s] PORTRAIT layerHide do not configured \n", __func__);
393 break;
394 }
395 hardInfo_.topLayer = &rog_->landscapeMap[rs_rcd::NODE_LANDSCAPE].layerUp;
396 hardInfo_.topLayer->curBitmap = &bitmapTopLadsOrit_;
397 break;
398 default:
399 RS_LOGE("[%{public}s] No showResourceType found with type %{public}d \n", __func__, showResourceType_);
400 break;
401 }
402 if (rog_->portraitMap.count(rs_rcd::NODE_PORTRAIT) < 1) {
403 RS_LOGE("[%{public}s] PORTRAIT layerHide do not configured \n", __func__);
404 return;
405 }
406 hardInfo_.bottomLayer = &rog_->portraitMap[rs_rcd::NODE_PORTRAIT].layerDown;
407 hardInfo_.bottomLayer->curBitmap = &bitmapBottomPortrait_;
408 }
409
DrawOneRoundCorner(RSPaintFilterCanvas * canvas,int surfaceType)410 void RoundCornerDisplay::DrawOneRoundCorner(RSPaintFilterCanvas* canvas, int surfaceType)
411 {
412 RS_TRACE_BEGIN("RCD::DrawOneRoundCorner : surfaceType" + std::to_string(surfaceType));
413 std::lock_guard<std::mutex> lock(resourceMut_);
414 if (canvas == nullptr) {
415 RS_LOGE("[%{public}s] Canvas is null \n", __func__);
416 return;
417 }
418 UpdateParameter(updateFlag_);
419 if (surfaceType == TOP_SURFACE) {
420 RS_LOGD("[%{public}s] draw TopSurface start \n", __func__);
421 if (curTop_ != nullptr) {
422 #ifndef USE_ROSEN_DRAWING
423 canvas->drawImage(curTop_, 0, 0);
424 #else
425 Drawing::Brush brush;
426 canvas->AttachBrush(brush);
427 canvas->DrawImage(*curTop_, 0, 0, Drawing::SamplingOptions());
428 canvas->DetachBrush();
429 #endif
430 RS_LOGD("[%{public}s] Draw top \n", __func__);
431 }
432 } else if (surfaceType == BOTTOM_SURFACE) {
433 RS_LOGD("[%{public}s] BottomSurface supported \n", __func__);
434 if (curBottom_ != nullptr) {
435 #ifndef USE_ROSEN_DRAWING
436 canvas->drawImage(curBottom_, 0, displayHeight_ - curBottom_->height());
437 #else
438 Drawing::Brush brush;
439 canvas->AttachBrush(brush);
440 canvas->DrawImage(*curBottom_, 0, displayHeight_ - curBottom_->GetHeight(), Drawing::SamplingOptions());
441 canvas->DetachBrush();
442 #endif
443 RS_LOGD("[%{public}s] Draw Bottom \n", __func__);
444 }
445 } else {
446 RS_LOGD("[%{public}s] Surface Type is not valid \n", __func__);
447 }
448 RS_TRACE_END();
449 }
450
DrawTopRoundCorner(RSPaintFilterCanvas * canvas)451 void RoundCornerDisplay::DrawTopRoundCorner(RSPaintFilterCanvas* canvas)
452 {
453 DrawOneRoundCorner(canvas, TOP_SURFACE);
454 }
455
DrawBottomRoundCorner(RSPaintFilterCanvas * canvas)456 void RoundCornerDisplay::DrawBottomRoundCorner(RSPaintFilterCanvas* canvas)
457 {
458 DrawOneRoundCorner(canvas, BOTTOM_SURFACE);
459 }
460
DrawRoundCorner(RSPaintFilterCanvas * canvas)461 void RoundCornerDisplay::DrawRoundCorner(RSPaintFilterCanvas* canvas)
462 {
463 DrawTopRoundCorner(canvas);
464 DrawBottomRoundCorner(canvas);
465 }
466 } // namespace Rosen
467 } // namespace OHOS
468