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 "common/rs_common_def.h"
17 #include "common/rs_optional_trace.h"
18 #include "platform/common/rs_log.h"
19 #include "render/rs_attraction_effect_filter.h"
20 #include "src/core/SkOpts.h"
21 #include "utils/point.h"
22 
23 namespace OHOS {
24 namespace Rosen {
RSAttractionEffectFilter(float attractionFraction)25 RSAttractionEffectFilter::RSAttractionEffectFilter(float attractionFraction)
26     : RSDrawingFilterOriginal(nullptr), attractionFraction_(attractionFraction)
27 {
28     type_ = FilterType::ATTRACTION_EFFECT;
29 
30     hash_ = SkOpts::hash(&type_, sizeof(type_), 0);
31     hash_ = SkOpts::hash(&attractionFraction_, sizeof(attractionFraction_), hash_);
32 }
33 
34 RSAttractionEffectFilter::~RSAttractionEffectFilter() = default;
35 
GetDescription()36 std::string RSAttractionEffectFilter::GetDescription()
37 {
38     return "RSAttractionEffectFilter " +  std::to_string(attractionFraction_);
39 }
40 
IsValid() const41 bool RSAttractionEffectFilter::IsValid() const
42 {
43     constexpr float epsilon = 0.001f;
44     return attractionFraction_ > epsilon;
45 }
46 
GetAttractionFraction() const47 float RSAttractionEffectFilter::GetAttractionFraction() const
48 {
49     return attractionFraction_;
50 }
51 
GetAttractionDirtyRegion() const52 RectI RSAttractionEffectFilter::GetAttractionDirtyRegion() const
53 {
54     return attractionDirtyRegion_;
55 }
56 
IsWithinThreshold(const float left,const float right,const float threshold)57 bool RSAttractionEffectFilter::IsWithinThreshold(const float left, const float right, const float threshold)
58 {
59     return (std::abs(left - right) <= threshold);
60 }
61 
LerpPoint(const Drawing::Point & firstPoint,const Drawing::Point & secondPoint,float firstFactor,float secondFactor)62 Drawing::Point RSAttractionEffectFilter::LerpPoint(const Drawing::Point &firstPoint, const Drawing::Point &secondPoint,
63     float firstFactor, float secondFactor)
64 {
65     Drawing::Point p = { 0.0f, 0.0f };
66     p = firstFactor * firstPoint + secondFactor * secondPoint;
67     return p;
68 }
69 
CubicBezier(const Drawing::Point & p0,const Drawing::Point & p1,const Drawing::Point & p2,const Drawing::Point & p3,float t)70 Drawing::Point RSAttractionEffectFilter::CubicBezier(const Drawing::Point &p0, const Drawing::Point &p1,
71     const Drawing::Point &p2, const Drawing::Point &p3, float t)
72 {
73     // p(t) = (1 - t)^3 * p0 + 3 * t * (1 - t)^2 * p1 + 3 * t^2 * (1-t) * p2 + t^3 * p3
74     float tSquared = t * t;
75     float tCubed = t * t * t;
76     float u = 1 - t;
77     float uSquared = u * u;
78     float uCubed = u * u * u;
79 
80     Drawing::Point p = { 0.0f, 0.0f };
81     float besselCoefficient = 3.0f;
82     p = p0 * uCubed + p1 * besselCoefficient * uSquared * t + p2 * besselCoefficient * u * tSquared + p3 * tCubed;
83     return p;
84 }
85 
CalculateCubic(float p1,float p2,float t)86 float RSAttractionEffectFilter::CalculateCubic(float p1, float p2, float t)
87 {
88     // p(t) = 3 * t * (1 - t)^2 * p1 + 3 * t^2 * (1-t) * p2 + t^3
89     return 3.0f * p1 * (1.0f - t) * (1.0f - t) * t + 3.0f * p2 * (1.0f - t) * t * t + t * t * t;
90 }
91 
BinarySearch(float targetX,const Drawing::Point & p1,const Drawing::Point & p2)92 float RSAttractionEffectFilter::BinarySearch(float targetX, const Drawing::Point &p1, const Drawing::Point &p2)
93 {
94     float start = 0.0f;
95     float end = 1.0f;
96     float midPoint = 0.0f;
97     int maxIterCount = 100;
98     int currentIter = 0;
99     while (currentIter < maxIterCount) {
100         midPoint = (start + end) / 2.0f;
101         float estimate = CalculateCubic(p1.GetX(), p2.GetX(), midPoint);
102         if (IsWithinThreshold(targetX, estimate, 0.001f)) {
103             return CalculateCubic(p1.GetY(), p2.GetY(), midPoint);
104         }
105         if (estimate < targetX) {
106             start = midPoint;
107         } else {
108             end = midPoint;
109         }
110         currentIter++;
111     }
112     return CalculateCubic(p1.GetY(), p2.GetY(), midPoint);
113 }
114 
CalculateCubicsCtrlPointOffset(const std::vector<Drawing::Point> controlPointOfVertex)115 std::vector<Drawing::Point> RSAttractionEffectFilter::CalculateCubicsCtrlPointOffset(
116     const std::vector<Drawing::Point> controlPointOfVertex)
117 {
118     std::vector<Drawing::Point> pathList;
119     Drawing::Point topLeft = controlPointOfVertex[0];
120     Drawing::Point topRight = controlPointOfVertex[1];
121     Drawing::Point bottomLeft = controlPointOfVertex[2];
122     Drawing::Point bottomRight = controlPointOfVertex[3];
123 
124     // The two numbers represent the weights of the two points
125     const float firstPointWeight = 0.33f;
126     const float secondPointWeight = 0.67f;
127     pathList.push_back(topLeft);                                                                 // 0:top left
128     pathList.push_back(LerpPoint(topLeft, topRight, secondPointWeight, firstPointWeight));       // 1:top one third
129     pathList.push_back(LerpPoint(topLeft, topRight, firstPointWeight, secondPointWeight));       // 2:top two thirds
130     pathList.push_back(topRight);                                                                // 3:top right
131     pathList.push_back(LerpPoint(topRight, bottomRight, secondPointWeight, firstPointWeight));   // 4:right one third
132     pathList.push_back(LerpPoint(topRight, bottomRight, firstPointWeight, secondPointWeight));   // 5:right two thirds
133     pathList.push_back(bottomRight);                                                             // 6:bottom right
134     pathList.push_back(LerpPoint(bottomLeft, bottomRight, firstPointWeight, secondPointWeight)); // 7:bottom two thirds
135     pathList.push_back(LerpPoint(bottomLeft, bottomRight, secondPointWeight, firstPointWeight)); // 8:bottom one third
136     pathList.push_back(bottomLeft);                                                              // 9:bottom left
137     pathList.push_back(LerpPoint(topLeft, bottomLeft, firstPointWeight, secondPointWeight));     // 10:left two thirds
138     pathList.push_back(LerpPoint(topLeft, bottomLeft, secondPointWeight, firstPointWeight));     // 11:left one third
139     return pathList;
140 }
141 
CreateIndexSequence(int direction)142 std::vector<int> RSAttractionEffectFilter::CreateIndexSequence(int direction)
143 {
144     // Select the parameter index of the window control point according to the window position.
145     // 0 to 11 indicate the index of the window control point, which is rotated clockwise.
146     if (!isBelowTarget_) {
147         return direction == 1 ?
148             std::vector<int>{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 } :
149             std::vector<int>{ 3, 2, 1, 0, 11, 10, 9, 8, 7, 6, 5, 4 };
150     } else {
151         return direction == 1 ?
152             std::vector<int>{ 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8 } :
153             std::vector<int>{ 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
154     }
155 }
156 
CalculateCubicsCtrlPoint(std::vector<Drawing::Point> controlPointOfVertex,const Drawing::Point points[],int direction,bool isFirstCtrl)157 std::vector<Drawing::Point> RSAttractionEffectFilter::CalculateCubicsCtrlPoint(
158     std::vector<Drawing::Point> controlPointOfVertex,
159     const Drawing::Point points[],          // Array instead of vector
160     int direction,                         // Determine whether the flag on the left or right is used.
161     bool isFirstCtrl)
162 {
163     std::vector<Drawing::Point> pathList = CalculateCubicsCtrlPointOffset(controlPointOfVertex);
164 
165     std::vector<int> indice = CreateIndexSequence(direction);
166     std::vector<Drawing::Point> pathCtrlPointList(POINT_NUM, Drawing::Point(0.0f, 0.0f));
167 
168     for (int i = 0; i < POINT_NUM; i++) {
169         int index = indice[i];
170         if (!isBelowTarget_) {
171             pathCtrlPointList[i] = pathList[index] +  (isFirstCtrl ? points[i] : points[0]);
172             continue;
173         }
174 
175         float px = isFirstCtrl ? points[i].GetX() : points[0].GetX();
176         float py = isFirstCtrl ? points[i].GetY() : points[0].GetY();
177 
178         if (direction == 1) {
179             px = -px;
180             pathCtrlPointList[i] = { -(pathList[index].GetY() +  px), pathList[index].GetX() +  py };
181         } else {
182             py = -py;
183             pathCtrlPointList[i] = { pathList[index].GetY() +  px, -(pathList[index].GetX() +  py) };
184         }
185     }
186     return pathCtrlPointList;
187 }
188 
CalculateBezierVelList(const std::vector<Drawing::Point> & velocityList,std::vector<Drawing::Point> & velocityCtrl,int direction)189 void RSAttractionEffectFilter::CalculateBezierVelList(const std::vector<Drawing::Point> &velocityList,
190     std::vector<Drawing::Point> &velocityCtrl, int direction)
191 {
192     std::vector<Drawing::Point> curveVelList;
193     Drawing::Point topVelocity = velocityList[0];
194     Drawing::Point bottomVelocity = velocityList[1];
195 
196     // The two numbers represent the weights of the two points
197     // Weights are obtained through regression of a large amount of data.
198     const float lerpPointWeight1 = 0.17f;
199     const float lerpPointWeight2 = 0.33f;
200     const float lerpPointWeight3 = 0.5f;
201     const float lerpPointWeight4 = 0.67f;
202     const float lerpPointWeight5 = 0.83f;
203     const float lerpPointWeight6 = 0.57f;
204 
205     curveVelList.push_back(LerpPoint(topVelocity, bottomVelocity, lerpPointWeight3, lerpPointWeight3));
206     curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, lerpPointWeight2, lerpPointWeight4));
207     curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, lerpPointWeight1, lerpPointWeight5));
208     curveVelList.push_back(topVelocity);
209     // The window is located below the dock bar and uses additional parameters.
210     if (isBelowTarget_) {
211         curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, lerpPointWeight1, lerpPointWeight4));
212         curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, lerpPointWeight2, lerpPointWeight6));
213     } else {
214         curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, lerpPointWeight1, lerpPointWeight5));
215         curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, lerpPointWeight2, lerpPointWeight4));
216     }
217     curveVelList.push_back(LerpPoint(topVelocity, bottomVelocity, lerpPointWeight3, lerpPointWeight3));
218     curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, lerpPointWeight4, lerpPointWeight2));
219     curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, lerpPointWeight5, lerpPointWeight1));
220     curveVelList.push_back(bottomVelocity);
221     curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, lerpPointWeight5, lerpPointWeight1));
222     curveVelList.push_back(LerpPoint(bottomVelocity, topVelocity, lerpPointWeight4, lerpPointWeight2));
223     std::vector<int> indice = CreateIndexSequence(direction);
224 
225     for (int i = 0; i < POINT_NUM; i++) {
226         int index = indice[i];
227         velocityCtrl[i] = curveVelList[index];
228     }
229 }
230 
InitWindowInitCtrlPoints()231 void RSAttractionEffectFilter::InitWindowInitCtrlPoints()
232 {
233     // Find the third division point
234     float third = 1.0f / 3.0f;
235     float twoThirds = 2.0f / 3.0f;
236     float widthOneThird = canvasWidth_ * third;
237     float widthTwoThirds = canvasWidth_ * twoThirds;
238     float heightOneThird = canvasHeight_ * third;
239     float heightTwoThirds = canvasHeight_ * twoThirds;
240 
241     windowCtrlPoints_[TOP_LEFT_INDEX] = { 0.0f, 0.0f };
242     windowCtrlPoints_[TOP_ONE_THIRD] = { widthOneThird, 0.0f };
243     windowCtrlPoints_[TOP_TWO_THIRDS] = { widthTwoThirds, 0.0f };
244     windowCtrlPoints_[TOP_RIGHT_INDEX] = { canvasWidth_, 0.0f };
245     windowCtrlPoints_[RIGHT_ONE_THIRD] = { canvasWidth_, heightOneThird };
246     windowCtrlPoints_[RIGHT_TWO_THIRDS] = { canvasWidth_, heightTwoThirds };
247     windowCtrlPoints_[BOTTOM_RIGHT_INDEX] = { canvasWidth_, canvasHeight_ };
248     windowCtrlPoints_[BOTTOM_TWO_THIRDS] = { widthTwoThirds, canvasHeight_ };
249     windowCtrlPoints_[BOTTOM_ONE_THIRD] = { widthOneThird, canvasHeight_ };
250     windowCtrlPoints_[BOTTOM_LEFT_INDEX] = { 0.0f, canvasHeight_ };
251     windowCtrlPoints_[LEFT_TWO_THIRDS] = { 0.0f, heightTwoThirds };
252     windowCtrlPoints_[LEFT_ONE_THIRD] = { 0.0f, heightOneThird };
253 }
254 
CalculateDeltaXAndDeltaY(const Drawing::Point & pointDst,float & deltaX,float & deltaY,int direction)255 void RSAttractionEffectFilter::CalculateDeltaXAndDeltaY(const Drawing::Point &pointDst, float &deltaX, float &deltaY,
256     int direction)
257 {
258     Drawing::Point windowCenter = { 0.5 * canvasWidth_, canvasHeight_ };
259     if (windowCenter.GetY() > pointDst.GetY()) {
260         if (direction == 1) {
261             deltaX = std::abs((windowCtrlPoints_[TOP_LEFT_INDEX].GetY() + windowCtrlPoints_[BOTTOM_LEFT_INDEX].GetY()) /
262                 2.0f - pointDst.GetY());
263             deltaY = std::abs(windowCtrlPoints_[TOP_LEFT_INDEX].GetX() - pointDst.GetX());
264         } else {
265             deltaX = std::abs(
266                 (windowCtrlPoints_[TOP_RIGHT_INDEX].GetY() + windowCtrlPoints_[BOTTOM_RIGHT_INDEX].GetY()) / 2.0f -
267                 pointDst.GetY());
268             deltaY = std::abs(windowCtrlPoints_[TOP_RIGHT_INDEX].GetX() - pointDst.GetX());
269         }
270     } else {
271         deltaX = std::abs(windowCenter.GetX() - pointDst.GetX());
272         deltaY = std::abs(windowCenter.GetY() - pointDst.GetY());
273     }
274 }
275 
CalculateUpperCtrlPointOfVertex(float deltaX,float deltaY,float width,float height,int direction)276 std::vector<Drawing::Point> RSAttractionEffectFilter::CalculateUpperCtrlPointOfVertex(float deltaX, float deltaY,
277     float width, float height, int direction)
278 {
279     // Different regression parameters are used for different scenarios
280     // The window is located below the dock bar. Parameters with greater distortion are used.
281     // Coordinates of the upper control point of the curve:(k1 * width + k2 * deltaX, k3 * height + k4 * deltaY)
282     Drawing::Point topLeft = isBelowTarget_ ?
283         Drawing::Point((0.016f * width - 0.08f * deltaX) * direction, 0.464f * height + 0.40f * deltaY) :
284         Drawing::Point((-0.100f * width - 0.008f * deltaX) * direction, 0.008f * height + 0.085f * deltaY);
285     Drawing::Point bottomLeft = isBelowTarget_ ?
286         Drawing::Point((-0.15f * width - 0.075f * deltaX) * direction, 0.0f * height + 0.2f * deltaY) :
287         Drawing::Point((-0.008f * width - 0.008f * deltaX) * direction, 0.0f * height - 0.008f * deltaY);
288     Drawing::Point topRight = { (-1.147f * width - 0.016f * deltaX) * direction, -0.187f * height + 0.30f * deltaY };
289     Drawing::Point bottomRight = { (-0.84f * width - 0.2f * deltaX) * direction, -0.859f * height - 0.2f * deltaY };
290     std::vector<Drawing::Point> upperControlPoint = { topLeft, topRight, bottomLeft, bottomRight };
291     return upperControlPoint;
292 }
293 
CalculateLowerCtrlPointOfVertex(float deltaX,float deltaY,float width,float height,int direction)294 std::vector<Drawing::Point> RSAttractionEffectFilter::CalculateLowerCtrlPointOfVertex(float deltaX, float deltaY,
295     float width, float height, int direction)
296 {
297     float inverseWidth = (width >= 1.0f) ? (1.0f / width) : 1.0f;
298     // Different regression parameters are used for different scenarios
299     // The window is located below the dock bar. Parameters with greater distortion are used.
300     // Coordinates of the lower control point of the curve:(m1*(deltaX * height/width - width)), m2 * deltaY)
301     Drawing::Point topLeft = isBelowTarget_ ?
302         Drawing::Point((0.300f * (deltaX * height * inverseWidth - width)) * direction, -0.20f * deltaY) :
303         Drawing::Point((0.131f * (deltaX * height * inverseWidth - width)) * direction, -0.20f * deltaY);
304     Drawing::Point topRight = isBelowTarget_ ?
305         Drawing::Point((0.450f * (deltaX * height * inverseWidth - width)) * direction, -0.30f * deltaY) :
306         Drawing::Point((0.147f * (deltaX * height * inverseWidth - width)) * direction, -0.30f * deltaY);
307     Drawing::Point bottomLeft = isBelowTarget_ ?
308         Drawing::Point((0.150f * (deltaX * height * inverseWidth - width)) * direction, -0.20f * deltaY) :
309         Drawing::Point((0.085f * (deltaX * height * inverseWidth - width)) * direction, 0.008f * deltaY);
310     Drawing::Point bottomRight = isBelowTarget_ ?
311         Drawing::Point((0.300f * (deltaX * height * inverseWidth - width)) * direction, -0.112f * deltaY) :
312         Drawing::Point((0.147f * (deltaX * height * inverseWidth - width)) * direction, -0.069f * deltaY);
313     std::vector<Drawing::Point> lowerControlPoint = { topLeft, topRight, bottomLeft, bottomRight };
314     return lowerControlPoint;
315 }
316 
CalculateVelocityCtrlPointUpper(std::vector<Drawing::Point> & velocityCtrlPointUpper)317 void RSAttractionEffectFilter::CalculateVelocityCtrlPointUpper(std::vector<Drawing::Point>& velocityCtrlPointUpper)
318 {
319     // Cubic Bezier curve with two control points
320     Drawing::Point topVelFirst = { 0.50f, 0.0f };
321     // Use faster speed when the lower edge of the window is above the dock bar
322     Drawing::Point bottomVelFirst = isBelowTarget_ ? Drawing::Point(0.2f, 0.0f) : Drawing::Point(0.0f, 0.0f);
323     velocityCtrlPointUpper.push_back(topVelFirst);
324     velocityCtrlPointUpper.push_back(bottomVelFirst);
325 }
326 
CalculateVelocityCtrlPointLower(std::vector<Drawing::Point> & velocityCtrlPointLower)327 void RSAttractionEffectFilter::CalculateVelocityCtrlPointLower(std::vector<Drawing::Point>& velocityCtrlPointLower)
328 {
329     // Cubic Bezier curve with two control points
330     Drawing::Point topVelSecond = { 0.50f, 1.0f };
331     // Use faster speed when the lower edge of the window is above the dock bar
332     Drawing::Point bottomVelSecond = isBelowTarget_ ? Drawing::Point(0.2f, 1.0f) : Drawing::Point(0.0f, 1.0f);
333     velocityCtrlPointLower.push_back(topVelSecond);
334     velocityCtrlPointLower.push_back(bottomVelSecond);
335 }
336 
UpdateDirtyRegion(float leftPoint,float topPonit)337 void RSAttractionEffectFilter::UpdateDirtyRegion(float leftPoint, float topPonit)
338 {
339     float dirtyRegionMinX = windowStatusPoints_[0].GetX();
340     float dirtyRegionMaxX = windowStatusPoints_[0].GetX();
341     float dirtyRegionMinY = windowStatusPoints_[0].GetY();
342     float dirtyRegionMaxY = windowStatusPoints_[0].GetY();
343 
344     ROSEN_LOGI("RSAttractionEffectFilter::UpdateDirtyRegion:%f", dirtyRegionMinX);
345     for (int i = 1; i < POINT_NUM; ++i) {
346         float x = windowStatusPoints_[i].GetX();
347         float y = windowStatusPoints_[i].GetY();
348         dirtyRegionMinX = std::min(dirtyRegionMinX, x);
349         dirtyRegionMaxX = std::max(dirtyRegionMaxX, x);
350         dirtyRegionMinY = std::min(dirtyRegionMinY, y);
351         dirtyRegionMaxY = std::max(dirtyRegionMaxY, y);
352     }
353 
354     int dirtyRegionLeftCurrent = static_cast<int>(dirtyRegionMinX + leftPoint);
355     int dirtyRegionTopCurrent = static_cast<int>(dirtyRegionMinY + topPonit);
356     int dirtyRegionRightCurrent = static_cast<int>(dirtyRegionMaxX + leftPoint);
357     int dirtyRegionBottomCurrent = static_cast<int>(dirtyRegionMaxY + topPonit);
358 
359     attractionDirtyRegion_.left_ = dirtyRegionLeftCurrent;
360     attractionDirtyRegion_.top_ = dirtyRegionTopCurrent;
361     attractionDirtyRegion_.width_ = dirtyRegionRightCurrent - dirtyRegionLeftCurrent;
362     attractionDirtyRegion_.height_ = dirtyRegionBottomCurrent - dirtyRegionTopCurrent;
363 }
364 
CalculateWindowStatus(float canvasWidth,float canvasHeight,Vector2f & destinationPoint)365 void RSAttractionEffectFilter::CalculateWindowStatus(float canvasWidth, float canvasHeight, Vector2f& destinationPoint)
366 {
367     canvasWidth_ = canvasWidth;
368     canvasHeight_ = canvasHeight;
369     InitWindowInitCtrlPoints();
370 
371     Drawing::Point pointDst[1] = { { destinationPoint.x_, destinationPoint.y_ } };
372     Drawing::Point windowBottomCenter = { 0.5 * canvasWidth_, 0.5 * canvasHeight_ };
373 
374     // 1 indicates that the window is to the right of the target point,
375     // and - 1 indicates that the window is to the left.
376     int direction = (windowBottomCenter.GetX() > pointDst[0].GetX()) ? 1 : -1;
377     // true indicates that the lower edge of the window is below the dock bar,
378     // and false indicates that the lower edge of the window is above the dock bar.
379     isBelowTarget_ = (windowBottomCenter.GetY() > pointDst[0].GetY()) ? true : false;
380 
381     float width = isBelowTarget_ ? canvasHeight_ : canvasWidth_;
382     float height = isBelowTarget_ ? canvasWidth_ : canvasHeight_;
383     float deltaX = 0.0f;
384     float deltaY = 0.0f;
385     CalculateDeltaXAndDeltaY(pointDst[0], deltaX, deltaY, direction);
386 
387     std::vector<Drawing::Point> upperControlPointOfVertex =
388         CalculateUpperCtrlPointOfVertex(deltaX, deltaY, width, height, direction);
389     std::vector<Drawing::Point> lowerControlPointOfVertex =
390         CalculateLowerCtrlPointOfVertex(deltaX, deltaY, width, height, direction);
391     std::vector<Drawing::Point> velocityCtrlPointUpper;
392     CalculateVelocityCtrlPointUpper(velocityCtrlPointUpper);
393     std::vector<Drawing::Point> velocityCtrlPointLower;
394     CalculateVelocityCtrlPointLower(velocityCtrlPointLower);
395 
396     std::vector<Drawing::Point> controlPointListFirst =
397         CalculateCubicsCtrlPoint(upperControlPointOfVertex, windowCtrlPoints_, direction, true);
398     std::vector<Drawing::Point> controlPointListSecond =
399         CalculateCubicsCtrlPoint(lowerControlPointOfVertex, pointDst, direction, false);
400 
401     std::vector<Drawing::Point> speedListsFirst(POINT_NUM, Drawing::Point(0.0f, 0.0f));
402     std::vector<Drawing::Point> speedListsSecond(POINT_NUM, Drawing::Point(0.0f, 0.0f));
403     CalculateBezierVelList(velocityCtrlPointUpper, speedListsFirst, direction);
404     CalculateBezierVelList(velocityCtrlPointLower, speedListsSecond, direction);
405 
406     for (int i = 0; i < POINT_NUM; ++i) {
407         float speed = BinarySearch(attractionFraction_, speedListsFirst[i], speedListsSecond[i]);
408         windowStatusPoints_[i] = CubicBezier(windowCtrlPoints_[i], controlPointListFirst[i], controlPointListSecond[i],
409             pointDst[0], speed);
410     }
411 }
412 
GetBrush(const std::shared_ptr<Drawing::Image> & image) const413 Drawing::Brush RSAttractionEffectFilter::GetBrush(const std::shared_ptr<Drawing::Image>& image) const
414 {
415     Drawing::Brush brush;
416     brush.SetBlendMode(Drawing::BlendMode::SRC_OVER);
417     Drawing::SamplingOptions samplingOptions;
418     Drawing::Matrix scaleMat;
419     brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
420         *image, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, samplingOptions, scaleMat));
421     return brush;
422 }
423 
DrawImageRect(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const Drawing::Rect & src,const Drawing::Rect & dst) const424 void RSAttractionEffectFilter::DrawImageRect(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
425     const Drawing::Rect& src, const Drawing::Rect& dst) const
426 {
427     if (!IsValid() || !image || image->GetWidth() == 0 || image->GetHeight() == 0) {
428         ROSEN_LOGE("RSAttractionEffectFilter::shader error");
429         return;
430     }
431     RS_OPTIONAL_TRACE_NAME_FMT("DrawAttraction:%f", attractionFraction_);
432     int width = image->GetWidth();
433     int height = image->GetHeight();
434 
435     auto brush = GetBrush(image);
436     canvas.AttachBrush(brush);
437 
438     // 4 coordinates of image texture
439     const Drawing::Point texCoords[4] = { { 0.0f, 0.0f }, { width, 0.0f }, { width, height }, { 0.0f, height } };
440 
441     canvas.DrawPatch(windowStatusPoints_, nullptr, texCoords, Drawing::BlendMode::SRC_OVER);
442     canvas.DetachBrush();
443 }
444 } // namespace Rosen
445 } // namespace OHOS