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_fly_out_shader_filter.h"
16 
17 #include "common/rs_common_def.h"
18 #include "common/rs_optional_trace.h"
19 #include "platform/common/rs_log.h"
20 #include "src/core/SkOpts.h"
21 
22 namespace OHOS {
23 namespace Rosen {
24 // 0.22 means the ratio of deformation distance of the first four points a, a1, b1, b to width when fly out
25 static const float FLYOUT_DEFORM_PERCENTAGE_ONE = 0.22f;
26 // 0.19 means the ratio of deformation distance of the points a2, b2 to width when fly out
27 static const float FLYOUT_DEFORM_PERCENTAGE_TWO = 0.19f;
28 // 0.07 means the ratio of deformation distance of the points c3, c2, d3, d2 to width when fly in
29 static const float FLYIN_DEFORM_PERCENTAGE_ONE = 0.07f;
30 // 0.04 means the ratio of deformation distance of the points c3, c2, d3, d2 to height when fly in
31 static const float FLYIN_DEFORM_PERCENTAGE_HEIGHT = 0.04f;
32 // 0.21 means the ratio of deformation distance of the points e, e2, f, f2 to width when fly in
33 static const float FLYIN_DEFORM_PERCENTAGE_TWO = 0.21f;
34 static const size_t POINT_NUM = 12; // 12 anchor points of a patch
35 static const uint32_t FLY_OUT_MODE = 0;
36 static const uint32_t FLY_IN_MODE = 1;
37 
38 
RSFlyOutShaderFilter(float degree,uint32_t flyMode)39 RSFlyOutShaderFilter::RSFlyOutShaderFilter(float degree, uint32_t flyMode)
40     : RSDrawingFilterOriginal(nullptr), degree_(degree), flyMode_(flyMode)
41 {
42     type_ = FilterType::FLY_OUT;
43 
44     hash_ = SkOpts::hash(&type_, sizeof(type_), 0);
45     hash_ = SkOpts::hash(&degree_, sizeof(degree_), hash_);
46     hash_ = SkOpts::hash(&flyMode_, sizeof(flyMode_), hash_);
47 }
48 
49 
50 RSFlyOutShaderFilter::~RSFlyOutShaderFilter() = default;
51 
GetDescription()52 std::string RSFlyOutShaderFilter::GetDescription()
53 {
54     return "RSFlyOutShaderFilter " + std::to_string(degree_);
55 }
56 
GetDegree() const57 float RSFlyOutShaderFilter::GetDegree() const
58 {
59     return degree_;
60 }
61 
GetFlyMode() const62 uint32_t RSFlyOutShaderFilter::GetFlyMode() const
63 {
64     return flyMode_;
65 }
66 
GetBrush(const std::shared_ptr<Drawing::Image> & image) const67 Drawing::Brush RSFlyOutShaderFilter::GetBrush(const std::shared_ptr<Drawing::Image>& image) const
68 {
69     Drawing::Brush brush;
70     if (image == nullptr) {
71         return brush;
72     }
73     brush.SetBlendMode(Drawing::BlendMode::SRC_OVER);
74     Drawing::SamplingOptions samplingOptions;
75     Drawing::Matrix scaleMat;
76     brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
77         *image, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, samplingOptions, scaleMat));
78     return brush;
79 }
80 
CalculateDeformation(std::array<Drawing::Point,POINT_NUM> & flyUp,std::array<Drawing::Point,POINT_NUM> & flyDown,const float deformWidth,const float deformHeight) const81 void RSFlyOutShaderFilter::CalculateDeformation(std::array<Drawing::Point, POINT_NUM>& flyUp,
82     std::array<Drawing::Point, POINT_NUM>& flyDown, const float deformWidth, const float deformHeight) const
83 {
84     float flyOutOffsetOne = FLYOUT_DEFORM_PERCENTAGE_ONE * deformWidth * degree_;
85     float flyOutOffsetTwo = FLYOUT_DEFORM_PERCENTAGE_TWO * deformWidth * degree_;
86     float flyInOffsetOne = FLYIN_DEFORM_PERCENTAGE_ONE * deformWidth * (1.0 - degree_);
87     float flyInOffsetTwo = FLYIN_DEFORM_PERCENTAGE_TWO * deformWidth * (1.0 - degree_);
88     float flyInOffsetHeight = FLYIN_DEFORM_PERCENTAGE_HEIGHT * deformHeight * (1.0 - degree_);
89 
90     if (flyMode_ == FLY_OUT_MODE) {
91         // upper half part
92         flyUp[0].Offset(flyOutOffsetOne, 0);  // Point 0  is a, which is the top left control point
93         flyUp[1].Offset(flyOutOffsetOne, 0);  // Point 1  is a1 on the left one-third of the top edge
94         flyUp[2].Offset(-flyOutOffsetOne, 0); // Point 2  is b1 on the right one-third of the top edge
95         flyUp[3].Offset(-flyOutOffsetOne, 0); // Point 3  is b, which is thetop right control point
96         flyUp[4].Offset(-flyOutOffsetTwo, 0); // Point 4  is b2 on the upper one-third of the right edge
97         flyUp[11].Offset(flyOutOffsetTwo, 0); // Point 11 is a2 on the upper one-third of the left edge
98     } else if (flyMode_ == FLY_IN_MODE) {
99         // upper half part
100         flyUp[5].Offset(flyInOffsetOne, flyInOffsetHeight); // Point 5 is d2 on the upper two-thirds of the right edge
101         flyUp[10].Offset(-flyInOffsetOne, flyInOffsetHeight); // Point 10 is c2 on the upper two-thirds of left edge
102         // lower half part
103         flyDown[4].Offset(-flyInOffsetOne, -flyInOffsetHeight); // Point 4 is d3 on the lower two-thirds of right edge
104         flyDown[5].Offset(-flyInOffsetTwo, 0); // Point 5  is f2 on the lower one-third of the right edge
105         flyDown[6].Offset(-flyInOffsetTwo, 0); // Point 6  is f, which is the bottom right control point
106         flyDown[7].Offset(flyInOffsetTwo, 0);  // Point 7  is f1 on the right one-third of the bottom edge
107         flyDown[8].Offset(-flyInOffsetTwo, 0); // Point 8  is e1 on the left one-third of the bottom edge
108         flyDown[9].Offset(flyInOffsetTwo, 0);  // Point 9  is e, which is the bottom left control point
109         flyDown[10].Offset(flyInOffsetTwo, 0); // Point 10 is e2 on the lower one-third of the left edge
110         flyDown[11].Offset(flyInOffsetOne, -flyInOffsetHeight); // Point 11 is c3 on the lower two-thirds of left edge
111     }
112 }
113 
DrawImageRect(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const Drawing::Rect & src,const Drawing::Rect & dst) const114 void RSFlyOutShaderFilter::DrawImageRect(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
115     const Drawing::Rect& src, const Drawing::Rect& dst) const
116 {
117     if (image == nullptr || image->GetWidth() <= 0 || image->GetHeight() <= 0) {
118         ROSEN_LOGE("RSFlyOutShaderFilter::shader error");
119         return;
120     }
121 
122     auto brush = GetBrush(image);
123     canvas.AttachBrush(brush);
124 
125     int imageWidth = image->GetWidth();
126     int imageHeight = image->GetHeight();
127     float width = imageWidth; // the width of two deformation part
128     float height = imageHeight / 2.0; // the height of two deformation part
129     // 4 coordinates of image texture
130     const std::array<Drawing::Point, 4> texCoordsUp = {
131         Drawing::Point{ 0.0f, 0.0f }, Drawing::Point{ imageWidth, 0.0f },
132         Drawing::Point{ imageWidth, height }, Drawing::Point{ 0.0f, height } };
133     // 4 coordinates of image texture
134     const std::array<Drawing::Point, 4> texCoordsDown = {
135         Drawing::Point{ 0.0f, height }, Drawing::Point{ imageWidth, height },
136         Drawing::Point{ imageWidth, imageHeight}, Drawing::Point{ 0.0f, imageHeight } };
137 
138     // coordinates init of deformation part
139     float segmentWidthOne = width / 3.0; // Anchor point 1 is located at one-third of the width.
140     float segmentWidthTwo = width / 3.0 * 2.0; // Anchor point 2 is located at two-thirds of the width.
141     float segmentHeightOne = height / 3.0; // Anchor point 1 is located at one-third of the height.
142     float segmentHeightTwo = height / 3.0 * 2.0; // Anchor point 2 is located at two-thirds of the height.
143     std::array<Drawing::Point, POINT_NUM> flyUp = {
144         // top edge control points of upper part
145         Drawing::Point{0.0f, 0.0f}, Drawing::Point{segmentWidthOne, 0.0f},
146         Drawing::Point{segmentWidthTwo, 0.0f}, Drawing::Point{width, 0.0f},
147         // right edge control points of upper part
148         Drawing::Point{width, segmentHeightOne}, Drawing::Point{width, segmentHeightTwo},
149         // bottom edge control points of upper part
150         Drawing::Point{width, height}, Drawing::Point{segmentWidthTwo, height},
151         Drawing::Point{segmentWidthOne, height}, Drawing::Point{0.0f, height},
152         // left edge control points of upper part
153         Drawing::Point{0.0f, segmentHeightTwo}, Drawing::Point{0.0f, segmentHeightOne}
154     };
155     std::array<Drawing::Point, POINT_NUM> flyDown = {
156         // top edge control points of lower part
157         Drawing::Point{0.0f, height}, Drawing::Point{segmentWidthOne, height},
158         Drawing::Point{segmentWidthTwo, height}, Drawing::Point{width, height},
159         // right edge control points of lower part
160         Drawing::Point{width, height + segmentHeightOne}, Drawing::Point{width, height + segmentHeightTwo},
161         // bottom edge control points of lower part
162         Drawing::Point{width, imageHeight}, Drawing::Point{segmentWidthTwo, imageHeight},
163         Drawing::Point{segmentWidthOne, imageHeight}, Drawing::Point{0.0f, imageHeight},
164         // left edge control points of lower part
165         Drawing::Point{0.0f, height + segmentHeightTwo}, Drawing::Point{0.0f, height + segmentHeightOne}
166     };
167 
168     // deformation coordinate
169     CalculateDeformation(flyUp, flyDown, width, imageHeight);
170 
171     Drawing::Path path;
172     // The 0th point is the starting point of drawing.
173     path.MoveTo(flyUp[0].GetX(), flyUp[0].GetY());
174     // The 1st, 2nd, and 3rd control points are connected to represent the upper edge.
175     path.CubicTo(flyUp[1], flyUp[2], flyUp[3]);
176     // The 4th, 5th and 6th control points are connected to represent the right edge of upper part.
177     path.CubicTo(flyUp[4], flyUp[5], flyUp[6]);
178     // The 4th, 5th and 6th control points are connected to represent the right edge of lower part.
179     path.CubicTo(flyDown[4], flyDown[5], flyDown[6]);
180     // The 7th, 8th, and 9th control points are connected to represent the bottom edge.
181     path.CubicTo(flyDown[7], flyDown[8], flyDown[9]);
182     // The 0th, 10th, and 11th control points are connected to represent the left edge of lower part.
183     path.CubicTo(flyDown[10], flyDown[11], flyDown[0]);
184     // The 0th, 10th, and 11th control points are connected to represent the left edge upper part.
185     path.CubicTo(flyUp[10], flyUp[11], flyUp[0]);
186     canvas.ClipPath(path, Drawing::ClipOp::INTERSECT, true);
187     canvas.DrawPatch(flyUp.data(), nullptr, texCoordsUp.data(), Drawing::BlendMode::SRC_OVER);
188     canvas.DrawPatch(flyDown.data(), nullptr, texCoordsDown.data(), Drawing::BlendMode::SRC_OVER);
189     canvas.DetachBrush();
190 }
191 } // namespace Rosen
192 } // namespace OHOS