9 #include <unordered_map>
12 #include "display_list/effects/color_filters/dl_blend_color_filter.h"
13 #include "display_list/effects/color_filters/dl_matrix_color_filter.h"
14 #include "display_list/effects/dl_color_filter.h"
15 #include "display_list/effects/dl_color_source.h"
16 #include "display_list/effects/dl_image_filter.h"
17 #include "display_list/image/dl_image.h"
18 #include "flutter/fml/logging.h"
19 #include "flutter/fml/trace_event.h"
58 bool IsPipelineBlendOrMatrixFilter(
const flutter::DlColorFilter* filter) {
59 return filter->type() == flutter::DlColorFilterType::kMatrix ||
60 (filter->type() == flutter::DlColorFilterType::kBlend &&
64 static bool UseColorSourceContents(
65 const std::shared_ptr<VerticesGeometry>& vertices,
69 if (vertices->HasVertexColors()) {
72 if (vertices->HasTextureCoordinates() && !paint.color_source) {
75 return !vertices->HasTextureCoordinates();
78 static void SetClipScissor(std::optional<Rect> clip_coverage,
80 Point global_pass_position) {
84 if (clip_coverage.has_value()) {
85 clip_coverage = clip_coverage->Shift(-global_pass_position);
92 pass.SetScissor(scissor);
95 static void ApplyFramebufferBlend(Entity& entity) {
96 auto src_contents = entity.GetContents();
97 auto contents = std::make_shared<FramebufferBlendContents>();
98 contents->SetChildContents(src_contents);
99 contents->SetBlendMode(entity.GetBlendMode());
100 entity.SetContents(std::move(contents));
106 static std::shared_ptr<Contents> CreateContentsForSubpassTarget(
108 const std::shared_ptr<Texture>& target,
109 const Matrix& effect_transform) {
111 contents->SetTexture(target);
112 contents->SetLabel(
"Subpass");
114 contents->SetOpacity(paint.color.alpha);
115 contents->SetDeferApplyingOpacity(
true);
117 return paint.WithFiltersForSubpassTarget(std::move(contents),
121 static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig =
122 RenderTarget::AttachmentConfig{
128 static std::unique_ptr<EntityPassTarget> CreateRenderTarget(
129 ContentContext& renderer,
131 const Color& clear_color) {
132 const std::shared_ptr<Context>& context = renderer.GetContext();
140 if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
141 target = renderer.GetRenderTargetCache()->CreateOffscreenMSAA(
147 RenderTarget::AttachmentConfigMSAA{
152 .clear_color = clear_color},
153 kDefaultStencilConfig);
155 target = renderer.GetRenderTargetCache()->CreateOffscreen(
160 RenderTarget::AttachmentConfig{
164 .clear_color = clear_color,
166 kDefaultStencilConfig
170 return std::make_unique<EntityPassTarget>(
172 renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
173 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()
179 std::shared_ptr<SolidRRectLikeBlurContents>
180 Canvas::RRectBlurShape::BuildBlurContent() {
181 return std::make_shared<SolidRRectBlurContents>();
184 Geometry& Canvas::RRectBlurShape::BuildGeometry(
Rect rect,
Scalar radius) {
185 return geom_.emplace(rect,
Size{radius, radius});
188 std::shared_ptr<SolidRRectLikeBlurContents>
189 Canvas::RSuperellipseBlurShape::BuildBlurContent() {
190 return std::make_shared<SolidRSuperellipseBlurContents>();
193 Geometry& Canvas::RSuperellipseBlurShape::BuildGeometry(
Rect rect,
195 return geom_.emplace(rect, radius);
201 bool requires_readback)
202 : renderer_(renderer),
203 render_target_(render_target),
204 is_onscreen_(is_onscreen),
205 requires_readback_(requires_readback),
207 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
208 Initialize(std::nullopt);
215 bool requires_readback,
217 : renderer_(renderer),
218 render_target_(render_target),
219 is_onscreen_(is_onscreen),
220 requires_readback_(requires_readback),
222 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
223 Initialize(cull_rect);
230 bool requires_readback,
232 : renderer_(renderer),
233 render_target_(render_target),
234 is_onscreen_(is_onscreen),
235 requires_readback_(requires_readback),
237 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
243 void Canvas::Initialize(std::optional<Rect> cull_rect) {
244 initial_cull_rect_ = cull_rect;
251 void Canvas::Reset() {
253 transform_stack_ = {};
265 transform_stack_.back().transform = {};
273 return transform_stack_.back().transform;
296 Point Canvas::GetGlobalPassPosition()
const {
297 if (save_layer_state_.empty()) {
300 return save_layer_state_.back().coverage.GetOrigin();
304 size_t Canvas::GetClipHeightFloor()
const {
305 if (transform_stack_.size() > 1) {
306 return transform_stack_[transform_stack_.size() - 2].clip_height;
312 return transform_stack_.size();
315 bool Canvas::IsSkipping()
const {
316 return transform_stack_.back().skipping;
334 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
337 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
347 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
354 bool Canvas::AttemptColorFilterOptimization(
355 const std::shared_ptr<Texture>& image,
369 if (paint.
color_filter->type() == flutter::DlColorFilterType::kBlend) {
370 const flutter::DlBlendColorFilter* blend_filter =
372 DrawImageRectAtlasGeometry geometry = DrawImageRectAtlasGeometry(
377 blend_filter->mode(),
379 src_rect_constraint ==
382 auto atlas_contents = std::make_shared<AtlasContents>();
383 atlas_contents->SetGeometry(&geometry);
389 entity.SetContents(atlas_contents);
391 AddRenderEntityToCurrentPass(entity);
399 const flutter::DlMatrixColorFilter* matrix_filter =
402 DrawImageRectAtlasGeometry geometry = DrawImageRectAtlasGeometry(
409 src_rect_constraint ==
412 auto atlas_contents = std::make_shared<ColorFilterAtlasContents>();
413 atlas_contents->SetGeometry(&geometry);
416 matrix_filter->get_matrix(color_matrix.
array);
417 atlas_contents->SetMatrix(color_matrix);
422 entity.SetContents(atlas_contents);
424 AddRenderEntityToCurrentPass(entity);
429 bool Canvas::AttemptDrawBlurredRRect(
const Rect& rect,
431 const Paint& paint) {
432 RRectBlurShape rrect_shape;
433 return AttemptDrawBlurredRRectLike(rect, corner_radii, paint, rrect_shape);
436 bool Canvas::AttemptDrawBlurredRSuperellipse(
const Rect& rect,
438 const Paint& paint) {
439 RSuperellipseBlurShape rsuperellipse_shape;
440 return AttemptDrawBlurredRRectLike(rect, corner_radii, paint,
441 rsuperellipse_shape);
444 bool Canvas::AttemptDrawBlurredRRectLike(
const Rect& rect,
447 RRectLikeBlurShape& shape) {
452 if (paint.color_source) {
456 if (!paint.mask_blur_descriptor.has_value()) {
466 if (fabsf(corner_radii.width - corner_radii.height) >
kEhCloseEnough) {
469 Scalar corner_radius = corner_radii.width;
473 Color rrect_color = paint.color;
474 if (paint.invert_colors) {
477 if (paint.color_filter) {
481 Paint rrect_paint = {.mask_blur_descriptor = paint.mask_blur_descriptor};
502 if ((paint.mask_blur_descriptor->style !=
504 paint.image_filter) ||
507 Rect render_bounds = rect;
508 if (paint.mask_blur_descriptor->style !=
511 render_bounds.
Expand(paint.mask_blur_descriptor->sigma.sigma * 4.0);
517 .image_filter = paint.image_filter,
518 .blend_mode = paint.blend_mode,
521 rrect_paint.color = rrect_color.WithAlpha(1);
523 rrect_paint.color = rrect_color;
524 rrect_paint.blend_mode = paint.blend_mode;
525 rrect_paint.image_filter = paint.image_filter;
529 auto draw_blurred_rrect = [
this, &rect, corner_radius, &rrect_paint,
531 auto contents = shape.BuildBlurContent();
533 contents->SetColor(rrect_paint.color);
534 contents->SetSigma(rrect_paint.mask_blur_descriptor->sigma);
535 contents->SetShape(rect, corner_radius);
537 Entity blurred_rrect_entity;
539 blurred_rrect_entity.SetBlendMode(rrect_paint.blend_mode);
541 rrect_paint.mask_blur_descriptor = std::nullopt;
542 blurred_rrect_entity.SetContents(
543 rrect_paint.WithFilters(std::move(contents)));
544 AddRenderEntityToCurrentPass(blurred_rrect_entity);
547 switch (rrect_paint.mask_blur_descriptor->style) {
549 draw_blurred_rrect();
554 draw_blurred_rrect();
558 entity.SetBlendMode(rrect_paint.blend_mode);
560 Geometry& geom = shape.BuildGeometry(rect, corner_radius);
561 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, rrect_paint,
566 Geometry& geom = shape.BuildGeometry(rect, corner_radius);
568 draw_blurred_rrect();
572 Geometry& geom = shape.BuildGeometry(rect, corner_radius);
574 draw_blurred_rrect();
592 auto geometry = std::make_unique<LineGeometry>(p0, p1, paint.
stroke);
594 if (renderer_.
GetContext()->GetFlags().antialiased_lines &&
599 AddRenderEntityToCurrentPass(entity, reuse_depth);
601 AddRenderEntityWithFiltersToCurrentPass(entity, geometry.get(), paint,
610 const Paint& paint) {
620 if (length > 0.0f && on_length >= 0.0f && off_length > 0.0f) {
626 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
633 if (AttemptDrawBlurredRRect(rect, {}, paint)) {
643 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
646 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
662 if (AttemptDrawBlurredRRect(rect, rect.
GetSize() * 0.5f, paint)) {
672 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
675 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
686 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
699 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
712 return DrawOval(oval_bounds, paint);
725 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
731 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
736 auto& radii = round_rect.
GetRadii();
737 if (radii.AreAllCornersSame()) {
738 if (AttemptDrawBlurredRRect(rect, radii.top_left, paint)) {
748 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
759 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
762 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
768 const Paint& paint) {
775 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
778 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
783 const Paint& paint) {
784 auto& rect = round_superellipse.
GetBounds();
785 auto& radii = round_superellipse.
GetRadii();
786 if (radii.AreAllCornersSame() &&
787 AttemptDrawBlurredRSuperellipse(rect, radii.top_left, paint)) {
797 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
800 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
806 const Paint& paint) {
807 Size half_size(radius, radius);
808 if (AttemptDrawBlurredRRect(
810 {radius, radius}, paint)) {
820 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
823 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
844 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
845 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
846 uint32_t clip_depth = transform_stack_.back().clip_depth;
848 const Matrix clip_transform =
852 std::optional<Rect> clip_coverage = geometry.
GetCoverage(clip_transform);
853 if (!clip_coverage.has_value()) {
858 clip_coverage.value(),
867 GetGlobalPassPosition(),
869 GetClipHeightFloor(),
875 *render_passes_.back().inline_pass_context->GetRenderPass(),
876 GetGlobalPassPosition());
879 ++transform_stack_.back().clip_height;
880 ++transform_stack_.back().num_clips;
897 *render_passes_.back().inline_pass_context->GetRenderPass()
904 renderer_, *render_passes_.back().inline_pass_context->GetRenderPass(),
923 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
950 ISize size = image->GetSize();
955 std::optional<Rect> clipped_source =
957 if (!clipped_source) {
961 if (AttemptColorFilterOptimization(image, source, dest, paint, sampler,
962 src_rect_constraint)) {
966 if (*clipped_source != source) {
976 texture_contents->SetTexture(image);
977 texture_contents->SetSourceRect(*clipped_source);
978 texture_contents->SetStrictSourceRect(src_rect_constraint ==
980 texture_contents->SetSamplerDescriptor(sampler);
981 texture_contents->SetOpacity(paint.
color.
alpha);
982 texture_contents->SetDeferApplyingOpacity(paint.
HasColorFilter());
990 AddRenderEntityToCurrentPass(entity);
998 AddRenderEntityToCurrentPass(entity);
1001 size_t Canvas::GetClipHeight()
const {
1002 return transform_stack_.back().clip_height;
1007 const Paint& paint) {
1020 if (UseColorSourceContents(vertices, paint)) {
1021 AddRenderEntityWithFiltersToCurrentPass(entity, vertices.get(), paint);
1027 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1028 contents->SetBlendMode(blend_mode);
1030 contents->SetGeometry(vertices);
1032 AddRenderEntityToCurrentPass(entity);
1039 paint.
color_source->type() == flutter::DlColorSourceType::kImage) {
1040 const flutter::DlImageColorSource* image_color_source =
1042 FML_DCHECK(image_color_source &&
1043 image_color_source->image()->impeller_texture());
1044 auto texture = image_color_source->image()->impeller_texture();
1046 image_color_source->horizontal_tile_mode());
1049 auto sampler_descriptor =
1051 auto effect_transform = image_color_source->matrix();
1053 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1054 contents->SetBlendMode(blend_mode);
1056 contents->SetGeometry(vertices);
1057 contents->SetEffectTransform(effect_transform);
1058 contents->SetTexture(texture);
1059 contents->SetTileMode(x_tile_mode, y_tile_mode);
1060 contents->SetSamplerDescriptor(sampler_descriptor);
1063 AddRenderEntityToCurrentPass(entity);
1067 auto src_paint = paint;
1070 std::shared_ptr<ColorSourceContents> src_contents =
1071 src_paint.CreateContents();
1072 src_contents->SetGeometry(vertices.get());
1080 auto size = src_contents->GetColorSourceSize();
1081 if (size.has_value()) {
1084 auto cvg = vertices->GetCoverage(
Matrix{});
1085 FML_CHECK(cvg.has_value());
1086 auto texture_coverage = vertices->GetTextureCoordinateCoverage();
1087 if (texture_coverage.has_value()) {
1090 texture_coverage->GetSize().Max({1, 1}));
1092 src_coverage = cvg.value();
1095 src_contents = src_paint.CreateContents();
1098 src_contents->SetGeometry(clip_geometry_.back().get());
1100 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1101 contents->SetBlendMode(blend_mode);
1103 contents->SetGeometry(vertices);
1104 contents->SetLazyTextureCoverage(src_coverage);
1105 contents->SetLazyTexture([src_contents,
1111 src_contents->RenderToSnapshot(renderer, {},
Rect::Round(src_coverage));
1112 return snapshot.has_value() ? snapshot->texture :
nullptr;
1115 AddRenderEntityToCurrentPass(entity);
1119 const Paint& paint) {
1127 AddRenderEntityToCurrentPass(entity);
1133 void Canvas::SetupRenderPass() {
1139 if (!stencil_attachment.has_value() || !depth_attachment.has_value()) {
1144 *renderer_.
GetContext()->GetResourceAllocator(),
1146 renderer_.
GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
1147 "ImpellerOnscreen", kDefaultStencilConfig);
1159 if (requires_readback_) {
1160 auto entity_pass_target =
1161 CreateRenderTarget(renderer_,
1164 render_passes_.push_back(
1165 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1167 auto entity_pass_target = std::make_unique<EntityPassTarget>(
1172 render_passes_.push_back(
1173 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1177 void Canvas::SkipUntilMatchingRestore(
size_t total_content_depth) {
1178 auto entry = CanvasStackEntry{};
1179 entry.skipping =
true;
1180 entry.clip_depth = current_depth_ + total_content_depth;
1181 transform_stack_.push_back(entry);
1186 return SkipUntilMatchingRestore(total_content_depth);
1190 entry.
transform = transform_stack_.back().transform;
1191 entry.clip_depth = current_depth_ + total_content_depth;
1192 entry.distributed_opacity = transform_stack_.back().distributed_opacity;
1193 FML_DCHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
1194 << entry.clip_depth <<
" <=? " << transform_stack_.back().clip_depth
1195 <<
" after allocating " << total_content_depth;
1196 entry.clip_height = transform_stack_.back().clip_height;
1198 transform_stack_.push_back(entry);
1205 return std::nullopt;
1208 std::optional<Rect> maybe_current_clip_coverage =
1210 if (!maybe_current_clip_coverage.has_value()) {
1211 return std::nullopt;
1214 Rect current_clip_coverage = maybe_current_clip_coverage.value();
1216 FML_CHECK(!render_passes_.empty());
1218 std::shared_ptr<Texture> back_texture =
1220 FML_CHECK(back_texture) <<
"Context is valid:"
1225 std::optional<Rect> maybe_coverage_limit =
1227 Size(back_texture->GetSize()))
1230 if (!maybe_coverage_limit.has_value() || maybe_coverage_limit->IsEmpty()) {
1231 return std::nullopt;
1234 return maybe_coverage_limit->Intersection(
1239 std::optional<Rect> bounds,
1240 const flutter::DlImageFilter* backdrop_filter,
1242 uint32_t total_content_depth,
1243 bool can_distribute_opacity,
1244 std::optional<int64_t> backdrop_id) {
1245 TRACE_EVENT0(
"flutter",
"Canvas::saveLayer");
1247 return SkipUntilMatchingRestore(total_content_depth);
1251 if (!maybe_coverage_limit.has_value()) {
1252 return SkipUntilMatchingRestore(total_content_depth);
1254 auto coverage_limit = maybe_coverage_limit.value();
1256 if (can_distribute_opacity && !backdrop_filter &&
1259 Save(total_content_depth);
1260 transform_stack_.back().distributed_opacity *= paint.
color.
alpha;
1264 std::shared_ptr<FilterContents> filter_contents = paint.
WithImageFilter(
1265 Rect(), transform_stack_.back().transform,
1270 transform_stack_.back().transform,
1275 !!backdrop_filter ||
1280 if (!maybe_subpass_coverage.has_value()) {
1281 return SkipUntilMatchingRestore(total_content_depth);
1284 auto subpass_coverage = maybe_subpass_coverage.value();
1295 bool did_round_out =
false;
1296 Point coverage_origin_adjustment =
Point{0, 0};
1300 did_round_out =
true;
1304 coverage_origin_adjustment =
1305 Point(subpass_coverage.GetLeftTop().x -
1306 std::floor(subpass_coverage.GetLeftTop().x),
1307 subpass_coverage.GetLeftTop().y -
1308 std::floor(subpass_coverage.GetLeftTop().y));
1311 return SkipUntilMatchingRestore(total_content_depth);
1319 ->GetMaximumRenderPassAttachmentSize());
1322 std::shared_ptr<FilterContents> backdrop_filter_contents;
1324 if (backdrop_filter) {
1325 local_position = subpass_coverage.GetOrigin() - GetGlobalPassPosition();
1327 [backdrop_filter = backdrop_filter](
1330 auto filter =
WrapInput(backdrop_filter, input);
1331 filter->SetEffectTransform(effect_transform);
1332 filter->SetRenderingMode(rendering_mode);
1336 std::shared_ptr<Texture> input_texture;
1341 bool will_cache_backdrop_texture =
false;
1346 size_t backdrop_count = 1;
1347 if (backdrop_id.has_value()) {
1348 std::unordered_map<int64_t, BackdropData>::iterator backdrop_data_it =
1349 backdrop_data_.find(backdrop_id.value());
1350 if (backdrop_data_it != backdrop_data_.end()) {
1351 backdrop_data = &backdrop_data_it->second;
1352 will_cache_backdrop_texture =
1354 backdrop_count = backdrop_data_it->second.backdrop_count;
1358 if (!will_cache_backdrop_texture || !backdrop_data->
texture_slot) {
1359 backdrop_count_ -= backdrop_count;
1365 const bool should_use_onscreen =
1367 backdrop_count_ == 0 && render_passes_.size() == 1u;
1368 input_texture = FlipBackdrop(
1369 GetGlobalPassPosition(),
1370 will_cache_backdrop_texture,
1373 if (!input_texture) {
1378 if (will_cache_backdrop_texture) {
1385 backdrop_filter_contents = backdrop_filter_proc(
1387 transform_stack_.back().transform.Basis(),
1390 transform_stack_.back().transform.HasTranslation()
1394 if (will_cache_backdrop_texture) {
1395 FML_DCHECK(backdrop_data);
1402 backdrop_filter_contents->RenderToSnapshot(renderer_, {});
1405 std::optional<Snapshot> maybe_snapshot =
1407 if (maybe_snapshot.has_value()) {
1408 Snapshot snapshot = maybe_snapshot.value();
1410 subpass_coverage.Shift(-GetGlobalPassPosition()));
1413 contents->SetTexture(snapshot.
texture);
1414 contents->SetSourceRect(scaled);
1424 backdrop_entity.
Render(renderer_, GetCurrentRenderPass());
1432 Paint paint_copy = paint;
1433 paint_copy.
color.
alpha *= transform_stack_.back().distributed_opacity;
1434 transform_stack_.back().distributed_opacity = 1.0;
1436 render_passes_.push_back(
1438 CreateRenderTarget(renderer_,
1443 paint_copy, subpass_coverage.Shift(-coverage_origin_adjustment)});
1446 entry.
transform = transform_stack_.back().transform;
1447 entry.
clip_depth = current_depth_ + total_content_depth;
1448 FML_DCHECK(entry.
clip_depth <= transform_stack_.back().clip_depth)
1449 << entry.
clip_depth <<
" <=? " << transform_stack_.back().clip_depth
1450 <<
" after allocating " << total_content_depth;
1451 entry.
clip_height = transform_stack_.back().clip_height;
1454 transform_stack_.emplace_back(entry);
1461 clip_coverage_stack_.
PushSubpass(subpass_coverage, GetClipHeight());
1463 if (!backdrop_filter_contents) {
1469 backdrop_entity.
SetContents(std::move(backdrop_filter_contents));
1472 backdrop_entity.
SetClipDepth(std::numeric_limits<uint32_t>::max());
1473 backdrop_entity.
Render(renderer_, GetCurrentRenderPass());
1477 FML_DCHECK(transform_stack_.size() > 0);
1478 if (transform_stack_.size() == 1) {
1495 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1496 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
1497 current_depth_ = transform_stack_.back().clip_depth;
1500 transform_stack_.pop_back();
1504 if (transform_stack_.back().rendering_mode ==
1506 transform_stack_.back().rendering_mode ==
1508 auto lazy_render_pass = std::move(render_passes_.back());
1509 render_passes_.pop_back();
1511 lazy_render_pass.inline_pass_context->GetRenderPass();
1514 save_layer_state_.pop_back();
1515 auto global_pass_position = GetGlobalPassPosition();
1517 std::shared_ptr<Contents> contents = CreateContentsForSubpassTarget(
1518 save_layer_state.
paint,
1519 lazy_render_pass.inline_pass_context->GetTexture(),
1521 transform_stack_.back().transform
1524 lazy_render_pass.inline_pass_context->EndPass();
1531 Point subpass_texture_position;
1532 if (transform_stack_.back().did_round_out) {
1535 subpass_texture_position =
1540 subpass_texture_position =
1554 ApplyFramebufferBlend(element_entity);
1565 auto input_texture = FlipBackdrop(GetGlobalPassPosition());
1566 if (!input_texture) {
1576 contents->SetCoverageHint(element_entity.
GetCoverage());
1584 *render_passes_.back().inline_pass_context->GetRenderPass()
1587 transform_stack_.pop_back();
1595 size_t num_clips = transform_stack_.back().num_clips;
1596 transform_stack_.pop_back();
1598 if (num_clips > 0) {
1609 *render_passes_.back().inline_pass_context->GetRenderPass(),
1610 GetGlobalPassPosition()
1618 bool Canvas::AttemptBlurredTextOptimization(
1619 const std::shared_ptr<TextFrame>& text_frame,
1620 const std::shared_ptr<TextContents>& text_contents,
1622 const Paint& paint) {
1636 std::shared_ptr<FilterContents> filter =
1641 std::optional<Glyph> maybe_glyph = text_frame->AsSingleGlyph();
1642 int64_t identifier = maybe_glyph.has_value()
1643 ? maybe_glyph.value().index
1644 :
reinterpret_cast<int64_t
>(text_frame.get());
1645 TextShadowCache::TextShadowCacheKey cache_key(
1648 maybe_glyph.has_value(),
1649 text_frame->GetFont(),
1653 renderer_, entity, filter, cache_key);
1654 if (result.has_value()) {
1655 AddRenderEntityToCurrentPass(result.value(),
false);
1669 const Paint& paint) {
1671 if (max_scale * text_frame->GetFont().GetMetrics().point_size >
1673 fml::StatusOr<flutter::DlPath> path = text_frame->GetPath();
1687 auto text_contents = std::make_shared<TextContents>();
1688 text_contents->SetTextFrame(text_frame);
1690 text_contents->SetScale(max_scale);
1691 text_contents->SetColor(paint.
color);
1692 text_contents->SetOffset(position);
1693 text_contents->SetTextProperties(paint.
color,
1695 ? std::optional(paint.
stroke)
1701 if (AttemptBlurredTextOptimization(text_frame, text_contents, entity,
1707 AddRenderEntityToCurrentPass(entity,
false);
1710 void Canvas::AddRenderEntityWithFiltersToCurrentPass(
Entity& entity,
1714 std::shared_ptr<ColorSourceContents> contents = paint.
CreateContents();
1717 contents->SetGeometry(geometry);
1719 AddRenderEntityToCurrentPass(entity, reuse_depth);
1727 if (needs_color_filter &&
1728 contents->ApplyColorFilter([&](Color color) -> Color {
1729 if (paint.color_filter) {
1730 color = GetCPUColorFilterProc(paint.color_filter)(color);
1733 color = color.ApplyColorMatrix(kColorInversion);
1737 needs_color_filter =
false;
1741 contents->SetGeometry(geometry);
1747 FillRectGeometry out_rect(
Rect{});
1749 contents, needs_color_filter ? paint.
color_filter :
nullptr,
1750 needs_color_filter ? paint.
invert_colors :
false, &out_rect);
1752 AddRenderEntityToCurrentPass(entity, reuse_depth);
1756 std::shared_ptr<Contents> contents_copy = std::move(contents);
1760 if (needs_color_filter &&
1762 paint.
color_source->type() != flutter::DlColorSourceType::kImage)) {
1776 std::shared_ptr<FilterContents> filter =
WrapInput(
1780 AddRenderEntityToCurrentPass(entity, reuse_depth);
1785 AddRenderEntityToCurrentPass(entity, reuse_depth);
1788 void Canvas::AddRenderEntityToCurrentPass(Entity& entity,
bool reuse_depth) {
1793 entity.SetTransform(
1794 Matrix::MakeTranslation(Vector3(-GetGlobalPassPosition())) *
1795 entity.GetTransform());
1796 entity.SetInheritedOpacity(transform_stack_.back().distributed_opacity);
1797 if (entity.GetBlendMode() == BlendMode::kSrcOver &&
1798 entity.GetContents()->IsOpaque(entity.GetTransform())) {
1799 entity.SetBlendMode(BlendMode::kSrc);
1805 if (render_passes_.back().IsApplyingClearColor()) {
1806 std::optional<Color> maybe_color = entity.AsBackgroundColor(
1807 render_passes_.back().inline_pass_context->GetTexture()->GetSize());
1808 if (maybe_color.has_value()) {
1809 Color color = maybe_color.value();
1810 RenderTarget& render_target = render_passes_.back()
1811 .inline_pass_context->GetPassTarget()
1813 ColorAttachment attachment = render_target.GetColorAttachment(0);
1816 attachment.clear_color = attachment.clear_color.Unpremultiply()
1817 .Blend(color, entity.GetBlendMode())
1819 render_target.SetColorAttachment(attachment, 0u);
1830 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1831 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
1832 entity.SetClipDepth(current_depth_);
1834 if (entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
1835 if (renderer_.GetDeviceCapabilities().SupportsFramebufferFetch()) {
1836 ApplyFramebufferBlend(entity);
1847 auto input_texture = FlipBackdrop(GetGlobalPassPosition(),
1851 if (!input_texture) {
1859 auto element_coverage_hint = entity.GetContents()->GetCoverageHint();
1860 entity.GetContents()->SetCoverageHint(Rect::Intersection(
1861 element_coverage_hint, clip_coverage_stack_.CurrentClipCoverage()));
1863 FilterInput::Vector inputs = {
1864 FilterInput::Make(input_texture, entity.GetTransform().Invert()),
1865 FilterInput::Make(entity.GetContents())};
1867 ColorFilterContents::MakeBlend(entity.GetBlendMode(), inputs);
1868 entity.SetContents(std::move(contents));
1869 entity.SetBlendMode(BlendMode::kSrc);
1873 const std::shared_ptr<RenderPass>& result =
1874 render_passes_.back().inline_pass_context->GetRenderPass();
1882 entity.Render(renderer_, *result);
1885 RenderPass& Canvas::GetCurrentRenderPass()
const {
1886 return *render_passes_.back().inline_pass_context->GetRenderPass();
1889 void Canvas::SetBackdropData(
1890 std::unordered_map<int64_t, BackdropData> backdrop_data,
1891 size_t backdrop_count) {
1892 backdrop_data_ = std::move(backdrop_data);
1893 backdrop_count_ = backdrop_count;
1896 std::shared_ptr<Texture> Canvas::FlipBackdrop(
Point global_pass_position,
1897 bool should_remove_texture,
1898 bool should_use_onscreen,
1899 bool post_depth_increment) {
1901 render_passes_.pop_back();
1917 <<
"Failed to end the current render pass in order to read from "
1918 "the backdrop texture and apply an advanced blend or backdrop "
1929 const std::shared_ptr<Texture>& input_texture =
1932 if (!input_texture) {
1933 VALIDATION_LOG <<
"Failed to fetch the color texture in order to "
1934 "apply an advanced blend or backdrop filter.";
1937 render_passes_.push_back(LazyRenderingConfig(
1943 if (should_use_onscreen) {
1944 ColorAttachment color0 = render_target_.GetColorAttachment(0);
1948 color0.
load_action = color0.resolve_texture !=
nullptr
1949 ? LoadAction::kDontCare
1950 : LoadAction::kLoad;
1951 render_target_.SetColorAttachment(color0, 0);
1953 auto entity_pass_target = std::make_unique<EntityPassTarget>(
1955 renderer_.GetDeviceCapabilities().SupportsReadFromResolve(),
1956 renderer_.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()
1958 render_passes_.push_back(
1959 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1960 requires_readback_ =
false;
1962 render_passes_.push_back(LazyRenderingConfig(
1967 if (should_remove_texture) {
1968 render_passes_.back().entity_pass_target->RemoveSecondary();
1971 RenderPass& current_render_pass =
1972 *render_passes_.back().inline_pass_context->GetRenderPass();
1981 Rect size_rect = Rect::MakeSize(input_texture->GetSize());
1982 auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect);
1983 msaa_backdrop_contents->SetStencilEnabled(
false);
1984 msaa_backdrop_contents->SetLabel(
"MSAA backdrop");
1985 msaa_backdrop_contents->SetSourceRect(size_rect);
1986 msaa_backdrop_contents->SetTexture(input_texture);
1988 Entity msaa_backdrop_entity;
1989 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
1990 msaa_backdrop_entity.SetBlendMode(BlendMode::kSrc);
1991 msaa_backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
1992 if (!msaa_backdrop_entity.Render(renderer_, current_render_pass)) {
1999 auto& replay_entities = clip_coverage_stack_.GetReplayEntities();
2000 uint64_t current_depth =
2001 post_depth_increment ? current_depth_ - 1 : current_depth_;
2002 for (
const auto& replay : replay_entities) {
2003 if (replay.clip_depth <= current_depth) {
2007 SetClipScissor(replay.clip_coverage, current_render_pass,
2008 global_pass_position);
2009 if (!replay.clip_contents.Render(renderer_, current_render_pass,
2010 replay.clip_depth)) {
2015 return input_texture;
2018 bool Canvas::SupportsBlitToOnscreen()
const {
2019 return renderer_.GetContext()
2021 ->SupportsTextureToTextureBlits() &&
2022 renderer_.GetContext()->GetBackendType() ==
2023 Context::BackendType::kMetal;
2026 bool Canvas::BlitToOnscreen(
bool is_onscreen) {
2027 auto command_buffer = renderer_.GetContext()->CreateCommandBuffer();
2028 command_buffer->SetLabel(
"EntityPass Root Command Buffer");
2029 auto offscreen_target = render_passes_.back()
2030 .inline_pass_context->GetPassTarget()
2032 if (SupportsBlitToOnscreen()) {
2033 auto blit_pass = command_buffer->CreateBlitPass();
2034 blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(),
2035 render_target_.GetRenderTargetTexture());
2036 if (!blit_pass->EncodeCommands()) {
2041 auto render_pass = command_buffer->CreateRenderPass(render_target_);
2042 render_pass->SetLabel(
"EntityPass Root Render Pass");
2045 auto size_rect = Rect::MakeSize(offscreen_target.GetRenderTargetSize());
2046 auto contents = TextureContents::MakeRect(size_rect);
2047 contents->SetTexture(offscreen_target.GetRenderTargetTexture());
2048 contents->SetSourceRect(size_rect);
2049 contents->SetLabel(
"Root pass blit");
2052 entity.SetContents(contents);
2053 entity.SetBlendMode(BlendMode::kSrc);
2055 if (!entity.Render(renderer_, *render_pass)) {
2061 if (!render_pass->EncodeCommands()) {
2068 return renderer_.GetContext()->SubmitOnscreen(std::move(command_buffer));
2070 return renderer_.GetContext()->EnqueueCommandBuffer(
2071 std::move(command_buffer));
2075 bool Canvas::EnsureFinalMipmapGeneration()
const {
2076 if (!render_target_.GetRenderTargetTexture()->NeedsMipmapGeneration()) {
2079 std::shared_ptr<CommandBuffer> cmd_buffer =
2080 renderer_.GetContext()->CreateCommandBuffer();
2084 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
2088 blit_pass->GenerateMipmap(render_target_.GetRenderTargetTexture());
2089 blit_pass->EncodeCommands();
2090 return renderer_.GetContext()->EnqueueCommandBuffer(std::move(cmd_buffer));
2093 void Canvas::EndReplay() {
2094 FML_DCHECK(render_passes_.size() == 1u);
2095 render_passes_.back().inline_pass_context->GetRenderPass();
2096 render_passes_.back().inline_pass_context->EndPass(
2097 !requires_readback_ && is_onscreen_);
2098 backdrop_data_.clear();
2103 if (requires_readback_) {
2104 BlitToOnscreen(is_onscreen_);
2106 if (!EnsureFinalMipmapGeneration()) {
2109 if (!renderer_.GetContext()->FlushCommandBuffers()) {
2113 render_passes_.clear();
2114 renderer_.GetRenderTargetCache()->End();
2115 clip_geometry_.clear();
2118 Initialize(initial_cull_rect_);
A Geometry that produces fillable vertices representing the stroked outline of an |Arc| object using ...
void ClipGeometry(const Geometry &geometry, Entity::ClipOperation clip_op, bool is_aa=true)
static constexpr uint32_t kMaxDepth
Canvas(ContentContext &renderer, const RenderTarget &render_target, bool is_onscreen, bool requires_readback)
void DrawRoundSuperellipse(const RoundSuperellipse &rse, const Paint &paint)
std::optional< Rect > GetLocalCoverageLimit() const
Return the culling bounds of the current render target, or nullopt if there is no coverage.
void SaveLayer(const Paint &paint, std::optional< Rect > bounds=std::nullopt, const flutter::DlImageFilter *backdrop_filter=nullptr, ContentBoundsPromise bounds_promise=ContentBoundsPromise::kUnknown, uint32_t total_content_depth=kMaxDepth, bool can_distribute_opacity=false, std::optional< int64_t > backdrop_id=std::nullopt)
const Matrix & GetCurrentTransform() const
void DrawVertices(const std::shared_ptr< VerticesGeometry > &vertices, BlendMode blend_mode, const Paint &paint)
void DrawOval(const Rect &rect, const Paint &paint)
void DrawImageRect(const std::shared_ptr< Texture > &image, Rect source, Rect dest, const Paint &paint, const SamplerDescriptor &sampler={}, SourceRectConstraint src_rect_constraint=SourceRectConstraint::kFast)
void RestoreToCount(size_t count)
size_t GetSaveCount() const
void Concat(const Matrix &transform)
void Transform(const Matrix &transform)
void DrawDashedLine(const Point &p0, const Point &p1, Scalar on_length, Scalar off_length, const Paint &paint)
void DrawDiffRoundRect(const RoundRect &outer, const RoundRect &inner, const Paint &paint)
void DrawPath(const flutter::DlPath &path, const Paint &paint)
std::function< std::shared_ptr< FilterContents >(FilterInput::Ref, const Matrix &effect_transform, Entity::RenderingMode rendering_mode)> BackdropFilterProc
void PreConcat(const Matrix &transform)
void Rotate(Radians radians)
void DrawPoints(const Point points[], uint32_t count, Scalar radius, const Paint &paint, PointStyle point_style)
void DrawTextFrame(const std::shared_ptr< TextFrame > &text_frame, Point position, const Paint &paint)
void DrawImage(const std::shared_ptr< Texture > &image, Point offset, const Paint &paint, const SamplerDescriptor &sampler={})
void DrawPaint(const Paint &paint)
void DrawRoundRect(const RoundRect &rect, const Paint &paint)
void Skew(Scalar sx, Scalar sy)
void Scale(const Vector2 &scale)
void Save(uint32_t total_content_depth=kMaxDepth)
void DrawRect(const Rect &rect, const Paint &paint)
void DrawAtlas(const std::shared_ptr< AtlasContents > &atlas_contents, const Paint &paint)
void DrawLine(const Point &p0, const Point &p1, const Paint &paint, bool reuse_depth=false)
void Translate(const Vector3 &offset)
void DrawCircle(const Point ¢er, Scalar radius, const Paint &paint)
void DrawArc(const Arc &arc, const Paint &paint)
virtual bool SupportsImplicitResolvingMSAA() const =0
Whether the context backend supports multisampled rendering to the on-screen surface without requirin...
virtual bool SupportsFramebufferFetch() const =0
Whether the context backend is able to support pipelines with shaders that read from the framebuffer ...
virtual bool SupportsReadFromResolve() const =0
Whether the context backend supports binding the current RenderPass attachments. This is supported if...
void SetGeometry(GeometryResult geometry)
Set the pre-tessellated clip geometry.
void SetClipOperation(Entity::ClipOperation clip_op)
bool Render(const ContentContext &renderer, RenderPass &pass, uint32_t clip_depth) const
static std::shared_ptr< ColorFilterContents > MakeBlend(BlendMode blend_mode, FilterInput::Vector inputs, std::optional< Color > foreground_color=std::nullopt)
the [inputs] are expected to be in the order of dst, src.
const Capabilities & GetDeviceCapabilities() const
const std::shared_ptr< RenderTargetAllocator > & GetRenderTargetCache() const
TextShadowCache & GetTextShadowCache() const
std::shared_ptr< Context > GetContext() const
A geometry that implements "drawPaint" like behavior by covering the entire render pass area.
A Geometry class that can directly generate vertices (with or without texture coordinates) for filled...
void SetTransform(const Matrix &transform)
Set the global transform matrix for this Entity.
std::optional< Rect > GetCoverage() const
@ kSubpassPrependSnapshotTransform
@ kSubpassAppendSnapshotTransform
const std::shared_ptr< Contents > & GetContents() const
void SetClipDepth(uint32_t clip_depth)
BlendMode GetBlendMode() const
void SetContents(std::shared_ptr< Contents > contents)
void SetBlendMode(BlendMode blend_mode)
bool Render(const ContentContext &renderer, RenderPass &parent_pass) const
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
static constexpr BlendMode kLastPipelineBlendMode
static bool IsBlendModeDestructive(BlendMode blend_mode)
Returns true if the blend mode is "destructive", meaning that even fully transparent source colors wo...
A class that tracks all clips that have been recorded in the current entity pass stencil.
std::optional< Rect > CurrentClipCoverage() const
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_height)
ReplayResult & GetLastReplayResult()
ClipStateResult RecordClip(const ClipContents &clip_contents, Matrix transform, Point global_pass_position, uint32_t clip_depth, size_t clip_height_floor, bool is_aa)
ClipStateResult RecordRestore(Point global_pass_position, size_t restore_height)
A Geometry that produces fillable vertices for the gap between a pair of |RoundRect| objects using th...
A Geometry that produces fillable vertices from a |DlPath| object using the |FillPathSourceGeometry| ...
A Geometry class that produces fillable vertices from any |RoundRect| object regardless of radii unif...
@ kNormal
Blurred inside and outside.
@ kOuter
Nothing inside, blurred outside.
@ kInner
Blurred inside, nothing outside.
@ kSolid
Solid inside, blurred outside.
static std::unique_ptr< Geometry > MakeRect(const Rect &rect)
virtual GeometryResult GetPositionBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const =0
virtual bool CanApplyMaskFilter() const
virtual std::optional< Rect > GetCoverage(const Matrix &transform) const =0
virtual bool IsAxisAlignedRect() const
static std::unique_ptr< LineContents > Make(std::unique_ptr< LineGeometry > geometry, Color color)
A geometry class specialized for Canvas::DrawPoints.
ColorAttachment GetColorAttachment(size_t index) const
Get the color attachment at [index].
RenderTarget & SetColorAttachment(const ColorAttachment &attachment, size_t index)
ISize GetRenderTargetSize() const
const std::optional< DepthAttachment > & GetDepthAttachment() const
const std::optional< StencilAttachment > & GetStencilAttachment() const
void SetupDepthStencilAttachments(const Context &context, Allocator &allocator, ISize size, bool msaa, std::string_view label="Offscreen", RenderTarget::AttachmentConfig stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &depth_stencil_texture=nullptr)
A Geometry class that generates fillable vertices (with or without texture coordinates) directly from...
A Geometry class that generates fillable vertices (with or without texture coordinates) directly from...
A Geometry that produces fillable vertices representing the stroked outline of a |DlPath| object usin...
A Geometry that produces fillable vertices representing the stroked outline of a pair of nested |Roun...
A Geometry class that produces fillable vertices representing the stroked outline of an ellipse with ...
A Geometry that produces fillable vertices representing the stroked outline of a |DlPath| object usin...
A Geometry class that produces fillable vertices representing the stroked outline of any |Roundrect| ...
A Geometry class that produces fillable vertices representing the stroked outline of any |RoundSupere...
std::optional< Entity > Lookup(const ContentContext &renderer, const Entity &entity, const std::shared_ptr< FilterContents > &contents, const TextShadowCacheKey &)
Lookup the entity in the cache with the given filter/text contents, returning the new entity to rende...
static std::shared_ptr< TextureContents > MakeRect(Rect destination)
ISize subpass_size
The output size of the down-sampling pass.
impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlImageSampling options)
Color ToColor(const flutter::DlColor &color)
static constexpr Scalar kMaxTextScale
std::shared_ptr< ColorFilterContents > WrapWithGPUColorFilter(const flutter::DlColorFilter *filter, const std::shared_ptr< FilterInput > &input, ColorFilterContents::AbsorbOpacity absorb_opacity)
SourceRectConstraint
Controls the behavior of the source rectangle given to DrawImageRect.
@ kStrict
Sample only within the source rectangle. May be slower.
std::shared_ptr< FilterContents > WrapInput(const flutter::DlImageFilter *filter, const FilterInput::Ref &input)
Generate a new FilterContents using this filter's configuration.
constexpr float kEhCloseEnough
std::shared_ptr< ColorFilterContents > WrapWithInvertColors(const std::shared_ptr< FilterInput > &input, ColorFilterContents::AbsorbOpacity absorb_opacity)
@ kRound
Points are drawn as squares.
ColorFilterProc GetCPUColorFilterProc(const flutter::DlColorFilter *filter)
@ kMayClipContents
The caller claims the bounds are a subset of an estimate of the reasonably tight bounds but likely cl...
@ kContainsContents
The caller claims the bounds are a reasonably tight estimate of the coverage of the contents and shou...
static constexpr const ColorMatrix kColorInversion
A color matrix which inverts colors.
std::optional< Rect > ComputeSaveLayerCoverage(const Rect &content_coverage, const Matrix &effect_transform, const Rect &coverage_limit, const std::shared_ptr< FilterContents > &image_filter, bool flood_output_coverage, bool flood_input_coverage)
Compute the coverage of a subpass in the global coordinate space.
constexpr bool IncludeCenter() const
constexpr bool IsFullCircle() const
const Rect & GetOvalBounds() const
Return the bounds of the oval in which this arc is inscribed.
constexpr Degrees GetSweep() const
constexpr Degrees GetStart() const
std::shared_ptr< Texture > texture
std::shared_ptr< Texture > texture_slot
std::optional< Snapshot > shared_filter_snapshot
Entity::RenderingMode rendering_mode
static constexpr Color BlackTransparent()
static constexpr Color Khaki()
static constexpr Color White()
constexpr Color WithAlpha(Scalar new_alpha) const
ClipContents clip_contents
std::unique_ptr< InlinePassContext > inline_pass_context
std::unique_ptr< EntityPassTarget > entity_pass_target
A 4x4 matrix using column-major storage.
static constexpr Matrix MakeTranslation(const Vector3 &t)
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
static constexpr Matrix MakeTranslateScale(const Vector3 &s, const Vector3 &t)
static Matrix MakeRotationZ(Radians r)
static constexpr Matrix MakeScale(const Vector3 &s)
Scalar GetMaxBasisLengthXY() const
Return the maximum scale applied specifically to either the X axis or Y axis unit vectors (the bases)...
std::shared_ptr< Contents > WithFilters(std::shared_ptr< Contents > input) const
Wrap this paint's configured filters to the given contents.
const flutter::DlColorFilter * color_filter
const flutter::DlColorSource * color_source
const flutter::DlImageFilter * image_filter
static bool CanApplyOpacityPeephole(const Paint &paint)
Whether or not a save layer with the provided paint can perform the opacity peephole optimization.
std::optional< MaskBlurDescriptor > mask_blur_descriptor
std::shared_ptr< FilterContents > WithImageFilter(const FilterInput::Variant &input, const Matrix &effect_transform, Entity::RenderingMode rendering_mode) const
std::shared_ptr< ColorSourceContents > CreateContents() const
bool HasColorFilter() const
Whether this paint has a color filter that can apply opacity.
constexpr const RoundingRadii & GetRadii() const
constexpr const Rect & GetBounds() const
constexpr const RoundingRadii & GetRadii() const
constexpr const Rect & GetBounds() const
Represents a texture and its intended draw transform/sampler configuration.
Matrix transform
The transform that should be applied to this texture for rendering.
std::shared_ptr< Texture > texture
SamplerDescriptor sampler_descriptor
constexpr Type GetDistance(const TPoint &p) const
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
constexpr auto GetBottom() const
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
constexpr auto GetTop() const
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified by the left/top or x/y values when it was...
constexpr std::optional< TRect > Intersection(const TRect &o) const
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
constexpr static TRect MakeOriginSize(const TPoint< Type > &origin, const TSize< Type > &size)
constexpr auto GetLeft() const
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
Round(const TRect< U > &r)
RoundOut(const TRect< U > &r)
constexpr auto GetRight() const
constexpr bool IsSquare() const
Returns true if width and height are equal and neither is NaN.
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
constexpr static TRect MakeSize(const TSize< U > &size)
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
constexpr Point GetCenter() const
Get the center point as a |Point|.
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
constexpr static TRect MakeMaximum()
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
std::vector< Point > points