Files
windowmanager/wmserver/src/window_layout_policy.cpp
T
huandong 4e67f5853a 增加vpr异常值校验,增加avoid_area异常值校验和异常ut
Change-Id: I033d56d12510e26ab35e6e646d38309e157568cb
Signed-off-by: huandong <huandong1@huawei.com>
2022-02-25 14:39:47 +08:00

375 lines
14 KiB
C++

/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "window_layout_policy.h"
#include "display_manager.h"
#include "window_helper.h"
#include "window_manager_hilog.h"
#include "wm_common_inner.h"
#include "wm_trace.h"
namespace OHOS {
namespace Rosen {
namespace {
constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowLayoutPolicy"};
}
WindowLayoutPolicy::WindowLayoutPolicy(const Rect& displayRect, const uint64_t& screenId,
sptr<WindowNode>& belowAppNode, sptr<WindowNode>& appNode, sptr<WindowNode>& aboveAppNode)
: displayRect_(displayRect), screenId_(screenId),
belowAppWindowNode_(belowAppNode), appWindowNode_(appNode), aboveAppWindowNode_(aboveAppNode)
{
}
void WindowLayoutPolicy::UpdateDisplayInfo()
{
limitRect_ = displayRect_;
UpdateDefaultFoatingRect();
}
void WindowLayoutPolicy::Launch()
{
UpdateDisplayInfo();
WLOGFI("WindowLayoutPolicy::Launch");
}
void WindowLayoutPolicy::Clean()
{
WLOGFI("WindowLayoutPolicy::Clean");
}
void WindowLayoutPolicy::Reorder()
{
WLOGFI("WindowLayoutPolicy::Reorder");
}
void WindowLayoutPolicy::LayoutWindowTree()
{
limitRect_ = displayRect_;
std::vector<sptr<WindowNode>> rootNodes = { aboveAppWindowNode_, appWindowNode_, belowAppWindowNode_ };
for (auto& node : rootNodes) { // ensure that the avoid area windows are traversed first
LayoutWindowNode(node);
}
}
void WindowLayoutPolicy::LayoutWindowNode(sptr<WindowNode>& node)
{
if (node == nullptr) {
return;
}
if (node->parent_ != nullptr) { // isn't root node
if (!node->currentVisibility_) {
WLOGFI("window[%{public}u] currently not visible, no need layout", node->GetWindowId());
return;
}
UpdateLayoutRect(node);
if (avoidTypes_.find(node->GetWindowType()) != avoidTypes_.end()) {
UpdateLimitRect(node, limitRect_);
}
}
for (auto& childNode : node->children_) {
LayoutWindowNode(childNode);
}
}
void WindowLayoutPolicy::AddWindowNode(sptr<WindowNode>& node)
{
WM_FUNCTION_TRACE();
if (WindowHelper::IsEmptyRect(node->GetWindowProperty()->GetWindowRect())) {
SetRectForFloating(node);
}
UpdateWindowNode(node); // currently, update and add do the same process
}
void WindowLayoutPolicy::UpdateDefaultFoatingRect()
{
constexpr uint32_t half = 2;
constexpr float ratio = 0.75; // 0.75: default height/width ratio
// calculate default H and w
uint32_t defaultW = static_cast<uint32_t>(displayRect_.width_ * ratio);
uint32_t defaultH = static_cast<uint32_t>(displayRect_.height_ * ratio);
// calculate default x and y
Rect resRect = {0, 0, defaultW, defaultH};
if (defaultW <= limitRect_.width_ && defaultH <= limitRect_.height_) {
int32_t centerPosX = limitRect_.posX_ + static_cast<int32_t>(limitRect_.width_ / half);
resRect.posX_ = centerPosX - static_cast<int32_t>(defaultW / half);
int32_t centerPosY = limitRect_.posY_ + static_cast<int32_t>(limitRect_.height_ / half);
resRect.posY_ = centerPosY - static_cast<int32_t>(defaultH / half);
}
defaultFloatingRect_ = resRect;
}
void WindowLayoutPolicy::SetRectForFloating(const sptr<WindowNode>& node)
{
float virtualPixelRatio = GetVirtualPixelRatio();
uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * virtualPixelRatio);
uint32_t winTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
// deduct decor size
Rect rect = defaultFloatingRect_;
if (node->GetWindowProperty()->GetDecorEnable()) {
rect.width_ -= (winFrameW + winFrameW);
rect.height_ -= (winTitleBarH + winFrameW);
}
node->SetWindowRect(rect);
}
bool WindowLayoutPolicy::IsVertical() const
{
return displayRect_.width_ < displayRect_.height_;
}
void WindowLayoutPolicy::RemoveWindowNode(sptr<WindowNode>& node)
{
WM_FUNCTION_TRACE();
auto type = node->GetWindowType();
// affect other windows, trigger off global layout
if (avoidTypes_.find(type) != avoidTypes_.end()) {
LayoutWindowTree();
} else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode
LayoutWindowTree();
}
Rect winRect = node->GetWindowProperty()->GetWindowRect();
node->SetLayoutRect(winRect);
node->GetWindowToken()->UpdateWindowRect(winRect, node->GetWindowSizeChangeReason());
}
void WindowLayoutPolicy::UpdateWindowNode(sptr<WindowNode>& node)
{
WM_FUNCTION_TRACE();
auto type = node->GetWindowType();
// affect other windows, trigger off global layout
if (avoidTypes_.find(type) != avoidTypes_.end()) {
LayoutWindowTree();
} else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode
LayoutWindowTree();
} else { // layout single window
LayoutWindowNode(node);
}
}
void WindowLayoutPolicy::UpdateFloatingLayoutRect(Rect& limitRect, Rect& winRect)
{
winRect.width_ = std::min(limitRect.width_, winRect.width_);
winRect.height_ = std::min(limitRect.height_, winRect.height_);
winRect.posX_ = std::max(limitRect.posX_, winRect.posX_);
winRect.posY_ = std::max(limitRect.posY_, winRect.posY_);
winRect.posX_ = std::min(
limitRect.posX_ + static_cast<int32_t>(limitRect.width_) - static_cast<int32_t>(winRect.width_),
winRect.posX_);
winRect.posY_ = std::min(
limitRect.posY_ + static_cast<int32_t>(limitRect.height_) - static_cast<int32_t>(winRect.height_),
winRect.posY_);
}
Rect WindowLayoutPolicy::ComputeDecoratedWindowRect(const Rect& winRect)
{
float virtualPixelRatio = GetVirtualPixelRatio();
uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * virtualPixelRatio);
uint32_t winTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
Rect rect;
rect.posX_ = winRect.posX_;
rect.posY_ = winRect.posY_;
rect.width_ = winRect.width_ + winFrameW + winFrameW;
rect.height_ = winRect.height_ + winTitleBarH + winFrameW;
return rect;
}
void WindowLayoutPolicy::UpdateLayoutRect(sptr<WindowNode>& node)
{
auto type = node->GetWindowType();
auto mode = node->GetWindowMode();
auto flags = node->GetWindowFlags();
auto decorEnbale = node->GetWindowProperty()->GetDecorEnable();
bool needAvoid = (flags & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_NEED_AVOID));
bool parentLimit = (flags & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_PARENT_LIMIT));
bool subWindow = WindowHelper::IsSubWindow(type);
bool floatingWindow = (mode == WindowMode::WINDOW_MODE_FLOATING);
const Rect& layoutRect = node->GetLayoutRect();
Rect lastRect = layoutRect;
Rect displayRect = displayRect_;
Rect limitRect = displayRect;
Rect winRect = node->GetWindowProperty()->GetWindowRect();
WLOGFI("Id:%{public}u, avoid:%{public}d parLimit:%{public}d floating:%{public}d, sub:%{public}d, " \
"deco:%{public}d, type:%{public}d, requestRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
node->GetWindowId(), needAvoid, parentLimit, floatingWindow, subWindow, decorEnbale,
static_cast<uint32_t>(type), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
if (needAvoid) {
limitRect = limitRect_;
}
if (!floatingWindow) { // fullscreen window
winRect = limitRect;
} else { // floating window
if (node->GetWindowProperty()->GetDecorEnable()) { // is decorable
winRect = ComputeDecoratedWindowRect(winRect);
}
if (subWindow && parentLimit) { // subwidow and limited by parent
limitRect = node->parent_->GetLayoutRect();
UpdateFloatingLayoutRect(limitRect, winRect);
}
}
// Limit window to the maximum window size
LimitWindowSize(node, displayRect, winRect);
node->SetLayoutRect(winRect);
CalcAndSetNodeHotZone(winRect, node);
if (!(lastRect == winRect)) {
node->GetWindowToken()->UpdateWindowRect(winRect, node->GetWindowSizeChangeReason());
node->surfaceNode_->SetBounds(winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
}
}
void WindowLayoutPolicy::CalcAndSetNodeHotZone(Rect layoutOutRect, sptr<WindowNode>& node)
{
Rect rect = layoutOutRect;
float virtualPixelRatio = GetVirtualPixelRatio();
uint32_t hotZone = static_cast<uint32_t>(HOTZONE * virtualPixelRatio);
uint32_t divHotZone = static_cast<uint32_t>(DIV_HOTZONE * virtualPixelRatio);
if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
if (rect.width_ < rect.height_) {
rect.posX_ -= divHotZone;
rect.width_ += (divHotZone + divHotZone);
} else {
rect.posY_ -= divHotZone;
rect.height_ += (divHotZone + divHotZone);
}
} else if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
rect.posX_ -= hotZone;
rect.posY_ -= hotZone;
rect.width_ += (hotZone + hotZone);
rect.height_ += (hotZone + hotZone);
}
node->SetHotZoneRect(rect);
}
void WindowLayoutPolicy::LimitWindowSize(const sptr<WindowNode>& node, const Rect& displayRect, Rect& winRect)
{
float virtualPixelRatio = GetVirtualPixelRatio();
uint32_t minVerticalFloatingW = static_cast<uint32_t>(MIN_VERTICAL_FLOATING_WIDTH * virtualPixelRatio);
uint32_t minVerticalFloatingH = static_cast<uint32_t>(MIN_VERTICAL_FLOATING_HEIGHT * virtualPixelRatio);
uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
WindowType windowType = node->GetWindowType();
WindowMode windowMode = node->GetWindowMode();
bool isVertical = (displayRect.height_ > displayRect.width_) ? true : false;
if (!WindowHelper::IsMainFloatingWindow(windowType, windowMode)) {
winRect.width_ = std::min(displayRect.width_ - winRect.posX_, winRect.width_);
winRect.height_ = std::min(displayRect.height_ - winRect.posY_, winRect.height_);
}
if ((windowMode == WindowMode::WINDOW_MODE_FLOATING) && !WindowHelper::IsSystemWindow(windowType)) {
if (isVertical) {
winRect.width_ = std::max(minVerticalFloatingW, winRect.width_);
winRect.height_ = std::max(minVerticalFloatingH, winRect.height_);
} else {
winRect.width_ = std::max(minVerticalFloatingH, winRect.width_);
winRect.height_ = std::max(minVerticalFloatingW, winRect.height_);
}
}
if (WindowHelper::IsMainFloatingWindow(windowType, windowMode)) {
winRect.posY_ = std::max(limitRect_.posY_, winRect.posY_);
winRect.posY_ = std::min(limitRect_.posY_ + static_cast<int32_t>(limitRect_.height_ - windowTitleBarH),
winRect.posY_);
}
}
AvoidPosType WindowLayoutPolicy::GetAvoidPosType(const Rect& rect)
{
if (rect.width_ >= rect.height_) {
if (rect.posY_ == 0) {
return AvoidPosType::AVOID_POS_TOP;
} else {
return AvoidPosType::AVOID_POS_BOTTOM;
}
} else {
if (rect.posX_ == 0) {
return AvoidPosType::AVOID_POS_LEFT;
} else {
return AvoidPosType::AVOID_POS_RIGHT;
}
}
return AvoidPosType::AVOID_POS_UNKNOWN;
}
void WindowLayoutPolicy::UpdateLimitRect(const sptr<WindowNode>& node, Rect& limitRect)
{
auto& layoutRect = node->GetLayoutRect();
int32_t limitH = static_cast<int32_t>(limitRect.height_);
int32_t limitW = static_cast<int32_t>(limitRect.width_);
int32_t layoutH = static_cast<int32_t>(layoutRect.height_);
int32_t layoutW = static_cast<int32_t>(layoutRect.width_);
if (node->GetWindowType() == WindowType::WINDOW_TYPE_STATUS_BAR ||
node->GetWindowType() == WindowType::WINDOW_TYPE_NAVIGATION_BAR) {
auto avoidPosType = GetAvoidPosType(layoutRect);
int32_t offsetH = 0;
int32_t offsetW = 0;
switch (avoidPosType) {
case AvoidPosType::AVOID_POS_TOP:
offsetH = layoutRect.posY_ + layoutH - limitRect.posY_;
limitRect.posY_ += offsetH;
limitH -= offsetH;
break;
case AvoidPosType::AVOID_POS_BOTTOM:
offsetH = limitRect.posY_ + limitH - layoutRect.posY_;
limitH -= offsetH;
break;
case AvoidPosType::AVOID_POS_LEFT:
offsetW = layoutRect.posX_ + layoutW - limitRect.posX_;
limitRect.posX_ += offsetW;
limitW -= offsetW;
break;
case AvoidPosType::AVOID_POS_RIGHT:
offsetW = limitRect.posX_ + limitW - layoutRect.posX_;
limitW -= offsetW;
break;
default:
WLOGFE("invaild avoidPosType: %{public}d", avoidPosType);
}
}
limitRect.height_ = static_cast<uint32_t>(limitH < 0 ? 0 : limitH);
limitRect.width_ = static_cast<uint32_t>(limitW < 0 ? 0 : limitW);
WLOGFI("Type: %{public}d, limitRect: %{public}d %{public}d %{public}u %{public}u",
node->GetWindowType(), limitRect.posX_, limitRect.posY_, limitRect.width_, limitRect.height_);
}
void WindowLayoutPolicy::Reset()
{
}
float WindowLayoutPolicy::GetVirtualPixelRatio() const
{
auto display = DisplayManager::GetInstance().GetDisplayById(screenId_);
if (display == nullptr) {
WLOGFE("GetVirtualPixel fail. Get display fail. displayId:%{public}" PRIu64", use Default vpr:1.0", screenId_);
return 1.0; // Use DefaultVPR 1.0
}
float virtualPixelRatio = display->GetVirtualPixelRatio();
if (virtualPixelRatio == 0.0) {
WLOGFE("GetVirtualPixel fail. vpr is 0.0. displayId:%{public}" PRIu64", use Default vpr:1.0", screenId_);
return 1.0; // Use DefaultVPR 1.0
}
WLOGFI("GetVirtualPixel success. displayId:%{public}" PRIu64", vpr:%{public}f", screenId_, virtualPixelRatio);
return virtualPixelRatio;
}
}
}