Flutter Impeller
impeller::Paint Struct Reference

#include <paint.h>

Classes

struct  MaskBlurDescriptor
 

Public Types

enum class  Style {
  kFill ,
  kStroke
}
 
using ImageFilterProc = std::function< std::shared_ptr< FilterContents >(FilterInput::Ref, const Matrix &effect_transform, Entity::RenderingMode rendering_mode)>
 
using MaskFilterProc = std::function< std::shared_ptr< FilterContents >(FilterInput::Ref, bool is_solid_color, const Matrix &effect_transform)>
 
using ColorSourceProc = std::function< std::shared_ptr< ColorSourceContents >()>
 

Public Member Functions

std::optional< StrokeParameters > GetStroke () const
 Return an optional StrokeParameters if this Paint is a stroked Paint, otherwise return a nullopt. More...
 
std::shared_ptr< Contents > WithFilters (const ContentContext &renderer, std::shared_ptr< Contents > input) const
 Wrap this paint's configured filters to the given contents. More...
 
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. More...
 
bool HasColorFilter () const
 Whether this paint has a color filter that can apply opacity. More...
 
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. More...
 
std::shared_ptr< Contents > WithMaskBlur (std::shared_ptr< Contents > input, bool is_solid_color, const Matrix &ctm) const
 
std::shared_ptr< FilterContents > WithImageFilter (const ContentContext &renderer, const FilterInput::Variant &input, const Matrix &effect_transform, Entity::RenderingMode rendering_mode) const
 

Static Public Member Functions

static bool CanApplyOpacityPeephole (const Paint &paint)
 Whether or not a save layer with the provided paint can perform the opacity peephole optimization. More...
 
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 stops monotonically increase from 0.0 to 1.0. More...
 

Public Attributes

Color color = Color::Black()
 
const flutter::DlColorSource * color_source = nullptr
 
const flutter::DlColorFilter * color_filter = nullptr
 
const flutter::DlImageFilter * image_filter = nullptr
 
StrokeParameters stroke
 
Style style = Style::kFill
 
BlendMode blend_mode = BlendMode::kSrcOver
 
bool invert_colors = false
 
bool anti_alias = true
 
std::optional< MaskBlurDescriptor > mask_blur_descriptor
 

Detailed Description

Definition at line 29 of file paint.h.

Member Typedef Documentation

◆ ColorSourceProc

using impeller::Paint::ColorSourceProc = std::function<std::shared_ptr<ColorSourceContents>()>

Definition at line 38 of file paint.h.

◆ ImageFilterProc

using impeller::Paint::ImageFilterProc = std::function<std::shared_ptr<FilterContents>( FilterInput::Ref, const Matrix& effect_transform, Entity::RenderingMode rendering_mode)>

Definition at line 30 of file paint.h.

◆ MaskFilterProc

using impeller::Paint::MaskFilterProc = std::function<std::shared_ptr<FilterContents>( FilterInput::Ref, bool is_solid_color, const Matrix& effect_transform)>

Definition at line 34 of file paint.h.

Member Enumeration Documentation

◆ Style

Enumerator
kFill 
kStroke 

Definition at line 49 of file paint.h.

49  {
50  kFill,
51  kStroke,
52  };

Member Function Documentation

◆ CanApplyOpacityPeephole()

static bool impeller::Paint::CanApplyOpacityPeephole ( const Paint &  paint)
inlinestatic

Whether or not a save layer with the provided paint can perform the opacity peephole optimization.

Definition at line 42 of file paint.h.

42  {
43  return paint.blend_mode == BlendMode::kSrcOver &&
44  paint.invert_colors == false &&
45  !paint.mask_blur_descriptor.has_value() &&
46  paint.image_filter == nullptr && paint.color_filter == nullptr;
47  }

References blend_mode, color_filter, image_filter, invert_colors, impeller::kSrcOver, and mask_blur_descriptor.

Referenced by impeller::Canvas::SaveLayer().

◆ ConvertStops()

void impeller::Paint::ConvertStops ( const flutter::DlGradientColorSourceBase *  gradient,
std::vector< Color > &  colors,
std::vector< float > &  stops 
)
static

Convert display list colors + stops into impeller colors and stops, taking care to ensure that the stops monotonically increase from 0.0 to 1.0.

The general process is:

  • Ensure that the first gradient stop value is 0.0. If not, insert a new stop with a value of 0.0 and use the first gradient color as this new stops color.
  • Ensure the last gradient stop value is 1.0. If not, insert a new stop with a value of 1.0 and use the last gradient color as this stops color.
  • Clamp all gradient values between the values of 0.0 and 1.0.
  • For all stop values, ensure that the values are monotonically increasing by clamping each value to a minimum of the previous stop value and itself. For example, with stop values of 0.0, 0.5, 0.4, 1.0, we would clamp such that the values were 0.0, 0.5, 0.5, 1.0.

Definition at line 39 of file paint.cc.

41  {
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 }
Color ToColor(const flutter::DlColor &color)

