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