1 /*
2 * Copyright (c) 2025 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 "session_coordinate_helper.h"
17
18 #include "dm_common.h"
19 #include "screen_session_manager_client/include/screen_session_manager_client.h"
20 #include "window_manager_hilog.h"
21 #include "wm_math.h"
22
23 namespace OHOS::Rosen {
RelativeToGlobalDisplayRect(ScreenId screenId,const WSRect & relativeRect)24 WSRect SessionCoordinateHelper::RelativeToGlobalDisplayRect(ScreenId screenId, const WSRect& relativeRect)
25 {
26 auto screenSession = ScreenSessionManagerClient::GetInstance().GetScreenSession(screenId);
27 if (!screenSession) {
28 TLOGW(WmsLogTag::WMS_LAYOUT,
29 "Screen not found, screenId: %{public}" PRIu64 ", relativeRect: %{public}s",
30 screenId, relativeRect.ToString().c_str());
31 return relativeRect;
32 }
33 const auto& screenProperty = screenSession->GetScreenProperty();
34 WSRect globalRect {
35 screenProperty.GetX() + relativeRect.posX_,
36 screenProperty.GetY() + relativeRect.posY_,
37 relativeRect.width_,
38 relativeRect.height_
39 };
40 TLOGD(WmsLogTag::WMS_LAYOUT, "screenId: %{public}" PRIu64 ", relativeRect: %{public}s, globalRect: %{public}s",
41 screenId, relativeRect.ToString().c_str(), globalRect.ToString().c_str());
42 return globalRect;
43 }
44
GlobalToScreenRelativeRect(ScreenId originalScreenId,const WSRect & globalRect)45 WSScreenRelativeRect SessionCoordinateHelper::GlobalToScreenRelativeRect(
46 ScreenId originalScreenId, const WSRect& globalRect)
47 {
48 auto originalScreen = ScreenSessionManagerClient::GetInstance().GetScreenSession(originalScreenId);
49 if (!originalScreen) {
50 return { MAIN_SCREEN_ID_DEFAULT, globalRect };
51 }
52
53 const float originalScreenVpr = originalScreen->GetScreenProperty().GetVirtualPixelRatio();
54 if (MathHelper::NearZero(originalScreenVpr)) {
55 return { MAIN_SCREEN_ID_DEFAULT, globalRect };
56 }
57
58 // Convert globalRect's size (width/height) to virtual pixel units using original screen's VPR.
59 // Keep posX/posY unchanged, only adjust width and height to match how large it would appear on different screens.
60 const float widthInVp = globalRect.width_ / originalScreenVpr;
61 const float heightInVp = globalRect.height_ / originalScreenVpr;
62
63 // Iterate all screens and find the one that has the largest intersection area with the scaled rect.
64 // For comparison, convert the width and height back into actual pixels using each screen's VPR.
65 ScreenId candidateScreenId = SCREEN_ID_INVALID;
66 WSRect candidateScreenRect = WSRect::EMPTY_RECT;
67 WSRect originalScreenRect = WSRect::EMPTY_RECT;
68 uint64_t maxIntersectionArea = 0;
69 const auto screenPropMap = ScreenSessionManagerClient::GetInstance().GetAllScreensProperties();
70 for (const auto& [screenId, screenProp] : screenPropMap) {
71 const float screenVpr = screenProp.GetVirtualPixelRatio();
72 WSRect screenRect {
73 screenProp.GetX(), screenProp.GetY(),
74 screenProp.GetBounds().rect_.GetWidth(),
75 screenProp.GetBounds().rect_.GetHeight()
76 };
77 if (screenId == originalScreenId) {
78 originalScreenRect = screenRect;
79 }
80
81 // Scale globalRect’s width/height to match how it would look on this screen.
82 WSRect scaledGlobalRect {
83 globalRect.posX_, globalRect.posY_,
84 static_cast<int32_t>(std::round(widthInVp * screenVpr)),
85 static_cast<int32_t>(std::round(heightInVp * screenVpr))
86 };
87
88 // Compute intersection area between this screen and the scaled globalRect.
89 uint64_t area = scaledGlobalRect.IntersectionArea<uint64_t>(screenRect);
90 if (area > maxIntersectionArea || (area == maxIntersectionArea && screenId < candidateScreenId)) {
91 maxIntersectionArea = area;
92 candidateScreenId = screenId;
93 candidateScreenRect = screenRect;
94 }
95 }
96
97 // Determine the final matched screen and compute the relative rect to it.
98 bool hasCandidate = candidateScreenId != SCREEN_ID_INVALID;
99 const auto matchedScreenId = hasCandidate ? candidateScreenId : originalScreenId;
100 const auto& matchedScreenRect = hasCandidate ? candidateScreenRect : originalScreenRect;
101 const WSRect relativeRect {
102 globalRect.posX_ - matchedScreenRect.posX_,
103 globalRect.posY_ - matchedScreenRect.posY_,
104 globalRect.width_, globalRect.height_
105 };
106 TLOGD(WmsLogTag::WMS_LAYOUT, "matchedScreenId: %{public}" PRIu64 ", relativeRect: %{public}s",
107 matchedScreenId, relativeRect.ToString().c_str());
108 return { matchedScreenId, relativeRect };
109 }
110 } // namespace OHOS::Rosen
111