1  /*
2   * Copyright (c) 2022 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 "display_zoom_controller.h"
16  #include "display_group_info.h"
17  #include "window_helper.h"
18  
19  namespace OHOS::Rosen {
20  namespace {
21  constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "DisplayZoomController"};
22  }
23  
SetAnchorAndScale(int32_t x,int32_t y,float scale)24  void DisplayZoomController::SetAnchorAndScale(int32_t x, int32_t y, float scale)
25  {
26      WLOGFD("DisplayZoom: On, anchor x:%{public}d, y:%{public}d, scale:%{public}f", x, y, scale);
27      if (scale <= 0) {
28          return;
29      } else if (zoomInfo_.scale * scale < DISPLAY_ZOOM_MIN_SCALE) {
30          scale = DISPLAY_ZOOM_MIN_SCALE / zoomInfo_.scale;
31      } else if (zoomInfo_.scale * scale > DISPLAY_ZOOM_MAX_SCALE) {
32          scale = DISPLAY_ZOOM_MAX_SCALE / zoomInfo_.scale;
33      }
34      DisplayId displayId = DisplayGroupInfo::GetInstance().GetDefaultDisplayId();
35      sptr<WindowNodeContainer> windowNodeContainer = windowRoot_->GetOrCreateWindowNodeContainer(displayId);
36      if (windowNodeContainer == nullptr) {
37          return;
38      }
39      std::vector<sptr<WindowNode>> windowNodes;
40      windowNodeContainer->TraverseContainer(windowNodes);
41      bool isAlreadyCalcu = false;
42      for (auto& node : windowNodes) {
43          if (displayZoomWindowTypeSkipped_.find(node->GetWindowProperty()->GetWindowType()) !=
44              displayZoomWindowTypeSkipped_.end()) {
45              continue;
46          }
47          Transform zoomTrans;
48          if (!isAlreadyCalcu) {
49              zoomTrans = CalcuZoomTrans(node, {x, y, scale, 0, 0});
50              zoomInfo_.scale *= scale;
51              Rect rect = node->GetWindowRect();
52              zoomInfo_.pivotX = rect.posX_ + zoomTrans.pivotX_ * rect.width_;
53              zoomInfo_.pivotY = rect.posY_ + zoomTrans.pivotY_ * rect.height_;
54              zoomInfo_.translateX = zoomTrans.translateX_;
55              zoomInfo_.translateY = zoomTrans.translateY_;
56              isAlreadyCalcu = true;
57          } else {
58              zoomTrans = CalcuZoomTransByZoomInfo(node);
59          }
60          UpdateClientAndSurfaceZoomInfo(node, zoomTrans);
61      }
62  }
63  
SetAnchorOffset(int32_t deltaX,int32_t deltaY)64  void DisplayZoomController::SetAnchorOffset(int32_t deltaX, int32_t deltaY)
65  {
66      WLOGFD("DisplayZoom: SetAnchorOffset");
67      DisplayId displayId = DisplayGroupInfo::GetInstance().GetDefaultDisplayId();
68      sptr<WindowNodeContainer> windowNodeContainer = windowRoot_->GetOrCreateWindowNodeContainer(displayId);
69      if (windowNodeContainer == nullptr) {
70          return;
71      }
72      if (!UpdateZoomTranslateInfo(windowNodeContainer, displayId, deltaX, deltaY)) {
73          return;
74      }
75      WindowNodeOperationFunc translateFunc = [this, deltaX, deltaY](sptr<WindowNode> node) {
76          if (displayZoomWindowTypeSkipped_.find(node->GetWindowProperty()->GetWindowType()) !=
77              displayZoomWindowTypeSkipped_.end()) {
78              return false;
79          }
80          Transform zoomTrans = node->GetZoomTransform();
81          zoomTrans.translateX_ += static_cast<float>(deltaX);
82          zoomTrans.translateY_ += static_cast<float>(deltaY);
83          UpdateClientAndSurfaceZoomInfo(node, zoomTrans);
84          return false;
85      };
86      windowNodeContainer->TraverseWindowTree(translateFunc, false);
87  }
88  
OffWindowZoom()89  void DisplayZoomController::OffWindowZoom()
90  {
91      WLOGFD("DisplayZoom: Off");
92      DisplayId displayId = DisplayGroupInfo::GetInstance().GetDefaultDisplayId();
93      sptr<WindowNodeContainer> windowNodeContainer = windowRoot_->GetOrCreateWindowNodeContainer(displayId);
94      if (windowNodeContainer == nullptr) {
95          return;
96      }
97      zoomInfo_ = {0, 0, 1.0, 0, 0};
98      std::vector<sptr<WindowNode>> windowNodes;
99      windowNodeContainer->TraverseContainer(windowNodes);
100      for (auto& node : windowNodes) {
101          if (displayZoomWindowTypeSkipped_.find(node->GetWindowProperty()->GetWindowType()) !=
102              displayZoomWindowTypeSkipped_.end()) {
103              continue;
104          }
105          ClearZoomTransformInner(node);
106      }
107  }
108  
UpdateAllWindowsZoomInfo(DisplayId displayId)109  void DisplayZoomController::UpdateAllWindowsZoomInfo(DisplayId displayId)
110  {
111      if (zoomInfo_.scale == DISPLAY_ZOOM_OFF_SCALE) {
112          return;
113      }
114      DisplayId defaultDisplayId = DisplayGroupInfo::GetInstance().GetDefaultDisplayId();
115      if (defaultDisplayId != displayId) {
116          return;
117      }
118      sptr<WindowNodeContainer> windowNodeContainer = windowRoot_->GetOrCreateWindowNodeContainer(displayId);
119      if (windowNodeContainer == nullptr) {
120          return;
121      }
122      int32_t deltaX, deltaY;
123      deltaX = deltaY = 0;
124      if (UpdateZoomTranslateInfo(windowNodeContainer, displayId, deltaX, deltaY)) {
125          WLOGFD("Change ZoomInfo translation, deltaX:%{public}d, deltaY:%{public}d", deltaX, deltaY);
126      }
127      std::vector<sptr<WindowNode>> windowNodes;
128      windowNodeContainer->TraverseContainer(windowNodes);
129      for (auto& node: windowNodes) {
130          HandleUpdateWindowZoomInfo(node);
131      }
132  }
133  
UpdateWindowZoomInfo(uint32_t windowId)134  void DisplayZoomController::UpdateWindowZoomInfo(uint32_t windowId)
135  {
136      if (zoomInfo_.scale == DISPLAY_ZOOM_OFF_SCALE) {
137          return;
138      }
139      auto node = windowRoot_->GetWindowNode(windowId);
140      if (node == nullptr) {
141          return;
142      }
143      if (!node->currentVisibility_) {
144          return;
145      }
146      DisplayId displayId = DisplayGroupInfo::GetInstance().GetDefaultDisplayId();
147      if (node->GetDisplayId() != displayId) {
148          return;
149      }
150      std::vector<sptr<WindowNode>> windowNodes;
151      windowNodes.push_back(node);
152      if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
153          windowNodes = windowRoot_->GetSplitScreenWindowNodes(node->GetDisplayId());
154      }
155      for (auto& windowNode: windowNodes) {
156          HandleUpdateWindowZoomInfo(windowNode);
157      }
158  }
159  
ClearZoomTransform(std::vector<sptr<WindowNode>> nodes)160  void DisplayZoomController::ClearZoomTransform(std::vector<sptr<WindowNode>> nodes)
161  {
162      if (zoomInfo_.scale == DISPLAY_ZOOM_OFF_SCALE) {
163          return;
164      }
165      for (auto& node: nodes) {
166          ClearZoomTransformInner(node);
167      }
168  }
169  
ClearZoomTransformInner(sptr<WindowNode> node)170  void DisplayZoomController::ClearZoomTransformInner(sptr<WindowNode> node)
171  {
172      Transform recoverTrans;
173      node->UpdateZoomTransform(recoverTrans, false);
174      auto surfaceNode = node->leashWinSurfaceNode_ ? node->leashWinSurfaceNode_ : node->surfaceNode_;
175      if (!node->GetWindowProperty()->IsAnimateWindow()) {
176          TransformSurfaceNode(surfaceNode, recoverTrans);
177      }
178  }
179  
UpdateZoomTranslateInfo(sptr<WindowNodeContainer> windowNodeContainer,DisplayId displayId,int32_t & deltaX,int32_t & deltaY)180  bool DisplayZoomController::UpdateZoomTranslateInfo(sptr<WindowNodeContainer> windowNodeContainer,
181      DisplayId displayId, int32_t& deltaX, int32_t& deltaY)
182  {
183      sptr<WindowNode> deskTop = windowNodeContainer->GetDeskTopWindow();
184      if (deskTop == nullptr) {
185          WLOGFE("DisplayZoom: can't find deskTop windowNode");
186          return false;
187      }
188      Transform zoomTrans = deskTop->GetZoomTransform();
189      Rect originalRect = deskTop->GetWindowRect();
190      Rect zoomRect = originalRect;
191      if (zoomTrans != Transform::Identity()) {
192          deskTop->ComputeTransform();
193          zoomRect = WindowHelper::TransformRect(deskTop->GetWindowProperty()->GetTransformMat(), originalRect);
194      }
195      sptr<DisplayInfo> displayInfo = DisplayGroupInfo::GetInstance().GetDisplayInfo(displayId);
196      if (displayInfo == nullptr) {
197          WLOGFE("DisplayZoom: can't get displayInfo");
198          return false;
199      }
200      int32_t deltaXMax = displayInfo->GetOffsetX() - zoomRect.posX_;
201      int32_t deltaXMin = displayInfo->GetOffsetX() + displayInfo->GetWidth() - zoomRect.posX_
202          - static_cast<int32_t>(zoomRect.width_);
203      int32_t deltaYMax = displayInfo->GetOffsetY() - zoomRect.posY_;
204      int32_t deltaYMin = displayInfo->GetOffsetY() + displayInfo->GetHeight() - zoomRect.posY_
205          - static_cast<int32_t>(zoomRect.height_);
206      deltaX = MathHelper::Clamp(deltaX, deltaXMin, deltaXMax);
207      deltaY = MathHelper::Clamp(deltaY, deltaYMin, deltaYMax);
208      if (deltaX == 0 && deltaY == 0) {
209          return false;
210      }
211      zoomInfo_.translateX += deltaX;
212      zoomInfo_.translateY += deltaY;
213      return true;
214  }
215  
CalcuAnimateZoomTrans(sptr<WindowNode> node)216  Transform DisplayZoomController::CalcuAnimateZoomTrans(sptr<WindowNode> node)
217  {
218      Rect rect = node->GetWindowRect();
219      if (rect.width_ == 0 || rect.height_ == 0) {
220          return Transform::Identity();
221      }
222      Transform lastZoomTrans = CalcuZoomTransByZoomInfo(node);
223      TransformHelper::Vector3 lastPivotPos = { rect.posX_ + lastZoomTrans.pivotX_ * rect.width_,
224          rect.posY_ + lastZoomTrans.pivotY_ * rect.height_, 0 };
225      TransformHelper::Matrix4 lastWorldMat = TransformHelper::CreateTranslation(-lastPivotPos) *
226          WindowHelper::ComputeWorldTransformMat4(lastZoomTrans) *
227          TransformHelper::CreateTranslation(lastPivotPos);
228  
229      Transform animateTrans = node->GetWindowProperty()->GetTransform();
230      if (animateTrans.translateZ_ != 0.f) {
231          node->GetWindowProperty()->ClearTransformZAxisOffset(animateTrans);
232      }
233      TransformHelper::Vector3 animatePivotPos = { rect.posX_ + animateTrans.pivotX_ * rect.width_,
234          rect.posY_ + animateTrans.pivotY_ * rect.height_, 0 };
235      TransformHelper::Matrix4 animateWorldMat = TransformHelper::CreateTranslation(-animatePivotPos) *
236          WindowHelper::ComputeWorldTransformMat4(animateTrans) *
237          TransformHelper::CreateTranslation(animatePivotPos);
238  
239      TransformHelper::Matrix4 finalWorldMat = animateWorldMat * lastWorldMat;
240      Transform finalZoomTrans;
241      finalZoomTrans.pivotX_ = (0 - rect.posX_) * 1.0 / rect.width_;
242      finalZoomTrans.pivotY_ = (0 - rect.posY_) * 1.0 / rect.height_;
243      TransformHelper::Vector3 scale = finalWorldMat.GetScale();
244      TransformHelper::Vector3 translation = finalWorldMat.GetTranslation();
245      finalZoomTrans.scaleX_ = scale.x_;
246      finalZoomTrans.scaleY_ = scale.y_;
247      finalZoomTrans.translateX_ = translation.x_;
248      finalZoomTrans.translateY_ = translation.y_;
249      finalZoomTrans.translateZ_ = translation.z_;
250      finalZoomTrans.rotationX_ = animateTrans.rotationX_;
251      finalZoomTrans.rotationY_ = animateTrans.rotationY_;
252      finalZoomTrans.rotationZ_ = animateTrans.rotationZ_;
253  
254      return finalZoomTrans;
255  }
256  
CalcuZoomTransByZoomInfo(sptr<WindowNode> node)257  Transform DisplayZoomController::CalcuZoomTransByZoomInfo(sptr<WindowNode> node)
258  {
259      Transform zoomTrans;
260      Rect rect = node->GetWindowRect();
261      if (rect.width_ == 0 || rect.height_ == 0) {
262          return zoomTrans;
263      }
264      zoomTrans.pivotX_ = (zoomInfo_.pivotX - rect.posX_) * 1.0 / rect.width_;
265      zoomTrans.pivotY_ = (zoomInfo_.pivotY - rect.posY_) * 1.0 / rect.height_;
266      zoomTrans.scaleX_ = zoomTrans.scaleY_ = zoomInfo_.scale;
267      zoomTrans.translateX_ = zoomInfo_.translateX;
268      zoomTrans.translateY_ = zoomInfo_.translateY;
269      return zoomTrans;
270  }
271  
CalcuZoomTrans(sptr<WindowNode> node,const DisplayZoomInfo & zoomInfo)272  Transform DisplayZoomController::CalcuZoomTrans(sptr<WindowNode> node, const DisplayZoomInfo& zoomInfo)
273  {
274      Rect rect = node->GetWindowRect();
275      if (rect.width_ == 0 || rect.height_ == 0) {
276          return Transform::Identity();
277      }
278      Transform lastZoomTrans = node->GetZoomTransform();
279      TransformHelper::Vector3 lastPivotPos = { rect.posX_ + lastZoomTrans.pivotX_ * rect.width_,
280          rect.posY_ + lastZoomTrans.pivotY_ * rect.height_, 0 };
281      TransformHelper::Matrix4 lastWorldMat = TransformHelper::CreateTranslation(-lastPivotPos) *
282          WindowHelper::ComputeWorldTransformMat4(lastZoomTrans) *
283          TransformHelper::CreateTranslation(lastPivotPos);
284  
285      Transform zoomTrans;
286      zoomTrans.scaleX_ = zoomTrans.scaleY_ = zoomInfo.scale;
287      zoomTrans.translateX_ = zoomInfo.translateX;
288      zoomTrans.translateY_ = zoomInfo.translateY;
289      TransformHelper::Vector3 pivotPos = { zoomInfo.pivotX, zoomInfo.pivotY, 0 };
290      TransformHelper::Matrix4 worldMat = TransformHelper::CreateTranslation(-pivotPos) *
291          WindowHelper::ComputeWorldTransformMat4(zoomTrans) *
292          TransformHelper::CreateTranslation(pivotPos);
293  
294      TransformHelper::Matrix4 finalWorldMat = lastWorldMat * worldMat;
295      Transform finalZoomTrans;
296      finalZoomTrans.pivotX_ = (0 - rect.posX_) * 1.0 / rect.width_;
297      finalZoomTrans.pivotY_ = (0 - rect.posY_) * 1.0 / rect.height_;
298      TransformHelper::Vector3 scale = finalWorldMat.GetScale();
299      TransformHelper::Vector3 translation = finalWorldMat.GetTranslation();
300      finalZoomTrans.scaleX_ = scale.x_;
301      finalZoomTrans.scaleY_ = scale.y_;
302      finalZoomTrans.translateX_ = translation.x_;
303      finalZoomTrans.translateY_ = translation.y_;
304  
305      return finalZoomTrans;
306  }
307  
UpdateClientAndSurfaceZoomInfo(sptr<WindowNode> node,const Transform & zoomTrans)308  void DisplayZoomController::UpdateClientAndSurfaceZoomInfo(sptr<WindowNode> node, const Transform& zoomTrans)
309  {
310      node->UpdateZoomTransform(zoomTrans, true);
311      auto surfaceNode = node->leashWinSurfaceNode_ ? node->leashWinSurfaceNode_ : node->surfaceNode_;
312      if (!node->GetWindowProperty()->IsAnimateWindow()) {
313          TransformSurfaceNode(surfaceNode, zoomTrans);
314      }
315      WLOGFD("%{public}s zoomTrans, pivotX:%{public}f, pivotY:%{public}f, scaleX:%{public}f, scaleY:%{public}f"
316          ", transX:%{public}f, transY:%{public}f, transZ:%{public}f, rotateX:%{public}f, rotateY:%{public}f "
317          "rotateZ:%{public}f", node->GetWindowName().c_str(), zoomTrans.pivotX_, zoomTrans.pivotY_, zoomTrans.scaleX_,
318          zoomTrans.scaleY_, zoomTrans.translateX_, zoomTrans.translateY_, zoomTrans.translateZ_, zoomTrans.rotationX_,
319          zoomTrans.rotationY_, zoomTrans.rotationZ_);
320  }
321  
HandleUpdateWindowZoomInfo(sptr<WindowNode> node)322  void DisplayZoomController::HandleUpdateWindowZoomInfo(sptr<WindowNode> node)
323  {
324      if (displayZoomWindowTypeSkipped_.find(node->GetWindowProperty()->GetWindowType()) !=
325          displayZoomWindowTypeSkipped_.end()) {
326          return;
327      }
328      Transform zoomTrans;
329      if (node->GetWindowProperty()->IsAnimateWindow()) {
330          zoomTrans = CalcuAnimateZoomTrans(node);
331      } else {
332          zoomTrans = CalcuZoomTransByZoomInfo(node);
333      }
334      UpdateClientAndSurfaceZoomInfo(node, zoomTrans);
335  }
336  
TransformSurfaceNode(std::shared_ptr<RSSurfaceNode> surfaceNode,const Transform & trans)337  void DisplayZoomController::TransformSurfaceNode(std::shared_ptr<RSSurfaceNode> surfaceNode, const Transform& trans)
338  {
339      if (surfaceNode == nullptr) {
340          return;
341      }
342      surfaceNode->SetPivotX(trans.pivotX_);
343      surfaceNode->SetPivotY(trans.pivotY_);
344      surfaceNode->SetScaleX(trans.scaleX_);
345      surfaceNode->SetScaleY(trans.scaleY_);
346      surfaceNode->SetTranslateX(trans.translateX_);
347      surfaceNode->SetTranslateY(trans.translateY_);
348      surfaceNode->SetTranslateZ(trans.translateZ_);
349      surfaceNode->SetRotationX(trans.rotationX_);
350      surfaceNode->SetRotationY(trans.rotationY_);
351      surfaceNode->SetRotation(trans.rotationZ_);
352  }
353  }