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_spherize_effect_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 {
RSSpherizeEffectFilter(float spherizeDegree)24 RSSpherizeEffectFilter::RSSpherizeEffectFilter(float spherizeDegree)
25 : RSDrawingFilterOriginal(nullptr), spherizeDegree_(spherizeDegree)
26 {
27 type_ = FilterType::SPHERIZE_EFFECT;
28
29 hash_ = SkOpts::hash(&type_, sizeof(type_), 0);
30 hash_ = SkOpts::hash(&spherizeDegree_, sizeof(spherizeDegree_), hash_);
31 }
32
33 RSSpherizeEffectFilter::~RSSpherizeEffectFilter() = default;
34
GetDescription()35 std::string RSSpherizeEffectFilter::GetDescription()
36 {
37 return "RSSpherizeEffectFilter " + std::to_string(spherizeDegree_);
38 }
39
IsValid() const40 bool RSSpherizeEffectFilter::IsValid() const
41 {
42 constexpr float epsilon = 0.001f;
43 return spherizeDegree_ > epsilon;
44 }
45
GetSpherizeDegree() const46 float RSSpherizeEffectFilter::GetSpherizeDegree() const
47 {
48 return spherizeDegree_;
49 }
50
GetBrush(const std::shared_ptr<Drawing::Image> & image) const51 Drawing::Brush RSSpherizeEffectFilter::GetBrush(const std::shared_ptr<Drawing::Image>& image) const
52 {
53 Drawing::Brush brush;
54 brush.SetBlendMode(Drawing::BlendMode::SRC_OVER);
55 Drawing::SamplingOptions samplingOptions;
56 Drawing::Matrix scaleMat;
57 brush.SetShaderEffect(Drawing::ShaderEffect::CreateImageShader(
58 *image, Drawing::TileMode::CLAMP, Drawing::TileMode::CLAMP, samplingOptions, scaleMat));
59 return brush;
60 }
61
DrawImageRect(Drawing::Canvas & canvas,const std::shared_ptr<Drawing::Image> & image,const Drawing::Rect & src,const Drawing::Rect & dst) const62 void RSSpherizeEffectFilter::DrawImageRect(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
63 const Drawing::Rect& src, const Drawing::Rect& dst) const
64 {
65 if (!spherizeDegree_ || !image || image->GetWidth() == 0 || image->GetHeight() == 0) {
66 ROSEN_LOGE("RSSpherizeEffectFilter::shader error");
67 return;
68 }
69 RS_OPTIONAL_TRACE_NAME_FMT("DrawSpherize:%f", spherizeDegree_);
70 int width = image->GetWidth();
71 int height = image->GetHeight();
72 bool isWidthGreater = width > height;
73
74 auto brush = GetBrush(image);
75 canvas.AttachBrush(brush);
76
77 // 4 coordinates of image texture
78 const Drawing::Point texCoords[4] = { { 0.0f, 0.0f }, { width, 0.0f }, { width, height }, { 0.0f, height } };
79 float offsetSquare = 0.f;
80 if (isWidthGreater) {
81 offsetSquare = (width - height) * spherizeDegree_ / 2.0; // 2.0 express half of the change distance
82 width = width - (width - height) * spherizeDegree_;
83 } else {
84 offsetSquare = (height - width) * spherizeDegree_ / 2.0; // 2.0 express half of the change distance
85 height = height - (height - width) * spherizeDegree_;
86 }
87
88 float segmentWidthOne = width / 3.0; // Anchor point of 1 is located at one-third of the image width.
89 float segmentWidthTwo = width / 3.0 * 2.0; // Anchor point 2 is located at two-thirds of the image width.
90 float segmentHeightOne = height / 3.0; // Anchor point 1 is located at one-third of the height of the image.
91 float segmentHeightTwo = height / 3.0 * 2.0; // Anchor point 2 is located at a height of two-thirds of the image.
92 // The width moving distance of the four corner anchor points of the image.
93 float offsetSphereWidth = width / 6.0 * spherizeDegree_;
94 // The high moving distance of the four corner anchor points of the image.
95 float offsetSphereHeight = height / 6.0 * spherizeDegree_;
96
97 const int PointNum = 12; // 12 anchor points
98 Drawing::Point ctrlPoints[PointNum] = {
99 // top edge control points
100 {0.0f, 0.0f}, {segmentWidthOne, 0.0f}, {segmentWidthTwo, 0.0f}, {width, 0.0f},
101 // right edge control points
102 {width, segmentHeightOne}, {width, segmentHeightTwo},
103 // bottom edge control points
104 {width, height}, {segmentWidthTwo, height}, {segmentWidthOne, height}, {0.0f, height},
105 // left edge control points
106 {0.0f, segmentHeightTwo}, {0.0f, segmentHeightOne}
107 };
108 ctrlPoints[0].Offset(offsetSphereWidth, offsetSphereHeight); // Point 0 express top left control point
109 ctrlPoints[3].Offset(-offsetSphereWidth, offsetSphereHeight); // Point 3 express top right control point
110 ctrlPoints[6].Offset(-offsetSphereWidth, -offsetSphereHeight); // Point 6 express bottom right control point
111 ctrlPoints[9].Offset(offsetSphereWidth, -offsetSphereHeight); // Point 9 express bottom left control point
112 if (isWidthGreater) {
113 for (int i = 0; i < PointNum; ++i) {
114 ctrlPoints[i].Offset(offsetSquare, 0);
115 }
116 } else {
117 for (int i = 0; i < PointNum; ++i) {
118 ctrlPoints[i].Offset(0, offsetSquare);
119 }
120 }
121 Drawing::Path path;
122 // The zeroth point express the starting point of drawing.
123 path.MoveTo(ctrlPoints[0].GetX(), ctrlPoints[0].GetY());
124 // The 1st, 2nd, and 3rd control points are connected to represent the upper edge.
125 path.CubicTo(ctrlPoints[1], ctrlPoints[2], ctrlPoints[3]);
126 // The 4th, 5th and 6th control points are connected to represent the right edge.
127 path.CubicTo(ctrlPoints[4], ctrlPoints[5], ctrlPoints[6]);
128 // The 7th, 8th, and 9th control points are connected to represent the bottom edge.
129 path.CubicTo(ctrlPoints[7], ctrlPoints[8], ctrlPoints[9]);
130 // The 0th, 10th, and 11th control points are connected to represent the left edge.
131 path.CubicTo(ctrlPoints[10], ctrlPoints[11], ctrlPoints[0]);
132 canvas.ClipPath(path, Drawing::ClipOp::INTERSECT, true);
133 canvas.DrawPatch(ctrlPoints, nullptr, texCoords, Drawing::BlendMode::SRC_OVER);
134 canvas.DetachBrush();
135 }
136 } // namespace Rosen
137 } // namespace OHOS