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