1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "window_system_effect.h"
17
18#include <common/rs_common_def.h>
19#include "color_parser.h"
20#include "display_group_info.h"
21#include "remote_animation.h"
22#include "window_helper.h"
23#include "window_inner_manager.h"
24#include "window_manager_hilog.h"
25
26namespace OHOS {
27namespace Rosen {
28namespace {
29constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowSystemEffect"};
30}
31
32AppWindowEffectConfig WindowSystemEffect::windowSystemEffectConfig_;
33wptr<WindowRoot> WindowSystemEffect::windowRoot_;
34
35void WindowSystemEffect::SetWindowSystemEffectConfig(AppWindowEffectConfig config)
36{
37    windowSystemEffectConfig_ = config;
38}
39
40void WindowSystemEffect::SetWindowRoot(const sptr<WindowRoot>& windowRoot)
41{
42    windowRoot_ = windowRoot;
43}
44
45WMError WindowSystemEffect::SetCornerRadius(const sptr<WindowNode>& node, bool needCheckAnimation)
46{
47    auto winRoot = windowRoot_.promote();
48    if (winRoot == nullptr || node == nullptr) {
49        WLOGFE("window root is null");
50        return WMError::WM_ERROR_NULLPTR;
51    }
52    // if change mode during animation, not set radius until animationFinish
53    if (needCheckAnimation && RemoteAnimation::IsRemoteAnimationEnabledAndFirst(node->GetDisplayId()) &&
54        node->stateMachine_.IsShowAnimationPlaying()) {
55        WLOGFW("not set radius during animation");
56        return WMError::WM_DO_NOTHING;
57    }
58
59    if (!IsAppMainOrSubOrFloatingWindow(node)) {
60        return WMError::WM_DO_NOTHING;
61    }
62    auto vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
63    auto fullscreenRadius = windowSystemEffectConfig_.fullScreenCornerRadius_ * vpr;
64    auto splitRadius = windowSystemEffectConfig_.splitCornerRadius_ * vpr;
65    auto floatRadius = windowSystemEffectConfig_.floatCornerRadius_ * vpr;
66
67    WLOGFD("[WEffect] [id:%{public}d] mode: %{public}u, vpr: %{public}f, [%{public}f, %{public}f, %{public}f]",
68        node->GetWindowId(), node->GetWindowMode(), vpr, fullscreenRadius, splitRadius, floatRadius);
69    if (MathHelper::NearZero(fullscreenRadius) && MathHelper::NearZero(splitRadius) &&
70        MathHelper::NearZero(floatRadius)) {
71        return WMError::WM_DO_NOTHING;
72    }
73    auto surfaceNode = node->leashWinSurfaceNode_ != nullptr ? node->leashWinSurfaceNode_ : node->surfaceNode_;
74    if (surfaceNode == nullptr) {
75        WLOGFE("window surfaceNode is null");
76        return WMError::WM_ERROR_NULLPTR;
77    }
78    if (WindowHelper::IsFullScreenWindow(node->GetWindowMode())) {
79        surfaceNode->SetCornerRadius(fullscreenRadius);
80    } else if (WindowHelper::IsSplitWindowMode(node->GetWindowMode())) {
81        surfaceNode->SetCornerRadius(splitRadius);
82    } else if (WindowHelper::IsFloatingWindow(node->GetWindowMode())) {
83        surfaceNode->SetCornerRadius(floatRadius);
84    }
85    return WMError::WM_OK;
86}
87
88bool WindowSystemEffect::IsAppMainOrSubOrFloatingWindow(const sptr<WindowNode>& node)
89{
90    if (WindowHelper::IsAppWindow(node->GetWindowType())) {
91        return true;
92    }
93    auto winRoot = windowRoot_.promote();
94    if (winRoot == nullptr) {
95        return false;
96    }
97    // Type float has main window
98    if (WindowHelper::IsAppFloatingWindow(node->GetWindowType()) &&
99        winRoot->FindMainWindowWithToken(node->abilityToken_)) {
100        return true;
101    }
102    WLOGFD("not appWindow or app floating window, id: %{public}u!", node->GetWindowId());
103    return false;
104}
105
106WMError WindowSystemEffect::SetWindowShadow(const sptr<WindowNode>& node)
107{
108    auto winRoot = windowRoot_.promote();
109    if (winRoot == nullptr || node == nullptr) {
110        return WMError::WM_ERROR_NULLPTR;
111    }
112
113    if (!IsAppMainOrSubOrFloatingWindow(node)) {
114        return WMError::WM_DO_NOTHING;
115    }
116
117    if (MathHelper::NearZero(windowSystemEffectConfig_.focusedShadow_.elevation_) &&
118        MathHelper::NearZero(windowSystemEffectConfig_.unfocusedShadow_.elevation_) &&
119        MathHelper::NearZero(windowSystemEffectConfig_.focusedShadow_.radius_) &&
120        MathHelper::NearZero(windowSystemEffectConfig_.unfocusedShadow_.radius_)) {
121        WLOGFD("shadow elevation and radius are both 0.0, id: %{public}u", node->GetWindowId());
122        return WMError::WM_DO_NOTHING;
123    }
124
125    auto surfaceNode = node->leashWinSurfaceNode_ != nullptr ? node->leashWinSurfaceNode_ : node->surfaceNode_;
126    if (surfaceNode == nullptr) {
127        WLOGFE("window surfaceNode is null");
128        return WMError::WM_ERROR_NULLPTR;
129    }
130
131    auto& shadow = node->isFocused_ ? windowSystemEffectConfig_.focusedShadow_ :
132        windowSystemEffectConfig_.unfocusedShadow_;
133
134    // when float mode change to fullscreen/split mode
135    if (!WindowHelper::IsFloatingWindow(node->GetWindowMode())) {
136        if (MathHelper::GreatNotEqual(shadow.elevation_, 0.f)) {
137            surfaceNode->SetShadowElevation(0.f);
138        } else {
139            surfaceNode->SetShadowRadius(0.f);
140        }
141        surfaceNode->SetShadowAlpha(0.f);
142        WLOGFD("[WEffect]close shadow id: %{public}u", node->GetWindowId());
143        return WMError::WM_OK;
144    }
145
146    uint32_t colorValue;
147    if (!ColorParser::Parse(shadow.color_, colorValue)) {
148        WLOGFE("[WEffect]invalid color string: %{public}s", shadow.color_.c_str());
149        return WMError::WM_ERROR_INVALID_PARAM;
150    }
151
152    WLOGFI("[WEffect]id: %{public}u focused: %{public}d elevation: %{public}f",
153        node->GetWindowId(), static_cast<int32_t>(node->isFocused_), shadow.elevation_);
154    WLOGFI("[WEffect]color: %{public}s offsetX: %{public}f offsetY: %{public}f alpha: %{public}f radius: %{public}f",
155        shadow.color_.c_str(), shadow.offsetX_, shadow.offsetY_, shadow.alpha_, shadow.radius_);
156    auto vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
157    if (MathHelper::GreatNotEqual(shadow.elevation_, 0.f)) {
158        surfaceNode->SetShadowElevation(shadow.elevation_ * vpr);
159    } else {
160        surfaceNode->SetShadowRadius(ConvertRadiusToSigma(shadow.radius_ * vpr));
161    }
162    surfaceNode->SetShadowColor(colorValue);
163    surfaceNode->SetShadowOffsetX(shadow.offsetX_ * vpr);
164    surfaceNode->SetShadowOffsetY(shadow.offsetY_ * vpr);
165    surfaceNode->SetShadowAlpha(shadow.alpha_);
166    return WMError::WM_OK;
167}
168
169WMError WindowSystemEffect::SetWindowEffect(const sptr<WindowNode>& node, bool needCheckAnimation)
170{
171    auto winRoot = windowRoot_.promote();
172    if (node == nullptr) {
173        WLOGFE("window node is null");
174        return WMError::WM_ERROR_NULLPTR;
175    }
176    SetCornerRadius(node, needCheckAnimation);
177    SetWindowShadow(node);
178    return WMError::WM_OK;
179}
180} // Rosen
181} // OHOS
182