11 #include "flutter/fml/logging.h"
12 #include "flutter/fml/trace_event.h"
34 static std::shared_ptr<Contents> CreateContentsForGeometryWithFilters(
36 std::shared_ptr<Geometry> geometry) {
37 std::shared_ptr<ColorSourceContents> contents =
44 if (needs_color_filter) {
46 if (contents->ApplyColorFilter(color_filter->GetCPUColorFilterProc())) {
47 needs_color_filter =
false;
51 bool can_apply_mask_filter = geometry->CanApplyMaskFilter();
52 contents->SetGeometry(std::move(geometry));
62 std::shared_ptr<Contents> contents_copy = std::move(contents);
65 if (needs_color_filter &&
68 contents_copy = color_filter->WrapWithGPUColorFilter(
83 struct GetTextureColorSourceDataVisitor {
84 GetTextureColorSourceDataVisitor() {}
86 std::optional<ImageData> operator()(
const LinearGradientData&
data) {
90 std::optional<ImageData> operator()(
const RadialGradientData&
data) {
94 std::optional<ImageData> operator()(
const ConicalGradientData&
data) {
98 std::optional<ImageData> operator()(
const SweepGradientData&
data) {
102 std::optional<ImageData> operator()(
const ImageData&
data) {
return data; }
104 std::optional<ImageData> operator()(
const RuntimeEffectData&
data) {
108 std::optional<ImageData> operator()(
const std::monostate&
data) {
112 #if IMPELLER_ENABLE_3D
113 std::optional<ImageData> operator()(
const SceneData&
data) {
116 #endif // IMPELLER_ENABLE_3D
119 static std::optional<ImageData> GetImageColorSourceData(
120 const ColorSource& color_source) {
121 return std::visit(GetTextureColorSourceDataVisitor{}, color_source.GetData());
124 static std::shared_ptr<Contents> CreatePathContentsWithFilters(
127 std::shared_ptr<Geometry> geometry;
139 return CreateContentsForGeometryWithFilters(
paint, std::move(geometry));
142 static std::shared_ptr<Contents> CreateCoverContentsWithFilters(
143 const Paint&
paint) {
166 base_pass_ = std::make_unique<EntityPass>();
168 current_pass_ = base_pass_.get();
174 FML_DCHECK(base_pass_->GetSubpassesDepth() == 1u);
178 base_pass_ =
nullptr;
179 current_pass_ =
nullptr;
185 Save(
false, total_content_depth);
194 virtual void Visit(
const LocalMatrixImageFilter& filter) {
195 required_mip_count_ = 1;
197 virtual void Visit(
const DilateImageFilter& filter) {
198 required_mip_count_ = 1;
200 virtual void Visit(
const ErodeImageFilter& filter) {
201 required_mip_count_ = 1;
203 virtual void Visit(
const MatrixImageFilter& filter) {
204 required_mip_count_ = 1;
206 virtual void Visit(
const ComposeImageFilter& filter) {
207 required_mip_count_ = 1;
209 virtual void Visit(
const ColorImageFilter& filter) {
210 required_mip_count_ = 1;
212 int32_t GetRequiredMipCount()
const {
return required_mip_count_; }
215 int32_t required_mip_count_ = -1;
220 uint32_t total_content_depth,
222 const std::shared_ptr<ImageFilter>& backdrop_filter) {
223 auto entry = CanvasStackEntry{};
228 if (create_subpass) {
229 entry.rendering_mode =
231 auto subpass = std::make_unique<EntityPass>();
232 if (backdrop_filter) {
234 [backdrop_filter = backdrop_filter->Clone()](
237 auto filter = backdrop_filter->WrapInput(input);
238 filter->SetEffectTransform(effect_transform);
239 filter->SetRenderingMode(rendering_mode);
242 subpass->SetBackdropFilter(backdrop_filter_proc);
243 MipCountVisitor mip_count_visitor;
244 backdrop_filter->Visit(mip_count_visitor);
247 mip_count_visitor.GetRequiredMipCount()));
249 subpass->SetBlendMode(blend_mode);
250 current_pass_ = GetCurrentPass().
AddSubpass(std::move(subpass));
271 FML_DCHECK(current_pass_);
304 if (cull_rect.has_value()) {
306 cull_rect = cull_rect.value().TransformBounds(inverse);
349 AddRenderEntityToCurrentPass(std::move(entity));
358 AddRenderEntityToCurrentPass(std::move(entity));
361 bool Canvas::AttemptDrawBlurredRRect(
const Rect& rect,
369 if (!
paint.mask_blur_descriptor.has_value()) {
382 paint.HasColorFilter()
384 ?
paint.GetColorFilter()->GetCPUColorFilterProc()(
paint.color)
387 Paint rrect_paint = {.mask_blur_descriptor =
paint.mask_blur_descriptor};
412 (!rrect_color.IsOpaque() ||
414 Rect render_bounds = rect;
426 rrect_paint.color = rrect_color.WithAlpha(1);
428 rrect_paint.color = rrect_color;
434 auto draw_blurred_rrect = [
this, &rect, &corner_radii, &rrect_paint]() {
435 auto contents = std::make_shared<SolidRRectBlurContents>();
437 contents->SetColor(rrect_paint.color);
438 contents->SetSigma(rrect_paint.mask_blur_descriptor->sigma);
439 contents->SetRRect(rect, corner_radii);
441 Entity blurred_rrect_entity;
442 blurred_rrect_entity.SetTransform(GetCurrentTransform());
443 blurred_rrect_entity.SetBlendMode(rrect_paint.blend_mode);
445 rrect_paint.mask_blur_descriptor = std::nullopt;
446 blurred_rrect_entity.SetContents(
447 rrect_paint.WithFilters(std::move(contents)));
448 AddRenderEntityToCurrentPass(std::move(blurred_rrect_entity));
451 switch (rrect_paint.mask_blur_descriptor->style) {
453 draw_blurred_rrect();
458 draw_blurred_rrect();
461 entity.SetTransform(GetCurrentTransform());
462 entity.SetBlendMode(rrect_paint.blend_mode);
463 entity.SetContents(CreateContentsForGeometryWithFilters(
465 AddRenderEntityToCurrentPass(std::move(entity),
true);
470 draw_blurred_rrect();
475 draw_blurred_rrect();
489 entity.
SetContents(CreateContentsForGeometryWithFilters(
490 paint, Geometry::MakeLine(p0, p1,
paint.stroke_width,
paint.stroke_cap)));
492 AddRenderEntityToCurrentPass(std::move(entity));
496 if (
paint.style == Paint::Style::kStroke) {
501 if (AttemptDrawBlurredRRect(rect, {},
paint)) {
509 CreateContentsForGeometryWithFilters(
paint, Geometry::MakeRect(rect)));
511 AddRenderEntityToCurrentPass(std::move(entity));
521 if (
paint.style == Paint::Style::kStroke) {
527 if (AttemptDrawBlurredRRect(rect, rect.
GetSize() * 0.5f,
paint)) {
535 CreateContentsForGeometryWithFilters(
paint, Geometry::MakeOval(rect)));
537 AddRenderEntityToCurrentPass(std::move(entity));
540 void Canvas::DrawRRect(
const Rect& rect,
541 const Size& corner_radii,
543 if (AttemptDrawBlurredRRect(rect, corner_radii,
paint)) {
547 if (
paint.style == Paint::Style::kFill) {
551 entity.
SetContents(CreateContentsForGeometryWithFilters(
552 paint, Geometry::MakeRoundRect(rect, corner_radii)));
554 AddRenderEntityToCurrentPass(std::move(entity));
563 DrawPath(path,
paint);
566 void Canvas::DrawCircle(
const Point& center,
569 Size half_size(radius, radius);
570 if (AttemptDrawBlurredRRect(
571 Rect::MakeOriginSize(center - half_size, half_size * 2),
572 {radius, radius},
paint)) {
580 paint.style == Paint::Style::kStroke
581 ? Geometry::MakeStrokedCircle(center, radius,
paint.stroke_width)
582 : Geometry::MakeCircle(center, radius);
584 CreateContentsForGeometryWithFilters(
paint, std::move(geometry)));
586 AddRenderEntityToCurrentPass(std::move(entity));
591 ClipGeometry(Geometry::MakeFillPath(path), clip_op);
592 if (clip_op == Entity::ClipOperation::kIntersect) {
593 if (bounds.has_value()) {
594 IntersectCulling(bounds.value());
600 auto geometry = Geometry::MakeRect(rect);
601 auto& cull_rect = transform_stack_.back().cull_rect;
602 if (clip_op == Entity::ClipOperation::kIntersect &&
603 cull_rect.has_value() &&
604 geometry->CoversArea(transform_stack_.back().transform, *cull_rect)
609 ClipGeometry(geometry, clip_op);
611 case Entity::ClipOperation::kIntersect:
612 IntersectCulling(rect);
614 case Entity::ClipOperation::kDifference:
615 SubtractCulling(rect);
621 auto geometry = Geometry::MakeOval(bounds);
622 auto& cull_rect = transform_stack_.back().cull_rect;
623 if (clip_op == Entity::ClipOperation::kIntersect &&
624 cull_rect.has_value() &&
625 geometry->CoversArea(transform_stack_.back().transform, *cull_rect)
630 ClipGeometry(geometry, clip_op);
632 case Entity::ClipOperation::kIntersect:
633 IntersectCulling(bounds);
635 case Entity::ClipOperation::kDifference:
640 void Canvas::ClipRRect(
const Rect& rect,
641 const Size& corner_radii,
646 auto geometry = Geometry::MakeRoundRect(rect, corner_radii);
647 auto& cull_rect = transform_stack_.back().cull_rect;
648 if (clip_op == Entity::ClipOperation::kIntersect &&
649 cull_rect.has_value() &&
650 geometry->CoversArea(transform_stack_.back().transform, *cull_rect)
655 ClipGeometry(geometry, clip_op);
657 case Entity::ClipOperation::kIntersect:
658 IntersectCulling(rect);
660 case Entity::ClipOperation::kDifference:
662 SubtractCulling(rect);
670 SubtractCulling(rect.
Expand(
Size{-corner_radii.width, 0.0}));
673 SubtractCulling(rect.
Expand(
Size{0.0, -corner_radii.height}));
680 void Canvas::ClipGeometry(
const std::shared_ptr<Geometry>& geometry,
682 auto contents = std::make_shared<ClipContents>();
683 contents->SetGeometry(geometry);
684 contents->SetClipOperation(clip_op);
690 AddClipEntityToCurrentPass(std::move(entity));
692 ++transform_stack_.back().clip_height;
693 ++transform_stack_.back().num_clips;
696 void Canvas::IntersectCulling(
Rect clip_rect) {
697 clip_rect = clip_rect.TransformBounds(GetCurrentTransform());
698 std::optional<Rect>& cull_rect = transform_stack_.back().cull_rect;
699 if (cull_rect.has_value()) {
700 cull_rect = cull_rect
702 .Intersection(clip_rect)
705 cull_rect = clip_rect;
709 void Canvas::SubtractCulling(
Rect clip_rect) {
710 std::optional<Rect>& cull_rect = transform_stack_.back().cull_rect;
711 if (cull_rect.has_value()) {
712 clip_rect = clip_rect.TransformBounds(GetCurrentTransform());
713 cull_rect = cull_rect
721 void Canvas::RestoreClip() {
726 auto clip_restore = std::make_shared<ClipRestoreContents>();
727 clip_restore->SetRestoreHeight(GetClipHeight());
728 entity.SetContents(std::move(clip_restore));
730 AddRenderEntityToCurrentPass(std::move(entity));
733 void Canvas::DrawPoints(std::vector<Point> points,
744 entity.
SetContents(CreateContentsForGeometryWithFilters(
746 Geometry::MakePointField(std::move(points), radius,
747 point_style == PointStyle::kRound)));
749 AddRenderEntityToCurrentPass(std::move(entity));
752 void Canvas::DrawImage(
const std::shared_ptr<Image>& image,
760 const auto source = Rect::MakeSize(image->GetSize());
761 const auto dest = source.Shift(
offset);
763 DrawImageRect(image, source, dest,
paint, std::move(sampler));
766 void Canvas::DrawImageRect(
const std::shared_ptr<Image>& image,
776 auto size = image->GetSize();
778 if (size.IsEmpty()) {
782 auto texture_contents = TextureContents::MakeRect(dest);
783 texture_contents->SetTexture(image->GetTexture());
784 texture_contents->SetSourceRect(source);
785 texture_contents->SetStrictSourceRect(src_rect_constraint ==
786 SourceRectConstraint::kStrict);
787 texture_contents->SetSamplerDescriptor(std::move(sampler));
788 texture_contents->SetOpacity(
paint.color.alpha);
789 texture_contents->SetDeferApplyingOpacity(
paint.HasColorFilter());
791 std::shared_ptr<Contents> contents = texture_contents;
792 if (
paint.mask_blur_descriptor.has_value()) {
793 contents =
paint.mask_blur_descriptor->CreateMaskBlur(texture_contents);
801 AddRenderEntityToCurrentPass(std::move(entity));
806 while (current_pass_ !=
nullptr) {
807 current_pass_->PopAllClips(current_depth_);
808 current_pass_ = current_pass_->GetSuperpass();
812 picture.
pass = std::move(base_pass_);
815 Initialize(initial_cull_rect_);
821 FML_DCHECK(current_pass_ !=
nullptr);
822 return *current_pass_;
825 size_t Canvas::GetClipHeight()
const {
826 return transform_stack_.back().clip_height;
829 void Canvas::AddRenderEntityToCurrentPass(
Entity entity,
bool reuse_depth) {
835 GetCurrentPass().AddEntity(std::move(entity));
838 void Canvas::AddClipEntityToCurrentPass(Entity entity) {
839 GetCurrentPass().PushClip(std::move(entity));
843 std::optional<Rect> bounds,
844 const std::shared_ptr<ImageFilter>& backdrop_filter,
846 uint32_t total_content_depth,
847 bool can_distribute_opacity) {
848 if (can_distribute_opacity && !backdrop_filter &&
849 Paint::CanApplyOpacityPeephole(
paint)) {
850 Save(
false, total_content_depth,
paint.blend_mode, backdrop_filter);
851 transform_stack_.back().distributed_opacity *=
paint.color.alpha;
854 TRACE_EVENT0(
"flutter",
"Canvas::saveLayer");
856 Save(
true, total_content_depth,
paint.blend_mode, backdrop_filter);
862 if (
paint.image_filter) {
863 transform_stack_.back().cull_rect = std::nullopt;
866 auto& new_layer_pass = GetCurrentPass();
868 new_layer_pass.SetBoundsLimit(bounds, bounds_promise);
871 if (
paint.image_filter) {
872 MipCountVisitor mip_count_visitor;
873 paint.image_filter->Visit(mip_count_visitor);
874 new_layer_pass.SetRequiredMipCount(mip_count_visitor.GetRequiredMipCount());
878 paint_copy.
color.
alpha *= transform_stack_.back().distributed_opacity;
879 transform_stack_.back().distributed_opacity = 1.0;
881 new_layer_pass.SetDelegate(std::make_shared<PaintPassDelegate>(paint_copy));
884 void Canvas::DrawTextFrame(
const std::shared_ptr<TextFrame>& text_frame,
890 auto text_contents = std::make_shared<TextContents>();
891 text_contents->SetTextFrame(text_frame);
892 text_contents->SetForceTextColor(
paint.mask_blur_descriptor.has_value());
893 text_contents->SetOffset(position);
894 text_contents->SetColor(
paint.color);
895 text_contents->SetTextProperties(
paint.color,
896 paint.style == Paint::Style::kStroke,
904 Matrix::MakeTranslation(position));
913 std::move(text_contents),
true, GetCurrentTransform())));
915 AddRenderEntityToCurrentPass(std::move(entity));
919 const std::shared_ptr<VerticesGeometry>& vertices,
923 if (vertices->HasVertexColors()) {
926 if (vertices->HasTextureCoordinates() &&
927 (
paint.color_source.GetType() == ColorSource::Type::kColor)) {
930 return !vertices->HasTextureCoordinates();
933 void Canvas::DrawVertices(
const std::shared_ptr<VerticesGeometry>& vertices,
939 if (
paint.color_source.GetType() == ColorSource::Type::kColor) {
940 blend_mode = BlendMode::kDestination;
950 AddRenderEntityToCurrentPass(std::move(entity));
955 if (blend_mode == BlendMode::kDestination) {
956 auto contents = std::make_shared<VerticesSimpleBlendContents>();
957 contents->SetBlendMode(blend_mode);
958 contents->SetAlpha(
paint.color.alpha);
959 contents->SetGeometry(vertices);
961 AddRenderEntityToCurrentPass(std::move(entity));
967 if (std::optional<ImageData> maybe_image_data =
968 GetImageColorSourceData(
paint.color_source)) {
969 const ImageData& image_data = maybe_image_data.value();
970 auto contents = std::make_shared<VerticesSimpleBlendContents>();
971 contents->SetBlendMode(blend_mode);
972 contents->SetAlpha(
paint.color.alpha);
973 contents->SetGeometry(vertices);
975 contents->SetTexture(image_data.
texture);
979 AddRenderEntityToCurrentPass(std::move(entity));
983 auto src_paint =
paint;
984 src_paint.color =
paint.color.WithAlpha(1.0);
986 std::shared_ptr<Contents> src_contents =
987 src_paint.CreateContentsForGeometry(vertices);
995 auto size = src_contents->GetColorSourceSize();
996 if (size.has_value()) {
997 src_coverage = Rect::MakeXYWH(0, 0, size->width, size->height);
999 auto cvg = vertices->GetCoverage(
Matrix{});
1000 FML_CHECK(cvg.has_value());
1004 vertices->GetTextureCoordinateCoverge().value_or(cvg.value());
1006 src_contents = src_paint.CreateContentsForGeometry(
1007 Geometry::MakeRect(Rect::Round(src_coverage)));
1009 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1010 contents->SetBlendMode(blend_mode);
1011 contents->SetAlpha(
paint.color.alpha);
1012 contents->SetGeometry(vertices);
1013 contents->SetLazyTextureCoverage(src_coverage);
1014 contents->SetLazyTexture(
1020 ->RenderToSnapshot(renderer, {}, Rect::Round(src_coverage))
1024 AddRenderEntityToCurrentPass(std::move(entity));
1027 void Canvas::DrawAtlas(
const std::shared_ptr<Image>& atlas,
1028 std::vector<Matrix> transforms,
1029 std::vector<Rect> texture_coordinates,
1030 std::vector<Color> colors,
1033 std::optional<Rect> cull_rect,
1039 std::shared_ptr<AtlasContents> contents = std::make_shared<AtlasContents>();
1040 contents->SetColors(std::move(colors));
1041 contents->SetTransforms(std::move(transforms));
1042 contents->SetTextureCoordinates(std::move(texture_coordinates));
1043 contents->SetTexture(atlas->GetTexture());
1044 contents->SetSamplerDescriptor(std::move(sampler));
1045 contents->SetBlendMode(blend_mode);
1046 contents->SetCullRect(cull_rect);
1047 contents->SetAlpha(
paint.color.alpha);
1054 AddRenderEntityToCurrentPass(std::move(entity));