1 /*
2  * Copyright (c) 2020-2021 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 "transition_impl.h"
17 #include <stdlib.h>
18 #include "ace_log.h"
19 #include "ace_mem_base.h"
20 #include "easing_equation.h"
21 #include "root_view.h"
22 #include "securec.h"
23 
24 namespace OHOS {
25 namespace ACELite {
Init()26 void TransitionImpl::Init()
27 {
28     if (animator_ != nullptr) {
29         return;
30     }
31     animator_ = new Animator(this, view_, 0, true);
32     if (animator_ == nullptr) {
33         HILOG_ERROR(HILOG_MODULE_ACE, "animator create failed");
34         return;
35     }
36 }
37 
Callback(UIView * view)38 void TransitionImpl::Callback(UIView *view)
39 {
40     (void)(view);
41     if (animator_ == nullptr) {
42         return;
43     }
44     int32_t elapsedTime = animator_->GetRunTime() - params_.delay; // animation execution time
45     if (elapsedTime <= 0) {
46         return;
47     }
48     if (elapsedTime >= params_.during) {
49         timeArrivaled_ = true;
50     }
51 
52     Perform(elapsedTime);
53 }
54 
Start()55 void TransitionImpl::Start()
56 {
57     if (animator_ == nullptr) {
58         HILOG_INFO(HILOG_MODULE_ACE, "animator not initial or has been started");
59         return;
60     }
61     uint8_t state = animator_->GetState();
62     if (((state == Animator::STOP) || (state == Animator::PAUSE)) && (params_.during > 0)) {
63         RecordViewStatus();
64         InitTransitionParams();
65         animator_->Start();
66     }
67 }
68 
Stop() const69 void TransitionImpl::Stop() const
70 {
71     if (animator_ == nullptr) {
72         HILOG_INFO(HILOG_MODULE_ACE, "animator not initial or is not running");
73         return;
74     }
75     uint8_t state = animator_->GetState();
76     if (state == Animator::START || state == Animator::RUNNING) {
77         animator_->Stop();
78     }
79 }
80 
InitTransitionParams()81 void TransitionImpl::InitTransitionParams()
82 {
83     InitTransitionParamsStyle();
84     InitTransitionParamsTransform();
85     InitTransitionParamsEasing();
86 }
87 
InitTransitionParamsStyle()88 void TransitionImpl::InitTransitionParamsStyle()
89 {
90     params_.delay = (params_.delay <= 0) ? 0 : params_.delay;
91     params_.during = (params_.during <= 0) ? 0 : params_.during;
92     oriIteration_ = params_.iterations;
93 
94     if (params_.fill == OptionsFill::FORWARDS) {
95         fill_ = OptionsFill::FORWARDS;
96     }
97 
98     if (params_.height_from >= 0 && params_.height_to >= 0) {
99         isTransitionSet_[GeneralType::IS_HEIGHT_TRANSITION_SET] = true;
100         heightSrc_ = params_.height_from;
101     }
102     if (params_.width_from >= 0 && params_.width_to >= 0) {
103         isTransitionSet_[GeneralType::IS_WIDTH_TRANSITION_SET] = true;
104         widthSrc_ = params_.width_from;
105     }
106     if (params_.opacity_from >= 0 && params_.opacity_to >= 0) {
107         isTransitionSet_[GeneralType::IS_OPACITY_TRANSITION_SET] = true;
108         opacitySrc_ = (params_.opacity_from <= OPA_OPAQUE) ? params_.opacity_from : OPA_OPAQUE;
109         params_.opacity_to = (params_.opacity_to <= OPA_OPAQUE) ? params_.opacity_to : OPA_OPAQUE;
110     }
111 
112     const uint32_t rgbValueMax = 0xFFFFFF;
113     if ((params_.background_color_from <= rgbValueMax) && (params_.background_color_to <= rgbValueMax)) {
114         isTransitionSet_[GeneralType::IS_BACKGROUND_COLOR_TRANSITION_SET] = true;
115         GetRGB(params_.background_color_from, rSrc_, gSrc_, bSrc_);
116         GetRGB(params_.background_color_to, rTo_, gTo_, bTo_);
117         steps_ = params_.during / INTERVAL;
118     }
119 }
120 
InitTransitionParamsTransform()121 void TransitionImpl::InitTransitionParamsTransform()
122 {
123     if (params_.transformType == nullptr) {
124         HILOG_INFO(HILOG_MODULE_ACE, "transformType not set");
125         return;
126     }
127     if (!strcmp(params_.transformType, TRANSITION_TRANSFORM_X)) {
128         transformType_ = TransformType::TRANSLATE_X;
129         xSrc_ = viewStatus_.x + params_.transform_from;
130     } else if (!strcmp(params_.transformType, TRANSITION_TRANSFORM_Y)) {
131         transformType_ = TransformType::TRANSLATE_Y;
132         ySrc_ = viewStatus_.y + params_.transform_from;
133     } else if (!strcmp(params_.transformType, TRANSITION_ROTATE)) {
134         transformType_ = TransformType::ROTATE;
135         rotateSrc_ = params_.transform_from;
136     }
137 }
138 
InitTransitionParamsEasing()139 void TransitionImpl::InitTransitionParamsEasing()
140 {
141     switch (params_.easing) {
142         case EasingType::EASE_IN:
143             easingType_[EasingType::EASE_IN] = true;
144             break;
145         case EasingType::EASE_OUT:
146             easingType_[EasingType::EASE_OUT] = true;
147             break;
148         case EasingType::EASE_IN_OUT:
149             easingType_[EasingType::EASE_IN_OUT] = true;
150             break;
151         default:
152             easingType_[EasingType::LINEAR] = true;
153             break;
154     }
155 }
156 
GetRGB(const uint32_t color,uint8_t & r,uint8_t & g,uint8_t & b) const157 void TransitionImpl::GetRGB(const uint32_t color, uint8_t &r, uint8_t &g, uint8_t &b) const
158 {
159     r = uint8_t((color & TEXT_RED_COLOR_MASK) >> RED_COLOR_START_BIT);
160     g = uint8_t((color & TEXT_GREEN_COLOR_MASK) >> GREEN_COLOR_START_BIT);
161     b = uint8_t((color & TEXT_BLUE_COLOR_MASK));
162 }
163 
GetNextFrameValue(int16_t from,int16_t to,int32_t elapsedTime) const164 int16_t TransitionImpl::GetNextFrameValue(int16_t from, int16_t to, int32_t elapsedTime) const
165 {
166     int16_t nextPoint;
167     if (easingType_[EasingType::EASE_IN]) {
168         nextPoint = EasingEquation::CubicEaseIn(from, to, elapsedTime, params_.during);
169     } else if (easingType_[EasingType::EASE_OUT]) {
170         nextPoint = EasingEquation::CubicEaseOut(from, to, elapsedTime, params_.during);
171     } else if (easingType_[EasingType::EASE_IN_OUT]) {
172         nextPoint = EasingEquation::CubicEaseInOut(from, to, elapsedTime, params_.during);
173     } else {
174         nextPoint = EasingEquation::LinearEaseNone(from, to, elapsedTime, params_.during);
175     }
176 
177     return nextPoint;
178 }
179 
SetTransformSrcPosition()180 void TransitionImpl::SetTransformSrcPosition()
181 {
182     if (params_.transformType == nullptr) {
183         return;
184     }
185     if (!strcmp(params_.transformType, TRANSITION_TRANSFORM_X)) {
186         view_->SetPosition(xSrc_, viewStatus_.y);
187         view_->GetParent()->Invalidate();
188     } else if (!strcmp(params_.transformType, TRANSITION_TRANSFORM_Y)) {
189         view_->SetPosition(viewStatus_.x, ySrc_);
190         view_->GetParent()->Invalidate();
191     } else if (!strcmp(params_.transformType, TRANSITION_ROTATE)) {
192         RotateAroundCenterPoint(rotateSrc_);
193     } else {
194         // do nothing
195     }
196 }
197 
RotateAroundCenterPoint(int16_t angle)198 void TransitionImpl::RotateAroundCenterPoint(int16_t angle)
199 {
200     TransformMap transMap(view_->GetOrigRect());
201     const int circleRate = 360;
202     angle = angle % circleRate;
203     float halfVal = 2.0f;
204     pivot_.x_ = (view_->GetWidth() - 1) / halfVal;
205     pivot_.y_ = (view_->GetHeight() - 1) / halfVal;
206     transMap.Rotate((angle), pivot_);
207     view_->SetTransformMap(transMap);
208 }
209 
Perform(int32_t elapsedTime)210 void TransitionImpl::Perform(int32_t elapsedTime)
211 {
212     if (timeArrivaled_) {
213         if (!RepeatAnimator()) {
214             this->Stop();
215         }
216     }
217 
218     if (!isTransformSrcSet_) {
219         SetTransformSrcPosition();
220         isTransformSrcSet_ = true;
221     }
222 
223     if (transformType_ == TransformType::TRANSLATE_X) {
224         PerformTransition(params_.transform_from, params_.transform_to, TransitionType::TTRANSLATE_X, xSrc_,
225                           elapsedTime);
226     } else if (transformType_ == TransformType::TRANSLATE_Y) {
227         PerformTransition(params_.transform_from, params_.transform_to, TransitionType::TTRANSLATE_Y, ySrc_,
228                           elapsedTime);
229     } else if (transformType_ == TransformType::ROTATE) {
230         PerformTransition(params_.transform_from, params_.transform_to, TransitionType::TROTATE, rotateSrc_,
231                           elapsedTime);
232     }
233 
234     if (isTransitionSet_[GeneralType::IS_HEIGHT_TRANSITION_SET]) {
235         PerformTransition(params_.height_from, params_.height_to, TransitionType::HEIGHT, heightSrc_, elapsedTime);
236     }
237     if (isTransitionSet_[GeneralType::IS_WIDTH_TRANSITION_SET]) {
238         PerformTransition(params_.width_from, params_.width_to, TransitionType::WIDTH, widthSrc_, elapsedTime);
239     }
240 
241     if (isTransitionSet_[GeneralType::IS_OPACITY_TRANSITION_SET]) {
242         PerformTransition(params_.opacity_from, params_.opacity_to, TransitionType::OPACITY, opacitySrc_, elapsedTime);
243     }
244 
245     if (isTransitionSet_[GeneralType::IS_BACKGROUND_COLOR_TRANSITION_SET]) {
246         PerformTransitionBgColorLinear(elapsedTime);
247     }
248 
249     if ((fill_ == OptionsFill::FNONE) && timeArrivaled_) {
250         RecoveryViewStatus(view_->GetRect());
251     }
252 
253     if (timeArrivaled_) {
254         ResetRepeatParam();
255     }
256 }
257 
PerformTransitionBgColorLinear(int32_t elapsedTime)258 void TransitionImpl::PerformTransitionBgColorLinear(int32_t elapsedTime)
259 {
260     if (timeArrivaled_) {
261         HILOG_DEBUG(HILOG_MODULE_ACE, "time arrived");
262         view_->SetStyle(STYLE_BACKGROUND_COLOR, Color::GetColorFromRGB(rTo_, gTo_, bTo_).full);
263         return;
264     }
265     if ((steps_ != 0) && (count_ <= steps_) && (elapsedTime <= params_.during)) {
266         if ((elapsedTime - bgcolorTimeSrc_) > INTERVAL) {
267             ColorType color = Color::GetColorFromRGB(rSrc_ + (rTo_ - rSrc_) * count_ / steps_,
268                                                      gSrc_ + (gTo_ - gSrc_) * count_ / steps_,
269                                                      bSrc_ + (bTo_ - bSrc_) * count_ / steps_);
270             view_->SetStyle(STYLE_BACKGROUND_COLOR, color.full);
271             view_->Invalidate();
272             bgcolorTimeSrc_ = elapsedTime;
273             count_++;
274         }
275     }
276 }
277 
PerformTransition(int16_t from,int16_t to,TransitionType transitionType,int16_t & updateAttrValue,int32_t elapsedTime)278 void TransitionImpl::PerformTransition(int16_t from,
279                                        int16_t to,
280                                        TransitionType transitionType,
281                                        int16_t &updateAttrValue,
282                                        int32_t elapsedTime)
283 {
284     if (timeArrivaled_) {
285         updateAttrValue = to;
286     } else {
287         int16_t prefetchedValue = 0;
288         prefetchedValue = GetNextFrameValue(from, to, elapsedTime);
289         int16_t diffDistance = prefetchedValue - updateAttrValue;
290         if (((diffDistance < 1) && (diffDistance > -1)) || (elapsedTime > params_.during)) {
291             return;
292         }
293         updateAttrValue = static_cast<int16_t>(prefetchedValue);
294     }
295 
296     Rect invalidatedArea = view_->GetRect();
297     switch (transitionType) {
298         case TransitionType::TTRANSLATE_X:
299             view_->SetPosition((updateAttrValue + viewStatus_.x), viewStatus_.y);
300             break;
301         case TransitionType::TTRANSLATE_Y:
302             view_->SetPosition(viewStatus_.x, (updateAttrValue + viewStatus_.y));
303             break;
304         case TransitionType::TROTATE: {
305             RotateAroundCenterPoint(updateAttrValue);
306             break;
307         }
308         case TransitionType::HEIGHT:
309             view_->SetHeight(updateAttrValue);
310             break;
311         case TransitionType::WIDTH:
312             view_->SetWidth(updateAttrValue);
313             break;
314         case TransitionType::OPACITY: {
315             double rate = (double)updateAttrValue / ALPHA_MAX;
316             view_->SetStyle(STYLE_BACKGROUND_OPA, static_cast<int64_t>(viewStatus_.rectOpacity * rate));
317             view_->SetStyle(STYLE_IMAGE_OPA, static_cast<int64_t>(viewStatus_.imageOpacity * rate));
318             view_->SetStyle(STYLE_LINE_OPA, static_cast<int64_t>(viewStatus_.lineOpacity * rate));
319             view_->SetStyle(STYLE_TEXT_OPA, static_cast<int64_t>(viewStatus_.textOpacity * rate));
320             break;
321         }
322         default:
323             HILOG_INFO(HILOG_MODULE_ACE, "animation nothing to do.");
324             break;
325     }
326 
327     invalidatedArea.Join(invalidatedArea, view_->GetRect());
328     view_->InvalidateRect(invalidatedArea);
329 }
GetNumIterations(const char * iterations)330 int8_t TransitionImpl::GetNumIterations(const char *iterations)
331 {
332     int8_t min = 1;
333     int8_t max = 127;
334     if (iterations == nullptr) {
335         return min;
336     }
337     if (!strcmp(iterations, "infinite")) {
338         return TransitionImpl::ITERATIONS_INFINITY;
339     }
340     long value = strtol(iterations, nullptr, DEC);
341     if ((value < min) || (value > max)) {
342         HILOG_ERROR(HILOG_MODULE_ACE, "animation iterations should set between 1 and 127");
343         return min;
344     }
345     return (int8_t)value;
346 }
347 
IsEndWith(const char * src,const char * end)348 bool TransitionImpl::IsEndWith(const char *src, const char *end)
349 {
350     if ((src == nullptr) || (end == nullptr)) {
351         return false;
352     }
353 
354     size_t strLen = strlen(src);
355     size_t endLen = strlen(end);
356     if ((strLen < endLen) || (strLen == 0) || (endLen == 0)) {
357         return false;
358     }
359 
360     while (endLen > 0) {
361         if (src[strLen - 1] != end[endLen - 1]) {
362             return false;
363         }
364         endLen--;
365         strLen--;
366     }
367     return true;
368 }
369 
RepeatAnimator()370 bool TransitionImpl::RepeatAnimator()
371 {
372     if (oriIteration_ != TransitionImpl::ITERATIONS_INFINITY) {
373         oriIteration_--;
374         if (oriIteration_ == 0) {
375             oriIteration_ = params_.iterations;
376             return false;
377         }
378     }
379     HILOG_DEBUG(HILOG_MODULE_ACE, "repeat");
380     return true;
381 }
382 
ResetRepeatParam()383 void TransitionImpl::ResetRepeatParam()
384 {
385     if (animator_ != nullptr) {
386         animator_->SetRunTime(0); // reset animation executing time
387     }
388     timeArrivaled_ = false; // reset timeArrivaled flag
389     bgcolorTimeSrc_ = 0;    // reset bg-color last update time
390     count_ = 1;             // reset bg-color update number of times
391 }
392 
RecordViewStatus()393 void TransitionImpl::RecordViewStatus()
394 {
395     viewStatus_.x = view_->GetX();
396     viewStatus_.y = view_->GetY();
397     viewStatus_.oriRect = view_->GetOrigRect();
398     viewStatus_.height = view_->GetHeight();
399     viewStatus_.width = view_->GetWidth();
400     viewStatus_.background_color.full = view_->GetStyle(STYLE_BACKGROUND_COLOR);
401     viewStatus_.rectOpacity = view_->GetStyle(STYLE_BACKGROUND_OPA);
402     viewStatus_.imageOpacity = view_->GetStyle(STYLE_IMAGE_OPA);
403     viewStatus_.lineOpacity = view_->GetStyle(STYLE_LINE_OPA);
404     viewStatus_.textOpacity = view_->GetStyle(STYLE_TEXT_OPA);
405 }
406 
RecoveryViewStatus(Rect invalidatedAreaBefore) const407 void TransitionImpl::RecoveryViewStatus(Rect invalidatedAreaBefore) const
408 {
409     view_->SetX(viewStatus_.x);
410     view_->SetY(viewStatus_.y);
411     view_->SetHeight(viewStatus_.height);
412     view_->SetWidth(viewStatus_.width);
413     TransformMap &transMap = view_->GetTransformMap();
414     Polygon polygon(Rect(0, 0, 0, 0));
415     transMap.SetPolygon(polygon);
416     view_->SetStyle(STYLE_BACKGROUND_COLOR, viewStatus_.background_color.full);
417     view_->SetStyle(STYLE_BACKGROUND_OPA, viewStatus_.rectOpacity);
418     view_->SetStyle(STYLE_IMAGE_OPA, viewStatus_.imageOpacity);
419     view_->SetStyle(STYLE_LINE_OPA, viewStatus_.lineOpacity);
420     view_->SetStyle(STYLE_TEXT_OPA, viewStatus_.textOpacity);
421     invalidatedAreaBefore.Join(invalidatedAreaBefore, view_->GetRect());
422     view_->InvalidateRect(invalidatedAreaBefore);
423 }
424 } // namespace ACELite
425 } // namespace OHOS
426