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 "window_layout_policy_cascade.h"
17
18 #include <hitrace_meter.h>
19
20 #include "minimize_app.h"
21 #include "window_helper.h"
22 #include "window_inner_manager.h"
23 #include "window_manager_hilog.h"
24
25 namespace OHOS {
26 namespace Rosen {
27 namespace {
28 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowLayoutPolicyCascade"};
29 }
30
WindowLayoutPolicyCascade(const sptr<DisplayGroupInfo> & displayGroupInfo,DisplayGroupWindowTree & displayGroupWindowTree)31 WindowLayoutPolicyCascade::WindowLayoutPolicyCascade(const sptr<DisplayGroupInfo>& displayGroupInfo,
32 DisplayGroupWindowTree& displayGroupWindowTree)
33 : WindowLayoutPolicy(displayGroupInfo, displayGroupWindowTree)
34 {
35 LayoutRects cascadeRects {
36 .primaryRect_ = {0, 0, 0, 0},
37 .secondaryRect_ = {0, 0, 0, 0},
38 .primaryLimitRect_ = {0, 0, 0, 0},
39 .secondaryLimitRect_ = {0, 0, 0, 0},
40 .dividerRect_ = {0, 0, 0, 0},
41 .firstCascadeRect_ = {0, 0, 0, 0},
42 };
43 for (auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
44 cascadeRectsMap_.insert(std::make_pair(iter.first, cascadeRects));
45 }
46 }
47
Launch()48 void WindowLayoutPolicyCascade::Launch()
49 {
50 InitAllRects();
51 for (const auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
52 DisplayId displayId = iter.first;
53 auto& displayWindowTree = displayGroupWindowTree_[displayId];
54 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::APP_WINDOW_NODE]));
55 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::BELOW_WINDOW_NODE]));
56 }
57 WLOGFI("WindowLayoutPolicyCascade::Launch");
58 }
59
Clean()60 void WindowLayoutPolicyCascade::Clean()
61 {
62 WLOGFI("WindowLayoutPolicyCascade::Clean");
63 }
64
Reset()65 void WindowLayoutPolicyCascade::Reset()
66 {
67 const auto& displayRectMap = displayGroupInfo_->GetAllDisplayRects();
68 // reset split and limit rects
69 for (auto& iter : displayRectMap) {
70 InitSplitRects(iter.first);
71 InitLimitRects(iter.first);
72 }
73 displayGroupLimitRect_ = displayGroupRect_;
74 }
75
InitAllRects()76 void WindowLayoutPolicyCascade::InitAllRects()
77 {
78 const auto& displayRectMap = displayGroupInfo_->GetAllDisplayRects();
79 for (auto& iter : displayRectMap) {
80 // init split and limit rects
81 InitSplitRects(iter.first);
82 InitLimitRects(iter.first);
83 // init full displayRect
84 displayGroupLimitRect_ = displayGroupRect_;
85 // init cascade rect
86 auto& displayWindowTree = displayGroupWindowTree_[iter.first];
87 LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]));
88 InitCascadeRect(iter.first);
89 }
90 }
91
LayoutWindowNode(const sptr<WindowNode> & node)92 void WindowLayoutPolicyCascade::LayoutWindowNode(const sptr<WindowNode>& node)
93 {
94 if (node == nullptr) {
95 return;
96 }
97 if (node->parent_ != nullptr) { // isn't root node
98 if (!node->currentVisibility_) {
99 WLOGFI("window[%{public}u] currently not visible, no need layout", node->GetWindowId());
100 return;
101 }
102 UpdateLayoutRect(node);
103 if (avoidTypes_.find(node->GetWindowType()) != avoidTypes_.end()) {
104 const DisplayId& displayId = node->GetDisplayId();
105 Rect& primaryLimitRect = cascadeRectsMap_[displayId].primaryLimitRect_;
106 Rect& secondaryLimitRect = cascadeRectsMap_[displayId].secondaryLimitRect_;
107 UpdateLimitRect(node, limitRectMap_[displayId]);
108 UpdateSplitLimitRect(limitRectMap_[displayId], primaryLimitRect);
109 UpdateSplitLimitRect(limitRectMap_[displayId], secondaryLimitRect);
110 UpdateSplitRatioPoints(displayId);
111 UpdateDisplayGroupLimitRect();
112 WLOGFI("priLimitRect: %{public}d %{public}d %{public}u %{public}u, " \
113 "secLimitRect: %{public}d %{public}d %{public}u %{public}u", primaryLimitRect.posX_,
114 primaryLimitRect.posY_, primaryLimitRect.width_, primaryLimitRect.height_, secondaryLimitRect.posX_,
115 secondaryLimitRect.posY_, secondaryLimitRect.width_, secondaryLimitRect.height_);
116 }
117 }
118 for (auto& childNode : node->children_) {
119 LayoutWindowNode(childNode);
120 }
121 }
122
LayoutWindowTree(DisplayId displayId)123 void WindowLayoutPolicyCascade::LayoutWindowTree(DisplayId displayId)
124 {
125 InitLimitRects(displayId);
126 WindowLayoutPolicy::LayoutWindowTree(displayId);
127 }
128
RemoveWindowNode(const sptr<WindowNode> & node)129 void WindowLayoutPolicyCascade::RemoveWindowNode(const sptr<WindowNode>& node)
130 {
131 HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER);
132 auto type = node->GetWindowType();
133 // affect other windows, trigger off global layout
134 if (avoidTypes_.find(type) != avoidTypes_.end()) {
135 LayoutWindowTree(node->GetDisplayId());
136 } else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode
137 InitSplitRects(node->GetDisplayId());
138 LayoutWindowTree(node->GetDisplayId());
139 }
140 UpdateClientRect(node->GetRequestRect(), node, WindowSizeChangeReason::HIDE);
141 }
142
GetExitSplitPoints(DisplayId displayId) const143 std::vector<int32_t> WindowLayoutPolicyCascade::GetExitSplitPoints(DisplayId displayId) const
144 {
145 return cascadeRectsMap_[displayId].exitSplitPoints_;
146 }
147
SpecialReasonProcess(const sptr<WindowNode> & node,bool isAddWindow) const148 bool WindowLayoutPolicyCascade::SpecialReasonProcess(const sptr<WindowNode>& node, bool isAddWindow) const
149 {
150 const DisplayId& displayId = node->GetDisplayId();
151 if ((node->GetWindowSizeChangeReason() == WindowSizeChangeReason::MOVE) ||
152 (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::RESIZE)) {
153 if ((node->GetRequestRect() == node->GetWindowRect()) && (!isAddWindow)) {
154 return false;
155 }
156 }
157 if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::ROTATION) {
158 const auto& windowNodeVecSptrs = displayGroupWindowTree_[displayId];
159 for (const auto& windowNodeVecSptr : windowNodeVecSptrs) {
160 const auto& windowNodeVec = *(windowNodeVecSptr.second);
161 for (auto& childNode : windowNodeVec) {
162 childNode->SetWindowSizeChangeReason(WindowSizeChangeReason::ROTATION);
163 }
164 }
165 }
166 return true;
167 }
168
UpdateWindowNode(const sptr<WindowNode> & node,bool isAddWindow)169 void WindowLayoutPolicyCascade::UpdateWindowNode(const sptr<WindowNode>& node, bool isAddWindow)
170 {
171 HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER);
172 auto type = node->GetWindowType();
173 const DisplayId& displayId = node->GetDisplayId();
174 UpdateWindowNodeRectOffset(node);
175 // affect other windows, trigger off global layout
176 if (avoidTypes_.find(type) != avoidTypes_.end()) {
177 bool ret = SpecialReasonProcess(node, isAddWindow);
178 if (ret != true) {
179 return;
180 }
181 LayoutWindowTree(displayId);
182 } else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode
183 UpdateLayoutRect(node);
184 auto splitDockerRect = node->GetWindowRect();
185 SetSplitRect(splitDockerRect, displayId); // calculate primary/secondary depend on divider rect
186 WLOGFI("UpdateDividerRects WinId: %{public}u, Rect: %{public}d %{public}d %{public}u %{public}u",
187 node->GetWindowId(), splitDockerRect.posX_, splitDockerRect.posY_,
188 splitDockerRect.width_, splitDockerRect.height_);
189 if (!isAddWindow) {
190 const auto& appWindowNodeVec = *(displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
191 for (auto& childNode : appWindowNodeVec) { // update split node size change reason
192 if (childNode->IsSplitMode()) {
193 childNode->SetWindowSizeChangeReason(WindowSizeChangeReason::DRAG);
194 }
195 }
196 }
197 LayoutWindowTree(displayId);
198 } else if (node->IsSplitMode()) {
199 LayoutWindowTree(displayId);
200 } else { // layout single window
201 LayoutWindowNode(node);
202 }
203 }
204
AddWindowNode(const sptr<WindowNode> & node)205 void WindowLayoutPolicyCascade::AddWindowNode(const sptr<WindowNode>& node)
206 {
207 HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER);
208 auto property = node->GetWindowProperty();
209 if (property == nullptr) {
210 WLOGFE("window property is nullptr.");
211 return;
212 }
213
214 if (WindowHelper::IsEmptyRect(property->GetRequestRect())) {
215 SetCascadeRect(node);
216 }
217 UpdateWindowNodeRectOffset(node);
218 if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
219 node->SetRequestRect(cascadeRectsMap_[node->GetDisplayId()].dividerRect_); // init divider bar
220 DisplayId displayId = node->GetDisplayId();
221 if (!WindowHelper::IsEmptyRect(restoringDividerWindowRects_[displayId])) {
222 node->SetRequestRect(restoringDividerWindowRects_[displayId]);
223 }
224 restoringDividerWindowRects_.erase(displayId);
225 }
226 UpdateWindowNode(node, true); // currently, update and add do the same process
227 }
228
SetSplitDividerWindowRects(std::map<DisplayId,Rect> dividerWindowRects)229 void WindowLayoutPolicyCascade::SetSplitDividerWindowRects(std::map<DisplayId, Rect> dividerWindowRects)
230 {
231 restoringDividerWindowRects_ = dividerWindowRects;
232 }
233
LimitDividerMoveBounds(Rect & rect,DisplayId displayId) const234 void WindowLayoutPolicyCascade::LimitDividerMoveBounds(Rect& rect, DisplayId displayId) const
235 {
236 const Rect& limitRect = limitRectMap_[displayId];
237 if (rect.width_ < rect.height_) {
238 if (rect.posX_ < limitRect.posX_) {
239 rect.posX_ = limitRect.posX_;
240 } else if (rect.posX_ + static_cast<int32_t>(rect.width_) >
241 limitRect.posX_ + static_cast<int32_t>(limitRect.width_)) {
242 rect.posX_ = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - rect.width_);
243 }
244 } else {
245 if (rect.posY_ < limitRect.posY_) {
246 rect.posY_ = limitRect.posY_;
247 } else if (rect.posY_ + static_cast<int32_t>(rect.height_) >
248 limitRect.posY_ + static_cast<int32_t>(limitRect.height_)) {
249 rect.posY_ = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - rect.height_);
250 }
251 }
252 WLOGFI("limit divider move bounds:[%{public}d, %{public}d, %{public}u, %{public}u]",
253 rect.posX_, rect.posY_, rect.width_, rect.height_);
254 }
255
InitCascadeRect(DisplayId displayId)256 void WindowLayoutPolicyCascade::InitCascadeRect(DisplayId displayId)
257 {
258 constexpr uint32_t half = 2;
259 constexpr float ratio = DEFAULT_ASPECT_RATIO;
260
261 /*
262 * Calculate default width and height, if width or height is
263 * smaller than minWidth or minHeight, use the minimum limits
264 */
265 const auto& displayRect = displayGroupInfo_->GetDisplayRect(displayId);
266 auto vpr = displayGroupInfo_->GetDisplayVirtualPixelRatio(displayId);
267 uint32_t defaultW = std::max(static_cast<uint32_t>(displayRect.width_ * ratio),
268 static_cast<uint32_t>(MIN_FLOATING_WIDTH * vpr));
269 uint32_t defaultH = std::max(static_cast<uint32_t>(displayRect.height_ * ratio),
270 static_cast<uint32_t>(MIN_FLOATING_HEIGHT * vpr));
271
272 // calculate default x and y
273 Rect resRect = {0, 0, defaultW, defaultH};
274 const Rect& limitRect = limitRectMap_[displayId];
275 if (defaultW <= limitRect.width_ && defaultH <= limitRect.height_) {
276 int32_t centerPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ / half);
277 resRect.posX_ = centerPosX - static_cast<int32_t>(defaultW / half);
278
279 int32_t centerPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ / half);
280 resRect.posY_ = centerPosY - static_cast<int32_t>(defaultH / half);
281 }
282 WLOGFI("init CascadeRect :[%{public}d, %{public}d, %{public}d, %{public}d]",
283 resRect.posX_, resRect.posY_, resRect.width_, resRect.height_);
284 cascadeRectsMap_[displayId].firstCascadeRect_ = resRect;
285 }
286
ApplyWindowRectConstraints(const sptr<WindowNode> & node,Rect & winRect) const287 void WindowLayoutPolicyCascade::ApplyWindowRectConstraints(const sptr<WindowNode>& node, Rect& winRect) const
288 {
289 WLOGFI("Before apply constraints winRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
290 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
291 auto reason = node->GetWindowSizeChangeReason();
292 DisplayId displayId = node->GetDisplayId();
293 if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
294 // make sure the divider is entirely within display
295 LimitDividerMoveBounds(winRect, displayId);
296 if (reason == WindowSizeChangeReason::DRAG_END) {
297 if (!IsVerticalDisplay(displayId)) {
298 UpdateDockSlicePosition(displayId, winRect.posX_);
299 } else {
300 UpdateDockSlicePosition(displayId, winRect.posY_);
301 }
302 }
303 /*
304 * use the layout orientation of the window and the layout orientation of the screen
305 * to determine whether the screen is rotating
306 */
307 if ((!WindowHelper::IsLandscapeRect(winRect) && IsVerticalDisplay(displayId)) ||
308 (WindowHelper::IsLandscapeRect(winRect) && !IsVerticalDisplay(displayId))) {
309 // resets the rect of the divider window when the screen is rotating
310 WLOGFD("Reset divider when display rotate rect:[%{public}d, %{public}d, %{public}u, %{public}u]",
311 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
312 winRect = cascadeRectsMap_[displayId].dividerRect_;
313 node->SetRequestRect(winRect);
314 }
315 }
316 LimitFloatingWindowSize(node, displayGroupInfo_->GetDisplayRect(node->GetDisplayId()), winRect);
317 LimitMainFloatingWindowPosition(node, winRect);
318 WLOGFI("After apply constraints winRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
319 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
320 }
321
UpdateLayoutRect(const sptr<WindowNode> & node)322 void WindowLayoutPolicyCascade::UpdateLayoutRect(const sptr<WindowNode>& node)
323 {
324 auto type = node->GetWindowType();
325 auto mode = node->GetWindowMode();
326 auto property = node->GetWindowProperty();
327 if (property == nullptr) {
328 WLOGFE("window property is nullptr.");
329 return;
330 }
331 UpdateWindowSizeLimits(node);
332 bool needAvoid = (node->GetWindowFlags() & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_NEED_AVOID));
333 bool parentLimit = (node->GetWindowFlags() & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_PARENT_LIMIT));
334 bool subWindow = WindowHelper::IsSubWindow(type) || WindowHelper::IsSystemSubWindow(type);
335 bool floatingWindow = (mode == WindowMode::WINDOW_MODE_FLOATING);
336 const Rect lastWinRect = node->GetWindowRect();
337 Rect displayRect = GetDisplayRect(mode, node->GetDisplayId());
338 Rect limitRect = displayRect;
339 ComputeDecoratedRequestRect(node);
340 Rect winRect = property->GetRequestRect();
341
342 WLOGFI("Id:%{public}u, avoid:%{public}d parLimit:%{public}d floating:%{public}d, sub:%{public}d, " \
343 "deco:%{public}d, type:%{public}d, requestRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
344 node->GetWindowId(), needAvoid, parentLimit, floatingWindow, subWindow, property->GetDecorEnable(),
345 static_cast<uint32_t>(type), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
346 if (needAvoid) {
347 limitRect = GetLimitRect(mode, node->GetDisplayId());
348 }
349
350 if (!floatingWindow) { // fullscreen window
351 winRect = limitRect;
352 } else { // floating window
353 if (subWindow && parentLimit && node->parent_) { // subwindow and limited by parent
354 limitRect = node->parent_->GetWindowRect();
355 UpdateFloatingLayoutRect(limitRect, winRect);
356 }
357 }
358 ApplyWindowRectConstraints(node, winRect);
359 node->SetWindowRect(winRect);
360 CalcAndSetNodeHotZone(winRect, node);
361 // update node bounds before reset reason
362 UpdateSurfaceBounds(node, winRect, lastWinRect);
363 UpdateClientRectAndResetReason(node, winRect);
364 }
365
InitLimitRects(DisplayId displayId)366 void WindowLayoutPolicyCascade::InitLimitRects(DisplayId displayId)
367 {
368 limitRectMap_[displayId] = displayGroupInfo_->GetDisplayRect(displayId);
369 cascadeRectsMap_[displayId].primaryLimitRect_ = cascadeRectsMap_[displayId].primaryRect_;
370 cascadeRectsMap_[displayId].secondaryLimitRect_ = cascadeRectsMap_[displayId].secondaryRect_;
371 UpdateSplitRatioPoints(displayId);
372 }
373
GetLimitRect(const WindowMode mode,DisplayId displayId) const374 Rect WindowLayoutPolicyCascade::GetLimitRect(const WindowMode mode, DisplayId displayId) const
375 {
376 if (mode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
377 return cascadeRectsMap_[displayId].primaryLimitRect_;
378 } else if (mode == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
379 return cascadeRectsMap_[displayId].secondaryLimitRect_;
380 } else {
381 return limitRectMap_[displayId];
382 }
383 }
384
GetDisplayRect(const WindowMode mode,DisplayId displayId) const385 Rect WindowLayoutPolicyCascade::GetDisplayRect(const WindowMode mode, DisplayId displayId) const
386 {
387 if (mode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
388 return cascadeRectsMap_[displayId].primaryRect_;
389 } else if (mode == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
390 return cascadeRectsMap_[displayId].secondaryRect_;
391 } else {
392 return displayGroupInfo_->GetDisplayRect(displayId);
393 }
394 }
395
UpdateSplitRatioPoints(DisplayId displayId)396 void WindowLayoutPolicyCascade::UpdateSplitRatioPoints(DisplayId displayId)
397 {
398 LayoutRects& cascadeRects = cascadeRectsMap_[displayId];
399 cascadeRects.exitSplitPoints_.clear();
400 cascadeRects.splitRatioPoints_.clear();
401 cascadeRects.exitSplitPoints_.push_back(GetSplitRatioPoint(splitRatioConfig_.exitSplitStartRatio, displayId));
402 cascadeRects.exitSplitPoints_.push_back(GetSplitRatioPoint(splitRatioConfig_.exitSplitEndRatio, displayId));
403 for (const auto& ratio : splitRatioConfig_.splitRatios) {
404 cascadeRects.splitRatioPoints_.push_back(GetSplitRatioPoint(ratio, displayId));
405 }
406 }
407
UpdateDockSlicePosition(DisplayId displayId,int32_t & origin) const408 void WindowLayoutPolicyCascade::UpdateDockSlicePosition(DisplayId displayId, int32_t& origin) const
409 {
410 const LayoutRects& cascadeRects = cascadeRectsMap_[displayId];
411 if (cascadeRects.splitRatioPoints_.size() == 0) {
412 return;
413 }
414 uint32_t minDiff = std::max(limitRectMap_[displayId].width_, limitRectMap_[displayId].height_);
415 int32_t closestPoint = origin;
416 for (const auto& elem : cascadeRects.splitRatioPoints_) {
417 uint32_t diff = (origin > elem) ? static_cast<uint32_t>(origin - elem) : static_cast<uint32_t>(elem - origin);
418 if (diff < minDiff) {
419 closestPoint = elem;
420 minDiff = diff;
421 }
422 }
423 origin = closestPoint;
424 }
425
UpdateSplitLimitRect(const Rect & limitRect,Rect & limitSplitRect)426 void WindowLayoutPolicyCascade::UpdateSplitLimitRect(const Rect& limitRect, Rect& limitSplitRect)
427 {
428 Rect curLimitRect = limitSplitRect;
429 limitSplitRect.posX_ = std::max(limitRect.posX_, curLimitRect.posX_);
430 limitSplitRect.posY_ = std::max(limitRect.posY_, curLimitRect.posY_);
431 limitSplitRect.width_ = std::min(limitRect.posX_ + limitRect.width_,
432 curLimitRect.posX_ + curLimitRect.width_) -
433 limitSplitRect.posX_;
434 limitSplitRect.height_ = std::min(limitRect.posY_ + limitRect.height_,
435 curLimitRect.posY_ + curLimitRect.height_) -
436 limitSplitRect.posY_;
437 }
438
InitSplitRects(DisplayId displayId)439 void WindowLayoutPolicyCascade::InitSplitRects(DisplayId displayId)
440 {
441 float virtualPixelRatio = GetVirtualPixelRatio(displayId);
442 uint32_t dividerWidth = static_cast<uint32_t>(DIVIDER_WIDTH * virtualPixelRatio);
443 auto& dividerRect = cascadeRectsMap_[displayId].dividerRect_;
444 const auto& displayRect = displayGroupInfo_->GetDisplayRect(displayId);
445 if (!IsVerticalDisplay(displayId)) {
446 dividerRect = { static_cast<uint32_t>((displayRect.width_ - dividerWidth) * DEFAULT_SPLIT_RATIO), 0,
447 dividerWidth, displayRect.height_ };
448 } else {
449 dividerRect = { 0, static_cast<uint32_t>((displayRect.height_ - dividerWidth) * DEFAULT_SPLIT_RATIO),
450 displayRect.width_, dividerWidth };
451 }
452 WLOGFI("init dividerRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
453 dividerRect.posX_, dividerRect.posY_, dividerRect.width_, dividerRect.height_);
454 SetSplitRect(dividerRect, displayId);
455 }
456
GetSplitRatioPoint(float ratio,DisplayId displayId)457 int32_t WindowLayoutPolicyCascade::GetSplitRatioPoint(float ratio, DisplayId displayId)
458 {
459 auto dividerRect = cascadeRectsMap_[displayId].dividerRect_;
460 auto displayRect = displayGroupInfo_->GetDisplayRect(displayId);
461 if (!IsVerticalDisplay(displayId)) {
462 return displayRect.posX_ +
463 static_cast<int32_t>((displayRect.width_ - dividerRect.width_) * ratio);
464 } else {
465 return displayRect.posY_ +
466 static_cast<int32_t>((displayRect.height_ - dividerRect.height_) * ratio);
467 }
468 }
469
SetSplitRect(const Rect & divRect,DisplayId displayId)470 void WindowLayoutPolicyCascade::SetSplitRect(const Rect& divRect, DisplayId displayId)
471 {
472 auto& dividerRect = cascadeRectsMap_[displayId].dividerRect_;
473 auto& primaryRect = cascadeRectsMap_[displayId].primaryRect_;
474 auto& secondaryRect = cascadeRectsMap_[displayId].secondaryRect_;
475 const auto& displayRect = displayGroupInfo_->GetDisplayRect(displayId);
476
477 dividerRect.width_ = divRect.width_;
478 dividerRect.height_ = divRect.height_;
479 if (!IsVerticalDisplay(displayId)) {
480 primaryRect.posX_ = displayRect.posX_;
481 primaryRect.posY_ = displayRect.posY_;
482 primaryRect.width_ = divRect.posX_;
483 primaryRect.height_ = displayRect.height_;
484
485 secondaryRect.posX_ = divRect.posX_ + static_cast<int32_t>(dividerRect.width_);
486 secondaryRect.posY_ = displayRect.posY_;
487 secondaryRect.width_ = static_cast<uint32_t>(static_cast<int32_t>(displayRect.width_) - secondaryRect.posX_);
488 secondaryRect.height_ = displayRect.height_;
489 } else {
490 primaryRect.posX_ = displayRect.posX_;
491 primaryRect.posY_ = displayRect.posY_;
492 primaryRect.height_ = divRect.posY_;
493 primaryRect.width_ = displayRect.width_;
494
495 secondaryRect.posX_ = displayRect.posX_;
496 secondaryRect.posY_ = divRect.posY_ + static_cast<int32_t>(dividerRect.height_);
497 secondaryRect.height_ = static_cast<uint32_t>(static_cast<int32_t>(displayRect.height_) - secondaryRect.posY_);
498 secondaryRect.width_ = displayRect.width_;
499 }
500 }
501
Reorder()502 void WindowLayoutPolicyCascade::Reorder()
503 {
504 WLOGFI("Cascade reorder start");
505 for (const auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
506 DisplayId displayId = iter.first;
507 Rect rect = cascadeRectsMap_[displayId].firstCascadeRect_;
508 bool isFirstReorderedWindow = true;
509 const auto& appWindowNodeVec = *(displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
510 for (auto nodeIter = appWindowNodeVec.begin(); nodeIter != appWindowNodeVec.end(); nodeIter++) {
511 auto node = *nodeIter;
512 if (node == nullptr || node->GetWindowType() != WindowType::WINDOW_TYPE_APP_MAIN_WINDOW) {
513 WLOGFI("get node failed or not app window.");
514 continue;
515 }
516 // if window don't support floating mode, or default rect of cascade is not satisfied with limits
517 if (!WindowHelper::IsWindowModeSupported(node->GetModeSupportInfo(), WindowMode::WINDOW_MODE_FLOATING) ||
518 !WindowHelper::IsRectSatisfiedWithSizeLimits(rect, node->GetWindowUpdatedSizeLimits())) {
519 MinimizeApp::AddNeedMinimizeApp(node, MinimizeReason::LAYOUT_CASCADE);
520 continue;
521 }
522 if (isFirstReorderedWindow) {
523 isFirstReorderedWindow = false;
524 } else {
525 rect = StepCascadeRect(rect, displayId);
526 }
527 node->SetRequestRect(rect);
528 node->SetDecoStatus(true);
529 if (node->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING) {
530 node->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING);
531 if (node->GetWindowToken()) {
532 node->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_FLOATING);
533 }
534 }
535 WLOGFI("Cascade reorder Id: %{public}d, rect:[%{public}d, %{public}d, %{public}d, %{public}d]",
536 node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_);
537 }
538 LayoutWindowTree(displayId);
539 }
540 WLOGFI("Reorder end");
541 }
542
GetCurCascadeRect(const sptr<WindowNode> & node) const543 Rect WindowLayoutPolicyCascade::GetCurCascadeRect(const sptr<WindowNode>& node) const
544 {
545 Rect cascadeRect = {0, 0, 0, 0};
546 const DisplayId& displayId = node->GetDisplayId();
547 const auto& appWindowNodeVec = *(const_cast<WindowLayoutPolicyCascade*>(this)->
548 displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
549 const auto& aboveAppWindowNodeVec = *(const_cast<WindowLayoutPolicyCascade*>(this)->
550 displayGroupWindowTree_[displayId][WindowRootNodeType::ABOVE_WINDOW_NODE]);
551
552 std::vector<std::vector<sptr<WindowNode>>> roots = { aboveAppWindowNodeVec, appWindowNodeVec };
553 for (auto& root : roots) {
554 for (auto iter = root.rbegin(); iter != root.rend(); iter++) {
555 if ((*iter)->GetWindowType() == WindowType::WINDOW_TYPE_APP_MAIN_WINDOW &&
556 (*iter)->GetWindowId() != node->GetWindowId()) {
557 auto property = (*iter)->GetWindowProperty();
558 if (property != nullptr) {
559 cascadeRect = ((*iter)->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING ?
560 property->GetWindowRect() : property->GetRequestRect());
561 }
562 WLOGFI("Get current cascadeRect: %{public}u [%{public}d, %{public}d, %{public}u, %{public}u]",
563 (*iter)->GetWindowId(), cascadeRect.posX_, cascadeRect.posY_,
564 cascadeRect.width_, cascadeRect.height_);
565 break;
566 }
567 }
568 }
569
570 if (WindowHelper::IsEmptyRect(cascadeRect)) {
571 WLOGFI("cascade rect is empty use first cascade rect");
572 return cascadeRectsMap_[displayId].firstCascadeRect_;
573 }
574 return StepCascadeRect(cascadeRect, displayId);
575 }
576
StepCascadeRect(Rect rect,DisplayId displayId) const577 Rect WindowLayoutPolicyCascade::StepCascadeRect(Rect rect, DisplayId displayId) const
578 {
579 float virtualPixelRatio = GetVirtualPixelRatio(displayId);
580 uint32_t cascadeWidth = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
581 uint32_t cascadeHeight = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
582
583 const Rect& limitRect = limitRectMap_[displayId];
584 Rect cascadeRect = {0, 0, 0, 0};
585 cascadeRect.width_ = rect.width_;
586 cascadeRect.height_ = rect.height_;
587 cascadeRect.posX_ = (rect.posX_ + static_cast<int32_t>(cascadeWidth) >= limitRect.posX_) &&
588 (rect.posX_ + static_cast<int32_t>(rect.width_ + cascadeWidth) <=
589 (limitRect.posX_ + static_cast<int32_t>(limitRect.width_))) ?
590 (rect.posX_ + static_cast<int32_t>(cascadeWidth)) : limitRect.posX_;
591 cascadeRect.posY_ = (rect.posY_ + static_cast<int32_t>(cascadeHeight) >= limitRect.posY_) &&
592 (rect.posY_ + static_cast<int32_t>(rect.height_ + cascadeHeight) <=
593 (limitRect.posY_ + static_cast<int32_t>(limitRect.height_))) ?
594 (rect.posY_ + static_cast<int32_t>(cascadeHeight)) : limitRect.posY_;
595 WLOGFI("step cascadeRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
596 cascadeRect.posX_, cascadeRect.posY_, cascadeRect.width_, cascadeRect.height_);
597 return cascadeRect;
598 }
599
SetCascadeRect(const sptr<WindowNode> & node)600 void WindowLayoutPolicyCascade::SetCascadeRect(const sptr<WindowNode>& node)
601 {
602 static bool isFirstAppWindow = true;
603 Rect rect;
604 auto property = node->GetWindowProperty();
605 if (property == nullptr) {
606 WLOGFE("window property is nullptr.");
607 return;
608 }
609 if (WindowHelper::IsAppWindow(property->GetWindowType()) && isFirstAppWindow) {
610 WLOGFI("set first app window cascade rect");
611 rect = cascadeRectsMap_[node->GetDisplayId()].firstCascadeRect_;
612 isFirstAppWindow = false;
613 } else if (WindowHelper::IsAppWindow(property->GetWindowType()) && !isFirstAppWindow) {
614 WLOGFI("set other app window cascade rect");
615 rect = GetCurCascadeRect(node);
616 } else {
617 // system window
618 WLOGFI("set system window cascade rect");
619 rect = cascadeRectsMap_[node->GetDisplayId()].firstCascadeRect_;
620 }
621 WLOGFI("set cascadeRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
622 rect.posX_, rect.posY_, rect.width_, rect.height_);
623 node->SetRequestRect(rect);
624 node->SetDecoStatus(true);
625 }
GetDividerRect(DisplayId displayId) const626 Rect WindowLayoutPolicyCascade::GetDividerRect(DisplayId displayId) const
627 {
628 Rect dividerRect = {0, 0, 0, 0};
629 if (cascadeRectsMap_.find(displayId) != std::end(cascadeRectsMap_)) {
630 dividerRect = cascadeRectsMap_[displayId].dividerRect_;
631 }
632 return dividerRect;
633 }
634
UpdateWindowNodeRectOffset(const sptr<WindowNode> & node) const635 void WindowLayoutPolicyCascade::UpdateWindowNodeRectOffset(const sptr<WindowNode>& node) const
636 {
637 WLOGFD("UpdateWindowNodeRectOffset, windowId: %{public}u", node->GetWindowId());
638 auto displayId = node->GetDisplayId();
639 const Rect& displayRect = displayGroupInfo_->GetDisplayRect(displayId);
640 auto displayInfo = displayGroupInfo_->GetDisplayInfo(displayId);
641 auto type = node->GetWindowType();
642 Rect rect = node->GetRequestRect();
643 WLOGFD("RequestRect before, width: %{public}u, height: %{public}u, posX:%{public}d, posY:%{public}d",
644 rect.width_, rect.height_, rect.posX_, rect.posY_);
645 switch (type) {
646 case WindowType::WINDOW_TYPE_STATUS_BAR: {
647 rect.posY_ = displayRect.posY_;
648 break;
649 }
650 case WindowType::WINDOW_TYPE_NAVIGATION_BAR: {
651 rect.posY_ = static_cast<int32_t>(displayRect.height_) + displayRect.posY_ -
652 static_cast<int32_t>(rect.height_);
653 break;
654 }
655 default: {
656 if (displayInfo->GetWaterfallDisplayCompressionStatus()) {
657 if (rect.posY_ < displayRect.posY_) {
658 rect.posY_ = displayRect.posY_;
659 } else if (rect.posY_ > displayRect.posY_ + static_cast<int32_t>(displayRect.height_)) {
660 rect.posY_ = displayRect.posY_ + static_cast<int32_t>(displayRect.height_);
661 }
662 }
663 }
664 }
665 node->SetRequestRect(rect);
666 WLOGFD("RequestRect after, width: %{public}u, height: %{public}u, posX:%{public}d, posY:%{public}d",
667 rect.width_, rect.height_, rect.posX_, rect.posY_);
668 }
669
670 } // Rosen
671 } // OHOS
672