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 contents->SetGeometry(std::move(geometry));
48 if (paint.mask_blur_descriptor.has_value()) {
52 return paint.mask_blur_descriptor->CreateMaskBlur(
53 contents, needs_color_filter ? paint.GetColorFilter() :
nullptr);
56 std::shared_ptr<Contents> contents_copy = std::move(contents);
59 if (needs_color_filter &&
61 std::shared_ptr<ColorFilter> color_filter = paint.GetColorFilter();
62 contents_copy = color_filter->WrapWithGPUColorFilter(
67 if (paint.image_filter) {
68 std::shared_ptr<FilterContents> filter = paint.image_filter->WrapInput(
77 static std::shared_ptr<Contents> CreatePathContentsWithFilters(
80 std::shared_ptr<Geometry> geometry;
81 switch (paint.style) {
87 paint.stroke_miter, paint.stroke_cap,
92 return CreateContentsForGeometryWithFilters(paint, std::move(geometry));
95 static std::shared_ptr<Contents> CreateCoverContentsWithFilters(
103 Initialize(std::nullopt);
107 Initialize(cull_rect);
117 void Canvas::Initialize(std::optional<Rect> cull_rect) {
118 initial_cull_rect_ = cull_rect;
119 base_pass_ = std::make_unique<EntityPass>();
120 current_pass_ = base_pass_.get();
123 FML_DCHECK(base_pass_->GetSubpassesDepth() == 1u);
126 void Canvas::Reset() {
127 base_pass_ =
nullptr;
128 current_pass_ =
nullptr;
129 transform_stack_ = {};
138 const std::shared_ptr<ImageFilter>& backdrop_filter) {
140 entry.
transform = transform_stack_.back().transform;
141 entry.cull_rect = transform_stack_.back().cull_rect;
142 entry.clip_depth = transform_stack_.back().clip_depth;
143 if (create_subpass) {
145 auto subpass = std::make_unique<EntityPass>();
146 subpass->SetEnableOffscreenCheckerboard(
148 if (backdrop_filter) {
150 [backdrop_filter = backdrop_filter->Clone()](
153 auto filter = backdrop_filter->WrapInput(input);
154 filter->SetEffectTransform(effect_transform);
155 filter->SetRenderingMode(rendering_mode);
158 subpass->SetBackdropFilter(backdrop_filter_proc);
160 subpass->SetBlendMode(blend_mode);
161 current_pass_ = GetCurrentPass().
AddSubpass(std::move(subpass));
162 current_pass_->
SetTransform(transform_stack_.back().transform);
163 current_pass_->
SetClipDepth(transform_stack_.back().clip_depth);
165 transform_stack_.emplace_back(entry);
169 FML_DCHECK(transform_stack_.size() > 0);
170 if (transform_stack_.size() == 1) {
173 if (transform_stack_.back().rendering_mode ==
176 FML_DCHECK(current_pass_);
179 bool contains_clips = transform_stack_.back().contains_clips;
180 transform_stack_.pop_back();
182 if (contains_clips) {
198 transform_stack_.back().transform = {};
206 return transform_stack_.back().transform;
210 auto cull_rect = transform_stack_.back().cull_rect;
211 if (cull_rect.has_value()) {
212 Matrix inverse = transform_stack_.back().transform.Invert();
213 cull_rect = cull_rect.value().TransformBounds(inverse);
239 return transform_stack_.size();
255 entity.
SetContents(CreatePathContentsWithFilters(paint, std::move(path)));
257 GetCurrentPass().
AddEntity(std::move(entity));
265 entity.
SetContents(CreateCoverContentsWithFilters(paint));
267 GetCurrentPass().
AddEntity(std::move(entity));
270 bool Canvas::AttemptDrawBlurredRRect(
const Rect& rect,
272 const Paint& paint) {
287 Paint new_paint = paint;
292 auto contents = std::make_shared<SolidRRectBlurContents>();
293 contents->SetColor(new_paint.color);
294 contents->SetSigma(new_paint.mask_blur_descriptor->sigma);
295 contents->SetRRect(rect, corner_radius);
297 new_paint.mask_blur_descriptor = std::nullopt;
301 entity.SetClipDepth(GetClipDepth());
302 entity.SetBlendMode(new_paint.blend_mode);
303 entity.SetContents(new_paint.WithFilters(std::move(contents)));
305 GetCurrentPass().
AddEntity(std::move(entity));
315 entity.
SetContents(CreateContentsForGeometryWithFilters(
318 GetCurrentPass().
AddEntity(std::move(entity));
327 if (AttemptDrawBlurredRRect(rect, {}, paint)) {
338 GetCurrentPass().
AddEntity(std::move(entity));
354 if (AttemptDrawBlurredRRect(rect, rect.
GetSize() * 0.5f, paint)) {
365 GetCurrentPass().
AddEntity(std::move(entity));
369 const Size& corner_radii,
370 const Paint& paint) {
371 if (AttemptDrawBlurredRRect(rect, corner_radii, paint)) {
380 entity.
SetContents(CreateContentsForGeometryWithFilters(
383 GetCurrentPass().
AddEntity(std::move(entity));
397 const Paint& paint) {
398 Size half_size(radius, radius);
399 if (AttemptDrawBlurredRRect(
401 {radius, radius}, paint)) {
414 CreateContentsForGeometryWithFilters(paint, std::move(geometry)));
416 GetCurrentPass().
AddEntity(std::move(entity));
423 if (bounds.has_value()) {
424 IntersectCulling(bounds.value());
431 auto& cull_rect = transform_stack_.back().cull_rect;
433 cull_rect.has_value() &&
434 geometry->CoversArea(transform_stack_.back().transform, *cull_rect)
439 ClipGeometry(geometry, clip_op);
442 IntersectCulling(rect);
445 SubtractCulling(rect);
452 auto& cull_rect = transform_stack_.back().cull_rect;
454 cull_rect.has_value() &&
455 geometry->CoversArea(transform_stack_.back().transform, *cull_rect)
460 ClipGeometry(geometry, clip_op);
463 IntersectCulling(bounds);
471 const Size& corner_radii,
477 auto& cull_rect = transform_stack_.back().cull_rect;
479 cull_rect.has_value() &&
480 geometry->CoversArea(transform_stack_.back().transform, *cull_rect)
485 ClipGeometry(geometry, clip_op);
488 IntersectCulling(rect);
492 SubtractCulling(rect);
500 SubtractCulling(rect.
Expand(
Size{-corner_radii.width, 0.0}));
503 SubtractCulling(rect.
Expand(
Size{0.0, -corner_radii.height}));
510 void Canvas::ClipGeometry(
const std::shared_ptr<Geometry>& geometry,
512 auto contents = std::make_shared<ClipContents>();
513 contents->SetGeometry(geometry);
514 contents->SetClipOperation(clip_op);
521 GetCurrentPass().
AddEntity(std::move(entity));
523 ++transform_stack_.back().clip_depth;
524 transform_stack_.back().contains_clips =
true;
527 void Canvas::IntersectCulling(
Rect clip_rect) {
529 std::optional<Rect>& cull_rect = transform_stack_.back().cull_rect;
530 if (cull_rect.has_value()) {
531 cull_rect = cull_rect
533 .Intersection(clip_rect)
536 cull_rect = clip_rect;
540 void Canvas::SubtractCulling(
Rect clip_rect) {
541 std::optional<Rect>& cull_rect = transform_stack_.back().cull_rect;
542 if (cull_rect.has_value()) {
544 cull_rect = cull_rect
552 void Canvas::RestoreClip() {
557 entity.SetContents(std::make_shared<ClipRestoreContents>());
558 entity.SetClipDepth(GetClipDepth());
560 GetCurrentPass().
AddEntity(std::move(entity));
575 entity.
SetContents(CreateContentsForGeometryWithFilters(
580 GetCurrentPass().
AddEntity(std::move(entity));
589 auto pass = picture.
pass->Clone();
591 pass->IterateAllElements([&](
auto& element) ->
bool {
592 if (
auto entity = std::get_if<Entity>(&element)) {
593 entity->IncrementStencilDepth(GetClipDepth());
598 if (
auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
599 subpass->get()->SetClipDepth(subpass->get()->GetClipDepth() +
621 const auto dest = source.Shift(offset);
623 DrawImageRect(image, source, dest, paint, std::move(sampler));
635 auto size = image->GetSize();
637 if (size.IsEmpty()) {
642 contents->SetTexture(image->GetTexture());
643 contents->SetSourceRect(source);
644 contents->SetSamplerDescriptor(std::move(sampler));
654 GetCurrentPass().
AddEntity(std::move(entity));
659 picture.
pass = std::move(base_pass_);
662 Initialize(initial_cull_rect_);
668 FML_DCHECK(current_pass_ !=
nullptr);
669 return *current_pass_;
672 size_t Canvas::GetClipDepth()
const {
673 return transform_stack_.back().clip_depth;
677 std::optional<Rect> bounds,
678 const std::shared_ptr<ImageFilter>& backdrop_filter) {
679 TRACE_EVENT0(
"flutter",
"Canvas::saveLayer");
687 transform_stack_.back().cull_rect = std::nullopt;
690 auto& new_layer_pass = GetCurrentPass();
691 new_layer_pass.SetBoundsLimit(bounds);
695 new_layer_pass.SetDelegate(
696 std::make_shared<OpacityPeepholePassDelegate>(paint));
698 new_layer_pass.SetDelegate(std::make_shared<PaintPassDelegate>(paint));
704 const Paint& paint) {
709 auto text_contents = std::make_shared<TextContents>();
710 text_contents->SetTextFrame(text_frame);
711 text_contents->SetColor(paint.
color);
726 GetCurrentPass().
AddEntity(std::move(entity));
730 const std::shared_ptr<VerticesGeometry>& vertices,
731 const Paint& paint) {
735 if (vertices->HasVertexColors()) {
738 if (vertices->HasTextureCoordinates() &&
743 return !vertices->HasTextureCoordinates();
748 const Paint& paint) {
764 entity.
SetContents(CreateContentsForGeometryWithFilters(paint, vertices));
765 GetCurrentPass().
AddEntity(std::move(entity));
769 auto src_paint = paint;
772 std::shared_ptr<Contents> src_contents =
773 src_paint.CreateContentsForGeometry(vertices);
774 if (vertices->HasTextureCoordinates()) {
781 auto size = src_contents->GetColorSourceSize();
782 if (size.has_value()) {
785 auto cvg = vertices->GetCoverage(
Matrix{});
786 FML_CHECK(cvg.has_value());
790 vertices->GetTextureCoordinateCoverge().value_or(cvg.value());
796 auto contents = std::make_shared<VerticesContents>();
798 contents->SetBlendMode(blend_mode);
799 contents->SetGeometry(vertices);
800 contents->SetSourceContents(std::move(src_contents));
803 GetCurrentPass().
AddEntity(std::move(entity));
807 std::vector<Matrix> transforms,
808 std::vector<Rect> texture_coordinates,
809 std::vector<Color> colors,
812 std::optional<Rect> cull_rect,
813 const Paint& paint) {
818 std::shared_ptr<AtlasContents> contents = std::make_shared<AtlasContents>();
819 contents->SetColors(std::move(colors));
820 contents->SetTransforms(std::move(transforms));
821 contents->SetTextureCoordinates(std::move(texture_coordinates));
822 contents->SetTexture(atlas->GetTexture());
823 contents->SetSamplerDescriptor(std::move(sampler));
824 contents->SetBlendMode(blend_mode);
825 contents->SetCullRect(cull_rect);
834 GetCurrentPass().
AddEntity(std::move(entity));