10 #include "flutter/fml/logging.h"
11 #include "flutter/fml/trace_event.h"
30 static std::shared_ptr<Contents> CreateContentsForGeometryWithFilters(
32 std::shared_ptr<Geometry> geometry) {
33 std::shared_ptr<ColorSourceContents> contents =
34 paint.color_source.GetContents(paint);
39 bool needs_color_filter = paint.HasColorFilter();
40 if (needs_color_filter) {
41 auto color_filter = paint.GetColorFilter();
42 if (contents->ApplyColorFilter(color_filter->GetCPUColorFilterProc())) {
43 needs_color_filter =
false;
47 bool can_apply_mask_filter = geometry->CanApplyMaskFilter();
48 contents->SetGeometry(std::move(geometry));
50 if (can_apply_mask_filter && paint.mask_blur_descriptor.has_value()) {
54 return paint.mask_blur_descriptor->CreateMaskBlur(
55 contents, needs_color_filter ? paint.GetColorFilter() :
nullptr);
58 std::shared_ptr<Contents> contents_copy = std::move(contents);
61 if (needs_color_filter &&
63 std::shared_ptr<ColorFilter> color_filter = paint.GetColorFilter();
64 contents_copy = color_filter->WrapWithGPUColorFilter(
69 if (paint.image_filter) {
70 std::shared_ptr<FilterContents> filter = paint.image_filter->WrapInput(
79 static std::shared_ptr<Contents> CreatePathContentsWithFilters(
82 std::shared_ptr<Geometry> geometry;
83 switch (paint.style) {
90 paint.stroke_cap, paint.stroke_join);
94 return CreateContentsForGeometryWithFilters(paint, std::move(geometry));
97 static std::shared_ptr<Contents> CreateCoverContentsWithFilters(
105 Initialize(std::nullopt);
109 Initialize(cull_rect);
119 void Canvas::Initialize(std::optional<Rect> cull_rect) {
120 initial_cull_rect_ = cull_rect;
121 base_pass_ = std::make_unique<EntityPass>();
122 base_pass_->SetNewClipDepth(++current_depth_);
123 current_pass_ = base_pass_.get();
126 FML_DCHECK(base_pass_->GetSubpassesDepth() == 1u);
129 void Canvas::Reset() {
130 base_pass_ =
nullptr;
131 current_pass_ =
nullptr;
133 transform_stack_ = {};
146 virtual void Visit(
const LocalMatrixImageFilter& filter) {
147 required_mip_count_ = 1;
149 virtual void Visit(
const DilateImageFilter& filter) {
150 required_mip_count_ = 1;
152 virtual void Visit(
const ErodeImageFilter& filter) {
153 required_mip_count_ = 1;
155 virtual void Visit(
const MatrixImageFilter& filter) {
156 required_mip_count_ = 1;
158 virtual void Visit(
const ComposeImageFilter& filter) {
159 required_mip_count_ = 1;
161 virtual void Visit(
const ColorImageFilter& filter) {
162 required_mip_count_ = 1;
164 int32_t GetRequiredMipCount()
const {
return required_mip_count_; }
167 int32_t required_mip_count_ = -1;
173 const std::shared_ptr<ImageFilter>& backdrop_filter) {
174 auto entry = CanvasStackEntry{};
175 entry.transform = transform_stack_.back().transform;
176 entry.cull_rect = transform_stack_.back().cull_rect;
177 entry.clip_depth = transform_stack_.back().clip_depth;
178 if (create_subpass) {
180 auto subpass = std::make_unique<EntityPass>();
181 subpass->SetEnableOffscreenCheckerboard(
183 if (backdrop_filter) {
185 [backdrop_filter = backdrop_filter->Clone()](
188 auto filter = backdrop_filter->WrapInput(input);
189 filter->SetEffectTransform(effect_transform);
190 filter->SetRenderingMode(rendering_mode);
193 subpass->SetBackdropFilter(backdrop_filter_proc);
194 MipCountVisitor mip_count_visitor;
195 backdrop_filter->Visit(mip_count_visitor);
198 mip_count_visitor.GetRequiredMipCount()));
200 subpass->SetBlendMode(blend_mode);
201 current_pass_ = GetCurrentPass().
AddSubpass(std::move(subpass));
202 current_pass_->
SetTransform(transform_stack_.back().transform);
203 current_pass_->
SetClipDepth(transform_stack_.back().clip_depth);
205 transform_stack_.emplace_back(entry);
209 FML_DCHECK(transform_stack_.size() > 0);
210 if (transform_stack_.size() == 1) {
213 size_t num_clips = transform_stack_.back().num_clips;
214 current_pass_->
PopClips(num_clips, current_depth_);
216 if (transform_stack_.back().rendering_mode ==
220 FML_DCHECK(current_pass_);
223 transform_stack_.pop_back();
240 transform_stack_.back().transform = {};
248 return transform_stack_.back().transform;
252 auto cull_rect = transform_stack_.back().cull_rect;
253 if (cull_rect.has_value()) {
254 Matrix inverse = transform_stack_.back().transform.Invert();
255 cull_rect = cull_rect.value().TransformBounds(inverse);
281 return transform_stack_.size();
297 entity.
SetContents(CreatePathContentsWithFilters(paint, path));
299 AddEntityToCurrentPass(std::move(entity));
307 entity.
SetContents(CreateCoverContentsWithFilters(paint));
309 AddEntityToCurrentPass(std::move(entity));
312 bool Canvas::AttemptDrawBlurredRRect(
const Rect& rect,
314 const Paint& paint) {
363 (!rrect_color.IsOpaque() ||
369 rrect_paint.color = rrect_color.WithAlpha(1);
371 rrect_paint.color = rrect_color;
377 auto draw_blurred_rrect = [
this, &rect, &corner_radii, &rrect_paint]() {
378 auto contents = std::make_shared<SolidRRectBlurContents>();
380 contents->SetColor(rrect_paint.color);
381 contents->SetSigma(rrect_paint.mask_blur_descriptor->sigma);
382 contents->SetRRect(rect, corner_radii);
384 Entity blurred_rrect_entity;
385 blurred_rrect_entity.SetTransform(GetCurrentTransform());
386 blurred_rrect_entity.SetClipDepth(GetClipDepth());
387 blurred_rrect_entity.SetBlendMode(rrect_paint.blend_mode);
389 rrect_paint.mask_blur_descriptor = std::nullopt;
390 blurred_rrect_entity.SetContents(
391 rrect_paint.WithFilters(std::move(contents)));
392 AddEntityToCurrentPass(std::move(blurred_rrect_entity));
395 switch (rrect_paint.mask_blur_descriptor->style) {
397 draw_blurred_rrect();
402 draw_blurred_rrect();
405 entity.SetTransform(GetCurrentTransform());
406 entity.SetClipDepth(GetClipDepth());
407 entity.SetBlendMode(rrect_paint.blend_mode);
408 entity.SetContents(CreateContentsForGeometryWithFilters(
410 AddEntityToCurrentPass(std::move(entity));
415 draw_blurred_rrect();
420 draw_blurred_rrect();
435 entity.
SetContents(CreateContentsForGeometryWithFilters(
438 AddEntityToCurrentPass(std::move(entity));
441 void Canvas::DrawRect(
const Rect& rect,
const Paint& paint) {
442 if (paint.
style == Paint::Style::kStroke) {
447 if (AttemptDrawBlurredRRect(rect, {}, paint)) {
456 CreateContentsForGeometryWithFilters(paint, Geometry::MakeRect(rect)));
458 AddEntityToCurrentPass(std::move(entity));
461 void Canvas::DrawOval(
const Rect& rect,
const Paint& paint) {
468 if (paint.
style == Paint::Style::kStroke) {
474 if (AttemptDrawBlurredRRect(rect, rect.
GetSize() * 0.5f, paint)) {
483 CreateContentsForGeometryWithFilters(paint, Geometry::MakeOval(rect)));
485 AddEntityToCurrentPass(std::move(entity));
488 void Canvas::DrawRRect(
const Rect& rect,
489 const Size& corner_radii,
490 const Paint& paint) {
491 if (AttemptDrawBlurredRRect(rect, corner_radii, paint)) {
495 if (paint.
style == Paint::Style::kFill) {
500 entity.
SetContents(CreateContentsForGeometryWithFilters(
501 paint, Geometry::MakeRoundRect(rect, corner_radii)));
503 AddEntityToCurrentPass(std::move(entity));
512 DrawPath(path, paint);
515 void Canvas::DrawCircle(
const Point& center,
517 const Paint& paint) {
518 Size half_size(radius, radius);
519 if (AttemptDrawBlurredRRect(
520 Rect::MakeOriginSize(center - half_size, half_size * 2),
521 {radius, radius}, paint)) {
530 paint.
style == Paint::Style::kStroke
531 ? Geometry::MakeStrokedCircle(center, radius, paint.
stroke_width)
532 : Geometry::MakeCircle(center, radius);
534 CreateContentsForGeometryWithFilters(paint, std::move(geometry)));
536 AddEntityToCurrentPass(std::move(entity));
541 ClipGeometry(Geometry::MakeFillPath(path), clip_op);
542 if (clip_op == Entity::ClipOperation::kIntersect) {
543 if (bounds.has_value()) {
544 IntersectCulling(bounds.value());
550 auto geometry = Geometry::MakeRect(rect);
551 auto& cull_rect = transform_stack_.back().cull_rect;
552 if (clip_op == Entity::ClipOperation::kIntersect &&
553 cull_rect.has_value() &&
554 geometry->CoversArea(transform_stack_.back().transform, *cull_rect)
559 ClipGeometry(geometry, clip_op);
561 case Entity::ClipOperation::kIntersect:
562 IntersectCulling(rect);
564 case Entity::ClipOperation::kDifference:
565 SubtractCulling(rect);
571 auto geometry = Geometry::MakeOval(bounds);
572 auto& cull_rect = transform_stack_.back().cull_rect;
573 if (clip_op == Entity::ClipOperation::kIntersect &&
574 cull_rect.has_value() &&
575 geometry->CoversArea(transform_stack_.back().transform, *cull_rect)
580 ClipGeometry(geometry, clip_op);
582 case Entity::ClipOperation::kIntersect:
583 IntersectCulling(bounds);
585 case Entity::ClipOperation::kDifference:
590 void Canvas::ClipRRect(
const Rect& rect,
591 const Size& corner_radii,
596 auto geometry = Geometry::MakeRoundRect(rect, corner_radii);
597 auto& cull_rect = transform_stack_.back().cull_rect;
598 if (clip_op == Entity::ClipOperation::kIntersect &&
599 cull_rect.has_value() &&
600 geometry->CoversArea(transform_stack_.back().transform, *cull_rect)
605 ClipGeometry(geometry, clip_op);
607 case Entity::ClipOperation::kIntersect:
608 IntersectCulling(rect);
610 case Entity::ClipOperation::kDifference:
612 SubtractCulling(rect);
620 SubtractCulling(rect.
Expand(
Size{-corner_radii.width, 0.0}));
623 SubtractCulling(rect.
Expand(
Size{0.0, -corner_radii.height}));
630 void Canvas::ClipGeometry(
const std::shared_ptr<Geometry>& geometry,
632 auto contents = std::make_shared<ClipContents>();
633 contents->SetGeometry(geometry);
634 contents->SetClipOperation(clip_op);
641 GetCurrentPass().PushClip(std::move(entity));
643 ++transform_stack_.back().clip_depth;
644 ++transform_stack_.back().num_clips;
647 void Canvas::IntersectCulling(
Rect clip_rect) {
648 clip_rect = clip_rect.TransformBounds(GetCurrentTransform());
649 std::optional<Rect>& cull_rect = transform_stack_.back().cull_rect;
650 if (cull_rect.has_value()) {
651 cull_rect = cull_rect
653 .Intersection(clip_rect)
656 cull_rect = clip_rect;
660 void Canvas::SubtractCulling(
Rect clip_rect) {
661 std::optional<Rect>& cull_rect = transform_stack_.back().cull_rect;
662 if (cull_rect.has_value()) {
663 clip_rect = clip_rect.TransformBounds(GetCurrentTransform());
664 cull_rect = cull_rect
672 void Canvas::RestoreClip() {
677 entity.SetContents(std::make_shared<ClipRestoreContents>());
678 entity.SetClipDepth(GetClipDepth());
680 AddEntityToCurrentPass(std::move(entity));
683 void Canvas::DrawPoints(std::vector<Point> points,
695 entity.
SetContents(CreateContentsForGeometryWithFilters(
697 Geometry::MakePointField(std::move(points), radius,
698 point_style == PointStyle::kRound)));
700 AddEntityToCurrentPass(std::move(entity));
703 void Canvas::DrawImage(
const std::shared_ptr<Image>& image,
711 const auto source = Rect::MakeSize(image->GetSize());
712 const auto dest = source.Shift(
offset);
714 DrawImageRect(image, source, dest, paint, std::move(sampler));
717 void Canvas::DrawImageRect(
const std::shared_ptr<Image>& image,
727 auto size = image->GetSize();
729 if (size.IsEmpty()) {
733 auto texture_contents = TextureContents::MakeRect(dest);
734 texture_contents->SetTexture(image->GetTexture());
735 texture_contents->SetSourceRect(source);
736 texture_contents->SetStrictSourceRect(src_rect_constraint ==
737 SourceRectConstraint::kStrict);
738 texture_contents->SetSamplerDescriptor(std::move(sampler));
739 texture_contents->SetOpacity(paint.
color.
alpha);
740 texture_contents->SetDeferApplyingOpacity(paint.
HasColorFilter());
742 std::shared_ptr<Contents> contents = texture_contents;
753 AddEntityToCurrentPass(std::move(entity));
758 while (current_pass_ !=
nullptr) {
759 current_pass_->PopAllClips(current_depth_);
760 current_pass_ = current_pass_->GetSuperpass();
764 picture.
pass = std::move(base_pass_);
767 Initialize(initial_cull_rect_);
773 FML_DCHECK(current_pass_ !=
nullptr);
774 return *current_pass_;
777 size_t Canvas::GetClipDepth()
const {
778 return transform_stack_.back().clip_depth;
781 void Canvas::AddEntityToCurrentPass(Entity entity) {
782 entity.SetNewClipDepth(++current_depth_);
783 GetCurrentPass().AddEntity(std::move(entity));
786 void Canvas::SaveLayer(
const Paint& paint,
787 std::optional<Rect> bounds,
788 const std::shared_ptr<ImageFilter>& backdrop_filter,
790 TRACE_EVENT0(
"flutter",
"Canvas::saveLayer");
791 Save(
true, paint.
blend_mode, backdrop_filter);
798 transform_stack_.back().cull_rect = std::nullopt;
801 auto& new_layer_pass = GetCurrentPass();
803 new_layer_pass.SetBoundsLimit(bounds, bounds_promise);
807 MipCountVisitor mip_count_visitor;
809 new_layer_pass.SetRequiredMipCount(mip_count_visitor.GetRequiredMipCount());
813 if (paint.
blend_mode == BlendMode::kSourceOver) {
814 new_layer_pass.SetDelegate(
815 std::make_shared<OpacityPeepholePassDelegate>(paint));
817 new_layer_pass.SetDelegate(std::make_shared<PaintPassDelegate>(paint));
821 void Canvas::DrawTextFrame(
const std::shared_ptr<TextFrame>& text_frame,
823 const Paint& paint) {
828 auto text_contents = std::make_shared<TextContents>();
829 text_contents->SetTextFrame(text_frame);
830 text_contents->SetColor(paint.
color);
834 Matrix::MakeTranslation(position));
845 AddEntityToCurrentPass(std::move(entity));
849 const std::shared_ptr<VerticesGeometry>& vertices,
850 const Paint& paint) {
854 if (vertices->HasVertexColors()) {
857 if (vertices->HasTextureCoordinates() &&
862 return !vertices->HasTextureCoordinates();
865 void Canvas::DrawVertices(
const std::shared_ptr<VerticesGeometry>& vertices,
867 const Paint& paint) {
872 blend_mode = BlendMode::kDestination;
883 entity.
SetContents(CreateContentsForGeometryWithFilters(paint, vertices));
884 AddEntityToCurrentPass(std::move(entity));
888 auto src_paint = paint;
891 std::shared_ptr<Contents> src_contents =
892 src_paint.CreateContentsForGeometry(vertices);
893 if (vertices->HasTextureCoordinates()) {
900 auto size = src_contents->GetColorSourceSize();
901 if (size.has_value()) {
902 src_coverage = Rect::MakeXYWH(0, 0, size->width, size->height);
904 auto cvg = vertices->GetCoverage(
Matrix{});
905 FML_CHECK(cvg.has_value());
909 vertices->GetTextureCoordinateCoverge().value_or(cvg.value());
912 src_paint.CreateContentsForGeometry(Geometry::MakeRect(src_coverage));
915 auto contents = std::make_shared<VerticesContents>();
917 contents->SetBlendMode(blend_mode);
918 contents->SetGeometry(vertices);
919 contents->SetSourceContents(std::move(src_contents));
922 AddEntityToCurrentPass(std::move(entity));
925 void Canvas::DrawAtlas(
const std::shared_ptr<Image>& atlas,
926 std::vector<Matrix> transforms,
927 std::vector<Rect> texture_coordinates,
928 std::vector<Color> colors,
931 std::optional<Rect> cull_rect,
932 const Paint& paint) {
937 std::shared_ptr<AtlasContents> contents = std::make_shared<AtlasContents>();
938 contents->SetColors(std::move(colors));
939 contents->SetTransforms(std::move(transforms));
940 contents->SetTextureCoordinates(std::move(texture_coordinates));
941 contents->SetTexture(atlas->GetTexture());
942 contents->SetSamplerDescriptor(std::move(sampler));
943 contents->SetBlendMode(blend_mode);
944 contents->SetCullRect(cull_rect);
953 AddEntityToCurrentPass(std::move(entity));