1 /*
2 * Copyright (c) 2025-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 #include "screen_pointer.h"
16
17 #include "define_multimodal.h"
18 #include "transaction/rs_transaction.h"
19 #include "transaction/rs_interfaces.h"
20
21 #undef MMI_LOG_DOMAIN
22 #define MMI_LOG_DOMAIN MMI_LOG_CURSOR
23 #undef MMI_LOG_TAG
24 #define MMI_LOG_TAG "ScreenPointer"
25
26 namespace OHOS::MMI {
27 const char* RS_SURFACE_NODE_NAME{"pointer window"};
28 const char* POINTER_SIZE{"pointerSize"};
29 constexpr int32_t RS_NODE_CANVAS_INDEX{-1};
30 constexpr int32_t DEFAULT_POINTER_SIZE{1};
31 constexpr int32_t DEVICE_INDEPENDENT_PIXELS{40};
32 constexpr int32_t BASELINE_DENSITY{160};
33 constexpr int32_t POINTER_WINDOW_INIT_SIZE{64};
34 constexpr int32_t BUFFER_RELEASE_WAIT_MS{1000};
35 constexpr int32_t NUM_TWO{2};
36 constexpr int32_t DEFAULT_BUFFER_SIZE{10};
37 constexpr int32_t DEFAULT_CURSOR_SIZE{512};
38 constexpr uint32_t FOCUS_POINT = DEFAULT_CURSOR_SIZE / NUM_TWO;
39 constexpr int32_t BUFFER_TIMEOUT{150};
40 constexpr int32_t STRIDE_ALIGNMENT{8};
41 constexpr float CALCULATE_MOUSE_ICON_BIAS{5.0f};
42 constexpr float INCREASE_RATIO{1.22f};
43 constexpr uint32_t RENDER_STRIDE{4};
44
GetScreenInfoWidth(screen_info_ptr_t si)45 uint32_t GetScreenInfoWidth(screen_info_ptr_t si)
46 {
47 uint32_t width = 0;
48 auto modeId = si->GetModeId();
49 auto modes = si->GetModes();
50 if (modeId < 0 || modeId >= modes.size()) {
51 return 0;
52 }
53 return modes[modeId]->width_;
54 }
GetScreenInfoHeight(screen_info_ptr_t si)55 uint32_t GetScreenInfoHeight(screen_info_ptr_t si)
56 {
57 uint32_t height = 0;
58 auto modeId = si->GetModeId();
59 auto modes = si->GetModes();
60 if (modeId < 0 || modeId >= modes.size()) {
61 return 0;
62 }
63 return modes[modeId]->height_;
64 }
65
ScreenPointer(hwcmgr_ptr_t hwcMgr,handler_ptr_t handler,const DisplayInfo & di)66 ScreenPointer::ScreenPointer(hwcmgr_ptr_t hwcMgr, handler_ptr_t handler, const DisplayInfo &di)
67 : hwcMgr_(hwcMgr), handler_(handler)
68 {
69 screenId_ = di.id;
70 width_ = di.width;
71 height_ = di.height;
72 rotation_ = static_cast<rotation_t>(di.direction);
73 if (rotation_ == rotation_t::ROTATION_90 ||
74 rotation_ == rotation_t::ROTATION_270) {
75 std::swap(width_, height_);
76 }
77 dpi_ = float(di.dpi) / BASELINE_DENSITY;
78 MMI_HILOGI("Construct with DisplayInfo, id=%{public}u, shape=(%{public}u, %{public}u), mode=%{public}u, "
79 "rotation=%{public}u, dpi=%{public}f", screenId_, width_, height_, mode_, rotation_, dpi_);
80 }
81
ScreenPointer(hwcmgr_ptr_t hwcMgr,handler_ptr_t handler,screen_info_ptr_t si)82 ScreenPointer::ScreenPointer(hwcmgr_ptr_t hwcMgr, handler_ptr_t handler, screen_info_ptr_t si)
83 : hwcMgr_(hwcMgr), handler_(handler)
84 {
85 screenId_ = si->GetScreenId();
86 width_ = GetScreenInfoWidth(si);
87 height_ = GetScreenInfoHeight(si);
88 mode_ = si->GetSourceMode();
89 rotation_ = si->GetRotation();
90 dpi_ = si->GetVirtualPixelRatio();
91 MMI_HILOGI("Construct with ScreenInfo, id=%{public}u, shape=(%{public}u, %{public}u), mode=%{public}u, "
92 "rotation=%{public}u, dpi=%{public}f", screenId_, width_, height_, mode_, rotation_, dpi_);
93 }
94
Init()95 bool ScreenPointer::Init()
96 {
97 if (!InitSurface()) {
98 MMI_HILOGE("ScreenPointer InitSurface failed");
99 return false;
100 }
101
102 // Init buffers
103 OHOS::BufferRequestConfig bufferCfg = {
104 .width = DEFAULT_CURSOR_SIZE,
105 .height = DEFAULT_CURSOR_SIZE,
106 .strideAlignment = STRIDE_ALIGNMENT,
107 .format = GRAPHIC_PIXEL_FMT_RGBA_8888,
108 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_HW_COMPOSER,
109 .timeout = BUFFER_TIMEOUT,
110 };
111 for (int32_t i = 0; i < DEFAULT_BUFFER_SIZE && buffers_.size() < DEFAULT_BUFFER_SIZE; i++) {
112 sptr<OHOS::SurfaceBuffer> buffer = OHOS::SurfaceBuffer::Create();
113 if (buffer == nullptr) {
114 MMI_HILOGE("SurfaceBuffer Create failed");
115 return false;
116 }
117 OHOS::GSError ret = buffer->Alloc(bufferCfg);
118 if (ret != OHOS::GSERROR_OK) {
119 MMI_HILOGE("SurfaceBuffer Alloc failed, %{public}s", GSErrorStr(ret).c_str());
120 return false;
121 }
122 buffers_.push_back(buffer);
123 }
124 return true;
125 }
126
InitSurface()127 bool ScreenPointer::InitSurface()
128 {
129 // create SurfaceNode
130 Rosen::RSSurfaceNodeConfig surfaceNodeConfig;
131 surfaceNodeConfig.SurfaceNodeName = RS_SURFACE_NODE_NAME;
132 surfaceNode_ = Rosen::RSSurfaceNode::Create(surfaceNodeConfig, Rosen::RSSurfaceNodeType::SELF_DRAWING_WINDOW_NODE);
133 CHKPF(surfaceNode_);
134 MMI_HILOGE("SurfaceNode::Create success");
135
136 // set soft cursor buffer size
137 auto surface = surfaceNode_->GetSurface();
138 surface->SetQueueSize(DEFAULT_BUFFER_SIZE);
139
140 surfaceNode_->SetVisible(true);
141 surfaceNode_->SetFrameGravity(Rosen::Gravity::TOP_LEFT);
142 surfaceNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
143 surfaceNode_->AttachToDisplay(screenId_);
144 MMI_HILOGI("AttachToDisplay %{public}d completed", screenId_);
145
146 // create canvas node
147 canvasNode_ = Rosen::RSCanvasNode::Create();
148 CHKPF(canvasNode_);
149 canvasNode_->SetBounds(0, 0, DEFAULT_CURSOR_SIZE, DEFAULT_CURSOR_SIZE);
150 canvasNode_->SetFrame(0, 0, DEFAULT_CURSOR_SIZE, DEFAULT_CURSOR_SIZE);
151 #ifndef USE_ROSEN_DRAWING
152 canvasNode_->SetBackgroundColor(SK_ColorTRANSPARENT);
153 #else
154 canvasNode_->SetBackgroundColor(Rosen::Drawing::Color::COLOR_TRANSPARENT);
155 #endif // USE_ROSEN_DRAWING
156
157 canvasNode_->SetCornerRadius(1);
158 canvasNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
159 canvasNode_->SetRotation(float(rotation_));
160 surfaceNode_->AddChild(canvasNode_, RS_NODE_CANVAS_INDEX);
161
162 MMI_HILOGI("InitSurface completed");
163 return true;
164 }
165
UpdateScreenInfo(const sptr<OHOS::Rosen::ScreenInfo> si)166 void ScreenPointer::UpdateScreenInfo(const sptr<OHOS::Rosen::ScreenInfo> si)
167 {
168 auto id = si->GetScreenId();
169 if (screenId_ != id) {
170 surfaceNode_->AttachToDisplay(id);
171 Rosen::RSTransaction::FlushImplicitTransaction();
172 }
173
174 screenId_ = si->GetScreenId();
175 width_ = GetScreenInfoWidth(si);
176 height_ = GetScreenInfoHeight(si);
177 mode_ = si->GetSourceMode();
178 rotation_ = si->GetRotation();
179 dpi_ = si->GetVirtualPixelRatio();
180 if (IsExtend()) {
181 surfaceNode_->AttachToDisplay(screenId_);
182 Rosen::RSTransaction::FlushImplicitTransaction();
183 }
184 MMI_HILOGI("Update with ScreenInfo, id=%{public}u, shape=(%{public}u, %{public}u), mode=%{public}u, "
185 "rotation=%{public}u, dpi=%{public}f", screenId_, width_, height_, mode_, rotation_, dpi_);
186 }
187
OnDisplayInfo(const DisplayInfo & di)188 void ScreenPointer::OnDisplayInfo(const DisplayInfo &di)
189 {
190 if (screenId_ != uint32_t(di.id)) {
191 return;
192 }
193
194 isCurrentOffScreenRendering_ = di.isCurrentOffScreenRendering;
195 dpi_ = float(di.dpi) / BASELINE_DENSITY;
196 if (!IsMirror()) {
197 rotation_ = static_cast<rotation_t>(di.direction);
198 }
199 MMI_HILOGD("Update with DisplayInfo, id=%{public}u, shape=(%{public}u, %{public}u), mode=%{public}u, "
200 "rotation=%{public}u, dpi=%{public}f", screenId_, width_, height_, mode_, rotation_, dpi_);
201 if (isCurrentOffScreenRendering_) {
202 screenRealDPI_ = di.screenRealDPI;
203 offRenderScale_ = float(di.screenRealWidth) / di.width;
204 MMI_HILOGD("Update with DisplayInfo, screenRealDPI=%{public}u, offRenderScale_=(%{public}f ",
205 screenRealDPI_, offRenderScale_);
206 }
207 }
208
UpdatePadding(uint32_t mainWidth,uint32_t mainHeight)209 bool ScreenPointer::UpdatePadding(uint32_t mainWidth, uint32_t mainHeight)
210 {
211 if (!IsMirror()) {
212 MMI_HILOGI("UpdatePadidng, reset padding, screenId=%{public}u, scale=%{public}f, "
213 "paddingTop_=%{public}u, paddingLeft_=%{public}u", screenId_, scale_, paddingTop_, paddingLeft_);
214 scale_ = 1.0;
215 paddingTop_ = 0;
216 paddingLeft_ = 0;
217 return false;
218 }
219 if (mainWidth == 0 || mainHeight == 0) {
220 MMI_HILOGE("Invalid parameters, mainWidth=%{public}u, mainHeight=%{public}u", mainWidth, mainHeight);
221 return false;
222 }
223 if (rotation_ == rotation_t::ROTATION_90 || rotation_ == rotation_t::ROTATION_270) {
224 std::swap(mainWidth, mainHeight);
225 }
226
227 // caculate padding for mirror screens
228 scale_ = fmin(float(width_) / mainWidth, float(height_) / mainHeight);
229 paddingTop_ = (height_ - mainHeight * scale_) / NUM_TWO;
230 paddingLeft_ = (width_ - mainWidth * scale_) / NUM_TWO;
231 MMI_HILOGI("UpdatePadding, screenId=%{public}u, scale=%{public}f, paddingTop_=%{public}u, paddingLeft_=%{public}u",
232 screenId_, scale_, paddingTop_, paddingLeft_);
233 return true;
234 }
235
RequestBuffer()236 sptr<OHOS::SurfaceBuffer> ScreenPointer::RequestBuffer()
237 {
238 if (!buffers_.size()) {
239 return nullptr;
240 }
241
242 bufferId_++;
243 bufferId_ %= buffers_.size();
244
245 return buffers_[bufferId_];
246 }
247
GetCurrentBuffer()248 sptr<OHOS::SurfaceBuffer> ScreenPointer::GetCurrentBuffer()
249 {
250 if (bufferId_ >= buffers_.size()) {
251 return nullptr;
252 }
253 return buffers_[bufferId_];
254 }
255
Rotate(rotation_t rotation,int32_t & x,int32_t & y)256 void ScreenPointer::Rotate(rotation_t rotation, int32_t& x, int32_t& y)
257 {
258 // 坐标轴绕原点旋转 再平移
259 int32_t tmpX = x;
260 int32_t tmpY = y;
261 int32_t width = static_cast<int32_t>(width_);
262 int32_t height = static_cast<int32_t>(height_);
263 if (IsMirror()) {
264 height -= paddingTop_ * NUM_TWO;
265 width -= paddingLeft_ * NUM_TWO;
266 }
267 // 主屏旋转 坐标系会一起旋转,但镜像屏此时坐标系不旋转
268 if (IsMirror() && (rotation_ == rotation_t::ROTATION_90 || rotation_ == rotation_t::ROTATION_270)) {
269 std::swap(width, height);
270 }
271
272 if (rotation == rotation_t(DIRECTION90)) {
273 x = height - tmpY;
274 y = tmpX;
275 } else if (rotation == rotation_t(DIRECTION180)) {
276 x = width - tmpX;
277 y = height - tmpY;
278 } else if (rotation == rotation_t(DIRECTION270)) {
279 x = tmpY;
280 y = width - tmpX;
281 }
282 }
283
CalculateHwcPositionForMirror(int32_t & x,int32_t & y)284 void ScreenPointer::CalculateHwcPositionForMirror(int32_t& x, int32_t& y)
285 {
286 x = x * scale_;
287 y = y * scale_;
288 Rotate(rotation_, x, y);
289
290 x += paddingLeft_;
291 y += paddingTop_;
292 }
293
CalculateHwcPositionForExtend(int32_t & x,int32_t & y)294 void ScreenPointer::CalculateHwcPositionForExtend(int32_t& x, int32_t& y)
295 {
296 x = x * offRenderScale_;
297 y = y * offRenderScale_;
298 }
299
Move(int32_t x,int32_t y,ICON_TYPE align)300 bool ScreenPointer::Move(int32_t x, int32_t y, ICON_TYPE align)
301 {
302 #ifdef OHOS_BUILD_ENABLE_HARDWARE_CURSOR
303 CHKPF(hwcMgr_);
304
305 int32_t px = 0;
306 int32_t py = 0;
307 if (IsMirror()) {
308 CalculateHwcPositionForMirror(x, y);
309 } else if (GetIsCurrentOffScreenRendering() && !IsMirror()) {
310 CalculateHwcPositionForExtend(x, y);
311 }
312
313 px = x - FOCUS_POINT;
314 py = y - FOCUS_POINT;
315
316 auto buffer = GetCurrentBuffer();
317 CHKPF(buffer);
318 auto bh = buffer->GetBufferHandle();
319 CHKPF(bh);
320 auto ret = hwcMgr_->SetPosition(screenId_, px, py, bh);
321 if (ret != RET_OK) {
322 MMI_HILOGE("SetPosition failed, screenId=%{public}u, pos=(%{public}d, %{public}d)", screenId_, px, py);
323 return false;
324 }
325 #endif // OHOS_BUILD_ENABLE_HARDWARE_CURSOR
326 return true;
327 }
328
MoveSoft(int32_t x,int32_t y,ICON_TYPE align)329 bool ScreenPointer::MoveSoft(int32_t x, int32_t y, ICON_TYPE align)
330 {
331 CHKPF(surfaceNode_);
332 int32_t px = 0;
333 int32_t py = 0;
334 if (IsMirror()) {
335 CalculateHwcPositionForMirror(x, y);
336 } else if (!IsExtend()) {
337 Rotate(rotation_, x, y);
338 }
339 px = x - FOCUS_POINT;
340 py = y - FOCUS_POINT;
341
342 if (!IsMirror()) {
343 int64_t nodeId = surfaceNode_->GetId();
344 Rosen::RSInterfaces::GetInstance().SetHwcNodeBounds(nodeId, px, py, DEFAULT_CURSOR_SIZE, DEFAULT_CURSOR_SIZE);
345 } else {
346 surfaceNode_->SetBounds(px, py, DEFAULT_CURSOR_SIZE, DEFAULT_CURSOR_SIZE);
347 }
348
349 return true;
350 }
351
SetInvisible()352 bool ScreenPointer::SetInvisible()
353 {
354 #ifdef OHOS_BUILD_ENABLE_HARDWARE_CURSOR
355 CHKPF(hwcMgr_);
356
357 auto buffer = RequestBuffer();
358 CHKPF(buffer);
359 auto addr = static_cast<uint8_t*>(buffer->GetVirAddr());
360 CHKPF(addr);
361 if (buffer->GetWidth() >= 0 && buffer->GetHeight() >= 0) {
362 uint32_t addrSize = static_cast<uint32_t>(buffer->GetWidth()) *
363 static_cast<uint32_t>(buffer->GetHeight()) * RENDER_STRIDE;
364 memset_s(addr, addrSize, 0, addrSize);
365 } else {
366 MMI_HILOGI("The input data is negative, and the data is incorrect.");
367 return false;
368 }
369
370 auto bh = buffer->GetBufferHandle();
371 CHKPF(bh);
372 auto ret = hwcMgr_->SetPosition(screenId_, 0, 0, bh);
373 if (ret != RET_OK) {
374 MMI_HILOGE("SetLocation failed, screenId=%{public}u, loc=(%{public}d, %{public}d)", screenId_, 0, 0);
375 return false;
376 }
377 MMI_HILOGI("SetInvisible success, screenId=%{public}u", screenId_);
378 #endif // OHOS_BUILD_ENABLE_HARDWARE_CURSOR
379 return true;
380 }
381
GetRenderDPI() const382 float ScreenPointer::GetRenderDPI() const
383 {
384 if (GetIsCurrentOffScreenRendering() && !IsMirror()) {
385 return float(GetScreenRealDPI()) / BASELINE_DENSITY;
386 } else {
387 return dpi_ * scale_;
388 }
389 }
390
391 } // namespace OHOS::MMI