1 /*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "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 #include "window_manager_service_utils.h"
25 #include "window_system_effect.h"
26 #include "wm_math.h"
27
28 namespace OHOS {
29 namespace Rosen {
30 namespace {
31 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "Cascade"};
32 }
33
WindowLayoutPolicyCascade(DisplayGroupWindowTree & displayGroupWindowTree)34 WindowLayoutPolicyCascade::WindowLayoutPolicyCascade(DisplayGroupWindowTree& displayGroupWindowTree)
35 : WindowLayoutPolicy(displayGroupWindowTree)
36 {
37 CascadeRects cascadeRects {
38 .primaryRect_ = {0, 0, 0, 0},
39 .secondaryRect_ = {0, 0, 0, 0},
40 .dividerRect_ = {0, 0, 0, 0},
41 .defaultCascadeRect_ = {0, 0, 0, 0},
42 };
43 for (auto& iter : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) {
44 cascadeRectsMap_.insert(std::make_pair(iter.first, cascadeRects));
45 }
46 }
47
Launch()48 void WindowLayoutPolicyCascade::Launch()
49 {
50 InitAllRects();
51 WLOGI("WindowLayoutPolicyCascade::Launch");
52 }
53
Reorder()54 void WindowLayoutPolicyCascade::Reorder()
55 {
56 WLOGFD("Cascade reorder start");
57 for (auto& iter : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) {
58 DisplayId displayId = iter.first;
59 Rect rect = cascadeRectsMap_[displayId].defaultCascadeRect_;
60 bool isFirstReorderedWindow = true;
61 const auto& appWindowNodeVec = *(displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
62 for (auto nodeIter = appWindowNodeVec.begin(); nodeIter != appWindowNodeVec.end(); nodeIter++) {
63 auto node = *nodeIter;
64 if (node == nullptr || node->GetWindowType() != WindowType::WINDOW_TYPE_APP_MAIN_WINDOW) {
65 WLOGFW("get node failed or not app window.");
66 continue;
67 }
68 // if window don't support floating mode, or default rect of cascade is not satisfied with limits
69 if (!WindowHelper::IsWindowModeSupported(node->GetModeSupportInfo(), WindowMode::WINDOW_MODE_FLOATING) ||
70 !WindowHelper::IsRectSatisfiedWithSizeLimits(rect, node->GetWindowUpdatedSizeLimits())) {
71 MinimizeApp::AddNeedMinimizeApp(node, MinimizeReason::LAYOUT_CASCADE);
72 continue;
73 }
74 if (isFirstReorderedWindow) {
75 isFirstReorderedWindow = false;
76 } else {
77 rect = StepCascadeRect(rect, displayId);
78 }
79 node->SetRequestRect(rect);
80 node->SetDecoStatus(true);
81 if (node->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING) {
82 node->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING);
83 // when change mode, need to reset shadow and radius
84 WindowSystemEffect::SetWindowEffect(node);
85 if (node->GetWindowToken()) {
86 node->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_FLOATING);
87 }
88 }
89 WLOGFD("Cascade reorder Id: %{public}d, rect:[%{public}d, %{public}d, %{public}d, %{public}d]",
90 node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_);
91 }
92 LayoutWindowTree(displayId);
93 }
94 WLOGI("Cascade Reorder end");
95 }
96
InitAllRects()97 void WindowLayoutPolicyCascade::InitAllRects()
98 {
99 UpdateDisplayGroupRect();
100 for (auto& iter : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) {
101 auto displayId = iter.first;
102 InitSplitRects(displayId);
103 LayoutWindowTree(displayId);
104 InitCascadeRect(displayId);
105 }
106 }
107
LayoutSplitNodes(DisplayId displayId,WindowUpdateType type,bool layoutByDivider)108 void WindowLayoutPolicyCascade::LayoutSplitNodes(DisplayId displayId, WindowUpdateType type, bool layoutByDivider)
109 {
110 std::vector<WindowRootNodeType> rootNodeType = {
111 WindowRootNodeType::ABOVE_WINDOW_NODE,
112 WindowRootNodeType::APP_WINDOW_NODE,
113 WindowRootNodeType::BELOW_WINDOW_NODE
114 };
115 for (const auto& rootType : rootNodeType) {
116 if (displayGroupWindowTree_[displayId].find(rootType) == displayGroupWindowTree_[displayId].end()) {
117 continue;
118 }
119 auto appWindowNodeVec = *(displayGroupWindowTree_[displayId][rootType]);
120 for (const auto& childNode : appWindowNodeVec) {
121 if (type == WindowUpdateType::WINDOW_UPDATE_REMOVED) {
122 /*
123 * If updateType is remove we need to layout all appNodes, cause remove split node or
124 * divider means exit split mode, split node may change to other mode
125 */
126 LayoutWindowNode(childNode);
127 } else if (childNode->IsSplitMode()) { // add or update type, layout split node
128 if (layoutByDivider && type == WindowUpdateType::WINDOW_UPDATE_ACTIVE) {
129 childNode->SetWindowSizeChangeReason(WindowSizeChangeReason::DRAG);
130 }
131 LayoutWindowNode(childNode);
132 }
133 }
134 }
135 }
136
LayoutDivider(const sptr<WindowNode> & node,WindowUpdateType type)137 void WindowLayoutPolicyCascade::LayoutDivider(const sptr<WindowNode>& node, WindowUpdateType type)
138 {
139 auto displayId = node->GetDisplayId();
140 switch (type) {
141 case WindowUpdateType::WINDOW_UPDATE_ADDED:
142 SetInitialDividerRect(node, displayId);
143 [[fallthrough]];
144 case WindowUpdateType::WINDOW_UPDATE_ACTIVE:
145 UpdateDividerPosition(node);
146 LayoutWindowNode(node);
147 SetSplitRectByDivider(node->GetWindowRect(), displayId); // set splitRect by divider
148 break;
149 case WindowUpdateType::WINDOW_UPDATE_REMOVED:
150 InitSplitRects(displayId); // reinit split rects when remove divider
151 break;
152 default:
153 WLOGFW("Unknown update type, type: %{public}u", type);
154 }
155 LayoutSplitNodes(displayId, type, true);
156 }
157
LayoutPreProcess(const sptr<WindowNode> & node,WindowUpdateType updateType)158 void WindowLayoutPolicyCascade::LayoutPreProcess(const sptr<WindowNode>& node, WindowUpdateType updateType)
159 {
160 if (updateType == WindowUpdateType::WINDOW_UPDATE_ADDED) {
161 // Get aspect ratio from persistent storage when add window
162 GetStoragedAspectRatio(node);
163 }
164 SetDefaultCascadeRect(node);
165 FixWindowRectWithinDisplay(node);
166 }
167
PerformWindowLayout(const sptr<WindowNode> & node,WindowUpdateType updateType)168 void WindowLayoutPolicyCascade::PerformWindowLayout(const sptr<WindowNode>& node, WindowUpdateType updateType)
169 {
170 HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER);
171 const auto& windowType = node->GetWindowType();
172 const auto& requestRect = node->GetRequestRect();
173 WLOGFD("windowId: %{public}u, windowType: %{public}u, updateType: %{public}u, requestRect: "
174 "requestRect: [%{public}d, %{public}d, %{public}u, %{public}u]", node->GetWindowId(), windowType, updateType,
175 requestRect.posX_, requestRect.posY_, requestRect.width_, requestRect.height_);
176
177 LayoutPreProcess(node, updateType);
178 switch (windowType) {
179 case WindowType::WINDOW_TYPE_DOCK_SLICE:
180 LayoutDivider(node, updateType);
181 break;
182 case WindowType::WINDOW_TYPE_STATUS_BAR:
183 case WindowType::WINDOW_TYPE_NAVIGATION_BAR:
184 case WindowType::WINDOW_TYPE_LAUNCHER_DOCK:
185 LayoutWindowTree(node->GetDisplayId());
186 // AvoidNodes will change limitRect, need to recalculate default cascade rect
187 InitCascadeRect(node->GetDisplayId());
188 break;
189 default:
190 if (node->IsSplitMode()) {
191 LayoutSplitNodes(node->GetDisplayId(), updateType);
192 } else {
193 LayoutWindowNode(node);
194 }
195 }
196 if (updateType == WindowUpdateType::WINDOW_UPDATE_REMOVED) {
197 NotifyClientAndAnimation(node, node->GetRequestRect(), WindowSizeChangeReason::HIDE);
198 }
199 }
200
SetInitialDividerRect(const sptr<WindowNode> & node,DisplayId displayId)201 void WindowLayoutPolicyCascade::SetInitialDividerRect(const sptr<WindowNode>& node, DisplayId displayId)
202 {
203 const auto& restoredRect = restoringDividerWindowRects_[displayId];
204 const auto& presetRect = cascadeRectsMap_[node->GetDisplayId()].dividerRect_;
205 auto divRect = WindowHelper::IsEmptyRect(restoredRect) ? presetRect : restoredRect;
206 node->SetRequestRect(divRect);
207 restoringDividerWindowRects_.erase(displayId);
208 }
209
SetSplitDividerWindowRects(std::map<DisplayId,Rect> dividerWindowRects)210 void WindowLayoutPolicyCascade::SetSplitDividerWindowRects(std::map<DisplayId, Rect> dividerWindowRects)
211 {
212 restoringDividerWindowRects_ = dividerWindowRects;
213 }
214
LimitDividerInDisplayRegion(Rect & rect,DisplayId displayId) const215 void WindowLayoutPolicyCascade::LimitDividerInDisplayRegion(Rect& rect, DisplayId displayId) const
216 {
217 const Rect& limitRect = limitRectMap_[displayId];
218 if (rect.width_ < rect.height_) {
219 if (rect.posX_ < limitRect.posX_) {
220 rect.posX_ = limitRect.posX_;
221 } else if (rect.posX_ + static_cast<int32_t>(rect.width_) >
222 limitRect.posX_ + static_cast<int32_t>(limitRect.width_)) {
223 rect.posX_ = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - rect.width_);
224 }
225 } else {
226 if (rect.posY_ < limitRect.posY_) {
227 rect.posY_ = limitRect.posY_;
228 } else if (rect.posY_ + static_cast<int32_t>(rect.height_) >
229 limitRect.posY_ + static_cast<int32_t>(limitRect.height_)) {
230 rect.posY_ = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - rect.height_);
231 }
232 }
233 WLOGFD("limit divider move bounds: [%{public}d, %{public}d, %{public}u, %{public}u]",
234 rect.posX_, rect.posY_, rect.width_, rect.height_);
235 }
236
UpdateDividerPosition(const sptr<WindowNode> & node) const237 void WindowLayoutPolicyCascade::UpdateDividerPosition(const sptr<WindowNode>& node) const
238 {
239 auto rect = node->GetRequestRect();
240 auto displayId = node->GetDisplayId();
241 LimitDividerInDisplayRegion(rect, displayId);
242 if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG_END) {
243 LimitDividerPositionBySplitRatio(displayId, rect);
244 }
245 node->SetRequestRect(rect);
246 }
247
InitCascadeRect(DisplayId displayId)248 void WindowLayoutPolicyCascade::InitCascadeRect(DisplayId displayId)
249 {
250 constexpr uint32_t half = 2;
251 constexpr float ratio = DEFAULT_ASPECT_RATIO;
252
253 /*
254 * Calculate default width and height, if width or height is
255 * smaller than minWidth or minHeight, use the minimum limits
256 */
257 const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
258 auto vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(displayId);
259 uint32_t defaultW = std::max(static_cast<uint32_t>(displayRect.width_ * ratio),
260 static_cast<uint32_t>(MIN_FLOATING_WIDTH * vpr));
261 uint32_t defaultH = std::max(static_cast<uint32_t>(displayRect.height_ * ratio),
262 static_cast<uint32_t>(MIN_FLOATING_HEIGHT * vpr));
263
264 // calculate default x and y
265 Rect resRect = {0, 0, defaultW, defaultH};
266 const Rect& limitRect = limitRectMap_[displayId];
267 if (defaultW <= limitRect.width_ && defaultH <= limitRect.height_) {
268 resRect.posX_ = limitRect.posX_ + static_cast<int32_t>((limitRect.width_ - defaultW) / half);
269
270 resRect.posY_ = limitRect.posY_ + static_cast<int32_t>((limitRect.height_ - defaultH) / half);
271 }
272 WLOGI("Init CascadeRect :[%{public}d, %{public}d, %{public}d, %{public}d]",
273 resRect.posX_, resRect.posY_, resRect.width_, resRect.height_);
274 cascadeRectsMap_[displayId].defaultCascadeRect_ = resRect;
275 }
276
CheckAspectRatioBySizeLimits(const sptr<WindowNode> & node,WindowSizeLimits & newLimits) const277 bool WindowLayoutPolicyCascade::CheckAspectRatioBySizeLimits(const sptr<WindowNode>& node,
278 WindowSizeLimits& newLimits) const
279 {
280 // get new limit config with the settings of system and app
281 const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
282 if (node->GetWindowProperty() != nullptr && !node->GetWindowProperty()->GetDecorEnable()) {
283 newLimits = sizeLimits;
284 } else {
285 float vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
286 uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) * 2; // 2 mean double decor width
287 uint32_t winFrameH = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) +
288 static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * vpr); // decor height
289
290 newLimits.maxWidth_ = sizeLimits.maxWidth_ - winFrameW;
291 newLimits.minWidth_ = sizeLimits.minWidth_ - winFrameW;
292 newLimits.maxHeight_ = sizeLimits.maxHeight_ - winFrameH;
293 newLimits.minHeight_ = sizeLimits.minHeight_ - winFrameH;
294 }
295
296 float maxRatio = static_cast<float>(newLimits.maxWidth_) / static_cast<float>(newLimits.minHeight_);
297 float minRatio = static_cast<float>(newLimits.minWidth_) / static_cast<float>(newLimits.maxHeight_);
298 float aspectRatio = node->GetAspectRatio();
299 if (MathHelper::GreatNotEqual(aspectRatio, maxRatio) ||
300 MathHelper::LessNotEqual(aspectRatio, minRatio)) {
301 return false;
302 }
303 uint32_t newMaxWidth = static_cast<uint32_t>(static_cast<float>(newLimits.maxHeight_) * aspectRatio);
304 newLimits.maxWidth_ = std::min(newMaxWidth, newLimits.maxWidth_);
305 uint32_t newMinWidth = static_cast<uint32_t>(static_cast<float>(newLimits.minHeight_) * aspectRatio);
306 newLimits.minWidth_ = std::max(newMinWidth, newLimits.minWidth_);
307 uint32_t newMaxHeight = static_cast<uint32_t>(static_cast<float>(newLimits.maxWidth_) / aspectRatio);
308 newLimits.maxHeight_ = std::min(newMaxHeight, newLimits.maxHeight_);
309 uint32_t newMinHeight = static_cast<uint32_t>(static_cast<float>(newLimits.minWidth_) / aspectRatio);
310 newLimits.minHeight_ = std::max(newMinHeight, newLimits.minHeight_);
311 return true;
312 }
313
ComputeRectByAspectRatio(const sptr<WindowNode> & node) const314 void WindowLayoutPolicyCascade::ComputeRectByAspectRatio(const sptr<WindowNode>& node) const
315 {
316 float aspectRatio = node->GetAspectRatio();
317 if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode()) ||
318 node->GetWindowSizeChangeReason() == WindowSizeChangeReason::MOVE || MathHelper::NearZero(aspectRatio)) {
319 return;
320 }
321
322 // 1. check ratio by size limits
323 WindowSizeLimits newLimits;
324 if (!CheckAspectRatioBySizeLimits(node, newLimits)) {
325 return;
326 }
327
328 float vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
329 uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) * 2; // 2 mean double decor width
330 uint32_t winFrameH = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) +
331 static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * vpr); // decor height
332
333 // 2. get rect without decoration if enable decoration
334 auto newRect = node->GetRequestRect();
335 if (node->GetWindowProperty() != nullptr && node->GetWindowProperty()->GetDecorEnable()) {
336 newRect.width_ -= winFrameW;
337 newRect.height_ -= winFrameH;
338 }
339 auto oriRect = newRect;
340
341 // 3. update window rect by new limits and aspect ratio
342 newRect.width_ = std::max(newLimits.minWidth_, newRect.width_);
343 newRect.height_ = std::max(newLimits.minHeight_, newRect.height_);
344 newRect.width_ = std::min(newLimits.maxWidth_, newRect.width_);
345 newRect.height_ = std::min(newLimits.maxHeight_, newRect.height_);
346 float curRatio = static_cast<float>(newRect.width_) / static_cast<float>(newRect.height_);
347 if (std::abs(curRatio - aspectRatio) > 0.0001f) {
348 if (node->GetDragType() == DragType::DRAG_BOTTOM_OR_TOP) {
349 // if drag height, use height to fix size.
350 newRect.width_ = static_cast<uint32_t>(static_cast<float>(newRect.height_) * aspectRatio);
351 } else {
352 // if drag width or corner, use width to fix size.
353 newRect.height_ = static_cast<uint32_t>(static_cast<float>(newRect.width_) / aspectRatio);
354 }
355 }
356
357 // 4. fix window pos in case of moving window when dragging
358 FixWindowRectWhenDrag(node, oriRect, newRect);
359
360 // 5. if posY is smaller than limit posY when drag, use the last window rect
361 if (newRect.posY_ < limitRectMap_[node->GetDisplayId()].posY_ &&
362 node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
363 auto lastRect = node->GetWindowRect();
364 lastRect.width_ -= winFrameW;
365 lastRect.height_ -= winFrameH;
366 newRect = lastRect;
367 }
368 node->SetRequestRect(newRect);
369 node->SetDecoStatus(false); // newRect is not rect with decor, reset decor status
370 WLOGFD("WinId: %{public}u, newRect: %{public}d %{public}d %{public}u %{public}u",
371 node->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
372 }
373
ComputeDecoratedRequestRect(const sptr<WindowNode> & node) const374 void WindowLayoutPolicyCascade::ComputeDecoratedRequestRect(const sptr<WindowNode>& node) const
375 {
376 auto property = node->GetWindowProperty();
377 if (property == nullptr) {
378 WLOGE("window property is nullptr");
379 return;
380 }
381
382 if (!property->GetDecorEnable() || property->GetDecoStatus() ||
383 node->GetWindowSizeChangeReason() == WindowSizeChangeReason::MOVE) {
384 return;
385 }
386
387 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
388 uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * virtualPixelRatio);
389 uint32_t winTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
390
391 auto oriRect = property->GetRequestRect();
392 Rect dstRect;
393 dstRect.posX_ = oriRect.posX_;
394 dstRect.posY_ = oriRect.posY_;
395 dstRect.width_ = oriRect.width_ + winFrameW + winFrameW;
396 dstRect.height_ = oriRect.height_ + winTitleBarH + winFrameW;
397 property->SetRequestRect(dstRect);
398 property->SetDecoStatus(true);
399 }
400
ApplyWindowRectConstraints(const sptr<WindowNode> & node,Rect & winRect) const401 void WindowLayoutPolicyCascade::ApplyWindowRectConstraints(const sptr<WindowNode>& node, Rect& winRect) const
402 {
403 WLOGFD("[Before constraints] windowId: %{public}u, winRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
404 node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
405 ComputeRectByAspectRatio(node);
406 ComputeDecoratedRequestRect(node);
407 winRect = node->GetRequestRect();
408 LimitFloatingWindowSize(node, winRect);
409 LimitMainFloatingWindowPosition(node, winRect);
410
411 /*
412 * Use the orientation of the window and display to determine
413 * whether the screen is rotating, then rotate the divider
414 */
415 if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE &&
416 ((!WindowHelper::IsLandscapeRect(winRect) && IsVerticalDisplay(node->GetDisplayId())) ||
417 (WindowHelper::IsLandscapeRect(winRect) && !IsVerticalDisplay(node->GetDisplayId())))) {
418 winRect = cascadeRectsMap_[node->GetDisplayId()].dividerRect_;
419 node->SetRequestRect(winRect);
420 WLOGFD("Reset divider when display rotation, divRect: [%{public}d, %{public}d, %{public}u, %{public}u]",
421 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
422 }
423
424 WLOGFD("[After constraints] windowId: %{public}u, winRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
425 node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
426 }
427
UpdateLayoutRect(const sptr<WindowNode> & node)428 void WindowLayoutPolicyCascade::UpdateLayoutRect(const sptr<WindowNode>& node)
429 {
430 auto property = node->GetWindowProperty();
431 if (property == nullptr) {
432 WLOGFE("window property is nullptr.");
433 return;
434 }
435 auto mode = node->GetWindowMode();
436 Rect winRect = property->GetRequestRect();
437 auto displayId = node->GetDisplayId();
438 WLOGFD("[Before CascadeLayout] windowId: %{public}u, mode: %{public}u, type: %{public}u requestRect: [%{public}d, "
439 "%{public}d, %{public}u, %{public}u]", node->GetWindowId(), mode, node->GetWindowType(), winRect.posX_,
440 winRect.posY_, winRect.width_, winRect.height_);
441 switch (mode) {
442 case WindowMode::WINDOW_MODE_SPLIT_PRIMARY:
443 winRect = cascadeRectsMap_[displayId].primaryRect_;
444 break;
445 case WindowMode::WINDOW_MODE_SPLIT_SECONDARY:
446 winRect = cascadeRectsMap_[displayId].secondaryRect_;
447 break;
448 case WindowMode::WINDOW_MODE_FULLSCREEN: {
449 bool needAvoid = (node->GetWindowFlags() & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_NEED_AVOID));
450 winRect = needAvoid ? limitRectMap_[displayId] : DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
451 auto displayInfo = DisplayGroupInfo::GetInstance().GetDisplayInfo(displayId);
452 if (displayInfo && WmsUtils::IsExpectedRotatableWindow(node->GetRequestedOrientation(),
453 displayInfo->GetDisplayOrientation(), node->GetWindowFlags())) {
454 WLOGFD("[FixOrientation] the window is expected rotatable, pre-calculated");
455 winRect = {winRect.posX_, winRect.posY_, winRect.height_, winRect.width_};
456 }
457 if (property->GetMaximizeMode() == MaximizeMode::MODE_AVOID_SYSTEM_BAR) {
458 // restore the origin rect so when recover from fullscreen we can use
459 node->SetRequestRect(node->GetOriginRect());
460 property->SetMaximizeMode(MaximizeMode::MODE_FULL_FILL);
461 }
462 break;
463 }
464 case WindowMode::WINDOW_MODE_FLOATING: {
465 if (node->GetWindowType() == WindowType::WINDOW_TYPE_APP_COMPONENT) {
466 break;
467 }
468 UpdateWindowSizeLimits(node);
469 winRect = property->GetRequestRect();
470 ApplyWindowRectConstraints(node, winRect);
471
472 if (property->GetMaximizeMode() == MaximizeMode::MODE_AVOID_SYSTEM_BAR) {
473 GetMaximizeRect(node, winRect);
474 WLOGFI("[In CascadeLayout] winId: %{public}u, maxRect: %{public}d, %{public}d, %{public}u, %{public}u",
475 node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
476 }
477 break;
478 }
479 default:
480 WLOGFW("Layout invalid mode, winId: %{public}u, mode: %{public}u", node->GetWindowId(), mode);
481 }
482 WLOGFD("[After CascadeLayout] windowId: %{public}u, isDecor: %{public}u, winRect: [%{public}d, %{public}d, "
483 "%{public}u, %{public}u], reason: %{public}u", node->GetWindowId(), node->GetDecoStatus(), winRect.posX_,
484 winRect.posY_, winRect.width_, winRect.height_, node->GetWindowSizeChangeReason());
485
486 const Rect& lastWinRect = node->GetWindowRect();
487 node->SetWindowRect(winRect);
488
489 // postProcess after update winRect
490 CalcAndSetNodeHotZone(winRect, node);
491 UpdateSurfaceBounds(node, winRect, lastWinRect);
492 NotifyClientAndAnimation(node, winRect, node->GetWindowSizeChangeReason());
493 }
494
LimitDividerPositionBySplitRatio(DisplayId displayId,Rect & winRect) const495 void WindowLayoutPolicyCascade::LimitDividerPositionBySplitRatio(DisplayId displayId, Rect& winRect) const
496 {
497 int32_t oriPos = IsVerticalDisplay(displayId) ? winRect.posY_ : winRect.posX_;
498 int32_t& dstPos = IsVerticalDisplay(displayId) ? winRect.posY_ : winRect.posX_;
499 if (splitRatioPointsMap_[displayId].size() == 0) {
500 return;
501 }
502 uint32_t minDiff = std::max(limitRectMap_[displayId].width_, limitRectMap_[displayId].height_);
503 int32_t closestPoint = oriPos;
504 for (const auto& elem : splitRatioPointsMap_[displayId]) {
505 uint32_t diff = (oriPos > elem) ? static_cast<uint32_t>(oriPos - elem) : static_cast<uint32_t>(elem - oriPos);
506 if (diff < minDiff) {
507 closestPoint = elem;
508 minDiff = diff;
509 }
510 }
511 dstPos = closestPoint;
512 }
513
InitSplitRects(DisplayId displayId)514 void WindowLayoutPolicyCascade::InitSplitRects(DisplayId displayId)
515 {
516 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(displayId);
517 uint32_t dividerWidth = static_cast<uint32_t>(DIVIDER_WIDTH * virtualPixelRatio);
518 auto& dividerRect = cascadeRectsMap_[displayId].dividerRect_;
519 const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
520 if (!IsVerticalDisplay(displayId)) {
521 dividerRect = { static_cast<uint32_t>((displayRect.width_ - dividerWidth) * DEFAULT_SPLIT_RATIO), 0,
522 dividerWidth, displayRect.height_ };
523 } else {
524 dividerRect = { 0, static_cast<uint32_t>((displayRect.height_ - dividerWidth) * DEFAULT_SPLIT_RATIO),
525 displayRect.width_, dividerWidth };
526 }
527 SetSplitRectByDivider(dividerRect, displayId);
528 }
529
SetSplitRectByDivider(const Rect & divRect,DisplayId displayId)530 void WindowLayoutPolicyCascade::SetSplitRectByDivider(const Rect& divRect, DisplayId displayId)
531 {
532 auto& dividerRect = cascadeRectsMap_[displayId].dividerRect_;
533 auto& primaryRect = cascadeRectsMap_[displayId].primaryRect_;
534 auto& secondaryRect = cascadeRectsMap_[displayId].secondaryRect_;
535 const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
536
537 dividerRect.width_ = divRect.width_;
538 dividerRect.height_ = divRect.height_;
539 if (!IsVerticalDisplay(displayId)) {
540 primaryRect.posX_ = displayRect.posX_;
541 primaryRect.posY_ = displayRect.posY_;
542 primaryRect.width_ = divRect.posX_;
543 primaryRect.height_ = displayRect.height_;
544
545 secondaryRect.posX_ = divRect.posX_ + static_cast<int32_t>(dividerRect.width_);
546 secondaryRect.posY_ = displayRect.posY_;
547 secondaryRect.width_ = static_cast<uint32_t>(static_cast<int32_t>(displayRect.width_) - secondaryRect.posX_);
548 secondaryRect.height_ = displayRect.height_;
549 } else {
550 primaryRect.posX_ = displayRect.posX_;
551 primaryRect.posY_ = displayRect.posY_;
552 primaryRect.height_ = divRect.posY_;
553 primaryRect.width_ = displayRect.width_;
554
555 secondaryRect.posX_ = displayRect.posX_;
556 secondaryRect.posY_ = divRect.posY_ + static_cast<int32_t>(dividerRect.height_);
557 secondaryRect.height_ = static_cast<uint32_t>(static_cast<int32_t>(displayRect.height_) - secondaryRect.posY_);
558 secondaryRect.width_ = displayRect.width_;
559 }
560 WLOGFD("DividerRect: [%{public}d %{public}d %{public}u %{public}u] "
561 "PrimaryRect: [%{public}d %{public}d %{public}u %{public}u] "
562 "SecondaryRect: [%{public}d %{public}d %{public}u %{public}u]",
563 dividerRect.posX_, dividerRect.posY_, dividerRect.width_, dividerRect.height_,
564 primaryRect.posX_, primaryRect.posY_, primaryRect.width_, primaryRect.height_,
565 secondaryRect.posX_, secondaryRect.posY_, secondaryRect.width_, secondaryRect.height_);
566 }
567
GetCurCascadeRect(const sptr<WindowNode> & node) const568 Rect WindowLayoutPolicyCascade::GetCurCascadeRect(const sptr<WindowNode>& node) const
569 {
570 Rect cascadeRect = {0, 0, 0, 0};
571 const DisplayId& displayId = node->GetDisplayId();
572 const auto& appWindowNodeVec = *(const_cast<WindowLayoutPolicyCascade*>(this)->
573 displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
574 const auto& aboveAppWindowNodeVec = *(const_cast<WindowLayoutPolicyCascade*>(this)->
575 displayGroupWindowTree_[displayId][WindowRootNodeType::ABOVE_WINDOW_NODE]);
576
577 std::vector<std::vector<sptr<WindowNode>>> roots = { aboveAppWindowNodeVec, appWindowNodeVec };
578 for (auto& root : roots) {
579 for (auto iter = root.rbegin(); iter != root.rend(); iter++) {
580 if ((*iter)->GetWindowType() == WindowType::WINDOW_TYPE_APP_MAIN_WINDOW &&
581 (*iter)->GetWindowId() != node->GetWindowId()) {
582 auto property = (*iter)->GetWindowProperty();
583 if (property != nullptr && property->GetMaximizeMode() != MaximizeMode::MODE_AVOID_SYSTEM_BAR) {
584 cascadeRect = ((*iter)->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING ?
585 property->GetWindowRect() : property->GetRequestRect());
586 }
587 WLOGFD("Get current cascadeRect: %{public}u [%{public}d, %{public}d, %{public}u, %{public}u]",
588 (*iter)->GetWindowId(), cascadeRect.posX_, cascadeRect.posY_,
589 cascadeRect.width_, cascadeRect.height_);
590 break;
591 }
592 }
593 }
594
595 if (WindowHelper::IsEmptyRect(cascadeRect)) {
596 WLOGFD("cascade rect is empty use first cascade rect");
597 return cascadeRectsMap_[displayId].defaultCascadeRect_;
598 }
599 return StepCascadeRect(cascadeRect, displayId);
600 }
601
StepCascadeRect(Rect rect,DisplayId displayId) const602 Rect WindowLayoutPolicyCascade::StepCascadeRect(Rect rect, DisplayId displayId) const
603 {
604 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(displayId);
605 uint32_t cascadeWidth = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
606 uint32_t cascadeHeight = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
607
608 const Rect& limitRect = limitRectMap_[displayId];
609 Rect cascadeRect = {0, 0, 0, 0};
610 cascadeRect.width_ = rect.width_;
611 cascadeRect.height_ = rect.height_;
612 cascadeRect.posX_ = (rect.posX_ + static_cast<int32_t>(cascadeWidth) >= limitRect.posX_) &&
613 (rect.posX_ + static_cast<int32_t>(rect.width_ + cascadeWidth) <=
614 (limitRect.posX_ + static_cast<int32_t>(limitRect.width_))) ?
615 (rect.posX_ + static_cast<int32_t>(cascadeWidth)) : limitRect.posX_;
616 cascadeRect.posY_ = (rect.posY_ + static_cast<int32_t>(cascadeHeight) >= limitRect.posY_) &&
617 (rect.posY_ + static_cast<int32_t>(rect.height_ + cascadeHeight) <=
618 (limitRect.posY_ + static_cast<int32_t>(limitRect.height_))) ?
619 (rect.posY_ + static_cast<int32_t>(cascadeHeight)) : limitRect.posY_;
620 WLOGFD("Step cascadeRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
621 cascadeRect.posX_, cascadeRect.posY_, cascadeRect.width_, cascadeRect.height_);
622 return cascadeRect;
623 }
624
SetDefaultCascadeRect(const sptr<WindowNode> & node)625 void WindowLayoutPolicyCascade::SetDefaultCascadeRect(const sptr<WindowNode>& node)
626 {
627 auto property = node->GetWindowProperty();
628 if (property == nullptr) {
629 WLOGFE("window property is nullptr.");
630 return;
631 }
632 if (!WindowHelper::IsEmptyRect(property->GetRequestRect())) {
633 return;
634 }
635
636 static bool isFirstAppWindow = true;
637 Rect rect;
638 if (WindowHelper::IsAppWindow(property->GetWindowType()) && isFirstAppWindow) {
639 WLOGFD("Set first app window cascade rect");
640 rect = cascadeRectsMap_[node->GetDisplayId()].defaultCascadeRect_;
641 isFirstAppWindow = false;
642 } else if (WindowHelper::IsAppWindow(property->GetWindowType()) && !isFirstAppWindow) {
643 WLOGFD("Set other app window cascade rect");
644 rect = GetCurCascadeRect(node);
645 } else {
646 // system window
647 WLOGFD("Set system window cascade rect");
648 rect = cascadeRectsMap_[node->GetDisplayId()].defaultCascadeRect_;
649 }
650 WLOGFD("Set cascadeRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
651 rect.posX_, rect.posY_, rect.width_, rect.height_);
652 node->SetRequestRect(rect);
653 node->SetDecoStatus(true);
654 }
655
GetDividerRect(DisplayId displayId) const656 Rect WindowLayoutPolicyCascade::GetDividerRect(DisplayId displayId) const
657 {
658 Rect dividerRect = {0, 0, 0, 0};
659 if (cascadeRectsMap_.find(displayId) != std::end(cascadeRectsMap_)) {
660 dividerRect = cascadeRectsMap_[displayId].dividerRect_;
661 }
662 return dividerRect;
663 }
664
GetDockWindowShowState(DisplayId displayId,Rect & dockWinRect) const665 DockWindowShowState WindowLayoutPolicyCascade::GetDockWindowShowState(DisplayId displayId, Rect& dockWinRect) const
666 {
667 auto& displayWindowTree = displayGroupWindowTree_[displayId];
668 auto& nodeVec = *(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]);
669 for (auto& node : nodeVec) {
670 if (node->GetWindowType() != WindowType::WINDOW_TYPE_LAUNCHER_DOCK) {
671 continue;
672 }
673
674 dockWinRect = node->GetWindowRect();
675 auto displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
676 WLOGI("begin dockWinRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
677 dockWinRect.posX_, dockWinRect.posY_, dockWinRect.width_, dockWinRect.height_);
678 if (dockWinRect.height_ < dockWinRect.width_) {
679 if (static_cast<uint32_t>(dockWinRect.posY_) + dockWinRect.height_ == displayRect.height_) {
680 return DockWindowShowState::SHOWN_IN_BOTTOM;
681 } else {
682 return DockWindowShowState::NOT_SHOWN;
683 }
684 } else {
685 if (dockWinRect.posX_ == 0) {
686 return DockWindowShowState::SHOWN_IN_LEFT;
687 } else if (static_cast<uint32_t>(dockWinRect.posX_) + dockWinRect.width_ == displayRect.width_) {
688 return DockWindowShowState::SHOWN_IN_RIGHT;
689 } else {
690 return DockWindowShowState::NOT_SHOWN;
691 }
692 }
693 }
694 return DockWindowShowState::NOT_SHOWN;
695 }
696
LimitFloatingWindowSize(const sptr<WindowNode> & node,Rect & winRect) const697 void WindowLayoutPolicyCascade::LimitFloatingWindowSize(const sptr<WindowNode>& node, Rect& winRect) const
698 {
699 if (node->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING) {
700 return;
701 }
702 Rect oriWinRect = winRect;
703 const Rect& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(node->GetDisplayId());
704 UpdateFloatingWindowSizeBySizeLimits(node, displayRect, winRect);
705 UpdateFloatingWindowSizeForStretchableWindow(node, displayRect, winRect);
706
707 // fix size in case of moving window when dragging
708 FixWindowRectWhenDrag(node, oriWinRect, winRect);
709 }
710
LimitMainFloatingWindowPosition(const sptr<WindowNode> & node,Rect & winRect) const711 void WindowLayoutPolicyCascade::LimitMainFloatingWindowPosition(const sptr<WindowNode>& node, Rect& winRect) const
712 {
713 if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
714 return;
715 }
716
717 auto reason = node->GetWindowSizeChangeReason();
718 // if drag or move window, limit size and position
719 if (reason == WindowSizeChangeReason::DRAG) {
720 LimitWindowPositionWhenDrag(node, winRect);
721 FixWindowSizeByRatioIfDragBeyondLimitRegion(node, winRect);
722 } else {
723 // Limit window position, such as init window rect when show
724 LimitWindowPositionWhenInitRectOrMove(node, winRect);
725 }
726 }
727
UpdateFloatingWindowSizeForStretchableWindow(const sptr<WindowNode> & node,const Rect & displayRect,Rect & winRect) const728 void WindowLayoutPolicyCascade::UpdateFloatingWindowSizeForStretchableWindow(const sptr<WindowNode>& node,
729 const Rect& displayRect, Rect& winRect) const
730 {
731 if (!node->GetStretchable() || !WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
732 return;
733 }
734 if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
735 const Rect &originRect = node->GetOriginRect();
736 if (originRect.height_ == 0 || originRect.width_ == 0) {
737 WLOGE("invalid originRect. window id: %{public}u", node->GetWindowId());
738 return;
739 }
740 auto dragType = node->GetDragType();
741 if (dragType == DragType::DRAG_BOTTOM_OR_TOP) {
742 // if drag height, use height to fix size.
743 winRect.width_ = winRect.height_ * originRect.width_ / originRect.height_;
744 } else if (dragType == DragType::DRAG_LEFT_TOP_CORNER || dragType == DragType::DRAG_RIGHT_TOP_CORNER ||
745 dragType == DragType::DRAG_LEFT_OR_RIGHT) {
746 // if drag width or corner, use width to fix size.
747 winRect.height_ = winRect.width_ * originRect.height_ / originRect.width_;
748 }
749 }
750 // limit minimum size of window
751
752 const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
753 float scale = std::min(static_cast<float>(winRect.width_) / sizeLimits.minWidth_,
754 static_cast<float>(winRect.height_) / sizeLimits.minHeight_);
755 if (scale == 0) {
756 WLOGE("invalid sizeLimits");
757 return;
758 }
759 if (scale < 1.0f) {
760 winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / scale);
761 winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) / scale);
762 }
763 }
764
FixWindowSizeByRatioIfDragBeyondLimitRegion(const sptr<WindowNode> & node,Rect & winRect) const765 void WindowLayoutPolicyCascade::FixWindowSizeByRatioIfDragBeyondLimitRegion(const sptr<WindowNode>& node,
766 Rect& winRect) const
767 {
768 if (!MathHelper::NearZero(node->GetAspectRatio())) {
769 return;
770 }
771 const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
772 if (sizeLimits.maxWidth_ == sizeLimits.minWidth_ && sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
773 WLOGFD("window rect can not be changed");
774 return;
775 }
776 if (winRect.height_ == 0) {
777 return;
778 }
779 float curRatio = static_cast<float>(winRect.width_) / static_cast<float>(winRect.height_);
780 if (sizeLimits.minRatio_ <= curRatio && curRatio <= sizeLimits.maxRatio_) {
781 WLOGFD("window ratio is satisfied with limit ratio, curRatio: %{public}f", curRatio);
782 return;
783 }
784
785 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
786 uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
787 Rect limitRect = (node->isShowingOnMultiDisplays_) ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
788 int32_t limitMinPosX = limitRect.posX_ + static_cast<int32_t>(windowTitleBarH);
789 int32_t limitMaxPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH);
790 int32_t limitMinPosY = limitRect.posY_;
791 int32_t limitMaxPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH);
792
793 Rect dockWinRect;
794 DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
795 WLOGFD("dock window show type: %{public}u", dockShownState);
796 if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
797 limitMaxPosY = dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH);
798 } else if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
799 limitMinPosX = dockWinRect.posX_ + static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH);
800 } else if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
801 limitMaxPosX = dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH);
802 }
803
804 float newRatio = curRatio < sizeLimits.minRatio_ ? sizeLimits.minRatio_ : sizeLimits.maxRatio_;
805 if ((winRect.posX_ + static_cast<int32_t>(winRect.width_) == limitMinPosX) || (winRect.posX_ == limitMaxPosX)) {
806 // height can not be changed
807 if (sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
808 return;
809 }
810 winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
811 }
812
813 if ((winRect.posY_ == limitMinPosY) || (winRect.posX_ == limitMaxPosY)) {
814 // width can not be changed
815 if (sizeLimits.maxWidth_ == sizeLimits.minWidth_) {
816 return;
817 }
818 winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
819 }
820 WLOGFD("After limit by ratio if beyond limit region, winRect: %{public}d %{public}d %{public}u %{public}u",
821 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
822 }
823
UpdateFloatingWindowSizeBySizeLimits(const sptr<WindowNode> & node,const Rect & displayRect,Rect & winRect) const824 void WindowLayoutPolicyCascade::UpdateFloatingWindowSizeBySizeLimits(const sptr<WindowNode>& node,
825 const Rect& displayRect, Rect& winRect) const
826 {
827 // get new limit config with the settings of system and app
828 const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
829
830 // limit minimum size of floating or subWindow (not system type) window
831 if ((!WindowHelper::IsSystemWindow(node->GetWindowType()) &&
832 (!WindowHelper::IsSubWindow(node->GetWindowType()))) ||
833 node->GetWindowType() == WindowType::WINDOW_TYPE_FLOAT_CAMERA) {
834 winRect.width_ = std::max(sizeLimits.minWidth_, winRect.width_);
835 winRect.height_ = std::max(sizeLimits.minHeight_, winRect.height_);
836 }
837 winRect.width_ = std::min(sizeLimits.maxWidth_, winRect.width_);
838 winRect.height_ = std::min(sizeLimits.maxHeight_, winRect.height_);
839 WLOGFD("After limit by size, winRect: %{public}d %{public}d %{public}u %{public}u",
840 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
841
842 // width and height can not be changed
843 if (sizeLimits.maxWidth_ == sizeLimits.minWidth_ &&
844 sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
845 winRect.width_ = sizeLimits.maxWidth_;
846 winRect.height_ = sizeLimits.maxHeight_;
847 WLOGFD("window rect can not be changed");
848 return;
849 }
850
851 if (!MathHelper::NearZero(node->GetAspectRatio())) {
852 return;
853 }
854 float curRatio = static_cast<float>(winRect.width_) / static_cast<float>(winRect.height_);
855 // there is no need to fix size by ratio if this is not main floating window
856 if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode()) ||
857 (sizeLimits.minRatio_ <= curRatio && curRatio <= sizeLimits.maxRatio_)) {
858 WLOGFD("window is system window or ratio is satisfied with limits, curSize: [%{public}d, %{public}d], "
859 "curRatio: %{public}f", winRect.width_, winRect.height_, curRatio);
860 return;
861 }
862
863 float newRatio = curRatio < sizeLimits.minRatio_ ? sizeLimits.minRatio_ : sizeLimits.maxRatio_;
864 if (sizeLimits.maxWidth_ == sizeLimits.minWidth_) {
865 winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
866 return;
867 }
868 if (sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
869 winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
870 return;
871 }
872
873 auto dragType = node->GetDragType();
874 if (dragType == DragType::DRAG_BOTTOM_OR_TOP) {
875 // if drag height, use height to fix size.
876 winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
877 } else {
878 // if drag width or corner, use width to fix size.
879 winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
880 }
881 WLOGI("After limit by customize config, winRect: %{public}d %{public}d %{public}u %{public}u",
882 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
883 }
884
FixWindowRectWhenDrag(const sptr<WindowNode> & node,const Rect & oriWinRect,Rect & winRect) const885 void WindowLayoutPolicyCascade::FixWindowRectWhenDrag(const sptr<WindowNode>& node,
886 const Rect& oriWinRect, Rect& winRect) const
887 {
888 // fix size in case of moving window when dragging
889 const auto& lastWinRect = node->GetWindowRect();
890 if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
891 if (oriWinRect.posX_ != lastWinRect.posX_) {
892 winRect.posX_ = oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) -
893 static_cast<int32_t>(winRect.width_);
894 }
895 if (oriWinRect.posY_ != lastWinRect.posY_) {
896 winRect.posY_ = oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) -
897 static_cast<int32_t>(winRect.height_);
898 }
899 }
900 }
901
LimitWindowPositionWhenDrag(const sptr<WindowNode> & node,Rect & winRect) const902 void WindowLayoutPolicyCascade::LimitWindowPositionWhenDrag(const sptr<WindowNode>& node, Rect& winRect) const
903 {
904 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
905 uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
906 const Rect& lastRect = node->GetWindowRect();
907 Rect oriWinRect = winRect;
908
909 Rect limitRect = (node->isShowingOnMultiDisplays_) ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
910 int32_t limitMinPosX = limitRect.posX_ + static_cast<int32_t>(windowTitleBarH);
911 int32_t limitMaxPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH);
912 int32_t limitMinPosY = limitRect.posY_;
913 int32_t limitMaxPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH);
914
915 Rect dockWinRect;
916 DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
917 if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
918 limitMaxPosY = dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH);
919 } else if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
920 limitMinPosX = dockWinRect.posX_ + static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH);
921 } else if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
922 limitMaxPosX = dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH);
923 }
924
925 // limitMinPosX is minimum (x + width)
926 if (oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) < limitMinPosX) {
927 if (oriWinRect.width_ != lastRect.width_) {
928 winRect.width_ = static_cast<uint32_t>(limitMinPosX - oriWinRect.posX_);
929 }
930 }
931 // maximum position x
932 if (oriWinRect.posX_ > limitMaxPosX) {
933 winRect.posX_ = limitMaxPosX;
934 if (oriWinRect.width_ != lastRect.width_) {
935 winRect.width_ = static_cast<uint32_t>(
936 oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) - winRect.posX_);
937 }
938 }
939 // minimum position y
940 if (oriWinRect.posY_ < limitMinPosY) {
941 winRect.posY_ = limitMinPosY;
942 if (oriWinRect.height_ != lastRect.height_) {
943 winRect.height_ = static_cast<uint32_t>(
944 oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - winRect.posY_);
945 }
946 }
947 // maximum position y
948 if (winRect.posY_ > limitMaxPosY) {
949 winRect.posY_ = limitMaxPosY;
950 if (oriWinRect.height_ != lastRect.height_) {
951 winRect.height_ = static_cast<uint32_t>(
952 oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - winRect.posY_);
953 }
954 }
955 WLOGI("After limit by position, winRect: %{public}d %{public}d %{public}u %{public}u",
956 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
957 }
958
LimitWindowPositionWhenInitRectOrMove(const sptr<WindowNode> & node,Rect & winRect) const959 void WindowLayoutPolicyCascade::LimitWindowPositionWhenInitRectOrMove(const sptr<WindowNode>& node, Rect& winRect) const
960 {
961 float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
962 uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
963
964 // if is cross-display window, the limit rect should be full limitRect
965 Rect limitRect = (node->isShowingOnMultiDisplays_) ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
966
967 // limit position of the main floating window(window which support dragging)
968 if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
969 Rect dockWinRect;
970 DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
971 winRect.posY_ = std::max(limitRect.posY_, winRect.posY_);
972 winRect.posY_ = std::min(limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH),
973 winRect.posY_);
974 if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
975 WLOGFD("dock window show in bottom");
976 winRect.posY_ = std::min(dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH),
977 winRect.posY_);
978 }
979 winRect.posX_ = std::max(limitRect.posX_ + static_cast<int32_t>(windowTitleBarH - winRect.width_),
980 winRect.posX_);
981 if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
982 WLOGFD("dock window show in left");
983 winRect.posX_ = std::max(static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH - winRect.width_),
984 winRect.posX_);
985 }
986 winRect.posX_ = std::min(limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH),
987 winRect.posX_);
988 if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
989 WLOGFD("dock window show in right");
990 winRect.posX_ = std::min(dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH),
991 winRect.posX_);
992 }
993 auto reason = node->GetWindowSizeChangeReason();
994 // if init window on pc, limit position
995 if (floatingBottomPosY_ != 0 && reason == WindowSizeChangeReason::UNDEFINED) {
996 int32_t bottomPosY = static_cast<int32_t>(floatingBottomPosY_ * virtualPixelRatio);
997 if (winRect.posY_ + static_cast<int32_t>(winRect.height_) >= bottomPosY) {
998 winRect.posY_ = limitRect.posY_;
999 }
1000 }
1001 }
1002 WLOGI("After limit by position if init or move, winRect: %{public}d %{public}d %{public}u %{public}u",
1003 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
1004 }
1005
GetMaximizeRect(const sptr<WindowNode> & node,Rect & maxRect)1006 void WindowLayoutPolicyCascade::GetMaximizeRect(const sptr<WindowNode>& node, Rect& maxRect)
1007 {
1008 auto property = node->GetWindowProperty();
1009 if (property == nullptr) {
1010 WLOGFE("window property is nullptr.");
1011 return;
1012 }
1013 const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(node->GetDisplayId());
1014 const Rect& limitRect = limitRectMap_[node->GetDisplayId()];
1015 Rect dockWinRect = { 0, 0, 0, 0 };
1016 DockWindowShowState dockState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
1017 uint32_t dockHeight = dockState == DockWindowShowState::SHOWN_IN_BOTTOM ? dockWinRect.height_ : 0;
1018 maxRect.posX_ = limitRect.posX_;
1019 maxRect.posY_ = limitRect.posY_;
1020 maxRect.width_ = limitRect.width_;
1021 maxRect.height_ = displayRect.height_ - limitRect.posY_ - dockHeight;
1022 WLOGFI("GetMaximizeRect maxRect = %{public}d, %{public}d, %{public}u, %{public}u ",
1023 maxRect.posX_, maxRect.posY_, maxRect.width_, maxRect.height_);
1024 }
1025 } // Rosen
1026 } // OHOS
1027