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