1 /*
2 * Copyright (c) 2021-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 "window_layout_policy.h"
17 #include "display_manager_service_inner.h"
18 #include "remote_animation.h"
19 #include "window_helper.h"
20 #include "window_manager_hilog.h"
21 #include "wm_common_inner.h"
22
23 namespace OHOS {
24 namespace Rosen {
25 namespace {
26 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowLayoutPolicy"};
27 }
28
29 uint32_t WindowLayoutPolicy::floatingBottomPosY_ = 0;
30
WindowLayoutPolicy(const sptr<DisplayGroupInfo> & displayGroupInfo,DisplayGroupWindowTree & displayGroupWindowTree)31 WindowLayoutPolicy::WindowLayoutPolicy(const sptr<DisplayGroupInfo>& displayGroupInfo,
32 DisplayGroupWindowTree& displayGroupWindowTree)
33 : displayGroupInfo_(displayGroupInfo), displayGroupWindowTree_(displayGroupWindowTree)
34 {
35 }
36
Launch()37 void WindowLayoutPolicy::Launch()
38 {
39 WLOGFI("WindowLayoutPolicy::Launch");
40 }
41
Clean()42 void WindowLayoutPolicy::Clean()
43 {
44 WLOGFI("WindowLayoutPolicy::Clean");
45 }
46
Reorder()47 void WindowLayoutPolicy::Reorder()
48 {
49 WLOGFI("WindowLayoutPolicy::Reorder");
50 }
51
GetExitSplitPoints(DisplayId displayId) const52 std::vector<int32_t> WindowLayoutPolicy::GetExitSplitPoints(DisplayId displayId) const
53 {
54 return {};
55 }
56
LimitWindowToBottomRightCorner(const sptr<WindowNode> & node)57 void WindowLayoutPolicy::LimitWindowToBottomRightCorner(const sptr<WindowNode>& node)
58 {
59 Rect windowRect = node->GetRequestRect();
60 Rect displayRect = displayGroupInfo_->GetDisplayRect(node->GetDisplayId());
61 windowRect.posX_ = std::max(windowRect.posX_, displayRect.posX_);
62 windowRect.posY_ = std::max(windowRect.posY_, displayRect.posY_);
63 windowRect.width_ = std::min(windowRect.width_, displayRect.width_);
64 windowRect.height_ = std::min(windowRect.height_, displayRect.height_);
65
66 if (windowRect.posX_ + static_cast<int32_t>(windowRect.width_) >
67 displayRect.posX_ + static_cast<int32_t>(displayRect.width_)) {
68 windowRect.posX_ = displayRect.posX_ + static_cast<int32_t>(displayRect.width_) -
69 static_cast<int32_t>(windowRect.width_);
70 }
71
72 if (windowRect.posY_ + static_cast<int32_t>(windowRect.height_) >
73 displayRect.posY_ + static_cast<int32_t>(displayRect.height_)) {
74 windowRect.posY_ = displayRect.posY_ + static_cast<int32_t>(displayRect.height_) -
75 static_cast<int32_t>(windowRect.height_);
76 }
77 node->SetRequestRect(windowRect);
78
79 WLOGFI("windowId: %{public}d, newRect: [%{public}d, %{public}d, %{public}d, %{public}d]",
80 node->GetWindowId(), windowRect.posX_, windowRect.posY_, windowRect.width_, windowRect.height_);
81
82 for (auto& childNode : node->children_) {
83 LimitWindowToBottomRightCorner(childNode);
84 }
85 }
86
UpdateDisplayGroupRect()87 void WindowLayoutPolicy::UpdateDisplayGroupRect()
88 {
89 Rect newDisplayGroupRect = { 0, 0, 0, 0 };
90 // current multi-display is only support left-right combination, maxNum is two
91 for (auto& elem : displayGroupInfo_->GetAllDisplayRects()) {
92 newDisplayGroupRect.posX_ = std::min(displayGroupRect_.posX_, elem.second.posX_);
93 newDisplayGroupRect.posY_ = std::min(displayGroupRect_.posY_, elem.second.posY_);
94 newDisplayGroupRect.width_ += elem.second.width_;
95 int32_t maxHeight = std::max(newDisplayGroupRect.posY_ + static_cast<int32_t>(newDisplayGroupRect.height_),
96 elem.second.posY_+ static_cast<int32_t>(elem.second.height_));
97 newDisplayGroupRect.height_ = maxHeight - newDisplayGroupRect.posY_;
98 }
99 displayGroupRect_ = newDisplayGroupRect;
100 WLOGFI("displayGroupRect_: [ %{public}d, %{public}d, %{public}d, %{public}d]",
101 displayGroupRect_.posX_, displayGroupRect_.posY_, displayGroupRect_.width_, displayGroupRect_.height_);
102 }
103
UpdateDisplayGroupLimitRect()104 void WindowLayoutPolicy::UpdateDisplayGroupLimitRect()
105 {
106 auto firstDisplayLimitRect = limitRectMap_.begin()->second;
107 Rect newDisplayGroupLimitRect = { firstDisplayLimitRect.posX_, firstDisplayLimitRect.posY_, 0, 0 };
108 for (auto& elem : limitRectMap_) {
109 newDisplayGroupLimitRect.posX_ = std::min(newDisplayGroupLimitRect.posX_, elem.second.posX_);
110 newDisplayGroupLimitRect.posY_ = std::min(newDisplayGroupLimitRect.posY_, elem.second.posY_);
111
112 int32_t maxWidth = std::max(newDisplayGroupLimitRect.posX_ +
113 static_cast<int32_t>(newDisplayGroupLimitRect.width_),
114 elem.second.posX_+ static_cast<int32_t>(elem.second.width_));
115
116 int32_t maxHeight = std::max(newDisplayGroupLimitRect.posY_ +
117 static_cast<int32_t>(newDisplayGroupLimitRect.height_),
118 elem.second.posY_+ static_cast<int32_t>(elem.second.height_));
119 newDisplayGroupLimitRect.width_ = static_cast<uint32_t>(maxWidth - newDisplayGroupLimitRect.posX_);
120 newDisplayGroupLimitRect.height_ = static_cast<uint32_t>(maxHeight - newDisplayGroupLimitRect.posY_);
121 }
122 displayGroupLimitRect_ = newDisplayGroupLimitRect;
123 WLOGFI("displayGroupLimitRect_: [ %{public}d, %{public}d, %{public}d, %{public}d]",
124 displayGroupLimitRect_.posX_, displayGroupLimitRect_.posY_,
125 displayGroupLimitRect_.width_, displayGroupLimitRect_.height_);
126 }
127
UpdateRectInDisplayGroup(const sptr<WindowNode> & node,const Rect & oriDisplayRect,const Rect & newDisplayRect)128 void WindowLayoutPolicy::UpdateRectInDisplayGroup(const sptr<WindowNode>& node,
129 const Rect& oriDisplayRect,
130 const Rect& newDisplayRect)
131 {
132 Rect newRect = node->GetRequestRect();
133 WLOGFI("before update rect in display group, windowId: %{public}d, rect: [%{public}d, %{public}d, "
134 "%{public}d, %{public}d]", node->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
135
136 newRect.posX_ = newRect.posX_ - oriDisplayRect.posX_ + newDisplayRect.posX_;
137 newRect.posY_ = newRect.posY_ - oriDisplayRect.posY_ + newDisplayRect.posY_;
138 node->SetRequestRect(newRect);
139 WLOGFI("after update rect in display group, windowId: %{public}d, newRect: [%{public}d, %{public}d, "
140 "%{public}d, %{public}d]", node->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
141
142 for (auto& childNode : node->children_) {
143 UpdateRectInDisplayGroup(childNode, oriDisplayRect, newDisplayRect);
144 }
145 }
146
IsMultiDisplay()147 bool WindowLayoutPolicy::IsMultiDisplay()
148 {
149 return isMultiDisplay_;
150 }
151
UpdateMultiDisplayFlag()152 void WindowLayoutPolicy::UpdateMultiDisplayFlag()
153 {
154 if (displayGroupInfo_->GetAllDisplayRects().size() > 1) {
155 isMultiDisplay_ = true;
156 WLOGFI("current mode is multi-display");
157 } else {
158 isMultiDisplay_ = false;
159 WLOGFI("current mode is not multi-display");
160 }
161 }
162
UpdateRectInDisplayGroupForAllNodes(DisplayId displayId,const Rect & oriDisplayRect,const Rect & newDisplayRect)163 void WindowLayoutPolicy::UpdateRectInDisplayGroupForAllNodes(DisplayId displayId,
164 const Rect& oriDisplayRect,
165 const Rect& newDisplayRect)
166 {
167 WLOGFI("displayId: %{public}" PRIu64", oriDisplayRect: [ %{public}d, %{public}d, %{public}d, %{public}d] "
168 "newDisplayRect: [ %{public}d, %{public}d, %{public}d, %{public}d]",
169 displayId, oriDisplayRect.posX_, oriDisplayRect.posY_, oriDisplayRect.width_, oriDisplayRect.height_,
170 newDisplayRect.posX_, newDisplayRect.posY_, newDisplayRect.width_, newDisplayRect.height_);
171
172 auto& displayWindowTree = displayGroupWindowTree_[displayId];
173 for (auto& iter : displayWindowTree) {
174 auto& nodeVector = *(iter.second);
175 for (auto& node : nodeVector) {
176 if (!node->isShowingOnMultiDisplays_) {
177 UpdateRectInDisplayGroup(node, oriDisplayRect, newDisplayRect);
178 }
179 if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
180 LimitWindowToBottomRightCorner(node);
181 }
182 }
183 WLOGFI("Recalculate window rect in display group, displayId: %{public}" PRIu64", rootType: %{public}d",
184 displayId, iter.first);
185 }
186 }
187
UpdateDisplayRectAndDisplayGroupInfo(const std::map<DisplayId,Rect> & displayRectMap)188 void WindowLayoutPolicy::UpdateDisplayRectAndDisplayGroupInfo(const std::map<DisplayId, Rect>& displayRectMap)
189 {
190 for (auto& elem : displayRectMap) {
191 auto& displayId = elem.first;
192 auto& displayRect = elem.second;
193 displayGroupInfo_->SetDisplayRect(displayId, displayRect);
194 }
195 }
196
PostProcessWhenDisplayChange()197 void WindowLayoutPolicy::PostProcessWhenDisplayChange()
198 {
199 displayGroupInfo_->UpdateLeftAndRightDisplayId();
200 UpdateMultiDisplayFlag();
201 UpdateDisplayGroupRect();
202 Launch();
203 }
204
ProcessDisplayCreate(DisplayId displayId,const std::map<DisplayId,Rect> & displayRectMap)205 void WindowLayoutPolicy::ProcessDisplayCreate(DisplayId displayId, const std::map<DisplayId, Rect>& displayRectMap)
206 {
207 const auto& oriDisplayRectMap = displayGroupInfo_->GetAllDisplayRects();
208 // check displayId and displayRectMap size
209 if (oriDisplayRectMap.find(displayId) == oriDisplayRectMap.end() ||
210 displayRectMap.size() != oriDisplayRectMap.size()) {
211 WLOGFE("current display is exited or displayInfo map size is error, displayId: %{public}" PRIu64"", displayId);
212 return;
213 }
214 for (auto& elem : displayRectMap) {
215 auto iter = oriDisplayRectMap.find(elem.first);
216 if (iter != oriDisplayRectMap.end()) {
217 const auto& oriDisplayRect = iter->second;
218 const auto& newDisplayRect = elem.second;
219 UpdateRectInDisplayGroupForAllNodes(elem.first, oriDisplayRect, newDisplayRect);
220 } else {
221 if (elem.first != displayId) {
222 WLOGFE("Wrong display, displayId: %{public}" PRIu64"", displayId);
223 return;
224 }
225 }
226 }
227 UpdateDisplayRectAndDisplayGroupInfo(displayRectMap);
228 PostProcessWhenDisplayChange();
229 WLOGFI("Process display create, displayId: %{public}" PRIu64"", displayId);
230 }
231
ProcessDisplayDestroy(DisplayId displayId,const std::map<DisplayId,Rect> & displayRectMap)232 void WindowLayoutPolicy::ProcessDisplayDestroy(DisplayId displayId, const std::map<DisplayId, Rect>& displayRectMap)
233 {
234 const auto& oriDisplayRectMap = displayGroupInfo_->GetAllDisplayRects();
235 // check displayId and displayRectMap size
236 if (oriDisplayRectMap.find(displayId) != oriDisplayRectMap.end() ||
237 displayRectMap.size() != oriDisplayRectMap.size()) {
238 WLOGFE("can not find current display or displayInfo map size is error, displayId: %{public}" PRIu64"",
239 displayId);
240 return;
241 }
242 for (auto oriIter = oriDisplayRectMap.begin(); oriIter != oriDisplayRectMap.end();) {
243 auto newIter = displayRectMap.find(oriIter->first);
244 if (newIter != displayRectMap.end()) {
245 const auto& oriDisplayRect = oriIter->second;
246 const auto& newDisplayRect = newIter->second;
247 UpdateRectInDisplayGroupForAllNodes(oriIter->first, oriDisplayRect, newDisplayRect);
248 } else {
249 if (oriIter->first != displayId) {
250 WLOGFE("Wrong display, displayId: %{public}" PRIu64"", displayId);
251 return;
252 }
253 }
254 ++oriIter;
255 }
256
257 UpdateDisplayRectAndDisplayGroupInfo(displayRectMap);
258 PostProcessWhenDisplayChange();
259 WLOGFI("Process display destroy, displayId: %{public}" PRIu64"", displayId);
260 }
261
ProcessDisplaySizeChangeOrRotation(DisplayId displayId,const std::map<DisplayId,Rect> & displayRectMap)262 void WindowLayoutPolicy::ProcessDisplaySizeChangeOrRotation(DisplayId displayId,
263 const std::map<DisplayId, Rect>& displayRectMap)
264 {
265 const auto& oriDisplayRectMap = displayGroupInfo_->GetAllDisplayRects();
266 // check displayId and displayRectMap size
267 if (oriDisplayRectMap.find(displayId) == oriDisplayRectMap.end() ||
268 displayRectMap.size() != oriDisplayRectMap.size()) {
269 WLOGFE("can not find current display or displayInfo map size is error, displayId: %{public}" PRIu64"",
270 displayId);
271 return;
272 }
273
274 for (auto& elem : displayRectMap) {
275 auto iter = oriDisplayRectMap.find(elem.first);
276 if (iter != oriDisplayRectMap.end()) {
277 UpdateRectInDisplayGroupForAllNodes(elem.first, iter->second, elem.second);
278 }
279 }
280
281 UpdateDisplayRectAndDisplayGroupInfo(displayRectMap);
282 PostProcessWhenDisplayChange();
283 WLOGFI("Process display change, displayId: %{public}" PRIu64"", displayId);
284 }
285
LayoutWindowNodesByRootType(const std::vector<sptr<WindowNode>> & nodeVec)286 void WindowLayoutPolicy::LayoutWindowNodesByRootType(const std::vector<sptr<WindowNode>>& nodeVec)
287 {
288 if (nodeVec.empty()) {
289 WLOGE("The node vector is empty!");
290 return;
291 }
292 for (auto& node : nodeVec) {
293 LayoutWindowNode(node);
294 }
295 }
296
NotifyAnimationSizeChangeIfNeeded()297 void WindowLayoutPolicy::NotifyAnimationSizeChangeIfNeeded()
298 {
299 if (!RemoteAnimation::CheckAnimationController()) {
300 WLOGFD("no animation controller!");
301 return;
302 }
303 std::vector<uint32_t> fullScreenWinIds;
304 std::vector<uint32_t> floatMainIds;
305 for (auto& iter : displayGroupWindowTree_) {
306 auto& displayWindowTree = iter.second;
307 auto& nodeVec = *(displayWindowTree[WindowRootNodeType::APP_WINDOW_NODE]);
308 if (nodeVec.empty()) {
309 WLOGE("The node vector is empty!");
310 return;
311 }
312 for (auto& node : nodeVec) {
313 // just has one fullscreen app node on foreground
314 if (WindowHelper::IsMainFullScreenWindow(node->GetWindowType(), node->GetWindowMode())) {
315 fullScreenWinIds.emplace_back(node->GetWindowId());
316 }
317 if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
318 floatMainIds.emplace_back(node->GetWindowId());
319 }
320 }
321 }
322 RemoteAnimation::NotifyAnimationTargetsUpdate(fullScreenWinIds, floatMainIds);
323 }
324
LayoutWindowTree(DisplayId displayId)325 void WindowLayoutPolicy::LayoutWindowTree(DisplayId displayId)
326 {
327 auto& displayWindowTree = displayGroupWindowTree_[displayId];
328 limitRectMap_[displayId] = displayGroupInfo_->GetDisplayRect(displayId);
329 // ensure that the avoid area windows are traversed first
330 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]));
331 if (IsFullScreenRecentWindowExist(*(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]))) {
332 WLOGFI("recent window on top, early exit layout tree");
333 return;
334 }
335 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::APP_WINDOW_NODE]));
336 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::BELOW_WINDOW_NODE]));
337 }
338
LayoutWindowNode(const sptr<WindowNode> & node)339 void WindowLayoutPolicy::LayoutWindowNode(const sptr<WindowNode>& node)
340 {
341 if (node == nullptr) {
342 return;
343 }
344 WLOGFI("LayoutWindowNode, window[%{public}u]", node->GetWindowId());
345 if (node->parent_ != nullptr) { // isn't root node
346 if (!node->currentVisibility_) {
347 WLOGFI("window[%{public}u] currently not visible, no need layout", node->GetWindowId());
348 return;
349 }
350 UpdateLayoutRect(node);
351 if (avoidTypes_.find(node->GetWindowType()) != avoidTypes_.end()) {
352 UpdateLimitRect(node, limitRectMap_[node->GetDisplayId()]);
353 UpdateDisplayGroupLimitRect();
354 }
355 }
356 for (auto& childNode : node->children_) {
357 LayoutWindowNode(childNode);
358 }
359 }
360
IsVerticalDisplay(DisplayId displayId) const361 bool WindowLayoutPolicy::IsVerticalDisplay(DisplayId displayId) const
362 {
363 return displayGroupInfo_->GetDisplayRect(displayId).width_ < displayGroupInfo_->GetDisplayRect(displayId).height_;
364 }
365
UpdateClientRect(const Rect & rect,const sptr<WindowNode> & node,WindowSizeChangeReason reason)366 void WindowLayoutPolicy::UpdateClientRect(const Rect& rect, const sptr<WindowNode>& node, WindowSizeChangeReason reason)
367 {
368 if (node->GetWindowToken()) {
369 WLOGFI("notify client id: %{public}d, windowRect:[%{public}d, %{public}d, %{public}u, %{public}u], reason: "
370 "%{public}u", node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_, reason);
371 node->GetWindowToken()->UpdateWindowRect(rect, node->GetDecoStatus(), reason);
372 }
373 NotifyAnimationSizeChangeIfNeeded();
374 }
375
UpdateClientRectAndResetReason(const sptr<WindowNode> & node,const Rect & winRect)376 void WindowLayoutPolicy::UpdateClientRectAndResetReason(const sptr<WindowNode>& node, const Rect& winRect)
377 {
378 auto reason = node->GetWindowSizeChangeReason();
379 UpdateClientRect(winRect, node, reason);
380 if ((reason != WindowSizeChangeReason::MOVE) && (node->GetWindowType() != WindowType::WINDOW_TYPE_DOCK_SLICE)) {
381 node->ResetWindowSizeChangeReason();
382 }
383 }
384
RemoveWindowNode(const sptr<WindowNode> & node)385 void WindowLayoutPolicy::RemoveWindowNode(const sptr<WindowNode>& node)
386 {
387 auto type = node->GetWindowType();
388 // affect other windows, trigger off global layout
389 if (avoidTypes_.find(type) != avoidTypes_.end()) {
390 LayoutWindowTree(node->GetDisplayId());
391 } else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode
392 LayoutWindowTree(node->GetDisplayId());
393 }
394 UpdateClientRect(node->GetRequestRect(), node, WindowSizeChangeReason::HIDE);
395 }
396
UpdateWindowNode(const sptr<WindowNode> & node,bool isAddWindow)397 void WindowLayoutPolicy::UpdateWindowNode(const sptr<WindowNode>& node, bool isAddWindow)
398 {
399 auto type = node->GetWindowType();
400 // affect other windows, trigger off global layout
401 if (avoidTypes_.find(type) != avoidTypes_.end()) {
402 LayoutWindowTree(node->GetDisplayId());
403 } else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode
404 LayoutWindowTree(node->GetDisplayId());
405 } else { // layout single window
406 LayoutWindowNode(node);
407 }
408 }
409
UpdateFloatingLayoutRect(Rect & limitRect,Rect & winRect)410 void WindowLayoutPolicy::UpdateFloatingLayoutRect(Rect& limitRect, Rect& winRect)
411 {
412 winRect.width_ = std::min(limitRect.width_, winRect.width_);
413 winRect.height_ = std::min(limitRect.height_, winRect.height_);
414 winRect.posX_ = std::max(limitRect.posX_, winRect.posX_);
415 winRect.posY_ = std::max(limitRect.posY_, winRect.posY_);
416 winRect.posX_ = std::min(
417 limitRect.posX_ + static_cast<int32_t>(limitRect.width_) - static_cast<int32_t>(winRect.width_),
418 winRect.posX_);
419 winRect.posY_ = std::min(
420 limitRect.posY_ + static_cast<int32_t>(limitRect.height_) - static_cast<int32_t>(winRect.height_),
421 winRect.posY_);
422 }
423
ComputeDecoratedRequestRect(const sptr<WindowNode> & node) const424 void WindowLayoutPolicy::ComputeDecoratedRequestRect(const sptr<WindowNode>& node) const
425 {
426 auto property = node->GetWindowProperty();
427 if (property == nullptr) {
428 WLOGE("window property is nullptr");
429 return;
430 }
431 auto reqRect = property->GetRequestRect();
432 if (!property->GetDecorEnable() || property->GetDecoStatus() ||
433 node->GetWindowSizeChangeReason() == WindowSizeChangeReason::MOVE) {
434 return;
435 }
436 float virtualPixelRatio = GetVirtualPixelRatio(node->GetDisplayId());
437 uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * virtualPixelRatio);
438 uint32_t winTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
439
440 Rect rect;
441 rect.posX_ = reqRect.posX_;
442 rect.posY_ = reqRect.posY_;
443 rect.width_ = reqRect.width_ + winFrameW + winFrameW;
444 rect.height_ = reqRect.height_ + winTitleBarH + winFrameW;
445 property->SetRequestRect(rect);
446 property->SetDecoStatus(true);
447 }
448
CalcEntireWindowHotZone(const sptr<WindowNode> & node,const Rect & winRect,uint32_t hotZone,float vpr,TransformHelper::Vector2 hotZoneScale) const449 Rect WindowLayoutPolicy::CalcEntireWindowHotZone(const sptr<WindowNode>& node, const Rect& winRect, uint32_t hotZone,
450 float vpr, TransformHelper::Vector2 hotZoneScale) const
451 {
452 Rect rect = winRect;
453 uint32_t hotZoneX = static_cast<uint32_t>(hotZone * vpr / hotZoneScale.x_);
454 uint32_t hotZoneY = static_cast<uint32_t>(hotZone * vpr / hotZoneScale.y_);
455
456 if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
457 if (rect.width_ < rect.height_) {
458 rect.posX_ -= static_cast<int32_t>(hotZoneX);
459 rect.width_ += (hotZoneX + hotZoneX);
460 } else {
461 rect.posY_ -= static_cast<int32_t>(hotZoneY);
462 rect.height_ += (hotZoneY + hotZoneY);
463 }
464 } else if (node->GetWindowType() == WindowType::WINDOW_TYPE_LAUNCHER_RECENT) {
465 rect = displayGroupInfo_->GetDisplayRect(node->GetDisplayId());
466 } else if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
467 rect.posX_ -= static_cast<int32_t>(hotZoneX);
468 rect.posY_ -= static_cast<int32_t>(hotZoneY);
469 rect.width_ += (hotZoneX + hotZoneX);
470 rect.height_ += (hotZoneY + hotZoneY);
471 }
472 return rect;
473 }
474
CalcAndSetNodeHotZone(const Rect & winRect,const sptr<WindowNode> & node) const475 void WindowLayoutPolicy::CalcAndSetNodeHotZone(const Rect& winRect, const sptr<WindowNode>& node) const
476 {
477 float virtualPixelRatio = GetVirtualPixelRatio(node->GetDisplayId());
478 TransformHelper::Vector2 hotZoneScale(1, 1);
479 if (node->GetWindowProperty()->isNeedComputerTransform()) {
480 node->ComputeTransform();
481 hotZoneScale = WindowHelper::CalculateHotZoneScale(node->GetWindowProperty()->GetTransformMat());
482 }
483
484 auto hotZoneRectTouch = CalcEntireWindowHotZone(node, winRect, HOTZONE_TOUCH, virtualPixelRatio, hotZoneScale);
485 auto hotZoneRectPointer = CalcEntireWindowHotZone(node, winRect, HOTZONE_POINTER, virtualPixelRatio, hotZoneScale);
486
487 node->SetEntireWindowTouchHotArea(hotZoneRectTouch);
488 node->SetEntireWindowPointerHotArea(hotZoneRectPointer);
489
490 std::vector<Rect> requestedHotAreas;
491 node->GetWindowProperty()->GetTouchHotAreas(requestedHotAreas);
492 std::vector<Rect> touchHotAreas;
493 std::vector<Rect> pointerHotAreas;
494 if (requestedHotAreas.empty()) {
495 touchHotAreas.emplace_back(hotZoneRectTouch);
496 pointerHotAreas.emplace_back(hotZoneRectPointer);
497 } else {
498 if (!WindowHelper::CalculateTouchHotAreas(winRect, requestedHotAreas, touchHotAreas)) {
499 WLOGFW("some parameters in requestedHotAreas are abnormal");
500 }
501 pointerHotAreas = touchHotAreas;
502 }
503 node->SetTouchHotAreas(touchHotAreas);
504 node->SetPointerHotAreas(pointerHotAreas);
505 }
506
FixWindowSizeByRatioIfDragBeyondLimitRegion(const sptr<WindowNode> & node,Rect & winRect)507 void WindowLayoutPolicy::FixWindowSizeByRatioIfDragBeyondLimitRegion(const sptr<WindowNode>& node, Rect& winRect)
508 {
509 const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
510 if (sizeLimits.maxWidth_ == sizeLimits.minWidth_ &&
511 sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
512 WLOGFI("window rect can not be changed");
513 return;
514 }
515 if (winRect.height_ == 0) {
516 WLOGFE("the height of window is zero");
517 return;
518 }
519 float curRatio = static_cast<float>(winRect.width_) / static_cast<float>(winRect.height_);
520 if (sizeLimits.minRatio_ <= curRatio && curRatio <= sizeLimits.maxRatio_) {
521 WLOGFI("window ratio is satisfied with limit ratio, curRatio: %{public}f", curRatio);
522 return;
523 }
524
525 float virtualPixelRatio = GetVirtualPixelRatio(node->GetDisplayId());
526 uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
527 Rect limitRect = isMultiDisplay_ ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
528 int32_t limitMinPosX = limitRect.posX_ + static_cast<int32_t>(windowTitleBarH);
529 int32_t limitMaxPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH);
530 int32_t limitMinPosY = limitRect.posY_;
531 int32_t limitMaxPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH);
532
533 Rect dockWinRect;
534 DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
535 if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
536 WLOGFD("dock window show in bottom");
537 limitMaxPosY = dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH);
538 } else if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
539 WLOGFD("dock window show in left");
540 limitMinPosX = dockWinRect.posX_ + static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH);
541 } else if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
542 WLOGFD("dock window show in right");
543 limitMaxPosX = dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH);
544 }
545
546 float newRatio = curRatio < sizeLimits.minRatio_ ? sizeLimits.minRatio_ : sizeLimits.maxRatio_;
547 if ((winRect.posX_ + static_cast<int32_t>(winRect.width_) == limitMinPosX) || (winRect.posX_ == limitMaxPosX)) {
548 // height can not be changed
549 if (sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
550 return;
551 }
552 winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
553 }
554
555 if ((winRect.posY_ == limitMinPosY) || (winRect.posX_ == limitMaxPosY)) {
556 // width can not be changed
557 if (sizeLimits.maxWidth_ == sizeLimits.minWidth_) {
558 return;
559 }
560 winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
561 }
562 WLOGFI("After limit by ratio if beyond limit region, winRect: %{public}d %{public}d %{public}u %{public}u",
563 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
564 }
565
GetSystemSizeLimits(const sptr<WindowNode> & node,const Rect & displayRect,float virtualPixelRatio)566 WindowSizeLimits WindowLayoutPolicy::GetSystemSizeLimits(const sptr<WindowNode>& node,
567 const Rect& displayRect, float virtualPixelRatio)
568 {
569 WindowSizeLimits systemLimits;
570 systemLimits.maxWidth_ = static_cast<uint32_t>(MAX_FLOATING_SIZE * virtualPixelRatio);
571 systemLimits.maxHeight_ = static_cast<uint32_t>(MAX_FLOATING_SIZE * virtualPixelRatio);
572
573 // Float camera window has a special limit:
574 // if display sw <= 600dp, portrait: min width = display sw * 30%, landscape: min width = sw * 50%
575 // if display sw > 600dp, portrait: min width = display sw * 12%, landscape: min width = sw * 30%
576 if (node->GetWindowType() == WindowType::WINDOW_TYPE_FLOAT_CAMERA) {
577 uint32_t smallWidth = displayRect.height_ <= displayRect.width_ ? displayRect.height_ : displayRect.width_;
578 float hwRatio = static_cast<float>(displayRect.height_) / static_cast<float>(displayRect.width_);
579 if (smallWidth <= static_cast<uint32_t>(600 * virtualPixelRatio)) { // sw <= 600dp
580 if (displayRect.width_ <= displayRect.height_) {
581 systemLimits.minWidth_ = static_cast<uint32_t>(smallWidth * 0.3); // min width = display sw * 0.3
582 } else {
583 systemLimits.minWidth_ = static_cast<uint32_t>(smallWidth * 0.5); // min width = display sw * 0.5
584 }
585 } else {
586 if (displayRect.width_ <= displayRect.height_) {
587 systemLimits.minWidth_ = static_cast<uint32_t>(smallWidth * 0.12); // min width = display sw * 0.12
588 } else {
589 systemLimits.minWidth_ = static_cast<uint32_t>(smallWidth * 0.3); // min width = display sw * 0.3
590 }
591 }
592 systemLimits.minHeight_ = static_cast<uint32_t>(systemLimits.minWidth_ * hwRatio);
593 } else {
594 systemLimits.minWidth_ = static_cast<uint32_t>(MIN_FLOATING_WIDTH * virtualPixelRatio);
595 systemLimits.minHeight_ = static_cast<uint32_t>(MIN_FLOATING_HEIGHT * virtualPixelRatio);
596 }
597 WLOGFD("[System SizeLimits] [maxWidth: %{public}u, minWidth: %{public}u, maxHeight: %{public}u, "
598 "minHeight: %{public}u]", systemLimits.maxWidth_, systemLimits.minWidth_,
599 systemLimits.maxHeight_, systemLimits.minHeight_);
600 return systemLimits;
601 }
602
UpdateWindowSizeLimits(const sptr<WindowNode> & node)603 void WindowLayoutPolicy::UpdateWindowSizeLimits(const sptr<WindowNode>& node)
604 {
605 const auto& displayRect = displayGroupInfo_->GetDisplayRect(node->GetDisplayId());
606 const auto& virtualPixelRatio = GetVirtualPixelRatio(node->GetDisplayId());
607 const auto& systemLimits = GetSystemSizeLimits(node, displayRect, virtualPixelRatio);
608 const auto& customizedLimits = node->GetWindowSizeLimits();
609
610 WindowSizeLimits newLimits = systemLimits;
611
612 // configured limits of floating window
613 uint32_t configuredMaxWidth = static_cast<uint32_t>(customizedLimits.maxWidth_ * virtualPixelRatio);
614 uint32_t configuredMaxHeight = static_cast<uint32_t>(customizedLimits.maxHeight_ * virtualPixelRatio);
615 uint32_t configuredMinWidth = static_cast<uint32_t>(customizedLimits.minWidth_ * virtualPixelRatio);
616 uint32_t configuredMinHeight = static_cast<uint32_t>(customizedLimits.minHeight_ * virtualPixelRatio);
617
618 // calculate new limit size
619 if (systemLimits.minWidth_ <= configuredMaxWidth && configuredMaxWidth <= systemLimits.maxWidth_) {
620 newLimits.maxWidth_ = configuredMaxWidth;
621 }
622 if (systemLimits.minHeight_ <= configuredMaxHeight && configuredMaxHeight <= systemLimits.maxHeight_) {
623 newLimits.maxHeight_ = configuredMaxHeight;
624 }
625 if (systemLimits.minWidth_ <= configuredMinWidth && configuredMinWidth <= newLimits.maxWidth_) {
626 newLimits.minWidth_ = configuredMinWidth;
627 }
628 if (systemLimits.minHeight_ <= configuredMinHeight && configuredMinHeight <= newLimits.maxHeight_) {
629 newLimits.minHeight_ = configuredMinHeight;
630 }
631
632 // calculate new limit ratio
633 newLimits.maxRatio_ = static_cast<float>(newLimits.maxWidth_) / static_cast<float>(newLimits.minHeight_);
634 newLimits.minRatio_ = static_cast<float>(newLimits.minWidth_) / static_cast<float>(newLimits.maxHeight_);
635 if (newLimits.minRatio_ <= customizedLimits.maxRatio_ && customizedLimits.maxRatio_ <= newLimits.maxRatio_) {
636 newLimits.maxRatio_ = customizedLimits.maxRatio_;
637 }
638 if (newLimits.minRatio_ <= customizedLimits.minRatio_ && customizedLimits.minRatio_ <= newLimits.maxRatio_) {
639 newLimits.minRatio_ = customizedLimits.minRatio_;
640 }
641
642 // recalculate limit size by new ratio
643 uint32_t newMaxWidth = static_cast<uint32_t>(static_cast<float>(newLimits.maxHeight_) * newLimits.maxRatio_);
644 newLimits.maxWidth_ = std::min(newMaxWidth, newLimits.maxWidth_);
645 uint32_t newMinWidth = static_cast<uint32_t>(static_cast<float>(newLimits.minHeight_) * newLimits.minRatio_);
646 newLimits.minWidth_ = std::max(newMinWidth, newLimits.minWidth_);
647 uint32_t newMaxHeight = static_cast<uint32_t>(static_cast<float>(newLimits.maxWidth_) / newLimits.minRatio_);
648 newLimits.maxHeight_ = std::min(newMaxHeight, newLimits.maxHeight_);
649 uint32_t newMinHeight = static_cast<uint32_t>(static_cast<float>(newLimits.minWidth_) / newLimits.maxRatio_);
650 newLimits.minHeight_ = std::max(newMinHeight, newLimits.minHeight_);
651
652 WLOGFI("[Update SizeLimits] winId: %{public}u, Width: [max:%{public}u, min:%{public}u], Height: [max:%{public}u, "
653 "min:%{public}u], Ratio: [max:%{public}f, min:%{public}f]", node->GetWindowId(), newLimits.maxWidth_,
654 newLimits.minWidth_, newLimits.maxHeight_, newLimits.minHeight_, newLimits.maxRatio_, newLimits.minRatio_);
655 node->SetWindowUpdatedSizeLimits(newLimits);
656 }
657
UpdateFloatingWindowSizeForStretchableWindow(const sptr<WindowNode> & node,const Rect & displayRect,Rect & winRect) const658 void WindowLayoutPolicy::UpdateFloatingWindowSizeForStretchableWindow(const sptr<WindowNode>& node,
659 const Rect& displayRect, Rect& winRect) const
660 {
661 if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
662 const Rect &originRect = node->GetOriginRect();
663 if (originRect.height_ == 0 || originRect.width_ == 0) {
664 WLOGE("invalid originRect. window id: %{public}u", node->GetWindowId());
665 return;
666 }
667 auto dragType = node->GetDragType();
668 if (dragType == DragType::DRAG_BOTTOM_OR_TOP) {
669 // if drag height, use height to fix size.
670 winRect.width_ = winRect.height_ * originRect.width_ / originRect.height_;
671 } else if (dragType == DragType::DRAG_LEFT_TOP_CORNER || dragType == DragType::DRAG_RIGHT_TOP_CORNER ||
672 dragType == DragType::DRAG_LEFT_OR_RIGHT) {
673 // if drag width or corner, use width to fix size.
674 winRect.height_ = winRect.width_ * originRect.height_ / originRect.width_;
675 }
676 }
677 // limit minimum size of window
678
679 const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
680 float scale = std::min(static_cast<float>(winRect.width_) / sizeLimits.minWidth_,
681 static_cast<float>(winRect.height_) / sizeLimits.minHeight_);
682 if (scale == 0) {
683 WLOGE("invalid sizeLimits");
684 return;
685 }
686 if (scale < 1.0f) {
687 winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / scale);
688 winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) / scale);
689 }
690 }
691
UpdateFloatingWindowSizeBySizeLimits(const sptr<WindowNode> & node,const Rect & displayRect,Rect & winRect) const692 void WindowLayoutPolicy::UpdateFloatingWindowSizeBySizeLimits(const sptr<WindowNode>& node,
693 const Rect& displayRect, Rect& winRect) const
694 {
695 // get new limit config with the settings of system and app
696 const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
697
698 // limit minimum size of floating (not system type) window
699 if (!WindowHelper::IsSystemWindow(node->GetWindowType()) ||
700 node->GetWindowType() == WindowType::WINDOW_TYPE_FLOAT_CAMERA) {
701 winRect.width_ = std::max(sizeLimits.minWidth_, winRect.width_);
702 winRect.height_ = std::max(sizeLimits.minHeight_, winRect.height_);
703 }
704 winRect.width_ = std::min(sizeLimits.maxWidth_, winRect.width_);
705 winRect.height_ = std::min(sizeLimits.maxHeight_, winRect.height_);
706 WLOGFD("After limit by size, winRect: %{public}d %{public}d %{public}u %{public}u",
707 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
708
709 // width and height can not be changed
710 if (sizeLimits.maxWidth_ == sizeLimits.minWidth_ &&
711 sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
712 winRect.width_ = sizeLimits.maxWidth_;
713 winRect.height_ = sizeLimits.maxHeight_;
714 WLOGFD("window rect can not be changed");
715 return;
716 }
717
718 float curRatio = static_cast<float>(winRect.width_) / static_cast<float>(winRect.height_);
719 // there is no need to fix size by ratio if this is not main floating window
720 if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode()) ||
721 (sizeLimits.minRatio_ <= curRatio && curRatio <= sizeLimits.maxRatio_)) {
722 WLOGFD("window is system window or ratio is satisfied with limits, curSize: [%{public}d, %{public}d], "
723 "curRatio: %{public}f", winRect.width_, winRect.height_, curRatio);
724 return;
725 }
726
727 float newRatio = curRatio < sizeLimits.minRatio_ ? sizeLimits.minRatio_ : sizeLimits.maxRatio_;
728 if (sizeLimits.maxWidth_ == sizeLimits.minWidth_) {
729 winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
730 return;
731 }
732 if (sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
733 winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
734 return;
735 }
736
737 auto dragType = node->GetDragType();
738 if (dragType == DragType::DRAG_BOTTOM_OR_TOP) {
739 // if drag height, use height to fix size.
740 winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
741 } else {
742 // if drag width or corner, use width to fix size.
743 winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
744 }
745 WLOGFI("After limit by customize config, winRect: %{public}d %{public}d %{public}u %{public}u",
746 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
747 }
748
LimitFloatingWindowSize(const sptr<WindowNode> & node,const Rect & displayRect,Rect & winRect) const749 void WindowLayoutPolicy::LimitFloatingWindowSize(const sptr<WindowNode>& node,
750 const Rect& displayRect,
751 Rect& winRect) const
752 {
753 if (node->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING
754 || node->GetWindowType() == WindowType::WINDOW_TYPE_APP_COMPONENT) {
755 return;
756 }
757 Rect oriWinRect = winRect;
758 UpdateFloatingWindowSizeBySizeLimits(node, displayRect, winRect);
759
760 if (node->GetStretchable() &&
761 WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
762 UpdateFloatingWindowSizeForStretchableWindow(node, displayRect, winRect);
763 }
764
765 // fix size in case of moving window when dragging
766 const auto& lastWinRect = node->GetWindowRect();
767 if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
768 if (oriWinRect.posX_ != lastWinRect.posX_) {
769 winRect.posX_ = oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) -
770 static_cast<int32_t>(winRect.width_);
771 }
772 if (oriWinRect.posY_ != lastWinRect.posY_) {
773 winRect.posY_ = oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) -
774 static_cast<int32_t>(winRect.height_);
775 }
776 }
777 }
778
LimitMainFloatingWindowPosition(const sptr<WindowNode> & node,Rect & winRect) const779 void WindowLayoutPolicy::LimitMainFloatingWindowPosition(const sptr<WindowNode>& node, Rect& winRect) const
780 {
781 if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
782 return;
783 }
784
785 auto reason = node->GetWindowSizeChangeReason();
786 // if drag or move window, limit size and position
787 if (reason == WindowSizeChangeReason::DRAG) {
788 LimitWindowPositionWhenDrag(node, winRect);
789 if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
790 const_cast<WindowLayoutPolicy*>(this)->FixWindowSizeByRatioIfDragBeyondLimitRegion(node, winRect);
791 }
792 } else {
793 // Limit window position, such as init window rect when show
794 LimitWindowPositionWhenInitRectOrMove(node, winRect);
795 }
796 }
797
LimitWindowPositionWhenDrag(const sptr<WindowNode> & node,Rect & winRect) const798 void WindowLayoutPolicy::LimitWindowPositionWhenDrag(const sptr<WindowNode>& node,
799 Rect& winRect) const
800 {
801 float virtualPixelRatio = GetVirtualPixelRatio(node->GetDisplayId());
802 uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
803 const Rect& lastRect = node->GetWindowRect();
804 Rect oriWinRect = winRect;
805
806 Rect limitRect = isMultiDisplay_ ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
807 int32_t limitMinPosX = limitRect.posX_ + static_cast<int32_t>(windowTitleBarH);
808 int32_t limitMaxPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH);
809 int32_t limitMinPosY = limitRect.posY_;
810 int32_t limitMaxPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH);
811
812 Rect dockWinRect;
813 DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
814 if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
815 WLOGFD("dock window show in bottom");
816 limitMaxPosY = dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH);
817 } else if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
818 WLOGFD("dock window show in left");
819 limitMinPosX = dockWinRect.posX_ + static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH);
820 } else if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
821 WLOGFD("dock window show in right");
822 limitMaxPosX = dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH);
823 }
824
825 // limitMinPosX is minimum (x + width)
826 if (oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) < limitMinPosX) {
827 if (oriWinRect.width_ != lastRect.width_) {
828 winRect.width_ = static_cast<uint32_t>(limitMinPosX - oriWinRect.posX_);
829 }
830 }
831 // maximum position x
832 if (oriWinRect.posX_ > limitMaxPosX) {
833 winRect.posX_ = limitMaxPosX;
834 if (oriWinRect.width_ != lastRect.width_) {
835 winRect.width_ = static_cast<uint32_t>(
836 oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) - winRect.posX_);
837 }
838 }
839 // minimum position y
840 if (oriWinRect.posY_ < limitMinPosY) {
841 winRect.posY_ = limitMinPosY;
842 if (oriWinRect.height_ != lastRect.height_) {
843 winRect.height_ = static_cast<uint32_t>(
844 oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - winRect.posY_);
845 }
846 }
847 // maximum position y
848 if (winRect.posY_ > limitMaxPosY) {
849 winRect.posY_ = limitMaxPosY;
850 if (oriWinRect.height_ != lastRect.height_) {
851 winRect.height_ = static_cast<uint32_t>(
852 oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - winRect.posY_);
853 }
854 }
855 WLOGFI("After limit by position, winRect: %{public}d %{public}d %{public}u %{public}u",
856 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
857 }
858
LimitWindowPositionWhenInitRectOrMove(const sptr<WindowNode> & node,Rect & winRect) const859 void WindowLayoutPolicy::LimitWindowPositionWhenInitRectOrMove(const sptr<WindowNode>& node, Rect& winRect) const
860 {
861 float virtualPixelRatio = GetVirtualPixelRatio(node->GetDisplayId());
862 uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
863
864 Rect limitRect;
865 // if is cross-display window, the limit rect should be full limitRect
866 if (node->isShowingOnMultiDisplays_) {
867 limitRect = displayGroupLimitRect_;
868 } else {
869 limitRect = limitRectMap_[node->GetDisplayId()];
870 }
871
872 // limit position of the main floating window(window which support dragging)
873 if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
874 Rect dockWinRect;
875 DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
876 winRect.posY_ = std::max(limitRect.posY_, winRect.posY_);
877 winRect.posY_ = std::min(limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH),
878 winRect.posY_);
879 if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
880 WLOGFD("dock window show in bottom");
881 winRect.posY_ = std::min(dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH),
882 winRect.posY_);
883 }
884 winRect.posX_ = std::max(limitRect.posX_ + static_cast<int32_t>(windowTitleBarH - winRect.width_),
885 winRect.posX_);
886 if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
887 WLOGFD("dock window show in left");
888 winRect.posX_ = std::max(static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH - winRect.width_),
889 winRect.posX_);
890 }
891 winRect.posX_ = std::min(limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH),
892 winRect.posX_);
893 if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
894 WLOGFD("dock window show in right");
895 winRect.posX_ = std::min(dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH),
896 winRect.posX_);
897 }
898 auto reason = node->GetWindowSizeChangeReason();
899 // if init window on pc, limit position
900 if (floatingBottomPosY_ != 0 && reason == WindowSizeChangeReason::UNDEFINED) {
901 uint32_t bottomPosY = static_cast<uint32_t>(floatingBottomPosY_ * virtualPixelRatio);
902 if (winRect.posY_ + static_cast<int32_t>(winRect.height_) >= bottomPosY) {
903 winRect.posY_ = limitRect.posY_;
904 }
905 }
906 }
907 WLOGFI("After limit by position if init or move, winRect: %{public}d %{public}d %{public}u %{public}u",
908 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
909 }
910
GetDockWindowShowState(DisplayId displayId,Rect & dockWinRect) const911 DockWindowShowState WindowLayoutPolicy::GetDockWindowShowState(DisplayId displayId, Rect& dockWinRect) const
912 {
913 auto& displayWindowTree = displayGroupWindowTree_[displayId];
914 auto& nodeVec = *(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]);
915 for (auto& node : nodeVec) {
916 if (node->GetWindowType() != WindowType::WINDOW_TYPE_LAUNCHER_DOCK) {
917 continue;
918 }
919
920 dockWinRect = node->GetWindowRect();
921 auto displayRect = displayGroupInfo_->GetDisplayRect(displayId);
922 WLOGFI("begin dockWinRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
923 dockWinRect.posX_, dockWinRect.posY_, dockWinRect.width_, dockWinRect.height_);
924 if (dockWinRect.height_ < dockWinRect.width_) {
925 if (static_cast<uint32_t>(dockWinRect.posY_) + dockWinRect.height_ == displayRect.height_) {
926 return DockWindowShowState::SHOWN_IN_BOTTOM;
927 } else {
928 return DockWindowShowState::NOT_SHOWN;
929 }
930 } else {
931 if (dockWinRect.posX_ == 0) {
932 return DockWindowShowState::SHOWN_IN_LEFT;
933 } else if (static_cast<uint32_t>(dockWinRect.posX_) + dockWinRect.width_ == displayRect.width_) {
934 return DockWindowShowState::SHOWN_IN_RIGHT;
935 } else {
936 return DockWindowShowState::NOT_SHOWN;
937 }
938 }
939 }
940 return DockWindowShowState::NOT_SHOWN;
941 }
942
GetAvoidPosType(const Rect & rect,DisplayId displayId) const943 AvoidPosType WindowLayoutPolicy::GetAvoidPosType(const Rect& rect, DisplayId displayId) const
944 {
945 const auto& displayRectMap = displayGroupInfo_->GetAllDisplayRects();
946 if (displayRectMap.find(displayId) == std::end(displayRectMap)) {
947 WLOGFE("GetAvoidPosType fail. Get display fail. displayId: %{public}" PRIu64"", displayId);
948 return AvoidPosType::AVOID_POS_UNKNOWN;
949 }
950 const auto& displayRect = displayGroupInfo_->GetDisplayRect(displayId);
951 return WindowHelper::GetAvoidPosType(rect, displayRect);
952 }
953
UpdateLimitRect(const sptr<WindowNode> & node,Rect & limitRect)954 void WindowLayoutPolicy::UpdateLimitRect(const sptr<WindowNode>& node, Rect& limitRect)
955 {
956 const auto& layoutRect = node->GetWindowRect();
957 int32_t limitH = static_cast<int32_t>(limitRect.height_);
958 int32_t limitW = static_cast<int32_t>(limitRect.width_);
959 int32_t layoutH = static_cast<int32_t>(layoutRect.height_);
960 int32_t layoutW = static_cast<int32_t>(layoutRect.width_);
961 if (node->GetWindowType() == WindowType::WINDOW_TYPE_STATUS_BAR ||
962 node->GetWindowType() == WindowType::WINDOW_TYPE_NAVIGATION_BAR) {
963 auto avoidPosType = GetAvoidPosType(layoutRect, node->GetDisplayId());
964 int32_t offsetH = 0;
965 int32_t offsetW = 0;
966 switch (avoidPosType) {
967 case AvoidPosType::AVOID_POS_TOP:
968 offsetH = layoutRect.posY_ + layoutH - limitRect.posY_;
969 limitRect.posY_ += offsetH;
970 limitH -= offsetH;
971 break;
972 case AvoidPosType::AVOID_POS_BOTTOM:
973 offsetH = limitRect.posY_ + limitH - layoutRect.posY_;
974 limitH -= offsetH;
975 break;
976 case AvoidPosType::AVOID_POS_LEFT:
977 offsetW = layoutRect.posX_ + layoutW - limitRect.posX_;
978 limitRect.posX_ += offsetW;
979 limitW -= offsetW;
980 break;
981 case AvoidPosType::AVOID_POS_RIGHT:
982 offsetW = limitRect.posX_ + limitW - layoutRect.posX_;
983 limitW -= offsetW;
984 break;
985 default:
986 WLOGFE("invalid avoidPosType: %{public}d", avoidPosType);
987 }
988 }
989 limitRect.height_ = static_cast<uint32_t>(limitH < 0 ? 0 : limitH);
990 limitRect.width_ = static_cast<uint32_t>(limitW < 0 ? 0 : limitW);
991 WLOGFI("Type: %{public}d, limitRect: %{public}d %{public}d %{public}u %{public}u",
992 node->GetWindowType(), limitRect.posX_, limitRect.posY_, limitRect.width_, limitRect.height_);
993 }
994
Reset()995 void WindowLayoutPolicy::Reset()
996 {
997 }
998
GetVirtualPixelRatio(DisplayId displayId) const999 float WindowLayoutPolicy::GetVirtualPixelRatio(DisplayId displayId) const
1000 {
1001 float virtualPixelRatio = displayGroupInfo_->GetDisplayVirtualPixelRatio(displayId);
1002 WLOGFI("GetVirtualPixel success. displayId:%{public}" PRIu64", vpr:%{public}f", displayId, virtualPixelRatio);
1003 return virtualPixelRatio;
1004 }
1005
IsFullScreenRecentWindowExist(const std::vector<sptr<WindowNode>> & nodeVec) const1006 bool WindowLayoutPolicy::IsFullScreenRecentWindowExist(const std::vector<sptr<WindowNode>>& nodeVec) const
1007 {
1008 for (auto& node : nodeVec) {
1009 if (node->GetWindowType() == WindowType::WINDOW_TYPE_LAUNCHER_RECENT &&
1010 node->GetWindowMode() == WindowMode::WINDOW_MODE_FULLSCREEN) {
1011 return true;
1012 }
1013 }
1014 return false;
1015 }
1016
SetBounds(const sptr<WindowNode> & node,const Rect & winRect,const Rect & preRect)1017 static void SetBounds(const sptr<WindowNode>& node, const Rect& winRect, const Rect& preRect)
1018 {
1019 if (node->GetWindowType() == WindowType::WINDOW_TYPE_APP_COMPONENT ||
1020 node->GetWindowSizeChangeReason() == WindowSizeChangeReason::TRANSFORM) {
1021 WLOGFI("not need to update bounds");
1022 return;
1023 }
1024 // set surface node gravity based on WindowSizeChangeReason
1025 if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG_START ||
1026 node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG ||
1027 node->GetWindowSizeChangeReason() == WindowSizeChangeReason::ROTATION) {
1028 if (node->surfaceNode_) {
1029 node->surfaceNode_->SetFrameGravity(Gravity::RESIZE);
1030 }
1031 } else {
1032 if (node->surfaceNode_) {
1033 node->surfaceNode_->SetFrameGravity(Gravity::TOP_LEFT);
1034 }
1035 }
1036 WLOGFD("name:%{public}s id:%{public}u preRect:[x:%{public}d, y:%{public}d, w:%{public}d, h:%{public}d]",
1037 node->GetWindowName().c_str(), node->GetWindowId(),
1038 preRect.posX_, preRect.posY_, preRect.width_, preRect.height_);
1039 WLOGFD("name:%{public}s id:%{public}u winRect:[x:%{public}d, y:%{public}d, w:%{public}d, h:%{public}d]",
1040 node->GetWindowName().c_str(), node->GetWindowId(),
1041 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
1042 if (node->leashWinSurfaceNode_) {
1043 if (winRect != preRect) {
1044 // avoid animation interpreted when client coming
1045 node->leashWinSurfaceNode_->SetBounds(winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
1046 }
1047 if (node->startingWinSurfaceNode_) {
1048 node->startingWinSurfaceNode_->SetBounds(0, 0, winRect.width_, winRect.height_);
1049 }
1050 if (node->surfaceNode_) {
1051 node->surfaceNode_->SetBounds(0, 0, winRect.width_, winRect.height_);
1052 }
1053 } else if (node->surfaceNode_) {
1054 node->surfaceNode_->SetBounds(winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
1055 }
1056 }
1057
UpdateSurfaceBounds(const sptr<WindowNode> & node,const Rect & winRect,const Rect & preRect)1058 void WindowLayoutPolicy::UpdateSurfaceBounds(const sptr<WindowNode>& node, const Rect& winRect, const Rect& preRect)
1059 {
1060 wptr<WindowNode> weakNode = node;
1061 auto SetBoundsFunc = [weakNode, winRect, preRect]() {
1062 auto winNode = weakNode.promote();
1063 if (winNode == nullptr) {
1064 WLOGFI("winNode is nullptr");
1065 return;
1066 }
1067 SetBounds(winNode, winRect, preRect);
1068 };
1069
1070 switch (node->GetWindowSizeChangeReason()) {
1071 case WindowSizeChangeReason::MAXIMIZE:
1072 [[fallthrough]];
1073 case WindowSizeChangeReason::RECOVER: {
1074 const RSAnimationTimingProtocol timingProtocol(400); // animation time
1075 RSNode::Animate(timingProtocol, RSAnimationTimingCurve::EASE_OUT, SetBoundsFunc);
1076 break;
1077 }
1078 case WindowSizeChangeReason::ROTATION: {
1079 const RSAnimationTimingProtocol timingProtocol(600); // animation time
1080 const RSAnimationTimingCurve curve_ = RSAnimationTimingCurve::CreateCubicCurve(
1081 0.2, 0.0, 0.2, 1.0); // animation curve: cubic [0.2, 0.0, 0.2, 1.0]
1082 RSNode::Animate(timingProtocol, curve_, SetBoundsFunc);
1083 break;
1084 }
1085 case WindowSizeChangeReason::UNDEFINED:
1086 [[fallthrough]];
1087 default:
1088 SetBoundsFunc();
1089 }
1090 }
1091
GetDisplayGroupRect() const1092 Rect WindowLayoutPolicy::GetDisplayGroupRect() const
1093 {
1094 return displayGroupRect_;
1095 }
1096
SetSplitRatioConfig(const SplitRatioConfig & splitRatioConfig)1097 void WindowLayoutPolicy::SetSplitRatioConfig(const SplitRatioConfig& splitRatioConfig)
1098 {
1099 splitRatioConfig_ = splitRatioConfig;
1100 }
1101
GetDividerRect(DisplayId displayId) const1102 Rect WindowLayoutPolicy::GetDividerRect(DisplayId displayId) const
1103 {
1104 return INVALID_EMPTY_RECT;
1105 }
1106
IsTileRectSatisfiedWithSizeLimits(const sptr<WindowNode> & node)1107 bool WindowLayoutPolicy::IsTileRectSatisfiedWithSizeLimits(const sptr<WindowNode>& node)
1108 {
1109 return true;
1110 }
1111
SetCascadeRectBottomPosYLimit(uint32_t floatingBottomPosY)1112 void WindowLayoutPolicy::SetCascadeRectBottomPosYLimit(uint32_t floatingBottomPosY)
1113 {
1114 floatingBottomPosY_ = floatingBottomPosY;
1115 }
1116 }
1117 }
1118