1 /*
2 * Copyright (c) 2021 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_material_filter.h"
16
17 #include <unordered_map>
18
19 #include "src/core/SkOpts.h"
20
21 #include "common/rs_common_def.h"
22 #include "pipeline/rs_paint_filter_canvas.h"
23 #include "property/rs_properties_painter.h"
24 #include "platform/common/rs_system_properties.h"
25
26 #if defined(NEW_SKIA)
27 #include "include/effects/SkImageFilters.h"
28 #include "include/core/SkTileMode.h"
29 #else
30 #include "include/effects/SkBlurImageFilter.h"
31 #endif
32
33 namespace OHOS {
34 namespace Rosen {
35 namespace {
36 constexpr float BLUR_SIGMA_SCALE = 0.57735f;
37 // style to MaterialParam map
38 std::unordered_map<MATERIAL_BLUR_STYLE, MaterialParam> materialParams_ {
39 // card blur params
40 { STYLE_CARD_THIN_LIGHT, { 23.0f, 1.05, 1.05, RSColor(0xFFFFFF33) } },
41 { STYLE_CARD_LIGHT, { 50.0f, 1.8, 1.2, RSColor(0xFAFAFA99) } },
42 { STYLE_CARD_THICK_LIGHT, { 57.0f, 1.2, 1.1, RSColor(0xFFFFFF8C) } },
43 { STYLE_CARD_THIN_DARK, { 75.0f, 1.35, 1.0, RSColor(0x1A1A1A6B) } },
44 { STYLE_CARD_DARK, { 50.0f, 2.15, 1.0, RSColor(0x1F1F1FD1) } },
45 { STYLE_CARD_THICK_DARK, { 75.0f, 2.15, 1.0, RSColor(0x1F1F1FD1) } },
46 // background blur params
47 { STYLE_BACKGROUND_SMALL_LIGHT, { 23.0f, 1.05, 1.0, RSColor(0x80808033) } },
48 { STYLE_BACKGROUND_MEDIUM_LIGHT, { 29.0f, 1.1, 1.0, RSColor(0x80808033) } },
49 { STYLE_BACKGROUND_LARGE_LIGHT, { 57.0f, 1.2, 1.0, RSColor(0x80808033) } },
50 { STYLE_BACKGROUND_XLARGE_LIGHT, { 120.0f, 1.3, 1.0, RSColor(0x6666664C) } },
51 { STYLE_BACKGROUND_SMALL_DARK, { 15.0f, 1.1, 1.0, RSColor(0x0D0D0D80) } },
52 { STYLE_BACKGROUND_MEDIUM_DARK, { 55.0f, 1.15, 1.0, RSColor(0x0D0D0D80) } },
53 { STYLE_BACKGROUND_LARGE_DARK, { 75.0f, 1.5, 1.0, RSColor(0x0D0D0D80) } },
54 { STYLE_BACKGROUND_XLARGE_DARK, { 130.0f, 1.3, 1.0, RSColor(0x0D0D0D80) } },
55 };
56 } // namespace
57
58 #ifndef USE_ROSEN_DRAWING
59 std::shared_ptr<KawaseBlurFilter> RSMaterialFilter::kawaseFunc_ = std::make_shared<KawaseBlurFilter>();
60 #endif
61
RSMaterialFilter(int style,float dipScale,BLUR_COLOR_MODE mode,float ratio)62 RSMaterialFilter::RSMaterialFilter(int style, float dipScale, BLUR_COLOR_MODE mode, float ratio)
63 #ifndef USE_ROSEN_DRAWING
64 : RSSkiaFilter(nullptr), colorMode_(mode)
65 #else
66 : RSDrawingFilter(nullptr), colorMode_(mode)
67 #endif
68 {
69 imageFilter_ = RSMaterialFilter::CreateMaterialStyle(static_cast<MATERIAL_BLUR_STYLE>(style), dipScale, ratio);
70 type_ = FilterType::MATERIAL;
71
72 #ifndef USE_ROSEN_DRAWING
73 hash_ = SkOpts::hash(&type_, sizeof(type_), 0);
74 hash_ = SkOpts::hash(&style, sizeof(style), hash_);
75 hash_ = SkOpts::hash(&colorMode_, sizeof(colorMode_), hash_);
76 hash_ = SkOpts::hash(&ratio, sizeof(ratio), hash_);
77 #endif
78 }
79
RSMaterialFilter(MaterialParam materialParam,BLUR_COLOR_MODE mode)80 RSMaterialFilter::RSMaterialFilter(MaterialParam materialParam, BLUR_COLOR_MODE mode)
81 #ifndef USE_ROSEN_DRAWING
82 : RSSkiaFilter(nullptr), colorMode_(mode), radius_(materialParam.radius), saturation_(materialParam.saturation),
83 #else
84 : RSDrawingFilter(nullptr), colorMode_(mode), radius_(materialParam.radius), saturation_(materialParam.saturation),
85 #endif
86 brightness_(materialParam.brightness), maskColor_(materialParam.maskColor)
87 {
88 imageFilter_ = RSMaterialFilter::CreateMaterialFilter(
89 materialParam.radius, materialParam.saturation, materialParam.brightness);
90 type_ = FilterType::MATERIAL;
91
92 #ifndef USE_ROSEN_DRAWING
93 hash_ = SkOpts::hash(&type_, sizeof(type_), 0);
94 hash_ = SkOpts::hash(&materialParam, sizeof(materialParam), hash_);
95 hash_ = SkOpts::hash(&colorMode_, sizeof(colorMode_), hash_);
96 #endif
97 }
98
99 RSMaterialFilter::~RSMaterialFilter() = default;
100
RadiusVp2Sigma(float radiusVp,float dipScale)101 float RSMaterialFilter::RadiusVp2Sigma(float radiusVp, float dipScale)
102 {
103 float radiusPx = radiusVp * dipScale;
104 #ifndef USE_ROSEN_DRAWING
105 return radiusPx > 0.0f ? BLUR_SIGMA_SCALE * radiusPx + SK_ScalarHalf : 0.0f;
106 #else
107 return radiusPx > 0.0f ? BLUR_SIGMA_SCALE * radiusPx + 0.5f : 0.0f;
108 #endif
109 }
110
GetDescription()111 std::string RSMaterialFilter::GetDescription()
112 {
113 return "RSMaterialFilter blur radius is " + std::to_string(radius_) + " sigma";
114 }
115
116 #ifndef USE_ROSEN_DRAWING
Compose(const std::shared_ptr<RSSkiaFilter> & other) const117 std::shared_ptr<RSSkiaFilter> RSMaterialFilter::Compose(const std::shared_ptr<RSSkiaFilter>& other) const
118 #else
119 std::shared_ptr<RSDrawingFilter> RSMaterialFilter::Compose(const std::shared_ptr<RSDrawingFilter>& other) const
120 #endif
121 {
122 if (other == nullptr) {
123 return nullptr;
124 }
125 MaterialParam materialParam = {radius_, saturation_, brightness_, maskColor_};
126 std::shared_ptr<RSMaterialFilter> result = std::make_shared<RSMaterialFilter>(materialParam, colorMode_);
127 #ifndef USE_ROSEN_DRAWING
128 result->imageFilter_ = SkImageFilters::Compose(imageFilter_, other->GetImageFilter());
129 auto otherHash = other->Hash();
130 result->hash_ = SkOpts::hash(&otherHash, sizeof(otherHash), hash_);
131 #else
132 result->imageFilter_ = Drawing::ImageFilter::CreateComposeImageFilter(imageFilter_, other->GetImageFilter());
133 #endif
134 return result;
135 }
136
137 #ifndef USE_ROSEN_DRAWING
GetColorFilter(float sat,float brightness)138 sk_sp<SkColorFilter> RSMaterialFilter::GetColorFilter(float sat, float brightness)
139 {
140 float normalizedDegree = brightness - 1.0;
141 const float brightnessMat[] = {
142 1.000000f, 0.000000f, 0.000000f, 0.000000f, normalizedDegree,
143 0.000000f, 1.000000f, 0.000000f, 0.000000f, normalizedDegree,
144 0.000000f, 0.000000f, 1.000000f, 0.000000f, normalizedDegree,
145 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
146 };
147
148 sk_sp<SkColorFilter> brightnessFilter = SkColorFilters::Matrix(brightnessMat); // brightness
149 SkColorMatrix cm;
150 cm.setSaturation(sat);
151 sk_sp<SkColorFilter> satFilter = SkColorFilters::Matrix(cm); // saturation
152 sk_sp<SkColorFilter> filterCompose = SkColorFilters::Compose(satFilter, brightnessFilter);
153 return filterCompose;
154 }
155
CreateMaterialFilter(float radius,float sat,float brightness)156 sk_sp<SkImageFilter> RSMaterialFilter::CreateMaterialFilter(float radius, float sat, float brightness)
157 {
158 colorFilter_ = GetColorFilter(sat, brightness);
159 #if defined(NEW_SKIA)
160 useKawase_ = RSSystemProperties::GetKawaseEnabled();
161 sk_sp<SkImageFilter> blurFilter = SkImageFilters::Blur(radius, radius, SkTileMode::kClamp, nullptr); // blur
162 #else
163 sk_sp<SkImageFilter> blurFilter = SkBlurImageFilter::Make(radius, radius, nullptr, nullptr,
164 SkBlurImageFilter::kClamp_TileMode); // blur
165 #endif
166
167 return SkImageFilters::ColorFilter(colorFilter_, blurFilter);
168 }
169 #else
CreateMaterialFilter(float radius,float sat,float brightness)170 std::shared_ptr<Drawing::ImageFilter> RSMaterialFilter::CreateMaterialFilter(float radius, float sat, float brightness)
171 {
172 std::shared_ptr<Drawing::ImageFilter> blurFilter =
173 Drawing::ImageFilter::CreateBlurImageFilter(radius, radius, Drawing::TileMode::CLAMP, nullptr);
174 float normalizedDegree = brightness - 1.0;
175 const Drawing::scalar brightnessMat[] = {
176 1.000000f, 0.000000f, 0.000000f, 0.000000f, normalizedDegree,
177 0.000000f, 1.000000f, 0.000000f, 0.000000f, normalizedDegree,
178 0.000000f, 0.000000f, 1.000000f, 0.000000f, normalizedDegree,
179 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
180 };
181
182 Drawing::ColorMatrix bm;
183 bm.SetArray(brightnessMat);
184 std::shared_ptr<Drawing::ColorFilter> brightnessFilter =
185 Drawing::ColorFilter::CreateMatrixColorFilter(bm); // brightness
186 Drawing::ColorMatrix cm;
187 cm.SetSaturation(sat);
188 std::shared_ptr<Drawing::ColorFilter> satFilter = Drawing::ColorFilter::CreateMatrixColorFilter(cm); // saturation
189 std::shared_ptr<Drawing::ColorFilter> filterCompose =
190 Drawing::ColorFilter::CreateComposeColorFilter(*brightnessFilter, *satFilter); // saturation
191
192 return Drawing::ImageFilter::CreateColorFilterImageFilter(*filterCompose, blurFilter);
193 }
194 #endif
195
196 #ifndef USE_ROSEN_DRAWING
CreateMaterialStyle(MATERIAL_BLUR_STYLE style,float dipScale,float ratio)197 sk_sp<SkImageFilter> RSMaterialFilter::CreateMaterialStyle(MATERIAL_BLUR_STYLE style, float dipScale, float ratio)
198 #else
199 std::shared_ptr<Drawing::ImageFilter> RSMaterialFilter::CreateMaterialStyle(
200 MATERIAL_BLUR_STYLE style, float dipScale, float ratio)
201 #endif
202 {
203 if (materialParams_.find(style) != materialParams_.end()) {
204 MaterialParam materialParam = materialParams_[style];
205 maskColor_ = RSColor(materialParam.maskColor.AsRgbaInt());
206 maskColor_.MultiplyAlpha(ratio);
207 radius_ = RSMaterialFilter::RadiusVp2Sigma(materialParam.radius, dipScale) * ratio;
208 saturation_ = (materialParam.saturation - 1) * ratio + 1.0;
209 brightness_ = (materialParam.brightness - 1) * ratio + 1.0;
210 return RSMaterialFilter::CreateMaterialFilter(radius_, saturation_, brightness_);
211 }
212 return nullptr;
213 }
214
215 #ifndef USE_ROSEN_DRAWING
PreProcess(sk_sp<SkImage> imageSnapshot)216 void RSMaterialFilter::PreProcess(sk_sp<SkImage> imageSnapshot)
217 {
218 if (colorMode_ == AVERAGE && imageSnapshot != nullptr) {
219 // update maskColor while persevere alpha
220 SkColor colorPicker = RSPropertiesPainter::CalcAverageColor(imageSnapshot);
221 maskColor_ = RSColor(
222 SkColorGetR(colorPicker), SkColorGetG(colorPicker), SkColorGetB(colorPicker), maskColor_.GetAlpha());
223 }
224 }
225 #else
PreProcess(std::shared_ptr<Drawing::Image> imageSnapshot)226 void RSMaterialFilter::PreProcess(std::shared_ptr<Drawing::Image> imageSnapshot)
227 {
228 if (colorMode_ == AVERAGE && imageSnapshot != nullptr) {
229 // update maskColor while persevere alpha
230 auto colorPicker = RSPropertiesPainter::CalcAverageColor(imageSnapshot);
231 maskColor_ = RSColor(Drawing::Color::ColorQuadGetR(colorPicker), Drawing::Color::ColorQuadGetG(colorPicker),
232 Drawing::Color::ColorQuadGetB(colorPicker), maskColor_.GetAlpha());
233 }
234 }
235 #endif
236
PostProcess(RSPaintFilterCanvas & canvas)237 void RSMaterialFilter::PostProcess(RSPaintFilterCanvas& canvas)
238 {
239 #ifndef USE_ROSEN_DRAWING
240 SkPaint paint;
241 paint.setColor(maskColor_.AsArgbInt());
242 canvas.drawPaint(paint);
243 #else
244 Drawing::Brush brush;
245 brush.SetColor(maskColor_.AsArgbInt());
246 canvas.DrawBackground(brush);
247 #endif
248 }
249
TransformFilter(float fraction) const250 std::shared_ptr<RSFilter> RSMaterialFilter::TransformFilter(float fraction) const
251 {
252 MaterialParam materialParam;
253 materialParam.radius = radius_ * fraction;
254 materialParam.saturation = (saturation_ - 1) * fraction + 1.0;
255 materialParam.brightness = (brightness_ - 1) * fraction + 1.0;
256 materialParam.maskColor = RSColor(maskColor_.GetRed(), maskColor_.GetGreen(),
257 maskColor_.GetBlue(), maskColor_.GetAlpha() * fraction);
258 return std::make_shared<RSMaterialFilter>(materialParam, colorMode_);
259 }
260
IsValid() const261 bool RSMaterialFilter::IsValid() const
262 {
263 constexpr float epsilon = 0.001f;
264 if (ROSEN_EQ(radius_, 0.f, epsilon)) {
265 return false;
266 }
267 return true;
268 }
269
Add(const std::shared_ptr<RSFilter> & rhs)270 std::shared_ptr<RSFilter> RSMaterialFilter::Add(const std::shared_ptr<RSFilter>& rhs)
271 {
272 if ((rhs == nullptr) || (rhs->GetFilterType() != FilterType::MATERIAL)) {
273 return shared_from_this();
274 }
275 auto materialR = std::static_pointer_cast<RSMaterialFilter>(rhs);
276
277 MaterialParam materialParam;
278 materialParam.radius = radius_ + materialR->radius_;
279 materialParam.saturation = saturation_ + materialR->saturation_;
280 materialParam.brightness = brightness_ + materialR->brightness_;
281 materialParam.maskColor = maskColor_ + materialR->maskColor_;
282 return std::make_shared<RSMaterialFilter>(materialParam, materialR->colorMode_);
283 }
284
Sub(const std::shared_ptr<RSFilter> & rhs)285 std::shared_ptr<RSFilter> RSMaterialFilter::Sub(const std::shared_ptr<RSFilter>& rhs)
286 {
287 if ((rhs == nullptr) || (rhs->GetFilterType() != FilterType::MATERIAL)) {
288 return shared_from_this();
289 }
290 auto materialR = std::static_pointer_cast<RSMaterialFilter>(rhs);
291 MaterialParam materialParam;
292 materialParam.radius = radius_ - materialR->radius_;
293 materialParam.saturation = saturation_ - materialR->saturation_;
294 materialParam.brightness = brightness_ - materialR->brightness_;
295 materialParam.maskColor = maskColor_ - materialR->maskColor_;
296 return std::make_shared<RSMaterialFilter>(materialParam, materialR->colorMode_);
297 }
298
Multiply(float rhs)299 std::shared_ptr<RSFilter> RSMaterialFilter::Multiply(float rhs)
300 {
301 MaterialParam materialParam;
302 materialParam.radius = radius_ * rhs;
303 materialParam.saturation = saturation_ * rhs;
304 materialParam.brightness = brightness_ * rhs;
305 materialParam.maskColor = maskColor_ * rhs;
306 return std::make_shared<RSMaterialFilter>(materialParam, colorMode_);
307 }
308
Negate()309 std::shared_ptr<RSFilter> RSMaterialFilter::Negate()
310 {
311 MaterialParam materialParam;
312 materialParam.radius = -radius_;
313 materialParam.saturation = -saturation_;
314 materialParam.brightness = -brightness_;
315 materialParam.maskColor = RSColor(0x00000000) - maskColor_;
316 return std::make_shared<RSMaterialFilter>(materialParam, colorMode_);
317 }
318
319 #ifndef USE_ROSEN_DRAWING
DrawImageRect(SkCanvas & canvas,const sk_sp<SkImage> & image,const SkRect & src,const SkRect & dst) const320 void RSMaterialFilter::DrawImageRect(
321 SkCanvas& canvas, const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst) const
322 #else
323 void RSMaterialFilter::DrawImageRect(Drawing::Canvas& canvas, const std::shared_ptr<Drawing::Image>& image,
324 const Drawing::Rect& src, const Drawing::Rect& dst) const
325 #endif
326 {
327 #ifndef USE_ROSEN_DRAWING
328 auto paint = GetPaint();
329 #ifdef NEW_SKIA
330 // if kawase blur failed, use gauss blur
331 KawaseParameter param = KawaseParameter(src, dst, radius_, colorFilter_, paint.getAlphaf());
332 if (useKawase_ && kawaseFunc_->ApplyKawaseBlur(canvas, image, param)) {
333 return;
334 }
335 canvas.drawImageRect(image.get(), src, dst, SkSamplingOptions(), &paint, SkCanvas::kStrict_SrcRectConstraint);
336 #else
337 canvas.drawImageRect(image.get(), src, dst, &paint);
338 #endif
339 #else
340 auto brush = GetBrush();
341 canvas.AttachBrush(brush);
342 canvas.DrawImageRect(*image, src, dst, Drawing::SamplingOptions());
343 canvas.DetachBrush();
344 #endif
345 }
346
CanSkipFrame() const347 bool RSMaterialFilter::CanSkipFrame() const
348 {
349 constexpr float HEAVY_BLUR_THRESHOLD = 25.0f;
350 return radius_ > HEAVY_BLUR_THRESHOLD;
351 };
352 } // namespace Rosen
353 } // namespace OHOS
354