/* * Copyright (c) 2022 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 "display_zoom_controller.h" #include "display_group_info.h" #include "window_helper.h" namespace OHOS::Rosen { namespace { constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "DisplayZoomController"}; } void DisplayZoomController::SetAnchorAndScale(int32_t x, int32_t y, float scale) { WLOGFD("DisplayZoom: On, anchor x:%{public}d, y:%{public}d, scale:%{public}f", x, y, scale); if (scale <= 0) { return; } else if (zoomInfo_.scale * scale < DISPLAY_ZOOM_MIN_SCALE) { scale = DISPLAY_ZOOM_MIN_SCALE / zoomInfo_.scale; } else if (zoomInfo_.scale * scale > DISPLAY_ZOOM_MAX_SCALE) { scale = DISPLAY_ZOOM_MAX_SCALE / zoomInfo_.scale; } DisplayId displayId = DisplayGroupInfo::GetInstance().GetDefaultDisplayId(); sptr windowNodeContainer = windowRoot_->GetOrCreateWindowNodeContainer(displayId); if (windowNodeContainer == nullptr) { return; } std::vector> windowNodes; windowNodeContainer->TraverseContainer(windowNodes); bool isAlreadyCalcu = false; for (auto& node : windowNodes) { if (displayZoomWindowTypeSkipped_.find(node->GetWindowProperty()->GetWindowType()) != displayZoomWindowTypeSkipped_.end()) { continue; } Transform zoomTrans; if (!isAlreadyCalcu) { zoomTrans = CalcuZoomTrans(node, {x, y, scale, 0, 0}); zoomInfo_.scale *= scale; Rect rect = node->GetWindowRect(); zoomInfo_.pivotX = rect.posX_ + zoomTrans.pivotX_ * rect.width_; zoomInfo_.pivotY = rect.posY_ + zoomTrans.pivotY_ * rect.height_; zoomInfo_.translateX = zoomTrans.translateX_; zoomInfo_.translateY = zoomTrans.translateY_; isAlreadyCalcu = true; } else { zoomTrans = CalcuZoomTransByZoomInfo(node); } UpdateClientAndSurfaceZoomInfo(node, zoomTrans); } } void DisplayZoomController::SetAnchorOffset(int32_t deltaX, int32_t deltaY) { WLOGFD("DisplayZoom: SetAnchorOffset"); DisplayId displayId = DisplayGroupInfo::GetInstance().GetDefaultDisplayId(); sptr windowNodeContainer = windowRoot_->GetOrCreateWindowNodeContainer(displayId); if (windowNodeContainer == nullptr) { return; } if (!UpdateZoomTranslateInfo(windowNodeContainer, displayId, deltaX, deltaY)) { return; } WindowNodeOperationFunc translateFunc = [this, deltaX, deltaY](sptr node) { if (displayZoomWindowTypeSkipped_.find(node->GetWindowProperty()->GetWindowType()) != displayZoomWindowTypeSkipped_.end()) { return false; } Transform zoomTrans = node->GetZoomTransform(); zoomTrans.translateX_ += static_cast(deltaX); zoomTrans.translateY_ += static_cast(deltaY); UpdateClientAndSurfaceZoomInfo(node, zoomTrans); return false; }; windowNodeContainer->TraverseWindowTree(translateFunc, false); } void DisplayZoomController::OffWindowZoom() { WLOGFD("DisplayZoom: Off"); DisplayId displayId = DisplayGroupInfo::GetInstance().GetDefaultDisplayId(); sptr windowNodeContainer = windowRoot_->GetOrCreateWindowNodeContainer(displayId); if (windowNodeContainer == nullptr) { return; } zoomInfo_ = {0, 0, 1.0, 0, 0}; std::vector> windowNodes; windowNodeContainer->TraverseContainer(windowNodes); for (auto& node : windowNodes) { if (displayZoomWindowTypeSkipped_.find(node->GetWindowProperty()->GetWindowType()) != displayZoomWindowTypeSkipped_.end()) { continue; } ClearZoomTransformInner(node); } } void DisplayZoomController::UpdateAllWindowsZoomInfo(DisplayId displayId) { if (zoomInfo_.scale == DISPLAY_ZOOM_OFF_SCALE) { return; } DisplayId defaultDisplayId = DisplayGroupInfo::GetInstance().GetDefaultDisplayId(); if (defaultDisplayId != displayId) { return; } sptr windowNodeContainer = windowRoot_->GetOrCreateWindowNodeContainer(displayId); if (windowNodeContainer == nullptr) { return; } int32_t deltaX, deltaY; deltaX = deltaY = 0; if (UpdateZoomTranslateInfo(windowNodeContainer, displayId, deltaX, deltaY)) { WLOGFD("Change ZoomInfo translation, deltaX:%{public}d, deltaY:%{public}d", deltaX, deltaY); } std::vector> windowNodes; windowNodeContainer->TraverseContainer(windowNodes); for (auto& node: windowNodes) { HandleUpdateWindowZoomInfo(node); } } void DisplayZoomController::UpdateWindowZoomInfo(uint32_t windowId) { if (zoomInfo_.scale == DISPLAY_ZOOM_OFF_SCALE) { return; } auto node = windowRoot_->GetWindowNode(windowId); if (node == nullptr) { return; } if (!node->currentVisibility_) { return; } DisplayId displayId = DisplayGroupInfo::GetInstance().GetDefaultDisplayId(); if (node->GetDisplayId() != displayId) { return; } std::vector> windowNodes; windowNodes.push_back(node); if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) { windowNodes = windowRoot_->GetSplitScreenWindowNodes(node->GetDisplayId()); } for (auto& windowNode: windowNodes) { HandleUpdateWindowZoomInfo(windowNode); } } void DisplayZoomController::ClearZoomTransform(std::vector> nodes) { if (zoomInfo_.scale == DISPLAY_ZOOM_OFF_SCALE) { return; } for (auto& node: nodes) { ClearZoomTransformInner(node); } } void DisplayZoomController::ClearZoomTransformInner(sptr node) { Transform recoverTrans; node->UpdateZoomTransform(recoverTrans, false); auto surfaceNode = node->leashWinSurfaceNode_ ? node->leashWinSurfaceNode_ : node->surfaceNode_; if (!node->GetWindowProperty()->IsAnimateWindow()) { TransformSurfaceNode(surfaceNode, recoverTrans); } } bool DisplayZoomController::UpdateZoomTranslateInfo(sptr windowNodeContainer, DisplayId displayId, int32_t& deltaX, int32_t& deltaY) { sptr deskTop = windowNodeContainer->GetDeskTopWindow(); if (deskTop == nullptr) { WLOGFE("DisplayZoom: can't find deskTop windowNode"); return false; } Transform zoomTrans = deskTop->GetZoomTransform(); Rect originalRect = deskTop->GetWindowRect(); Rect zoomRect = originalRect; if (zoomTrans != Transform::Identity()) { deskTop->ComputeTransform(); zoomRect = WindowHelper::TransformRect(deskTop->GetWindowProperty()->GetTransformMat(), originalRect); } sptr displayInfo = DisplayGroupInfo::GetInstance().GetDisplayInfo(displayId); if (displayInfo == nullptr) { WLOGFE("DisplayZoom: can't get displayInfo"); return false; } int32_t deltaXMax = displayInfo->GetOffsetX() - zoomRect.posX_; int32_t deltaXMin = displayInfo->GetOffsetX() + displayInfo->GetWidth() - zoomRect.posX_ - static_cast(zoomRect.width_); int32_t deltaYMax = displayInfo->GetOffsetY() - zoomRect.posY_; int32_t deltaYMin = displayInfo->GetOffsetY() + displayInfo->GetHeight() - zoomRect.posY_ - static_cast(zoomRect.height_); deltaX = MathHelper::Clamp(deltaX, deltaXMin, deltaXMax); deltaY = MathHelper::Clamp(deltaY, deltaYMin, deltaYMax); if (deltaX == 0 && deltaY == 0) { return false; } zoomInfo_.translateX += deltaX; zoomInfo_.translateY += deltaY; return true; } Transform DisplayZoomController::CalcuAnimateZoomTrans(sptr node) { Rect rect = node->GetWindowRect(); if (rect.width_ == 0 || rect.height_ == 0) { return Transform::Identity(); } Transform lastZoomTrans = CalcuZoomTransByZoomInfo(node); TransformHelper::Vector3 lastPivotPos = { rect.posX_ + lastZoomTrans.pivotX_ * rect.width_, rect.posY_ + lastZoomTrans.pivotY_ * rect.height_, 0 }; TransformHelper::Matrix4 lastWorldMat = TransformHelper::CreateTranslation(-lastPivotPos) * WindowHelper::ComputeWorldTransformMat4(lastZoomTrans) * TransformHelper::CreateTranslation(lastPivotPos); Transform animateTrans = node->GetWindowProperty()->GetTransform(); if (animateTrans.translateZ_ != 0.f) { node->GetWindowProperty()->ClearTransformZAxisOffset(animateTrans); } TransformHelper::Vector3 animatePivotPos = { rect.posX_ + animateTrans.pivotX_ * rect.width_, rect.posY_ + animateTrans.pivotY_ * rect.height_, 0 }; TransformHelper::Matrix4 animateWorldMat = TransformHelper::CreateTranslation(-animatePivotPos) * WindowHelper::ComputeWorldTransformMat4(animateTrans) * TransformHelper::CreateTranslation(animatePivotPos); TransformHelper::Matrix4 finalWorldMat = animateWorldMat * lastWorldMat; Transform finalZoomTrans; finalZoomTrans.pivotX_ = (0 - rect.posX_) * 1.0 / rect.width_; finalZoomTrans.pivotY_ = (0 - rect.posY_) * 1.0 / rect.height_; TransformHelper::Vector3 scale = finalWorldMat.GetScale(); TransformHelper::Vector3 translation = finalWorldMat.GetTranslation(); finalZoomTrans.scaleX_ = scale.x_; finalZoomTrans.scaleY_ = scale.y_; finalZoomTrans.translateX_ = translation.x_; finalZoomTrans.translateY_ = translation.y_; finalZoomTrans.translateZ_ = translation.z_; finalZoomTrans.rotationX_ = animateTrans.rotationX_; finalZoomTrans.rotationY_ = animateTrans.rotationY_; finalZoomTrans.rotationZ_ = animateTrans.rotationZ_; return finalZoomTrans; } Transform DisplayZoomController::CalcuZoomTransByZoomInfo(sptr node) { Transform zoomTrans; Rect rect = node->GetWindowRect(); if (rect.width_ == 0 || rect.height_ == 0) { return zoomTrans; } zoomTrans.pivotX_ = (zoomInfo_.pivotX - rect.posX_) * 1.0 / rect.width_; zoomTrans.pivotY_ = (zoomInfo_.pivotY - rect.posY_) * 1.0 / rect.height_; zoomTrans.scaleX_ = zoomTrans.scaleY_ = zoomInfo_.scale; zoomTrans.translateX_ = zoomInfo_.translateX; zoomTrans.translateY_ = zoomInfo_.translateY; return zoomTrans; } Transform DisplayZoomController::CalcuZoomTrans(sptr node, const DisplayZoomInfo& zoomInfo) { Rect rect = node->GetWindowRect(); if (rect.width_ == 0 || rect.height_ == 0) { return Transform::Identity(); } Transform lastZoomTrans = node->GetZoomTransform(); TransformHelper::Vector3 lastPivotPos = { rect.posX_ + lastZoomTrans.pivotX_ * rect.width_, rect.posY_ + lastZoomTrans.pivotY_ * rect.height_, 0 }; TransformHelper::Matrix4 lastWorldMat = TransformHelper::CreateTranslation(-lastPivotPos) * WindowHelper::ComputeWorldTransformMat4(lastZoomTrans) * TransformHelper::CreateTranslation(lastPivotPos); Transform zoomTrans; zoomTrans.scaleX_ = zoomTrans.scaleY_ = zoomInfo.scale; zoomTrans.translateX_ = zoomInfo.translateX; zoomTrans.translateY_ = zoomInfo.translateY; TransformHelper::Vector3 pivotPos = { zoomInfo.pivotX, zoomInfo.pivotY, 0 }; TransformHelper::Matrix4 worldMat = TransformHelper::CreateTranslation(-pivotPos) * WindowHelper::ComputeWorldTransformMat4(zoomTrans) * TransformHelper::CreateTranslation(pivotPos); TransformHelper::Matrix4 finalWorldMat = lastWorldMat * worldMat; Transform finalZoomTrans; finalZoomTrans.pivotX_ = (0 - rect.posX_) * 1.0 / rect.width_; finalZoomTrans.pivotY_ = (0 - rect.posY_) * 1.0 / rect.height_; TransformHelper::Vector3 scale = finalWorldMat.GetScale(); TransformHelper::Vector3 translation = finalWorldMat.GetTranslation(); finalZoomTrans.scaleX_ = scale.x_; finalZoomTrans.scaleY_ = scale.y_; finalZoomTrans.translateX_ = translation.x_; finalZoomTrans.translateY_ = translation.y_; return finalZoomTrans; } void DisplayZoomController::UpdateClientAndSurfaceZoomInfo(sptr node, const Transform& zoomTrans) { node->UpdateZoomTransform(zoomTrans, true); auto surfaceNode = node->leashWinSurfaceNode_ ? node->leashWinSurfaceNode_ : node->surfaceNode_; if (!node->GetWindowProperty()->IsAnimateWindow()) { TransformSurfaceNode(surfaceNode, zoomTrans); } WLOGFD("%{public}s zoomTrans, pivotX:%{public}f, pivotY:%{public}f, scaleX:%{public}f, scaleY:%{public}f" ", transX:%{public}f, transY:%{public}f, transZ:%{public}f, rotateX:%{public}f, rotateY:%{public}f " "rotateZ:%{public}f", node->GetWindowName().c_str(), zoomTrans.pivotX_, zoomTrans.pivotY_, zoomTrans.scaleX_, zoomTrans.scaleY_, zoomTrans.translateX_, zoomTrans.translateY_, zoomTrans.translateZ_, zoomTrans.rotationX_, zoomTrans.rotationY_, zoomTrans.rotationZ_); } void DisplayZoomController::HandleUpdateWindowZoomInfo(sptr node) { if (displayZoomWindowTypeSkipped_.find(node->GetWindowProperty()->GetWindowType()) != displayZoomWindowTypeSkipped_.end()) { return; } Transform zoomTrans; if (node->GetWindowProperty()->IsAnimateWindow()) { zoomTrans = CalcuAnimateZoomTrans(node); } else { zoomTrans = CalcuZoomTransByZoomInfo(node); } UpdateClientAndSurfaceZoomInfo(node, zoomTrans); } void DisplayZoomController::TransformSurfaceNode(std::shared_ptr surfaceNode, const Transform& trans) { if (surfaceNode == nullptr) { return; } surfaceNode->SetPivotX(trans.pivotX_); surfaceNode->SetPivotY(trans.pivotY_); surfaceNode->SetScaleX(trans.scaleX_); surfaceNode->SetScaleY(trans.scaleY_); surfaceNode->SetTranslateX(trans.translateX_); surfaceNode->SetTranslateY(trans.translateY_); surfaceNode->SetTranslateZ(trans.translateZ_); surfaceNode->SetRotationX(trans.rotationX_); surfaceNode->SetRotationY(trans.rotationY_); surfaceNode->SetRotation(trans.rotationZ_); } }