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);
88 scissor = scissor.Intersection(
IRect::MakeSize(pass.GetRenderTargetSize()))
91 pass.SetScissor(scissor);
94 static void ApplyFramebufferBlend(Entity& entity) {
95 auto src_contents = entity.GetContents();
96 auto contents = std::make_shared<FramebufferBlendContents>();
97 contents->SetChildContents(src_contents);
98 contents->SetBlendMode(entity.GetBlendMode());
99 entity.SetContents(std::move(contents));
105 static std::shared_ptr<Contents> CreateContentsForSubpassTarget(
107 const std::shared_ptr<Texture>& target,
108 const Matrix& effect_transform) {
110 contents->SetTexture(target);
111 contents->SetLabel(
"Subpass");
113 contents->SetOpacity(paint.color.alpha);
114 contents->SetDeferApplyingOpacity(
true);
116 return paint.WithFiltersForSubpassTarget(std::move(contents),
120 static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig =
121 RenderTarget::AttachmentConfig{
127 static std::unique_ptr<EntityPassTarget> CreateRenderTarget(
128 ContentContext& renderer,
130 const Color& clear_color) {
131 const std::shared_ptr<Context>& context = renderer.GetContext();
139 if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
140 target = renderer.GetRenderTargetCache()->CreateOffscreenMSAA(
146 RenderTarget::AttachmentConfigMSAA{
151 .clear_color = clear_color},
152 kDefaultStencilConfig);
154 target = renderer.GetRenderTargetCache()->CreateOffscreen(
159 RenderTarget::AttachmentConfig{
163 .clear_color = clear_color,
165 kDefaultStencilConfig
169 return std::make_unique<EntityPassTarget>(
171 renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
172 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()
178 std::shared_ptr<SolidRRectLikeBlurContents>
179 Canvas::RRectBlurShape::BuildBlurContent() {
180 return std::make_shared<SolidRRectBlurContents>();
183 Geometry& Canvas::RRectBlurShape::BuildGeometry(
Rect rect,
Scalar radius) {
184 return geom_.emplace(rect,
Size{radius, radius});
187 std::shared_ptr<SolidRRectLikeBlurContents>
188 Canvas::RSuperellipseBlurShape::BuildBlurContent() {
189 return std::make_shared<SolidRSuperellipseBlurContents>();
192 Geometry& Canvas::RSuperellipseBlurShape::BuildGeometry(
Rect rect,
194 return geom_.emplace(rect, radius);
200 bool requires_readback)
201 : renderer_(renderer),
202 render_target_(render_target),
203 is_onscreen_(is_onscreen),
204 requires_readback_(requires_readback),
206 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
207 Initialize(std::nullopt);
214 bool requires_readback,
216 : renderer_(renderer),
217 render_target_(render_target),
218 is_onscreen_(is_onscreen),
219 requires_readback_(requires_readback),
221 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
222 Initialize(cull_rect);
229 bool requires_readback,
231 : renderer_(renderer),
232 render_target_(render_target),
233 is_onscreen_(is_onscreen),
234 requires_readback_(requires_readback),
236 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
242 void Canvas::Initialize(std::optional<Rect> cull_rect) {
243 initial_cull_rect_ = cull_rect;
250 void Canvas::Reset() {
252 transform_stack_ = {};
264 transform_stack_.back().transform = {};
272 return transform_stack_.back().transform;
295 Point Canvas::GetGlobalPassPosition()
const {
296 if (save_layer_state_.empty()) {
299 return save_layer_state_.back().coverage.GetOrigin();
303 size_t Canvas::GetClipHeightFloor()
const {
304 if (transform_stack_.size() > 1) {
305 return transform_stack_[transform_stack_.size() - 2].clip_height;
311 return transform_stack_.size();
314 bool Canvas::IsSkipping()
const {
315 return transform_stack_.back().skipping;
333 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
336 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
346 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
353 bool Canvas::AttemptColorFilterOptimization(
354 const std::shared_ptr<Texture>& image,
368 if (paint.
color_filter->type() == flutter::DlColorFilterType::kBlend) {
369 const flutter::DlBlendColorFilter* blend_filter =
371 DrawImageRectAtlasGeometry geometry = DrawImageRectAtlasGeometry(
376 blend_filter->mode(),
378 src_rect_constraint ==
381 auto atlas_contents = std::make_shared<AtlasContents>();
382 atlas_contents->SetGeometry(&geometry);
388 entity.SetContents(atlas_contents);
390 AddRenderEntityToCurrentPass(entity);
398 const flutter::DlMatrixColorFilter* matrix_filter =
401 DrawImageRectAtlasGeometry geometry = DrawImageRectAtlasGeometry(
408 src_rect_constraint ==
411 auto atlas_contents = std::make_shared<ColorFilterAtlasContents>();
412 atlas_contents->SetGeometry(&geometry);
415 matrix_filter->get_matrix(color_matrix.
array);
416 atlas_contents->SetMatrix(color_matrix);
421 entity.SetContents(atlas_contents);
423 AddRenderEntityToCurrentPass(entity);
428 bool Canvas::AttemptDrawBlurredRRect(
const Rect& rect,
430 const Paint& paint) {
431 RRectBlurShape rrect_shape;
432 return AttemptDrawBlurredRRectLike(rect, corner_radii, paint, rrect_shape);
435 bool Canvas::AttemptDrawBlurredRSuperellipse(
const Rect& rect,
437 const Paint& paint) {
438 RSuperellipseBlurShape rsuperellipse_shape;
439 return AttemptDrawBlurredRRectLike(rect, corner_radii, paint,
440 rsuperellipse_shape);
443 bool Canvas::AttemptDrawBlurredRRectLike(
const Rect& rect,
446 RRectLikeBlurShape& shape) {
451 if (paint.color_source) {
455 if (!paint.mask_blur_descriptor.has_value()) {
465 if (fabsf(corner_radii.width - corner_radii.height) >
kEhCloseEnough) {
468 Scalar corner_radius = corner_radii.width;
472 Color rrect_color = paint.color;
473 if (paint.invert_colors) {
476 if (paint.color_filter) {
480 Paint rrect_paint = {.mask_blur_descriptor = paint.mask_blur_descriptor};
501 if ((paint.mask_blur_descriptor->style !=
503 paint.image_filter) ||
506 Rect render_bounds = rect;
507 if (paint.mask_blur_descriptor->style !=
510 render_bounds.
Expand(paint.mask_blur_descriptor->sigma.sigma * 4.0);
516 .image_filter = paint.image_filter,
517 .blend_mode = paint.blend_mode,
520 rrect_paint.color = rrect_color.WithAlpha(1);
522 rrect_paint.color = rrect_color;
523 rrect_paint.blend_mode = paint.blend_mode;
524 rrect_paint.image_filter = paint.image_filter;
528 auto draw_blurred_rrect = [
this, &rect, corner_radius, &rrect_paint,
530 auto contents = shape.BuildBlurContent();
532 contents->SetColor(rrect_paint.color);
533 contents->SetSigma(rrect_paint.mask_blur_descriptor->sigma);
534 contents->SetShape(rect, corner_radius);
536 Entity blurred_rrect_entity;
538 blurred_rrect_entity.SetBlendMode(rrect_paint.blend_mode);
540 rrect_paint.mask_blur_descriptor = std::nullopt;
541 blurred_rrect_entity.SetContents(
542 rrect_paint.WithFilters(std::move(contents)));
543 AddRenderEntityToCurrentPass(blurred_rrect_entity);
546 switch (rrect_paint.mask_blur_descriptor->style) {
548 draw_blurred_rrect();
553 draw_blurred_rrect();
557 entity.SetBlendMode(rrect_paint.blend_mode);
559 Geometry& geom = shape.BuildGeometry(rect, corner_radius);
560 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, rrect_paint,
565 Geometry& geom = shape.BuildGeometry(rect, corner_radius);
567 draw_blurred_rrect();
571 Geometry& geom = shape.BuildGeometry(rect, corner_radius);
573 draw_blurred_rrect();
591 auto geometry = std::make_unique<LineGeometry>(p0, p1, paint.
stroke);
593 if (renderer_.
GetContext()->GetFlags().antialiased_lines &&
598 AddRenderEntityToCurrentPass(entity, reuse_depth);
600 AddRenderEntityWithFiltersToCurrentPass(entity, geometry.get(), paint,
609 const Paint& paint) {
619 if (length > 0.0f && on_length >= 0.0f && off_length > 0.0f) {
625 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
632 if (AttemptDrawBlurredRRect(rect, {}, paint)) {
642 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
645 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
661 if (AttemptDrawBlurredRRect(rect, rect.
GetSize() * 0.5f, paint)) {
671 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
674 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
685 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
698 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
711 return DrawOval(oval_bounds, paint);
724 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
730 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
735 auto& radii = round_rect.
GetRadii();
736 if (radii.AreAllCornersSame()) {
737 if (AttemptDrawBlurredRRect(rect, radii.top_left, paint)) {
747 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
758 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
761 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
767 const Paint& paint) {
774 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
777 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
782 const Paint& paint) {
783 auto& rect = round_superellipse.
GetBounds();
784 auto& radii = round_superellipse.
GetRadii();
785 if (radii.AreAllCornersSame() &&
786 AttemptDrawBlurredRSuperellipse(rect, radii.top_left, paint)) {
796 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
799 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
805 const Paint& paint) {
806 Size half_size(radius, radius);
807 if (AttemptDrawBlurredRRect(
809 {radius, radius}, paint)) {
819 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
822 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
843 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
844 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
845 uint32_t clip_depth = transform_stack_.back().clip_depth;
847 const Matrix clip_transform =
851 std::optional<Rect> clip_coverage = geometry.
GetCoverage(clip_transform);
852 if (!clip_coverage.has_value()) {
857 clip_coverage.value(),
866 GetGlobalPassPosition(),
868 GetClipHeightFloor(),
874 *render_passes_.back().inline_pass_context->GetRenderPass(),
875 GetGlobalPassPosition());
878 ++transform_stack_.back().clip_height;
879 ++transform_stack_.back().num_clips;
896 *render_passes_.back().inline_pass_context->GetRenderPass()
903 renderer_, *render_passes_.back().inline_pass_context->GetRenderPass(),
922 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
949 ISize size = image->GetSize();
954 std::optional<Rect> clipped_source =
956 if (!clipped_source) {
960 if (AttemptColorFilterOptimization(image, source, dest, paint, sampler,
961 src_rect_constraint)) {
965 if (*clipped_source != source) {
975 texture_contents->SetTexture(image);
976 texture_contents->SetSourceRect(*clipped_source);
977 texture_contents->SetStrictSourceRect(src_rect_constraint ==
979 texture_contents->SetSamplerDescriptor(sampler);
980 texture_contents->SetOpacity(paint.
color.
alpha);
981 texture_contents->SetDeferApplyingOpacity(paint.
HasColorFilter());
989 AddRenderEntityToCurrentPass(entity);
997 AddRenderEntityToCurrentPass(entity);
1000 size_t Canvas::GetClipHeight()
const {
1001 return transform_stack_.back().clip_height;
1006 const Paint& paint) {
1019 if (UseColorSourceContents(vertices, paint)) {
1020 AddRenderEntityWithFiltersToCurrentPass(entity, vertices.get(), paint);
1026 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1027 contents->SetBlendMode(blend_mode);
1029 contents->SetGeometry(vertices);
1031 AddRenderEntityToCurrentPass(entity);
1038 paint.
color_source->type() == flutter::DlColorSourceType::kImage) {
1039 const flutter::DlImageColorSource* image_color_source =
1041 FML_DCHECK(image_color_source &&
1042 image_color_source->image()->impeller_texture());
1043 auto texture = image_color_source->image()->impeller_texture();
1045 image_color_source->horizontal_tile_mode());
1048 auto sampler_descriptor =
1050 auto effect_transform = image_color_source->matrix();
1052 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1053 contents->SetBlendMode(blend_mode);
1055 contents->SetGeometry(vertices);
1056 contents->SetEffectTransform(effect_transform);
1057 contents->SetTexture(texture);
1058 contents->SetTileMode(x_tile_mode, y_tile_mode);
1059 contents->SetSamplerDescriptor(sampler_descriptor);
1062 AddRenderEntityToCurrentPass(entity);
1066 auto src_paint = paint;
1069 std::shared_ptr<ColorSourceContents> src_contents =
1070 src_paint.CreateContents();
1071 src_contents->SetGeometry(vertices.get());
1079 auto size = src_contents->GetColorSourceSize();
1080 if (size.has_value()) {
1083 auto cvg = vertices->GetCoverage(
Matrix{});
1084 FML_CHECK(cvg.has_value());
1085 auto texture_coverage = vertices->GetTextureCoordinateCoverage();
1086 if (texture_coverage.has_value()) {
1089 texture_coverage->GetSize().Max({1, 1}));
1091 src_coverage = cvg.value();
1094 src_contents = src_paint.CreateContents();
1097 src_contents->SetGeometry(clip_geometry_.back().get());
1099 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1100 contents->SetBlendMode(blend_mode);
1102 contents->SetGeometry(vertices);
1103 contents->SetLazyTextureCoverage(src_coverage);
1104 contents->SetLazyTexture([src_contents,
1110 src_contents->RenderToSnapshot(renderer, {},
Rect::Round(src_coverage));
1111 return snapshot.has_value() ? snapshot->texture :
nullptr;
1114 AddRenderEntityToCurrentPass(entity);
1118 const Paint& paint) {
1126 AddRenderEntityToCurrentPass(entity);
1132 void Canvas::SetupRenderPass() {
1138 if (!stencil_attachment.has_value() || !depth_attachment.has_value()) {
1143 *renderer_.
GetContext()->GetResourceAllocator(),
1145 renderer_.
GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
1146 "ImpellerOnscreen", kDefaultStencilConfig);
1158 if (requires_readback_) {
1159 auto entity_pass_target =
1160 CreateRenderTarget(renderer_,
1163 render_passes_.push_back(
1164 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1166 auto entity_pass_target = std::make_unique<EntityPassTarget>(
1171 render_passes_.push_back(
1172 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1176 void Canvas::SkipUntilMatchingRestore(
size_t total_content_depth) {
1177 auto entry = CanvasStackEntry{};
1178 entry.skipping =
true;
1179 entry.clip_depth = current_depth_ + total_content_depth;
1180 transform_stack_.push_back(entry);
1185 return SkipUntilMatchingRestore(total_content_depth);
1189 entry.
transform = transform_stack_.back().transform;
1190 entry.clip_depth = current_depth_ + total_content_depth;
1191 entry.distributed_opacity = transform_stack_.back().distributed_opacity;
1192 FML_DCHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
1193 << entry.clip_depth <<
" <=? " << transform_stack_.back().clip_depth
1194 <<
" after allocating " << total_content_depth;
1195 entry.clip_height = transform_stack_.back().clip_height;
1197 transform_stack_.push_back(entry);
1204 return std::nullopt;
1208 if (!maybe_current_clip_coverage.has_value()) {
1209 return std::nullopt;
1212 auto current_clip_coverage = maybe_current_clip_coverage.value();
1216 std::optional<Rect> maybe_coverage_limit =
1218 Size(render_passes_.back()
1219 .inline_pass_context->GetTexture()
1223 if (!maybe_coverage_limit.has_value() || maybe_coverage_limit->IsEmpty()) {
1224 return std::nullopt;
1227 return maybe_coverage_limit->Intersection(
1232 std::optional<Rect> bounds,
1233 const flutter::DlImageFilter* backdrop_filter,
1235 uint32_t total_content_depth,
1236 bool can_distribute_opacity,
1237 std::optional<int64_t> backdrop_id) {
1238 TRACE_EVENT0(
"flutter",
"Canvas::saveLayer");
1240 return SkipUntilMatchingRestore(total_content_depth);
1244 if (!maybe_coverage_limit.has_value()) {
1245 return SkipUntilMatchingRestore(total_content_depth);
1247 auto coverage_limit = maybe_coverage_limit.value();
1249 if (can_distribute_opacity && !backdrop_filter &&
1252 Save(total_content_depth);
1253 transform_stack_.back().distributed_opacity *= paint.
color.
alpha;
1257 std::shared_ptr<FilterContents> filter_contents = paint.
WithImageFilter(
1258 Rect(), transform_stack_.back().transform,
1263 transform_stack_.back().transform,
1268 !!backdrop_filter ||
1273 if (!maybe_subpass_coverage.has_value()) {
1274 return SkipUntilMatchingRestore(total_content_depth);
1277 auto subpass_coverage = maybe_subpass_coverage.value();
1288 bool did_round_out =
false;
1289 Point coverage_origin_adjustment =
Point{0, 0};
1293 did_round_out =
true;
1297 coverage_origin_adjustment =
1298 Point(subpass_coverage.GetLeftTop().x -
1299 std::floor(subpass_coverage.GetLeftTop().x),
1300 subpass_coverage.GetLeftTop().y -
1301 std::floor(subpass_coverage.GetLeftTop().y));
1304 return SkipUntilMatchingRestore(total_content_depth);
1312 ->GetMaximumRenderPassAttachmentSize());
1315 std::shared_ptr<FilterContents> backdrop_filter_contents;
1317 if (backdrop_filter) {
1318 local_position = subpass_coverage.GetOrigin() - GetGlobalPassPosition();
1320 [backdrop_filter = backdrop_filter](
1323 auto filter =
WrapInput(backdrop_filter, input);
1324 filter->SetEffectTransform(effect_transform);
1325 filter->SetRenderingMode(rendering_mode);
1329 std::shared_ptr<Texture> input_texture;
1334 bool will_cache_backdrop_texture =
false;
1339 size_t backdrop_count = 1;
1340 if (backdrop_id.has_value()) {
1341 std::unordered_map<int64_t, BackdropData>::iterator backdrop_data_it =
1342 backdrop_data_.find(backdrop_id.value());
1343 if (backdrop_data_it != backdrop_data_.end()) {
1344 backdrop_data = &backdrop_data_it->second;
1345 will_cache_backdrop_texture =
1347 backdrop_count = backdrop_data_it->second.backdrop_count;
1351 if (!will_cache_backdrop_texture || !backdrop_data->
texture_slot) {
1352 backdrop_count_ -= backdrop_count;
1358 const bool should_use_onscreen =
1360 backdrop_count_ == 0 && render_passes_.size() == 1u;
1361 input_texture = FlipBackdrop(
1362 GetGlobalPassPosition(),
1363 will_cache_backdrop_texture,
1366 if (!input_texture) {
1371 if (will_cache_backdrop_texture) {
1378 backdrop_filter_contents = backdrop_filter_proc(
1380 transform_stack_.back().transform.Basis(),
1383 transform_stack_.back().transform.HasTranslation()
1387 if (will_cache_backdrop_texture) {
1388 FML_DCHECK(backdrop_data);
1395 backdrop_filter_contents->RenderToSnapshot(renderer_, {});
1398 std::optional<Snapshot> maybe_snapshot =
1400 if (maybe_snapshot.has_value()) {
1401 Snapshot snapshot = maybe_snapshot.value();
1403 subpass_coverage.Shift(-GetGlobalPassPosition()));
1406 contents->SetTexture(snapshot.
texture);
1407 contents->SetSourceRect(scaled);
1417 backdrop_entity.
Render(renderer_, GetCurrentRenderPass());
1425 Paint paint_copy = paint;
1426 paint_copy.
color.
alpha *= transform_stack_.back().distributed_opacity;
1427 transform_stack_.back().distributed_opacity = 1.0;
1429 render_passes_.push_back(
1431 CreateRenderTarget(renderer_,
1436 paint_copy, subpass_coverage.Shift(-coverage_origin_adjustment)});
1439 entry.
transform = transform_stack_.back().transform;
1440 entry.
clip_depth = current_depth_ + total_content_depth;
1441 FML_DCHECK(entry.
clip_depth <= transform_stack_.back().clip_depth)
1442 << entry.
clip_depth <<
" <=? " << transform_stack_.back().clip_depth
1443 <<
" after allocating " << total_content_depth;
1444 entry.
clip_height = transform_stack_.back().clip_height;
1447 transform_stack_.emplace_back(entry);
1454 clip_coverage_stack_.
PushSubpass(subpass_coverage, GetClipHeight());
1456 if (!backdrop_filter_contents) {
1462 backdrop_entity.
SetContents(std::move(backdrop_filter_contents));
1465 backdrop_entity.
SetClipDepth(std::numeric_limits<uint32_t>::max());
1466 backdrop_entity.
Render(renderer_, GetCurrentRenderPass());
1470 FML_DCHECK(transform_stack_.size() > 0);
1471 if (transform_stack_.size() == 1) {
1488 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1489 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
1490 current_depth_ = transform_stack_.back().clip_depth;
1493 transform_stack_.pop_back();
1497 if (transform_stack_.back().rendering_mode ==
1499 transform_stack_.back().rendering_mode ==
1501 auto lazy_render_pass = std::move(render_passes_.back());
1502 render_passes_.pop_back();
1504 lazy_render_pass.inline_pass_context->GetRenderPass();
1507 save_layer_state_.pop_back();
1508 auto global_pass_position = GetGlobalPassPosition();
1510 std::shared_ptr<Contents> contents = CreateContentsForSubpassTarget(
1511 save_layer_state.
paint,
1512 lazy_render_pass.inline_pass_context->GetTexture(),
1514 transform_stack_.back().transform
1517 lazy_render_pass.inline_pass_context->EndPass();
1524 Point subpass_texture_position;
1525 if (transform_stack_.back().did_round_out) {
1528 subpass_texture_position =
1533 subpass_texture_position =
1547 ApplyFramebufferBlend(element_entity);
1558 auto input_texture = FlipBackdrop(GetGlobalPassPosition());
1559 if (!input_texture) {
1569 contents->SetCoverageHint(element_entity.
GetCoverage());
1577 *render_passes_.back().inline_pass_context->GetRenderPass()
1580 transform_stack_.pop_back();
1588 size_t num_clips = transform_stack_.back().num_clips;
1589 transform_stack_.pop_back();
1591 if (num_clips > 0) {
1602 *render_passes_.back().inline_pass_context->GetRenderPass(),
1603 GetGlobalPassPosition()
1611 bool Canvas::AttemptBlurredTextOptimization(
1612 const std::shared_ptr<TextFrame>& text_frame,
1613 const std::shared_ptr<TextContents>& text_contents,
1615 const Paint& paint) {
1629 std::shared_ptr<FilterContents> filter =
1634 std::optional<Glyph> maybe_glyph = text_frame->AsSingleGlyph();
1635 int64_t identifier = maybe_glyph.has_value()
1636 ? maybe_glyph.value().index
1637 :
reinterpret_cast<int64_t
>(text_frame.get());
1638 TextShadowCache::TextShadowCacheKey cache_key(
1641 maybe_glyph.has_value(),
1642 text_frame->GetFont(),
1646 renderer_, entity, filter, cache_key);
1647 if (result.has_value()) {
1648 AddRenderEntityToCurrentPass(result.value(),
false);
1662 const Paint& paint) {
1664 if (max_scale * text_frame->GetFont().GetMetrics().point_size >
1666 fml::StatusOr<flutter::DlPath> path = text_frame->GetPath();
1680 auto text_contents = std::make_shared<TextContents>();
1681 text_contents->SetTextFrame(text_frame);
1683 text_contents->SetScale(max_scale);
1684 text_contents->SetColor(paint.
color);
1685 text_contents->SetOffset(position);
1686 text_contents->SetTextProperties(paint.
color,
1688 ? std::optional(paint.
stroke)
1694 if (AttemptBlurredTextOptimization(text_frame, text_contents, entity,
1700 AddRenderEntityToCurrentPass(entity,
false);
1703 void Canvas::AddRenderEntityWithFiltersToCurrentPass(
Entity& entity,
1707 std::shared_ptr<ColorSourceContents> contents = paint.
CreateContents();
1710 contents->SetGeometry(geometry);
1712 AddRenderEntityToCurrentPass(entity, reuse_depth);
1720 if (needs_color_filter &&
1721 contents->ApplyColorFilter([&](Color color) -> Color {
1722 if (paint.color_filter) {
1723 color = GetCPUColorFilterProc(paint.color_filter)(color);
1726 color = color.ApplyColorMatrix(kColorInversion);
1730 needs_color_filter =
false;
1734 contents->SetGeometry(geometry);
1740 FillRectGeometry out_rect(
Rect{});
1742 contents, needs_color_filter ? paint.
color_filter :
nullptr,
1743 needs_color_filter ? paint.
invert_colors :
false, &out_rect);
1745 AddRenderEntityToCurrentPass(entity, reuse_depth);
1749 std::shared_ptr<Contents> contents_copy = std::move(contents);
1753 if (needs_color_filter &&
1755 paint.
color_source->type() != flutter::DlColorSourceType::kImage)) {
1769 std::shared_ptr<FilterContents> filter =
WrapInput(
1773 AddRenderEntityToCurrentPass(entity, reuse_depth);
1778 AddRenderEntityToCurrentPass(entity, reuse_depth);
1781 void Canvas::AddRenderEntityToCurrentPass(Entity& entity,
bool reuse_depth) {
1786 entity.SetTransform(
1787 Matrix::MakeTranslation(Vector3(-GetGlobalPassPosition())) *
1788 entity.GetTransform());
1789 entity.SetInheritedOpacity(transform_stack_.back().distributed_opacity);
1790 if (entity.GetBlendMode() == BlendMode::kSrcOver &&
1791 entity.GetContents()->IsOpaque(entity.GetTransform())) {
1792 entity.SetBlendMode(BlendMode::kSrc);
1798 if (render_passes_.back().IsApplyingClearColor()) {
1799 std::optional<Color> maybe_color = entity.AsBackgroundColor(
1800 render_passes_.back().inline_pass_context->GetTexture()->GetSize());
1801 if (maybe_color.has_value()) {
1802 Color color = maybe_color.value();
1803 RenderTarget& render_target = render_passes_.back()
1804 .inline_pass_context->GetPassTarget()
1806 ColorAttachment attachment = render_target.GetColorAttachment(0);
1809 attachment.clear_color = attachment.clear_color.Unpremultiply()
1810 .Blend(color, entity.GetBlendMode())
1812 render_target.SetColorAttachment(attachment, 0u);
1823 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1824 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
1825 entity.SetClipDepth(current_depth_);
1827 if (entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
1828 if (renderer_.GetDeviceCapabilities().SupportsFramebufferFetch()) {
1829 ApplyFramebufferBlend(entity);
1840 auto input_texture = FlipBackdrop(GetGlobalPassPosition(),
1844 if (!input_texture) {
1852 auto element_coverage_hint = entity.GetContents()->GetCoverageHint();
1853 entity.GetContents()->SetCoverageHint(Rect::Intersection(
1854 element_coverage_hint, clip_coverage_stack_.CurrentClipCoverage()));
1856 FilterInput::Vector inputs = {
1857 FilterInput::Make(input_texture, entity.GetTransform().Invert()),
1858 FilterInput::Make(entity.GetContents())};
1860 ColorFilterContents::MakeBlend(entity.GetBlendMode(), inputs);
1861 entity.SetContents(std::move(contents));
1862 entity.SetBlendMode(BlendMode::kSrc);
1866 const std::shared_ptr<RenderPass>& result =
1867 render_passes_.back().inline_pass_context->GetRenderPass();
1875 entity.Render(renderer_, *result);
1878 RenderPass& Canvas::GetCurrentRenderPass()
const {
1879 return *render_passes_.back().inline_pass_context->GetRenderPass();
1882 void Canvas::SetBackdropData(
1883 std::unordered_map<int64_t, BackdropData> backdrop_data,
1884 size_t backdrop_count) {
1885 backdrop_data_ = std::move(backdrop_data);
1886 backdrop_count_ = backdrop_count;
1889 std::shared_ptr<Texture> Canvas::FlipBackdrop(
Point global_pass_position,
1890 bool should_remove_texture,
1891 bool should_use_onscreen,
1892 bool post_depth_increment) {
1894 render_passes_.pop_back();
1910 <<
"Failed to end the current render pass in order to read from "
1911 "the backdrop texture and apply an advanced blend or backdrop "
1922 const std::shared_ptr<Texture>& input_texture =
1925 if (!input_texture) {
1926 VALIDATION_LOG <<
"Failed to fetch the color texture in order to "
1927 "apply an advanced blend or backdrop filter.";
1930 render_passes_.push_back(LazyRenderingConfig(
1936 if (should_use_onscreen) {
1937 ColorAttachment color0 = render_target_.GetColorAttachment(0);
1941 color0.
load_action = color0.resolve_texture !=
nullptr
1942 ? LoadAction::kDontCare
1943 : LoadAction::kLoad;
1944 render_target_.SetColorAttachment(color0, 0);
1946 auto entity_pass_target = std::make_unique<EntityPassTarget>(
1948 renderer_.GetDeviceCapabilities().SupportsReadFromResolve(),
1949 renderer_.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()
1951 render_passes_.push_back(
1952 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1953 requires_readback_ =
false;
1955 render_passes_.push_back(LazyRenderingConfig(
1960 if (should_remove_texture) {
1961 render_passes_.back().entity_pass_target->RemoveSecondary();
1964 RenderPass& current_render_pass =
1965 *render_passes_.back().inline_pass_context->GetRenderPass();
1974 Rect size_rect = Rect::MakeSize(input_texture->GetSize());
1975 auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect);
1976 msaa_backdrop_contents->SetStencilEnabled(
false);
1977 msaa_backdrop_contents->SetLabel(
"MSAA backdrop");
1978 msaa_backdrop_contents->SetSourceRect(size_rect);
1979 msaa_backdrop_contents->SetTexture(input_texture);
1981 Entity msaa_backdrop_entity;
1982 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
1983 msaa_backdrop_entity.SetBlendMode(BlendMode::kSrc);
1984 msaa_backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
1985 if (!msaa_backdrop_entity.Render(renderer_, current_render_pass)) {
1992 auto& replay_entities = clip_coverage_stack_.GetReplayEntities();
1993 uint64_t current_depth =
1994 post_depth_increment ? current_depth_ - 1 : current_depth_;
1995 for (
const auto& replay : replay_entities) {
1996 if (replay.clip_depth <= current_depth) {
2000 SetClipScissor(replay.clip_coverage, current_render_pass,
2001 global_pass_position);
2002 if (!replay.clip_contents.Render(renderer_, current_render_pass,
2003 replay.clip_depth)) {
2008 return input_texture;
2011 bool Canvas::SupportsBlitToOnscreen()
const {
2012 return renderer_.GetContext()
2014 ->SupportsTextureToTextureBlits() &&
2015 renderer_.GetContext()->GetBackendType() ==
2016 Context::BackendType::kMetal;
2019 bool Canvas::BlitToOnscreen(
bool is_onscreen) {
2020 auto command_buffer = renderer_.GetContext()->CreateCommandBuffer();
2021 command_buffer->SetLabel(
"EntityPass Root Command Buffer");
2022 auto offscreen_target = render_passes_.back()
2023 .inline_pass_context->GetPassTarget()
2025 if (SupportsBlitToOnscreen()) {
2026 auto blit_pass = command_buffer->CreateBlitPass();
2027 blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(),
2028 render_target_.GetRenderTargetTexture());
2029 if (!blit_pass->EncodeCommands()) {
2034 auto render_pass = command_buffer->CreateRenderPass(render_target_);
2035 render_pass->SetLabel(
"EntityPass Root Render Pass");
2038 auto size_rect = Rect::MakeSize(offscreen_target.GetRenderTargetSize());
2039 auto contents = TextureContents::MakeRect(size_rect);
2040 contents->SetTexture(offscreen_target.GetRenderTargetTexture());
2041 contents->SetSourceRect(size_rect);
2042 contents->SetLabel(
"Root pass blit");
2045 entity.SetContents(contents);
2046 entity.SetBlendMode(BlendMode::kSrc);
2048 if (!entity.Render(renderer_, *render_pass)) {
2054 if (!render_pass->EncodeCommands()) {
2061 return renderer_.GetContext()->SubmitOnscreen(std::move(command_buffer));
2063 return renderer_.GetContext()->EnqueueCommandBuffer(
2064 std::move(command_buffer));
2068 bool Canvas::EnsureFinalMipmapGeneration()
const {
2069 if (!render_target_.GetRenderTargetTexture()->NeedsMipmapGeneration()) {
2072 std::shared_ptr<CommandBuffer> cmd_buffer =
2073 renderer_.GetContext()->CreateCommandBuffer();
2077 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
2081 blit_pass->GenerateMipmap(render_target_.GetRenderTargetTexture());
2082 blit_pass->EncodeCommands();
2083 return renderer_.GetContext()->EnqueueCommandBuffer(std::move(cmd_buffer));
2086 void Canvas::EndReplay() {
2087 FML_DCHECK(render_passes_.size() == 1u);
2088 render_passes_.back().inline_pass_context->GetRenderPass();
2089 render_passes_.back().inline_pass_context->EndPass(
2090 !requires_readback_ && is_onscreen_);
2091 backdrop_data_.clear();
2096 if (requires_readback_) {
2097 BlitToOnscreen(is_onscreen_);
2099 if (!EnsureFinalMipmapGeneration()) {
2102 if (!renderer_.GetContext()->FlushCommandBuffers()) {
2106 render_passes_.clear();
2107 renderer_.GetRenderTargetCache()->End();
2108 clip_geometry_.clear();
2111 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
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