Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
paint.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
8
9#include <memory>
10
14#include "fml/logging.h"
30
31namespace impeller {
32
38
40 std::vector<Color>& colors,
41 std::vector<float>& stops) {
42 FML_DCHECK(gradient->stop_count() >= 2)
43 << "stop_count:" << gradient->stop_count();
44
45 auto* dl_colors = gradient->colors();
46 auto* dl_stops = gradient->stops();
47 if (dl_stops[0] != 0.0) {
48 colors.emplace_back(skia_conversions::ToColor(dl_colors[0]));
49 stops.emplace_back(0);
50 }
51 for (auto i = 0; i < gradient->stop_count(); i++) {
52 colors.emplace_back(skia_conversions::ToColor(dl_colors[i]));
53 stops.emplace_back(std::clamp(dl_stops[i], 0.0f, 1.0f));
54 }
55 if (dl_stops[gradient->stop_count() - 1] != 1.0) {
56 colors.emplace_back(colors.back());
57 stops.emplace_back(1.0);
58 }
59 for (auto i = 1; i < gradient->stop_count(); i++) {
60 stops[i] = std::clamp(stops[i], stops[i - 1], stops[i]);
61 }
62}
63
64std::shared_ptr<ColorSourceContents> Paint::CreateContents(
65 const ContentContext& renderer,
66 const Geometry* geometry,
67 const std::optional<Matrix>& geometry_transform) const {
68 if (color_source == nullptr) {
69 auto contents = std::make_shared<SolidColorContents>(geometry);
70 contents->SetColor(color);
71 return contents;
72 }
73
74 Matrix inverted_geometry_transform =
75 geometry_transform.has_value() ? geometry_transform->Invert() : Matrix();
76
77 switch (color_source->type()) {
81 FML_DCHECK(linear);
82 auto start_point = linear->start_point();
83 auto end_point = linear->end_point();
84 std::vector<Color> colors;
85 std::vector<float> stops;
86 ConvertStops(linear, colors, stops);
87
88 auto tile_mode = static_cast<Entity::TileMode>(linear->tile_mode());
89 auto effect_transform = linear->matrix();
90
91 auto contents = std::make_shared<LinearGradientContents>(geometry);
92 contents->SetOpacityFactor(color.alpha);
93 contents->SetColors(std::move(colors));
94 contents->SetStops(std::move(stops));
95 contents->SetEndPoints(start_point, end_point);
96 contents->SetTileMode(tile_mode);
97 contents->SetEffectTransform(inverted_geometry_transform *
98 effect_transform);
99
100 std::array<Point, 2> bounds{start_point, end_point};
101 auto intrinsic_size = Rect::MakePointBounds(bounds.begin(), bounds.end());
102 if (intrinsic_size.has_value()) {
103 contents->SetColorSourceSize(intrinsic_size->GetSize().Max({1, 1}));
104 }
105 return contents;
106 }
108 const flutter::DlRadialGradientColorSource* radialGradient =
110 FML_DCHECK(radialGradient);
111 auto center = radialGradient->center();
112 auto radius = radialGradient->radius();
113 std::vector<Color> colors;
114 std::vector<float> stops;
115 ConvertStops(radialGradient, colors, stops);
116
117 auto tile_mode =
118 static_cast<Entity::TileMode>(radialGradient->tile_mode());
119 auto effect_transform = radialGradient->matrix();
120
121 auto contents = std::make_shared<RadialGradientContents>(geometry);
122 contents->SetOpacityFactor(color.alpha);
123 contents->SetColors(std::move(colors));
124 contents->SetStops(std::move(stops));
125 contents->SetCenterAndRadius(center, radius);
126 contents->SetTileMode(tile_mode);
127 contents->SetEffectTransform(inverted_geometry_transform *
128 effect_transform);
129
130 auto intrinsic_size = Rect::MakeCircleBounds(center, std::abs(radius));
131 contents->SetColorSourceSize(intrinsic_size.GetSize().Max({1, 1}));
132 return contents;
133 }
135 const flutter::DlConicalGradientColorSource* conical_gradient =
137 FML_DCHECK(conical_gradient);
138 Point center = conical_gradient->end_center();
139 DlScalar radius = conical_gradient->end_radius();
140 Point focus_center = conical_gradient->start_center();
141 DlScalar focus_radius = conical_gradient->start_radius();
142 std::vector<Color> colors;
143 std::vector<float> stops;
144 ConvertStops(conical_gradient, colors, stops);
145
146 auto tile_mode =
147 static_cast<Entity::TileMode>(conical_gradient->tile_mode());
148 auto effect_transform = conical_gradient->matrix();
149
150 auto contents = std::make_shared<ConicalGradientContents>(geometry);
151 contents->SetOpacityFactor(color.alpha);
152 contents->SetColors(std::move(colors));
153 contents->SetStops(std::move(stops));
154 contents->SetCenterAndRadius(center, radius);
155 contents->SetTileMode(tile_mode);
156 contents->SetEffectTransform(inverted_geometry_transform *
157 effect_transform);
158 contents->SetFocus(focus_center, focus_radius);
159
160 auto intrinsic_size = Rect::MakeCircleBounds(center, std::abs(radius));
161 contents->SetColorSourceSize(intrinsic_size.GetSize().Max({1, 1}));
162 return contents;
163 }
165 const flutter::DlSweepGradientColorSource* sweepGradient =
167 FML_DCHECK(sweepGradient);
168
169 auto center = sweepGradient->center();
170 auto start_angle = Degrees(sweepGradient->start());
171 auto end_angle = Degrees(sweepGradient->end());
172 std::vector<Color> colors;
173 std::vector<float> stops;
174 ConvertStops(sweepGradient, colors, stops);
175
176 auto tile_mode =
177 static_cast<Entity::TileMode>(sweepGradient->tile_mode());
178 auto effect_transform = sweepGradient->matrix();
179
180 auto contents = std::make_shared<SweepGradientContents>(geometry);
181 contents->SetOpacityFactor(color.alpha);
182 contents->SetCenterAndAngles(center, start_angle, end_angle);
183 contents->SetColors(std::move(colors));
184 contents->SetStops(std::move(stops));
185 contents->SetTileMode(tile_mode);
186 contents->SetEffectTransform(inverted_geometry_transform *
187 effect_transform);
188
189 return contents;
190 }
192 const flutter::DlImageColorSource* image_color_source =
194 FML_DCHECK(image_color_source);
195 auto texture =
196 image_color_source->image()->asImpellerImage()->GetCachedTexture(
197 renderer);
199 auto x_tile_mode = static_cast<Entity::TileMode>(
200 image_color_source->horizontal_tile_mode());
201 auto y_tile_mode = static_cast<Entity::TileMode>(
202 image_color_source->vertical_tile_mode());
203 auto sampler_descriptor =
204 skia_conversions::ToSamplerDescriptor(image_color_source->sampling());
205 // See https://github.com/flutter/flutter/issues/165205
206 flutter::DlMatrix effect_transform = image_color_source->matrix().To3x3();
207
208 auto contents = std::make_shared<TiledTextureContents>(geometry);
209 contents->SetOpacityFactor(color.alpha);
210 contents->SetTexture(texture);
211 contents->SetTileModes(x_tile_mode, y_tile_mode);
212 contents->SetSamplerDescriptor(sampler_descriptor);
213 contents->SetEffectTransform(inverted_geometry_transform *
214 effect_transform);
220 std::shared_ptr<FilterContents> color_filter_output =
225 FilterInput::Make(color_filter_output),
227 }
228 if (color_filter) {
232 }
235 };
236 contents->SetColorFilter(filter_proc);
237 }
238 contents->SetColorSourceSize(Size::Ceil(texture->GetSize()));
239 return contents;
240 }
242 const flutter::DlRuntimeEffectColorSource* runtime_effect_color_source =
244 auto runtime_stage =
245 runtime_effect_color_source->runtime_effect()->runtime_stage();
246 auto uniform_data = runtime_effect_color_source->uniform_data();
247 auto samplers = runtime_effect_color_source->samplers();
248
249 std::vector<RuntimeEffectContents::TextureInput> texture_inputs;
250
251 for (auto& sampler : samplers) {
252 if (sampler == nullptr) {
253 VALIDATION_LOG << "Runtime effect sampler is null";
254 auto contents = std::make_shared<SolidColorContents>(geometry);
255 contents->SetColor(Color::BlackTransparent());
256 return contents;
257 }
258 auto* image = sampler->asImage();
259 if (!sampler->asImage()) {
260 VALIDATION_LOG << "Runtime effect sampler is not an image";
261 auto contents = std::make_shared<SolidColorContents>(geometry);
262 contents->SetColor(Color::BlackTransparent());
263 return contents;
264 }
265 auto texture =
266 image->image()->asImpellerImage()->GetCachedTexture(renderer);
268 texture_inputs.push_back({
269 .sampler_descriptor =
271 .texture = std::move(texture),
272 });
273 }
274
275 auto contents = std::make_shared<RuntimeEffectContents>(geometry);
276 contents->SetOpacityFactor(color.alpha);
277 contents->SetRuntimeStage(std::move(runtime_stage));
278 contents->SetUniformData(std::move(uniform_data));
279 contents->SetTextureInputs(std::move(texture_inputs));
280 return contents;
281 }
282 }
284}
285
286std::shared_ptr<Contents> Paint::WithFilters(
287 const ContentContext& renderer,
288 std::shared_ptr<Contents> input) const {
290 auto image_filter = WithImageFilter(renderer, input, Matrix(),
292 if (image_filter) {
294 }
295 return input;
296}
297
298std::shared_ptr<Contents> Paint::WithFiltersForSubpassTarget(
299 const ContentContext& renderer,
300 std::shared_ptr<Contents> input,
301 const Matrix& effect_transform) const {
302 auto image_filter =
303 WithImageFilter(renderer, input, effect_transform,
305 if (image_filter) {
307 }
309 return input;
310}
311
312std::shared_ptr<Contents> Paint::WithMaskBlur(std::shared_ptr<Contents> input,
313 bool is_solid_color,
314 const Matrix& ctm) const {
315 if (mask_blur_descriptor.has_value()) {
317 is_solid_color, ctm);
318 }
319 return input;
320}
321
322std::shared_ptr<FilterContents> Paint::WithImageFilter(
323 const ContentContext& renderer,
325 const Matrix& effect_transform,
326 Entity::RenderingMode rendering_mode) const {
327 if (!image_filter) {
328 return nullptr;
329 }
330 auto filter = WrapInput(renderer, image_filter, FilterInput::Make(input));
331 filter->SetRenderingMode(rendering_mode);
332 filter->SetEffectTransform(effect_transform);
333 return filter;
334}
335
336std::shared_ptr<Contents> Paint::WithColorFilter(
337 std::shared_ptr<Contents> input,
338 ColorFilterContents::AbsorbOpacity absorb_opacity) const {
339 // Image input types will directly set their color filter,
340 // if any. See `TiledTextureContents.SetColorFilter`.
341 if (color_source &&
343 return input;
344 }
345
346 if (!color_filter && !invert_colors) {
347 return input;
348 }
349
350 // Attempt to apply the color filter on the CPU first.
351 // Note: This is not just an optimization; some color sources rely on
352 // CPU-applied color filters to behave properly.
353 if (input->ApplyColorFilter([&](Color color) -> Color {
354 if (color_filter) {
355 color = GetCPUColorFilterProc(color_filter)(color);
356 }
357 if (invert_colors) {
359 }
360 return color;
361 })) {
362 return input;
363 }
364
365 if (color_filter) {
367 absorb_opacity);
368 }
369 if (invert_colors) {
371 }
372
373 return input;
374}
375
376std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
377 std::shared_ptr<TextureContents> texture_contents,
378 FillRectGeometry* rect_geom) const {
379 Scalar expand_amount = GaussianBlurFilterContents::CalculateBlurRadius(
380 GaussianBlurFilterContents::ScaleSigma(sigma.sigma));
381 texture_contents->SetSourceRect(
382 texture_contents->GetSourceRect().Expand(expand_amount, expand_amount));
383 std::optional<Rect> coverage = texture_contents->GetCoverage({});
384 Geometry* geometry = nullptr;
385 if (coverage) {
386 texture_contents->SetDestinationRect(
387 coverage.value().Expand(expand_amount, expand_amount));
388 *rect_geom = FillRectGeometry(coverage.value());
389 geometry = rect_geom;
390 }
391 auto mask = std::make_shared<SolidColorContents>(geometry);
392 mask->SetColor(Color::White());
393 auto descriptor = texture_contents->GetSamplerDescriptor();
394 texture_contents->SetSamplerDescriptor(descriptor);
395 std::shared_ptr<FilterContents> blurred_mask =
396 FilterContents::MakeGaussianBlur(
397 FilterInput::Make(mask), sigma, sigma, Entity::TileMode::kDecal,
398 /*bounds=*/std::nullopt, style, geometry);
399
400 return ColorFilterContents::MakeBlend(
401 BlendMode::kSrcIn,
402 {FilterInput::Make(blurred_mask), FilterInput::Make(texture_contents)});
403}
404
405std::shared_ptr<Contents> Paint::MaskBlurDescriptor::CreateMaskBlur(
406 const Paint& paint,
407 const ContentContext& renderer,
408 const Geometry* geometry,
409 std::shared_ptr<ColorSourceContents> contents,
410 bool needs_color_filter,
411 FillRectGeometry* out_geom) const {
412 // If it's a solid color then we can just get away with doing one Gaussian
413 // blur. The color filter will always be applied on the CPU.
414 if (contents->IsSolidColor()) {
415 return FilterContents::MakeGaussianBlur(
416 FilterInput::Make(contents), sigma, sigma, Entity::TileMode::kDecal,
417 /*bounds=*/std::nullopt, style, geometry);
418 }
419
420 /// 1. Create an opaque white mask of the original geometry.
421 auto mask = std::make_shared<SolidColorContents>(geometry);
422 mask->SetColor(Color::White());
423
424 /// 2. Blur the mask.
425 auto blurred_mask = FilterContents::MakeGaussianBlur(
426 FilterInput::Make(mask), sigma, sigma, Entity::TileMode::kDecal,
427 /*bounds=*/std::nullopt, style, geometry);
428
429 /// 3. Replace the geometry of the original color source with a rectangle that
430 /// covers the full region of the blurred mask. Note that geometry is in
431 /// local bounds.
432 std::optional<Rect> expanded_local_bounds = blurred_mask->GetCoverage({});
433 if (!expanded_local_bounds.has_value()) {
434 expanded_local_bounds = Rect();
435 }
436 *out_geom = FillRectGeometry(expanded_local_bounds.value());
437
438 std::shared_ptr<ColorSourceContents> expanded_contents =
439 paint.CreateContents(renderer, out_geom);
440 std::shared_ptr<Contents> final_contents = expanded_contents;
441
442 /// 4. Apply the user set color filter on the GPU, if applicable.
443 if (needs_color_filter) {
444 if (paint.color_filter) {
445 final_contents = WrapWithGPUColorFilter(
446 paint.color_filter, FilterInput::Make(std::move(final_contents)),
447 ColorFilterContents::AbsorbOpacity::kYes);
448 }
449 if (paint.invert_colors) {
450 final_contents =
451 WrapWithInvertColors(FilterInput::Make(std::move(final_contents)),
452 ColorFilterContents::AbsorbOpacity::kYes);
453 }
454 }
455
456 /// 5. Composite the color source with the blurred mask.
457 return ColorFilterContents::MakeBlend(
458 BlendMode::kSrcIn,
459 {FilterInput::Make(blurred_mask), FilterInput::Make(final_contents)});
460}
461
462std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
463 const FilterInput::Ref& input,
464 bool is_solid_color,
465 const Matrix& ctm) const {
466 Vector2 blur_sigma(sigma.sigma, sigma.sigma);
467 if (!respect_ctm) {
468 blur_sigma /=
470 }
471 if (is_solid_color) {
472 return FilterContents::MakeGaussianBlur(
473 input, Sigma(blur_sigma.x), Sigma(blur_sigma.y),
474 Entity::TileMode::kDecal, /*bounds=*/std::nullopt, style);
475 }
476 return FilterContents::MakeBorderMaskBlur(input, Sigma(blur_sigma.x),
477 Sigma(blur_sigma.y), style);
478}
479
480bool Paint::HasColorFilter() const {
481 return color_filter || invert_colors;
482}
483
484} // namespace impeller
virtual T type() const =0
virtual const DlRuntimeEffectColorSource * asRuntimeEffect() const
virtual const DlRadialGradientColorSource * asRadialGradient() const
virtual const DlLinearGradientColorSource * asLinearGradient() const
virtual const DlImageColorSource * asImage() const
virtual const DlSweepGradientColorSource * asSweepGradient() const
virtual const DlConicalGradientColorSource * asConicalGradient() const
DlImageSampling sampling() const
DlTileMode horizontal_tile_mode() const
sk_sp< const DlImage > image() const
const std::shared_ptr< std::vector< uint8_t > > uniform_data() const
const sk_sp< DlRuntimeEffect > runtime_effect() const
const std::vector< std::shared_ptr< DlColorSource > > samplers() const
std::shared_ptr< FilterInput > Ref
std::variant< std::shared_ptr< FilterContents >, std::shared_ptr< Contents >, std::shared_ptr< Texture >, Rect > Variant
static FilterInput::Ref Make(Variant input, bool msaa_enabled=true)
std::function< std::shared_ptr< ColorFilterContents >(FilterInput::Ref)> ColorFilterProc
static int input(yyscan_t yyscanner)
FlutterVulkanImage * image
if(engine==nullptr)
#define FML_UNREACHABLE()
Definition logging.h:128
#define FML_DCHECK(condition)
Definition logging.h:122
FlTexture * texture
impeller::Scalar DlScalar
impeller::Rect DlRect
impeller::IRect32 DlIRect
impeller::Point DlPoint
impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlImageSampling options)
Color ToColor(const flutter::DlColor &color)
std::shared_ptr< ColorFilterContents > WrapWithGPUColorFilter(const flutter::DlColorFilter *filter, const std::shared_ptr< FilterInput > &input, ColorFilterContents::AbsorbOpacity absorb_opacity)
flutter::DlRect DlRect
float Scalar
Definition scalar.h:19
flutter::DlIRect DlIRect
std::shared_ptr< ColorFilterContents > WrapWithInvertColors(const std::shared_ptr< FilterInput > &input, ColorFilterContents::AbsorbOpacity absorb_opacity)
flutter::DlPoint DlPoint
std::shared_ptr< FilterContents > WrapInput(const ContentContext &renderer, const flutter::DlImageFilter *filter, const FilterInput::Ref &input)
Generate a new FilterContents using this filter's configuration.
flutter::DlPath DlPath
flutter::DlScalar DlScalar
static const constexpr ColorMatrix kColorInversion
A color matrix which inverts colors.
FlutterVulkanImageHandle image
Definition embedder.h:938
static constexpr Color BlackTransparent()
Definition color.h:275
Scalar alpha
Definition color.h:143
Color ApplyColorMatrix(const ColorMatrix &color_matrix) const
A color filter that transforms colors through a 4x5 color matrix.
Definition color.cc:299
A 4x4 matrix using column-major storage.
Definition matrix.h:37
constexpr Vector3 GetBasisY() const
Definition matrix.h:390
Matrix Invert() const
Definition matrix.cc:99
constexpr Vector3 GetBasisX() const
Definition matrix.h:388
constexpr Matrix To3x3() const
Definition matrix.h:252
std::shared_ptr< FilterContents > WithImageFilter(const ContentContext &renderer, const FilterInput::Variant &input, const Matrix &effect_transform, Entity::RenderingMode rendering_mode) const
Definition paint.cc:322
const flutter::DlColorFilter * color_filter
Definition paint.h:81
std::shared_ptr< Contents > WithFiltersForSubpassTarget(const ContentContext &renderer, std::shared_ptr< Contents > input, const Matrix &effect_transform=Matrix()) const
Wrap this paint's configured filters to the given contents of subpass target.
Definition paint.cc:298
const flutter::DlColorSource * color_source
Definition paint.h:80
static void ConvertStops(const flutter::DlGradientColorSourceBase *gradient, std::vector< Color > &colors, std::vector< float > &stops)
Convert display list colors + stops into impeller colors and stops, taking care to ensure that the st...
Definition paint.cc:39
const flutter::DlImageFilter * image_filter
Definition paint.h:82
std::shared_ptr< Contents > WithFilters(const ContentContext &renderer, std::shared_ptr< Contents > input) const
Wrap this paint's configured filters to the given contents.
Definition paint.cc:286
std::shared_ptr< Contents > WithMaskBlur(std::shared_ptr< Contents > input, bool is_solid_color, const Matrix &ctm) const
Definition paint.cc:312
bool invert_colors
Definition paint.h:87
std::optional< MaskBlurDescriptor > mask_blur_descriptor
Definition paint.h:90
Color color
Definition paint.h:79
std::shared_ptr< ColorSourceContents > CreateContents(const ContentContext &renderer, const Geometry *geometry, const std::optional< Matrix > &geometry_transform=std::nullopt) const
Create a ColorSourceContents representing this paint's shader/colors.
Definition paint.cc:64
In filters that use Gaussian distributions, "sigma" is a size of one standard deviation in terms of t...
Definition sigma.h:32
static constexpr TRect MakeCircleBounds(const TPoint< Type > &center, Type radius)
Definition rect.h:156
static constexpr std::optional< TRect > MakePointBounds(const U &value)
Definition rect.h:189
constexpr TSize Ceil() const
Definition size.h:114
Scalar GetLength() const
Definition vector.h:47
#define VALIDATION_LOG
Definition validation.h:91