1 /*
2  * Copyright (c) 2024 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 "animation/rs_cubic_bezier_interpolator.h"
17 
18 namespace OHOS {
19 namespace Rosen {
20 namespace {
GetCubicBezierValue(const float time,const float ctl1,const float ctl2)21 inline float GetCubicBezierValue(const float time, const float ctl1, const float ctl2)
22 {
23     if (time < 0.0f) {
24         return 0.0f;
25     }
26     if (time > 1.0f) {
27         return 1.0f;
28     }
29     constexpr static int three = 3.0;
30     const float oneMinusTime = 1.0f - time;
31     return three * oneMinusTime * oneMinusTime * time * ctl1 + three * oneMinusTime * time * time * ctl2 +
32            time * time * time;
33 }
34 } // namespace
35 
RSCubicBezierInterpolator(float ctlX1,float ctlY1,float ctlX2,float ctlY2)36 RSCubicBezierInterpolator::RSCubicBezierInterpolator(float ctlX1, float ctlY1, float ctlX2, float ctlY2)
37     : controlX1_(ctlX1), controlY1_(ctlY1), controlX2_(ctlX2), controlY2_(ctlY2)
38 {}
39 
RSCubicBezierInterpolator(uint64_t id,float ctlX1,float ctlY1,float ctlX2,float ctlY2)40 RSCubicBezierInterpolator::RSCubicBezierInterpolator(uint64_t id, float ctlX1, float ctlY1, float ctlX2, float ctlY2)
41     : RSInterpolator(id), controlX1_(ctlX1), controlY1_(ctlY1), controlX2_(ctlX2), controlY2_(ctlY2)
42 {}
43 
InterpolateImpl(float input) const44 float RSCubicBezierInterpolator::InterpolateImpl(float input) const
45 {
46     constexpr float ONE = 1.0f;
47     if (ROSEN_EQ(input, ONE, 1e-6f)) {
48         return ONE;
49     }
50     return GetCubicBezierValue(SEARCH_STEP * BinarySearch(input), controlY1_, controlY2_);
51 }
52 
Marshalling(Parcel & parcel) const53 bool RSCubicBezierInterpolator::Marshalling(Parcel& parcel) const
54 {
55     if (!parcel.WriteUint16(InterpolatorType::CUBIC_BEZIER)) {
56         return false;
57     }
58     if (!parcel.WriteUint64(id_)) {
59         return false;
60     }
61     if (!(parcel.WriteFloat(controlX1_) && parcel.WriteFloat(controlY1_) && parcel.WriteFloat(controlX2_) &&
62             parcel.WriteFloat(controlY2_))) {
63         return false;
64     }
65     return true;
66 }
67 
Unmarshalling(Parcel & parcel)68 RSCubicBezierInterpolator* RSCubicBezierInterpolator::Unmarshalling(Parcel& parcel)
69 {
70     auto id = parcel.ReadUint64();
71     if (id == 0) {
72         return nullptr;
73     }
74     float x1 = 0;
75     float y1 = 0;
76     float x2 = 0;
77     float y2 = 0;
78     if (!(parcel.ReadFloat(x1) && parcel.ReadFloat(y1) && parcel.ReadFloat(x2) && parcel.ReadFloat(y2))) {
79         return nullptr;
80     }
81     return new RSCubicBezierInterpolator(id, x1, y1, x2, y2);
82 }
83 
BinarySearch(float key) const84 int RSCubicBezierInterpolator::BinarySearch(float key) const
85 {
86     int low = 0;
87     int high = MAX_RESOLUTION;
88     int middle = 0;
89     float approximation = 0.0;
90     constexpr float epsilon = 1e-6f;
91     while (low <= high) {
92         middle = (static_cast<unsigned int>(low + high)) >> 1;
93         approximation = GetCubicBezierValue(SEARCH_STEP * middle, controlX1_, controlX2_);
94         if (ROSEN_EQ(approximation, key, epsilon)) {
95             // Early exit if the key is found within an acceptable error range
96             return middle;
97         } else if (approximation < key) {
98             low = middle + 1;
99         } else {
100             high = middle - 1;
101         }
102     }
103     return low;
104 }
105 } // namespace Rosen
106 } // namespace OHOS
107