1 /*
2  * Copyright (c) 2021-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 
16 #include "core/components/transform/rosen_render_transform.h"
17 
18 #include "render_service_client/core/animation/rs_transition.h"
19 #include "render_service_client/core/ui/rs_node.h"
20 
21 namespace OHOS::Ace {
22 
Update(const RefPtr<Component> & component)23 void RosenRenderTransform::Update(const RefPtr<Component>& component)
24 {
25     RenderTransform::Update(component);
26     pendingUpdateTransformLayer_ = true;
27     MarkNeedSyncGeometryProperties();
28     if (pendingAppearingTransition_ && hasAppearTransition_) {
29         // we have a pending appearing transition
30         OnRSTransition(TransitionType::APPEARING);
31         pendingAppearingTransition_ = false;
32     }
33 }
34 
UpdateTransformLayer()35 void RosenRenderTransform::UpdateTransformLayer()
36 {
37     auto rsNode = GetRSNode();
38     if (!rsNode) {
39         return;
40     }
41 
42     if (needUpdateTransform_) {
43         UpdateTransform(); // Update transform param to Matrix.
44     }
45     SyncOriginToRsNode(rsNode);
46 
47     auto transform = UpdateWithEffectMatrix(transform_);
48     if (transform == previousTransformMatrix_ && !firstUpdateTransform_) {
49         return;
50     }
51     firstUpdateTransform_ = false;
52     SyncTransformToRsNode(rsNode, transform);
53     previousTransformMatrix_ = transform;
54 }
55 
SyncTransformToRsNode(const std::shared_ptr<RSNode> & rsNode,const Matrix4 & transformMatrix)56 void RosenRenderTransform::SyncTransformToRsNode(const std::shared_ptr<RSNode>& rsNode, const Matrix4& transformMatrix)
57 {
58     if (rsNode == nullptr) {
59         return;
60     }
61 
62     DecomposedTransform transform;
63     if (!TransformUtil::DecomposeTransform(transform, transformMatrix)) {
64         // fallback to basic matrix decompose
65         rsNode->SetTranslate(transformMatrix.Get(0, 3), transformMatrix.Get(1, 3), transformMatrix.Get(2, 3));
66         rsNode->SetScale(0);
67         return;
68     }
69 
70     // translate
71     rsNode->SetTranslate(transform.translate[0], transform.translate[1], 0.0f);
72 
73     // scale
74     rsNode->SetScale(transform.scale[0], transform.scale[1]);
75 
76     // rotation
77     rsNode->SetRotation({
78         transform.quaternion.GetX(),
79         transform.quaternion.GetY(),
80         transform.quaternion.GetZ(),
81         transform.quaternion.GetW(),
82     });
83 }
84 
SyncOriginToRsNode(const std::shared_ptr<RSNode> & rsNode)85 void RosenRenderTransform::SyncOriginToRsNode(const std::shared_ptr<RSNode>& rsNode)
86 {
87     if (!needUpdateOrigin_ || rsNode == nullptr) {
88         return;
89     }
90 
91     UpdateTransformOrigin();
92     needUpdateOrigin_ = false;
93 
94     rsNode->SetPivot(ConvertDimensionToScaleBySize(originX_, GetLayoutSize().Width()),
95         ConvertDimensionToScaleBySize(originY_, GetLayoutSize().Height()));
96 }
97 
OnAttachContext()98 void RosenRenderTransform::OnAttachContext()
99 {
100     transformAnimation_.SetContextAndCallback(context_, [weak = AceType::WeakClaim(this)]() {
101         auto renderNode = weak.Upgrade();
102         if (renderNode) {
103             renderNode->UpdateTransformLayer();
104         }
105     });
106 
107     transformEffects_.SetContextAndCallback(context_, [weak = AceType::WeakClaim(this)]() {
108         auto renderNode = weak.Upgrade();
109         if (renderNode) {
110             renderNode->needUpdateTransform_ = true;
111             renderNode->ResetTransform();
112             renderNode->UpdateTransformLayer();
113         }
114     });
115 }
116 
SyncGeometryProperties()117 void RosenRenderTransform::SyncGeometryProperties()
118 {
119     RenderNode::SyncGeometryProperties();
120     if (pendingUpdateTransformLayer_) {
121         UpdateTransformLayer();
122         pendingUpdateTransformLayer_ = false;
123     }
124 }
125 
GetTransformPoint(const Point & point)126 Point RosenRenderTransform::GetTransformPoint(const Point& point)
127 {
128     Matrix4 transform = GetEffectiveTransform(GetPosition());
129     return Matrix4::Invert(transform) * point;
130 }
131 
GetTransformRect(const Rect & rect)132 Rect RosenRenderTransform::GetTransformRect(const Rect& rect)
133 {
134     Matrix4 transform = GetEffectiveTransform(GetTransitionPaintRect().GetOffset());
135     Point ltPoint = transform * Point(rect.Left(), rect.Top());
136     Point rtPoint = transform * Point(rect.Right(), rect.Top());
137     Point lbPoint = transform * Point(rect.Left(), rect.Bottom());
138     Point rbPoint = transform * Point(rect.Right(), rect.Bottom());
139     auto left = std::min(std::min(ltPoint.GetX(), rtPoint.GetX()), std::min(lbPoint.GetX(), rbPoint.GetX()));
140     auto right = std::max(std::max(ltPoint.GetX(), rtPoint.GetX()), std::max(lbPoint.GetX(), rbPoint.GetX()));
141     auto top = std::min(std::min(ltPoint.GetY(), rtPoint.GetY()), std::min(lbPoint.GetY(), rbPoint.GetY()));
142     auto bottom = std::max(std::max(ltPoint.GetY(), rtPoint.GetY()), std::max(lbPoint.GetY(), rbPoint.GetY()));
143     return Rect(left, top, right - left, bottom - top).CombineRect(rect);
144 }
145 
GetEffectiveTransform(const Offset & offset)146 Matrix4 RosenRenderTransform::GetEffectiveTransform(const Offset& offset)
147 {
148     Matrix4 transform = GetTransformByOffset(UpdateWithEffectMatrix(transform_), origin_);
149     if (!offset.IsZero()) {
150         transform = GetTransformByOffset(transform, offset);
151     }
152     return transform;
153 }
154 
HasEffectiveTransform() const155 bool RosenRenderTransform::HasEffectiveTransform() const
156 {
157     return previousTransformMatrix_.IsIdentityMatrix();
158 }
159 
CheckNeedPaint() const160 bool RosenRenderTransform::CheckNeedPaint() const
161 {
162     double rotateX = 0.0;
163     double rotateY = 0.0;
164     double sy = sqrt(transform_[0] * transform_[0] + transform_[4] * transform_[4]);
165     if (NearZero(sy)) {
166         rotateX = atan2(-transform_[6], transform_[5]);
167         rotateY = atan2(-transform_[8], sy);
168     } else {
169         rotateX = atan2(transform_[9], transform_[10]);
170         rotateY = atan2(-transform_[8], sy);
171     }
172     rotateX = std::abs(rotateX * (180.0f / M_PI));
173     rotateY = std::abs(rotateY * (180.0f / M_PI));
174     if (NearEqual(rotateX, 90.0, 1e-5) || NearEqual(rotateY, 90.0, 1e-5)) {
175         return false; // If RotateX or RotateY is 90 deg, not need to paint.
176     }
177     return true;
178 }
179 
Mirror(const Offset & center,const Offset & global)180 void RosenRenderTransform::Mirror(const Offset& center, const Offset& global)
181 {
182     float angle = 180.0f;
183     if (!center.IsZero()) {
184         transform_ = RosenRenderTransform::GetTransformByOffset(transform_, center);
185     }
186     Matrix4 rotate = Matrix4::CreateRotate(angle, 0.0f, 1.0f, 0.0f);
187     transform_ = rotate * transform_;
188 
189     auto context = context_.Upgrade();
190     if (context) {
191         context->MarkForcedRefresh();
192     }
193 }
194 
ConvertDimensionToScaleBySize(const Dimension & dimension,double size)195 double RosenRenderTransform::ConvertDimensionToScaleBySize(const Dimension& dimension, double size)
196 {
197     if (dimension.Unit() == DimensionUnit::PERCENT) {
198         return dimension.Value();
199     }
200 
201     auto context = GetContext().Upgrade();
202     if (size <= 0. || context == nullptr) {
203         return 0.5;
204     }
205 
206     auto dipScale = context->GetDipScale();
207     return dimension.ConvertToPx(dipScale) / size;
208 }
209 
PerformLayout()210 void RosenRenderTransform::PerformLayout()
211 {
212     RenderTransform::PerformLayout();
213     if (auto rsNode = GetRSNode()) {
214         SyncOriginToRsNode(rsNode);
215     }
216 }
217 
OnRSTransition(TransitionType type)218 void RosenRenderTransform::OnRSTransition(TransitionType type)
219 {
220     if (GetRSNode() == nullptr) {
221         return;
222     }
223     std::vector<TransformOperation>* transforms;
224     bool appearing;
225     if (type == TransitionType::APPEARING && hasAppearTransition_) {
226         transforms = &transformEffectsAppearing_;
227         appearing = true;
228     } else if (type == TransitionType::DISAPPEARING && hasDisappearTransition_) {
229         transforms = &transformEffectsDisappearing_;
230         appearing = false;
231     } else {
232         return;
233     }
234 
235     auto effect = Rosen::RSTransitionEffect::Create();
236     for (auto& transform : *transforms) {
237         switch (transform.type_) {
238             case TransformOperationType::SCALE: {
239                 auto& scale = transform.scaleOperation_;
240                 effect->Scale({ scale.scaleX, scale.scaleY, scale.scaleZ });
241                 break;
242             }
243             case TransformOperationType::TRANSLATE: {
244                 auto& translate = transform.translateOperation_;
245                 effect->Translate({ translate.dx.Value(), translate.dy.Value(), translate.dz.Value() });
246                 break;
247             }
248             case TransformOperationType::ROTATE: {
249                 auto& rotate = transform.rotateOperation_;
250                 effect->Rotate({ rotate.dx, rotate.dy, rotate.dz, rotate.angle });
251                 break;
252             }
253             default: {
254                 break;
255             }
256         }
257     }
258     GetRSNode()->NotifyTransition(effect, appearing);
259 }
260 
261 } // namespace OHOS::Ace
262