References impeller::skia_conversions::ToColor().

Referenced by CreateContents(), and impeller::testing::TEST().

◆ CreateContents()

std::shared_ptr< ColorSourceContents > impeller::Paint::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.

Parameters
[in]rendererThe content context renderer.
[in]geometryThe geometry the color source is drawn onto.
[in]geometry_transformAn optional transform representing a layout/positioning transform applied to the geometry. If provided, this is used to adjust the color source's effect transform to align it with the geometry's coordinate space.
Returns
The generated color source contents.

Definition at line 64 of file paint.cc.

67  {
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()) {
78  case flutter::DlColorSourceType::kLinearGradient: {
79  const flutter::DlLinearGradientColorSource* linear =
80  color_source->asLinearGradient();
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  }
107  case flutter::DlColorSourceType::kRadialGradient: {
108  const flutter::DlRadialGradientColorSource* radialGradient =
109  color_source->asRadialGradient();
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  }
134  case flutter::DlColorSourceType::kConicalGradient: {
135  const flutter::DlConicalGradientColorSource* conical_gradient =
136  color_source->asConicalGradient();
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  }
164  case flutter::DlColorSourceType::kSweepGradient: {
165  const flutter::DlSweepGradientColorSource* sweepGradient =
166  color_source->asSweepGradient();
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  }
191  case flutter::DlColorSourceType::kImage: {
192  const flutter::DlImageColorSource* image_color_source =
193  color_source->asImage();
194  FML_DCHECK(image_color_source);
195  auto texture =
196  image_color_source->image()->asImpellerImage()->GetCachedTexture(
197  renderer);
198  FML_DCHECK(texture);
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);
215  if (color_filter || invert_colors) {
218  invert_colors = invert_colors](const FilterInput::Ref& input) {
219  if (invert_colors && color_filter) {
220  std::shared_ptr<FilterContents> color_filter_output =
222  color_filter, input,
224  return WrapWithInvertColors(
225  FilterInput::Make(color_filter_output),
227  }
228  if (color_filter) {
229  return WrapWithGPUColorFilter(
230  color_filter, input,
232  }
233  return WrapWithInvertColors(
235  };
236  contents->SetColorFilter(filter_proc);
237  }
238  contents->SetColorSourceSize(Size::Ceil(texture->GetSize()));
239  return contents;
240  }
241  case flutter::DlColorSourceType::kRuntimeEffect: {
242  const flutter::DlRuntimeEffectColorSource* runtime_effect_color_source =
243  color_source->asRuntimeEffect();
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);
267  FML_DCHECK(texture);
268  texture_inputs.push_back({
269  .sampler_descriptor =
270  skia_conversions::ToSamplerDescriptor(image->sampling()),
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  }
283  FML_UNREACHABLE();
284 }
std::shared_ptr< FilterInput > Ref
Definition: filter_input.h:32
static FilterInput::Ref Make(Variant input, bool msaa_enabled=true)
Definition: filter_input.cc:19
std::function< std::shared_ptr< ColorFilterContents >(FilterInput::Ref)> ColorFilterProc
impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlImageSampling options)
std::shared_ptr< ColorFilterContents > WrapWithGPUColorFilter(const flutter::DlColorFilter *filter, const std::shared_ptr< FilterInput > &input, ColorFilterContents::AbsorbOpacity absorb_opacity)
Definition: color_filter.cc:24
std::shared_ptr< ColorFilterContents > WrapWithInvertColors(const std::shared_ptr< FilterInput > &input, ColorFilterContents::AbsorbOpacity absorb_opacity)
Definition: color_filter.cc:16
TPoint< Scalar > Point
Definition: point.h:426
flutter::DlScalar DlScalar
Definition: dl_dispatcher.h:28
static constexpr Color BlackTransparent()
Definition: color.h:275
Scalar alpha
Definition: color.h:143
const flutter::DlColorFilter * color_filter
Definition: paint.h:81
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
bool invert_colors
Definition: paint.h:87
Color color
Definition: paint.h:79
constexpr static TRect MakeCircleBounds(const TPoint< Type > &center, Type radius)
Definition: rect.h:156
constexpr static std::optional< TRect > MakePointBounds(const U &value)
Definition: rect.h:189
constexpr TSize Ceil() const
Definition: size.h:114
#define VALIDATION_LOG
Definition: validation.h:91

References impeller::Color::alpha, impeller::Color::BlackTransparent(), impeller::TSize< Scalar >::Ceil(), color, color_filter, color_source, ConvertStops(), impeller::Matrix::Invert(), invert_colors, impeller::ColorFilterContents::kNo, impeller::FilterInput::Make(), impeller::TRect< Scalar >::MakeCircleBounds(), impeller::TRect< Scalar >::MakePointBounds(), impeller::skia_conversions::ToSamplerDescriptor(), VALIDATION_LOG, impeller::WrapWithGPUColorFilter(), and impeller::WrapWithInvertColors().

Referenced by impeller::Paint::MaskBlurDescriptor::CreateMaskBlur(), and impeller::Canvas::DrawRoundSuperellipse().

◆ GetStroke()

std::optional<StrokeParameters> impeller::Paint::GetStroke ( ) const
inline

Return an optional StrokeParameters if this Paint is a stroked Paint, otherwise return a nullopt.

Returns
An optional set of StrokeParameters

Definition at line 95 of file paint.h.

95  {
96  return (style == Style::kStroke) ? std::optional(stroke) : std::nullopt;
97  }
Definition: comparable.h:93
Style style
Definition: paint.h:85
StrokeParameters stroke
Definition: paint.h:84

References kStroke, stroke, and style.

Referenced by impeller::Canvas::DrawCircle(), impeller::Canvas::DrawRect(), impeller::Canvas::DrawRoundSuperellipse(), impeller::FirstPassDispatcher::drawText(), impeller::Canvas::DrawTextFrame(), and impeller::testing::TEST().

◆ HasColorFilter()

bool impeller::Paint::HasColorFilter ( ) const

Whether this paint has a color filter that can apply opacity.

Definition at line 480 of file paint.cc.

480  {
481  return color_filter || invert_colors;
482 }

Referenced by impeller::Canvas::DrawImageRect().

◆ WithFilters()

std::shared_ptr< Contents > impeller::Paint::WithFilters ( const ContentContext &  renderer,
std::shared_ptr< Contents >  input 
) const

Wrap this paint's configured filters to the given contents.

Parameters
[in]inputThe contents to wrap with paint's filters.
Returns
The filter-wrapped contents. If there are no filters that need to be wrapped for the current paint configuration, the original contents is returned.

Definition at line 286 of file paint.cc.

288  {
289  input = WithColorFilter(input, ColorFilterContents::AbsorbOpacity::kYes);
290  auto image_filter = WithImageFilter(renderer, input, Matrix(),
292  if (image_filter) {
293  input = image_filter;
294  }
295  return input;
296 }
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::DlImageFilter * image_filter
Definition: paint.h:82

References image_filter, impeller::Entity::kDirect, impeller::ColorFilterContents::kYes, and WithImageFilter().

Referenced by impeller::Canvas::DrawAtlas(), impeller::Canvas::DrawImageRect(), impeller::Canvas::DrawTextFrame(), and impeller::Canvas::DrawVertices().

◆ WithFiltersForSubpassTarget()

std::shared_ptr< Contents > impeller::Paint::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.

Parameters
[in]inputThe contents of subpass target to wrap with paint's filters.
Returns
The filter-wrapped contents. If there are no filters that need to be wrapped for the current paint configuration, the original contents is returned.

Definition at line 298 of file paint.cc.

301  {
302  auto image_filter =
303  WithImageFilter(renderer, input, effect_transform,
305  if (image_filter) {
306  input = image_filter;
307  }
308  input = WithColorFilter(input, ColorFilterContents::AbsorbOpacity::kYes);
309  return input;
310 }

References image_filter, impeller::Entity::kSubpassPrependSnapshotTransform, impeller::ColorFilterContents::kYes, and WithImageFilter().

◆ WithImageFilter()

std::shared_ptr< FilterContents > impeller::Paint::WithImageFilter ( const ContentContext &  renderer,
const FilterInput::Variant &  input,
const Matrix &  effect_transform,
Entity::RenderingMode  rendering_mode 
) const

Definition at line 322 of file paint.cc.

326  {
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 }
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.
Definition: image_filter.cc:20

References image_filter, impeller::FilterInput::Make(), and impeller::WrapInput().

Referenced by impeller::Canvas::SaveLayer(), WithFilters(), and WithFiltersForSubpassTarget().

◆ WithMaskBlur()

std::shared_ptr< Contents > impeller::Paint::WithMaskBlur ( std::shared_ptr< Contents >  input,
bool  is_solid_color,
const Matrix &  ctm 
) const

Definition at line 312 of file paint.cc.

314  {
315  if (mask_blur_descriptor.has_value()) {
316  input = mask_blur_descriptor->CreateMaskBlur(FilterInput::Make(input),
317  is_solid_color, ctm);
318  }
319  return input;
320 }
std::optional< MaskBlurDescriptor > mask_blur_descriptor
Definition: paint.h:90

References impeller::FilterInput::Make(), and mask_blur_descriptor.

Member Data Documentation

◆ anti_alias

bool impeller::Paint::anti_alias = true

◆ blend_mode

◆ color

◆ color_filter

const flutter::DlColorFilter* impeller::Paint::color_filter = nullptr

◆ color_source

const flutter::DlColorSource* impeller::Paint::color_source = nullptr

◆ image_filter

const flutter::DlImageFilter* impeller::Paint::image_filter = nullptr

◆ invert_colors

bool impeller::Paint::invert_colors = false

◆ mask_blur_descriptor

◆ stroke

◆ style


The documentation for this struct was generated from the following files: