| Flutter Impeller |

canvas.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "impeller/aiks/canvas.h"
6
7 #include <memory>
8 #include <optional>
9 #include <utility>
10
11 #include "flutter/fml/logging.h"
12 #include "flutter/fml/trace_event.h"
13 #include "impeller/aiks/color_source.h"
14 #include "impeller/aiks/image_filter.h"
15 #include "impeller/aiks/paint_pass_delegate.h"
16 #include "impeller/entity/contents/atlas_contents.h"
17 #include "impeller/entity/contents/clip_contents.h"
18 #include "impeller/entity/contents/color_source_contents.h"
19 #include "impeller/entity/contents/content_context.h"
20 #include "impeller/entity/contents/filters/filter_contents.h"
21 #include "impeller/entity/contents/solid_rrect_blur_contents.h"
22 #include "impeller/entity/contents/text_contents.h"
23 #include "impeller/entity/contents/texture_contents.h"
24 #include "impeller/entity/contents/vertices_contents.h"
25 #include "impeller/entity/geometry/geometry.h"
26 #include "impeller/geometry/color.h"
27 #include "impeller/geometry/constants.h"
28 #include "impeller/geometry/path_builder.h"
29
30 namespace impeller {
31
32 namespace {
33
34 static std::shared_ptr<Contents> CreateContentsForGeometryWithFilters(
35 const Paint& paint,
36 std::shared_ptr<Geometry> geometry) {
37 std::shared_ptr<ColorSourceContents> contents =
38 paint.color_source.GetContents(paint);
39
40 // Attempt to apply the color filter on the CPU first.
41 // Note: This is not just an optimization; some color sources rely on
42 // CPU-applied color filters to behave properly.
43 bool needs_color_filter = paint.HasColorFilter();
44 if (needs_color_filter) {
45 auto color_filter = paint.GetColorFilter();
46 if (contents->ApplyColorFilter(color_filter->GetCPUColorFilterProc())) {
47 needs_color_filter = false;
48 }
49 }
50
51 bool can_apply_mask_filter = geometry->CanApplyMaskFilter();
52 contents->SetGeometry(std::move(geometry));
53
54 if (can_apply_mask_filter && paint.mask_blur_descriptor.has_value()) {
55 // If there's a mask blur and we need to apply the color filter on the GPU,
56 // we need to be careful to only apply the color filter to the source
57 // colors. CreateMaskBlur is able to handle this case.
58 return paint.mask_blur_descriptor->CreateMaskBlur(
59 contents, needs_color_filter ? paint.GetColorFilter() : nullptr);
60 }
61
62 std::shared_ptr<Contents> contents_copy = std::move(contents);
63 // Image input types will directly set their color filter,
64 // if any. See `TiledTextureContents.SetColorFilter`.
65 if (needs_color_filter &&
66 paint.color_source.GetType() != ColorSource::Type::kImage) {
67 std::shared_ptr<ColorFilter> color_filter = paint.GetColorFilter();
68 contents_copy = color_filter->WrapWithGPUColorFilter(
69 FilterInput::Make(std::move(contents_copy)),
70 ColorFilterContents::AbsorbOpacity::kYes);
71 }
72
73 if (paint.image_filter) {
74 std::shared_ptr<FilterContents> filter = paint.image_filter->WrapInput(
75 FilterInput::Make(std::move(contents_copy)));
76 filter->SetRenderingMode(Entity::RenderingMode::kDirect);
77 return filter;
78 }
79
80 return contents_copy;
81 }
82
83 struct GetTextureColorSourceDataVisitor {
84 GetTextureColorSourceDataVisitor() {}
85
86 std::optional<ImageData> operator()(const LinearGradientData& data) {
87 return std::nullopt;
88 }
89
90 std::optional<ImageData> operator()(const RadialGradientData& data) {
91 return std::nullopt;
92 }
93
94 std::optional<ImageData> operator()(const ConicalGradientData& data) {
95 return std::nullopt;
96 }
97
98 std::optional<ImageData> operator()(const SweepGradientData& data) {
99 return std::nullopt;
100 }
101
102 std::optional<ImageData> operator()(const ImageData& data) { return data; }
103
104 std::optional<ImageData> operator()(const RuntimeEffectData& data) {
105 return std::nullopt;
106 }
107
108 std::optional<ImageData> operator()(const std::monostate& data) {
109 return std::nullopt;
110 }
111
112 #if IMPELLER_ENABLE_3D
113 std::optional<ImageData> operator()(const SceneData& data) {
114 return std::nullopt;
115 }
116 #endif // IMPELLER_ENABLE_3D
117 };
118
119 static std::optional<ImageData> GetImageColorSourceData(
120 const ColorSource& color_source) {
121 return std::visit(GetTextureColorSourceDataVisitor{}, color_source.GetData());
122 }
123
124 static std::shared_ptr<Contents> CreatePathContentsWithFilters(
125 const Paint& paint,
126 const Path& path) {
127 std::shared_ptr<Geometry> geometry;
128 switch (paint.style) {
129 case Paint::Style::kFill:
130 geometry = Geometry::MakeFillPath(path);
131 break;
132 case Paint::Style::kStroke:
133 geometry =
134 Geometry::MakeStrokePath(path, paint.stroke_width, paint.stroke_miter,
135 paint.stroke_cap, paint.stroke_join);
136 break;
137 }
138
139 return CreateContentsForGeometryWithFilters(paint, std::move(geometry));
140 }
141
142 static std::shared_ptr<Contents> CreateCoverContentsWithFilters(
143 const Paint& paint) {
144 return CreateContentsForGeometryWithFilters(paint, Geometry::MakeCover());
145 }
146
147 } // namespace
148
149 Canvas::Canvas() {
150 Initialize(std::nullopt);
151 }
152
153 Canvas::Canvas(Rect cull_rect) {
154 Initialize(cull_rect);
155 }
156
157 Canvas::Canvas(IRect cull_rect) {
158 Initialize(Rect::MakeLTRB(cull_rect.GetLeft(), cull_rect.GetTop(),
159 cull_rect.GetRight(), cull_rect.GetBottom()));
160 }
161
162 Canvas::~Canvas() = default;
163
164 void Canvas::Initialize(std::optional<Rect> cull_rect) {
165 initial_cull_rect_ = cull_rect;
166 base_pass_ = std::make_unique<EntityPass>();
167 base_pass_->SetClipDepth(++current_depth_);
168 current_pass_ = base_pass_.get();
169 transform_stack_.emplace_back(CanvasStackEntry{
170 .cull_rect = cull_rect,
171 .clip_depth = kMaxDepth,
172 });
173 FML_DCHECK(GetSaveCount() == 1u);
174 FML_DCHECK(base_pass_->GetSubpassesDepth() == 1u);
175 }
176
177 void Canvas::Reset() {
178 base_pass_ = nullptr;
179 current_pass_ = nullptr;
180 current_depth_ = 0u;
181 transform_stack_ = {};
182 }
183
184 void Canvas::Save(uint32_t total_content_depth) {
185 Save(false, total_content_depth);
186 }
187
188 namespace {
189 class MipCountVisitor : public ImageFilterVisitor {
190 public:
191 virtual void Visit(const BlurImageFilter& filter) {
192 required_mip_count_ = FilterContents::kBlurFilterRequiredMipCount;
193 }
194 virtual void Visit(const LocalMatrixImageFilter& filter) {
195 required_mip_count_ = 1;
196 }
197 virtual void Visit(const DilateImageFilter& filter) {
198 required_mip_count_ = 1;
199 }
200 virtual void Visit(const ErodeImageFilter& filter) {
201 required_mip_count_ = 1;
202 }
203 virtual void Visit(const MatrixImageFilter& filter) {
204 required_mip_count_ = 1;
205 }
206 virtual void Visit(const ComposeImageFilter& filter) {
207 required_mip_count_ = 1;
208 }
209 virtual void Visit(const ColorImageFilter& filter) {
210 required_mip_count_ = 1;
211 }
212 int32_t GetRequiredMipCount() const { return required_mip_count_; }
213
214 private:
215 int32_t required_mip_count_ = -1;
216 };
217 } // namespace
218
219 void Canvas::Save(bool create_subpass,
220 uint32_t total_content_depth,
221 BlendMode blend_mode,
222 const std::shared_ptr<ImageFilter>& backdrop_filter) {
223 auto entry = CanvasStackEntry{};
224 entry.transform = transform_stack_.back().transform;
225 entry.cull_rect = transform_stack_.back().cull_rect;
226 entry.clip_height = transform_stack_.back().clip_height;
227 entry.distributed_opacity = transform_stack_.back().distributed_opacity;
228 if (create_subpass) {
229 entry.rendering_mode =
230 Entity::RenderingMode::kSubpassAppendSnapshotTransform;
231 auto subpass = std::make_unique<EntityPass>();
232 if (backdrop_filter) {
233 EntityPass::BackdropFilterProc backdrop_filter_proc =
234 [backdrop_filter = backdrop_filter->Clone()](
235 const FilterInput::Ref& input, const Matrix& effect_transform,
236 Entity::RenderingMode rendering_mode) {
237 auto filter = backdrop_filter->WrapInput(input);
238 filter->SetEffectTransform(effect_transform);
239 filter->SetRenderingMode(rendering_mode);
240 return filter;
241 };
242 subpass->SetBackdropFilter(backdrop_filter_proc);
243 MipCountVisitor mip_count_visitor;
244 backdrop_filter->Visit(mip_count_visitor);
245 current_pass_->SetRequiredMipCount(
246 std::max(current_pass_->GetRequiredMipCount(),
247 mip_count_visitor.GetRequiredMipCount()));
248 }
249 subpass->SetBlendMode(blend_mode);
250 current_pass_ = GetCurrentPass().AddSubpass(std::move(subpass));
251 current_pass_->SetTransform(transform_stack_.back().transform);
252 current_pass_->SetClipHeight(transform_stack_.back().clip_height);
253 }
254 transform_stack_.emplace_back(entry);
255 }
256
257 bool Canvas::Restore() {
258 FML_DCHECK(transform_stack_.size() > 0);
259 if (transform_stack_.size() == 1) {
260 return false;
261 }
262 size_t num_clips = transform_stack_.back().num_clips;
263 current_pass_->PopClips(num_clips, current_depth_);
264
265 if (transform_stack_.back().rendering_mode ==
266 Entity::RenderingMode::kSubpassAppendSnapshotTransform ||
267 transform_stack_.back().rendering_mode ==
268 Entity::RenderingMode::kSubpassPrependSnapshotTransform) {
269 current_pass_->SetClipDepth(++current_depth_);
270 current_pass_ = GetCurrentPass().GetSuperpass();
271 FML_DCHECK(current_pass_);
272 }
273
274 transform_stack_.pop_back();
275 if (num_clips > 0) {
276 RestoreClip();
277 }
278
279 return true;
280 }
281
282 void Canvas::Concat(const Matrix& transform) {
283 transform_stack_.back().transform = GetCurrentTransform() * transform;
284 }
285
286 void Canvas::PreConcat(const Matrix& transform) {
287 transform_stack_.back().transform = transform * GetCurrentTransform();
288 }
289
290 void Canvas::ResetTransform() {
291 transform_stack_.back().transform = {};
292 }
293
294 void Canvas::Transform(const Matrix& transform) {
295 Concat(transform);
296 }
297
298 const Matrix& Canvas::GetCurrentTransform() const {
299 return transform_stack_.back().transform;
300 }
301
302 const std::optional<Rect> Canvas::GetCurrentLocalCullingBounds() const {
303 auto cull_rect = transform_stack_.back().cull_rect;
304 if (cull_rect.has_value()) {
305 Matrix inverse = transform_stack_.back().transform.Invert();
306 cull_rect = cull_rect.value().TransformBounds(inverse);
307 }
308 return cull_rect;
309 }
310
311 void Canvas::Translate(const Vector3& offset) {
312 Concat(Matrix::MakeTranslation(offset));
313 }
314
315 void Canvas::Scale(const Vector2& scale) {
316 Concat(Matrix::MakeScale(scale));
317 }
318
319 void Canvas::Scale(const Vector3& scale) {
320 Concat(Matrix::MakeScale(scale));
321 }
322
323 void Canvas::Skew(Scalar sx, Scalar sy) {
324 Concat(Matrix::MakeSkew(sx, sy));
325 }
326
327 void Canvas::Rotate(Radians radians) {
328 Concat(Matrix::MakeRotationZ(radians));
329 }
330
331 size_t Canvas::GetSaveCount() const {
332 return transform_stack_.size();
333 }
334
335 void Canvas::RestoreToCount(size_t count) {
336 while (GetSaveCount() > count) {
337 if (!Restore()) {
338 return;
339 }
340 }
341 }
342
343 void Canvas::DrawPath(const Path& path, const Paint& paint) {
344 Entity entity;
345 entity.SetTransform(GetCurrentTransform());
346 entity.SetBlendMode(paint.blend_mode);
347 entity.SetContents(CreatePathContentsWithFilters(paint, path));
348
349 AddRenderEntityToCurrentPass(std::move(entity));
350 }
351
352 void Canvas::DrawPaint(const Paint& paint) {
353 Entity entity;
354 entity.SetTransform(GetCurrentTransform());
355 entity.SetBlendMode(paint.blend_mode);
356 entity.SetContents(CreateCoverContentsWithFilters(paint));
357
358 AddRenderEntityToCurrentPass(std::move(entity));
359 }
360
361 bool Canvas::AttemptDrawBlurredRRect(const Rect& rect,
362 Size corner_radii,
363 const Paint& paint) {
364 if (paint.color_source.GetType() != ColorSource::Type::kColor ||
365 paint.style != Paint::Style::kFill) {
366 return false;
367 }
368
369 if (!paint.mask_blur_descriptor.has_value()) {
370 return false;
371 }
372
373 // A blur sigma that is not positive enough should not result in a blur.
374 if (paint.mask_blur_descriptor->sigma.sigma <= kEhCloseEnough) {
375 return false;
376 }
377
378 // For symmetrically mask blurred solid RRects, absorb the mask blur and use
379 // a faster SDF approximation.
380
381 Color rrect_color =
382 paint.HasColorFilter()
383 // Absorb the color filter, if any.
384 ? paint.GetColorFilter()->GetCPUColorFilterProc()(paint.color)
385 : paint.color;
386
387 Paint rrect_paint = {.mask_blur_descriptor = paint.mask_blur_descriptor};
388
389 // In some cases, we need to render the mask blur to a separate layer.
390 //
391 // 1. If the blur style is normal, we'll be drawing using one draw call and
392 // no clips. And so we can just wrap the RRect contents with the
393 // ImageFilter, which will get applied to the result as per usual.
394 //
395 // 2. If the blur style is solid, we combine the non-blurred RRect with the
396 // blurred RRect via two separate draw calls, and so we need to defer any
397 // fancy blending, translucency, or image filtering until after these two
398 // draws have been combined in a separate layer.
399 //
400 // 3. If the blur style is outer or inner, we apply the blur style via a
401 // clip. The ImageFilter needs to be applied to the mask blurred result.
402 // And so if there's an ImageFilter, we need to defer applying it until
403 // after the clipped RRect blur has been drawn to a separate texture.
404 // However, since there's only one draw call that produces color, we
405 // don't need to worry about the blend mode or translucency (unlike with
406 // BlurStyle::kSolid).
407 //
408 if ((paint.mask_blur_descriptor->style !=
409 FilterContents::BlurStyle::kNormal &&
410 paint.image_filter) ||
411 (paint.mask_blur_descriptor->style == FilterContents::BlurStyle::kSolid &&
412 (!rrect_color.IsOpaque() ||
413 paint.blend_mode != BlendMode::kSourceOver))) {
414 Rect render_bounds = rect;
415 if (paint.mask_blur_descriptor->style !=
416 FilterContents::BlurStyle::kInner) {
417 render_bounds =
418 render_bounds.Expand(paint.mask_blur_descriptor->sigma.sigma * 4.0);
419 }
420 // Defer the alpha, blend mode, and image filter to a separate layer.
421 SaveLayer({.color = Color::White().WithAlpha(rrect_color.alpha),
422 .blend_mode = paint.blend_mode,
423 .image_filter = paint.image_filter},
424 render_bounds, nullptr, ContentBoundsPromise::kContainsContents,
425 1u);
426 rrect_paint.color = rrect_color.WithAlpha(1);
427 } else {
428 rrect_paint.color = rrect_color;
429 rrect_paint.blend_mode = paint.blend_mode;
430 rrect_paint.image_filter = paint.image_filter;
431 Save(1u);
432 }
433
434 auto draw_blurred_rrect = [this, &rect, &corner_radii, &rrect_paint]() {
435 auto contents = std::make_shared<SolidRRectBlurContents>();
436
437 contents->SetColor(rrect_paint.color);
438 contents->SetSigma(rrect_paint.mask_blur_descriptor->sigma);
439 contents->SetRRect(rect, corner_radii);
440
441 Entity blurred_rrect_entity;
442 blurred_rrect_entity.SetTransform(GetCurrentTransform());
443 blurred_rrect_entity.SetBlendMode(rrect_paint.blend_mode);
444
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));
449 };
450
451 switch (rrect_paint.mask_blur_descriptor->style) {
452 case FilterContents::BlurStyle::kNormal: {
453 draw_blurred_rrect();
454 break;
455 }
456 case FilterContents::BlurStyle::kSolid: {
457 // First, draw the blurred RRect.
458 draw_blurred_rrect();
459 // Then, draw the non-blurred RRect on top.
460 Entity entity;
461 entity.SetTransform(GetCurrentTransform());
462 entity.SetBlendMode(rrect_paint.blend_mode);
463 entity.SetContents(CreateContentsForGeometryWithFilters(
464 rrect_paint, Geometry::MakeRoundRect(rect, corner_radii)));
465 AddRenderEntityToCurrentPass(std::move(entity), true);
466 break;
467 }
468 case FilterContents::BlurStyle::kOuter: {
469 ClipRRect(rect, corner_radii, Entity::ClipOperation::kDifference);
470 draw_blurred_rrect();
471 break;
472 }
473 case FilterContents::BlurStyle::kInner: {
474 ClipRRect(rect, corner_radii, Entity::ClipOperation::kIntersect);
475 draw_blurred_rrect();
476 break;
477 }
478 }
479
480 Restore();
481
482 return true;
483 }
484
485 void Canvas::DrawLine(const Point& p0, const Point& p1, const Paint& paint) {
486 Entity entity;
487 entity.SetTransform(GetCurrentTransform());
488 entity.SetBlendMode(paint.blend_mode);
489 entity.SetContents(CreateContentsForGeometryWithFilters(
490 paint, Geometry::MakeLine(p0, p1, paint.stroke_width, paint.stroke_cap)));
491
492 AddRenderEntityToCurrentPass(std::move(entity));
493 }
494
495 void Canvas::DrawRect(const Rect& rect, const Paint& paint) {
496 if (paint.style == Paint::Style::kStroke) {
497 DrawPath(PathBuilder{}.AddRect(rect).TakePath(), paint);
498 return;
499 }
500
501 if (AttemptDrawBlurredRRect(rect, {}, paint)) {
502 return;
503 }
504
505 Entity entity;
506 entity.SetTransform(GetCurrentTransform());
507 entity.SetBlendMode(paint.blend_mode);
508 entity.SetContents(
509 CreateContentsForGeometryWithFilters(paint, Geometry::MakeRect(rect)));
510
511 AddRenderEntityToCurrentPass(std::move(entity));
512 }
513
514 void Canvas::DrawOval(const Rect& rect, const Paint& paint) {
515 if (rect.IsSquare()) {
516 // Circles have slightly less overhead and can do stroking
517 DrawCircle(rect.GetCenter(), rect.GetWidth() * 0.5f, paint);
518 return;
519 }
520
521 if (paint.style == Paint::Style::kStroke) {
522 // No stroked ellipses yet
523 DrawPath(PathBuilder{}.AddOval(rect).TakePath(), paint);
524 return;
525 }
526
527 if (AttemptDrawBlurredRRect(rect, rect.GetSize() * 0.5f, paint)) {
528 return;
529 }
530
531 Entity entity;
532 entity.SetTransform(GetCurrentTransform());
533 entity.SetBlendMode(paint.blend_mode);
534 entity.SetContents(
535 CreateContentsForGeometryWithFilters(paint, Geometry::MakeOval(rect)));
536
537 AddRenderEntityToCurrentPass(std::move(entity));
538 }
539
540 void Canvas::DrawRRect(const Rect& rect,
541 const Size& corner_radii,
542 const Paint& paint) {
543 if (AttemptDrawBlurredRRect(rect, corner_radii, paint)) {
544 return;
545 }
546
547 if (paint.style == Paint::Style::kFill) {
548 Entity entity;
549 entity.SetTransform(GetCurrentTransform());
550 entity.SetBlendMode(paint.blend_mode);
551 entity.SetContents(CreateContentsForGeometryWithFilters(
552 paint, Geometry::MakeRoundRect(rect, corner_radii)));
553
554 AddRenderEntityToCurrentPass(std::move(entity));
555 return;
556 }
557
558 auto path = PathBuilder{}
559 .SetConvexity(Convexity::kConvex)
560 .AddRoundedRect(rect, corner_radii)
561 .SetBounds(rect)
562 .TakePath();
563 DrawPath(path, paint);
564 }
565
566 void Canvas::DrawCircle(const Point& center,
567 Scalar radius,
568 const Paint& paint) {
569 Size half_size(radius, radius);
570 if (AttemptDrawBlurredRRect(
571 Rect::MakeOriginSize(center - half_size, half_size * 2),
572 {radius, radius}, paint)) {
573 return;
574 }
575
576 Entity entity;
577 entity.SetTransform(GetCurrentTransform());
578 entity.SetBlendMode(paint.blend_mode);
579 auto geometry =
580 paint.style == Paint::Style::kStroke
581 ? Geometry::MakeStrokedCircle(center, radius, paint.stroke_width)
582 : Geometry::MakeCircle(center, radius);
583 entity.SetContents(
584 CreateContentsForGeometryWithFilters(paint, std::move(geometry)));
585
586 AddRenderEntityToCurrentPass(std::move(entity));
587 }
588
589 void Canvas::ClipPath(const Path& path, Entity::ClipOperation clip_op) {
590 auto bounds = path.GetBoundingBox();
591 ClipGeometry(Geometry::MakeFillPath(path), clip_op);
592 if (clip_op == Entity::ClipOperation::kIntersect) {
593 if (bounds.has_value()) {
594 IntersectCulling(bounds.value());
595 }
596 }
597 }
598
599 void Canvas::ClipRect(const Rect& rect, Entity::ClipOperation clip_op) {
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) //
605 ) {
606 return; // This clip will do nothing, so skip it.
607 }
608
609 ClipGeometry(geometry, clip_op);
610 switch (clip_op) {
611 case Entity::ClipOperation::kIntersect:
612 IntersectCulling(rect);
613 break;
614 case Entity::ClipOperation::kDifference:
615 SubtractCulling(rect);
616 break;
617 }
618 }
619
620 void Canvas::ClipOval(const Rect& bounds, Entity::ClipOperation clip_op) {
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) //
626 ) {
627 return; // This clip will do nothing, so skip it.
628 }
629
630 ClipGeometry(geometry, clip_op);
631 switch (clip_op) {
632 case Entity::ClipOperation::kIntersect:
633 IntersectCulling(bounds);
634 break;
635 case Entity::ClipOperation::kDifference:
636 break;
637 }
638 }
639
640 void Canvas::ClipRRect(const Rect& rect,
641 const Size& corner_radii,
642 Entity::ClipOperation clip_op) {
643 // Does the rounded rect have a flat part on the top/bottom or left/right?
644 bool flat_on_TB = corner_radii.width * 2 < rect.GetWidth();
645 bool flat_on_LR = corner_radii.height * 2 < rect.GetHeight();
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) //
651 ) {
652 return; // This clip will do nothing, so skip it.
653 }
654
655 ClipGeometry(geometry, clip_op);
656 switch (clip_op) {
657 case Entity::ClipOperation::kIntersect:
658 IntersectCulling(rect);
659 break;
660 case Entity::ClipOperation::kDifference:
661 if (corner_radii.IsEmpty()) {
662 SubtractCulling(rect);
663 } else {
664 // We subtract the inner "tall" and "wide" rectangle pieces
665 // that fit inside the corners which cover the greatest area
666 // without involving the curved corners
667 // Since this is a subtract operation, we can subtract each
668 // rectangle piece individually without fear of interference.
669 if (flat_on_TB) {
670 SubtractCulling(rect.Expand(Size{-corner_radii.width, 0.0}));
671 }
672 if (flat_on_LR) {
673 SubtractCulling(rect.Expand(Size{0.0, -corner_radii.height}));
674 }
675 }
676 break;
677 }
678 }
679
680 void Canvas::ClipGeometry(const std::shared_ptr<Geometry>& geometry,
681 Entity::ClipOperation clip_op) {
682 auto contents = std::make_shared<ClipContents>();
683 contents->SetGeometry(geometry);
684 contents->SetClipOperation(clip_op);
685
686 Entity entity;
687 entity.SetTransform(GetCurrentTransform());
688 entity.SetContents(std::move(contents));
689
690 AddClipEntityToCurrentPass(std::move(entity));
691
692 ++transform_stack_.back().clip_height;
693 ++transform_stack_.back().num_clips;
694 }
695
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
701 .value() //
702 .Intersection(clip_rect) //
703 .value_or(Rect{});
704 } else {
705 cull_rect = clip_rect;
706 }
707 }
708
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
714 .value() //
715 .Cutout(clip_rect) //
716 .value_or(Rect{});
717 }
718 // else (no cull) diff (any clip) is non-rectangular
719 }
720
721 void Canvas::RestoreClip() {
722 Entity entity;
723 entity.SetTransform(GetCurrentTransform());
724 // This path is empty because ClipRestoreContents just generates a quad that
725 // takes up the full render target.
726 auto clip_restore = std::make_shared<ClipRestoreContents>();
727 clip_restore->SetRestoreHeight(GetClipHeight());
728 entity.SetContents(std::move(clip_restore));
729
730 AddRenderEntityToCurrentPass(std::move(entity));
731 }
732
733 void Canvas::DrawPoints(std::vector<Point> points,
734 Scalar radius,
735 const Paint& paint,
736 PointStyle point_style) {
737 if (radius <= 0) {
738 return;
739 }
740
741 Entity entity;
742 entity.SetTransform(GetCurrentTransform());
743 entity.SetBlendMode(paint.blend_mode);
744 entity.SetContents(CreateContentsForGeometryWithFilters(
745 paint,
746 Geometry::MakePointField(std::move(points), radius,
747 /*round=*/point_style == PointStyle::kRound)));
748
749 AddRenderEntityToCurrentPass(std::move(entity));
750 }
751
752 void Canvas::DrawImage(const std::shared_ptr<Image>& image,
753 Point offset,
754 const Paint& paint,
755 SamplerDescriptor sampler) {
756 if (!image) {
757 return;
758 }
759
760 const auto source = Rect::MakeSize(image->GetSize());
761 const auto dest = source.Shift(offset);
762
763 DrawImageRect(image, source, dest, paint, std::move(sampler));
764 }
765
766 void Canvas::DrawImageRect(const std::shared_ptr<Image>& image,
767 Rect source,
768 Rect dest,
769 const Paint& paint,
770 SamplerDescriptor sampler,
771 SourceRectConstraint src_rect_constraint) {
772 if (!image || source.IsEmpty() || dest.IsEmpty()) {
773 return;
774 }
775
776 auto size = image->GetSize();
777
778 if (size.IsEmpty()) {
779 return;
780 }
781
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());
790
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);
794 }
795
796 Entity entity;
797 entity.SetBlendMode(paint.blend_mode);
798 entity.SetContents(paint.WithFilters(contents));
799 entity.SetTransform(GetCurrentTransform());
800
801 AddRenderEntityToCurrentPass(std::move(entity));
802 }
803
804 Picture Canvas::EndRecordingAsPicture() {
805 // Assign clip depths to any outstanding clip entities.
806 while (current_pass_ != nullptr) {
807 current_pass_->PopAllClips(current_depth_);
808 current_pass_ = current_pass_->GetSuperpass();
809 }
810
811 Picture picture;
812 picture.pass = std::move(base_pass_);
813
814 Reset();
815 Initialize(initial_cull_rect_);
816
817 return picture;
818 }
819
820 EntityPass& Canvas::GetCurrentPass() {
821 FML_DCHECK(current_pass_ != nullptr);
822 return *current_pass_;
823 }
824
825 size_t Canvas::GetClipHeight() const {
826 return transform_stack_.back().clip_height;
827 }
828
829 void Canvas::AddRenderEntityToCurrentPass(Entity entity, bool reuse_depth) {
830 if (!reuse_depth) {
831 ++current_depth_;
832 }
833 entity.SetClipDepth(current_depth_);
834 entity.SetInheritedOpacity(transform_stack_.back().distributed_opacity);
835 GetCurrentPass().AddEntity(std::move(entity));
836 }
837
838 void Canvas::AddClipEntityToCurrentPass(Entity entity) {
839 GetCurrentPass().PushClip(std::move(entity));
840 }
841
842 void Canvas::SaveLayer(const Paint& paint,
843 std::optional<Rect> bounds,
844 const std::shared_ptr<ImageFilter>& backdrop_filter,
845 ContentBoundsPromise bounds_promise,
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;
852 return;
853 }
854 TRACE_EVENT0("flutter", "Canvas::saveLayer");
855
856 Save(true, total_content_depth, paint.blend_mode, backdrop_filter);
857
858 // The DisplayList bounds/rtree doesn't account for filters applied to parent
859 // layers, and so sub-DisplayLists are getting culled as if no filters are
860 // applied.
861 // See also: https://github.com/flutter/flutter/issues/139294
862 if (paint.image_filter) {
863 transform_stack_.back().cull_rect = std::nullopt;
864 }
865
866 auto& new_layer_pass = GetCurrentPass();
867 if (bounds) {
868 new_layer_pass.SetBoundsLimit(bounds, bounds_promise);
869 }
870
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());
875 }
876 // When applying a save layer, absorb any pending distributed opacity.
877 Paint paint_copy = paint;
878 paint_copy.color.alpha *= transform_stack_.back().distributed_opacity;
879 transform_stack_.back().distributed_opacity = 1.0;
880
881 new_layer_pass.SetDelegate(std::make_shared<PaintPassDelegate>(paint_copy));
882 }
883
884 void Canvas::DrawTextFrame(const std::shared_ptr<TextFrame>& text_frame,
885 Point position,
886 const Paint& paint) {
887 Entity entity;
888 entity.SetBlendMode(paint.blend_mode);
889
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, //
897 paint.stroke_width, //
898 paint.stroke_cap, //
899 paint.stroke_join, //
900 paint.stroke_miter //
901 );
902
903 entity.SetTransform(GetCurrentTransform() *
904 Matrix::MakeTranslation(position));
905
906 // TODO(bdero): This mask blur application is a hack. It will always wind up
907 // doing a gaussian blur that affects the color source itself
908 // instead of just the mask. The color filter text support
909 // needs to be reworked in order to interact correctly with
910 // mask filters.
911 // https://github.com/flutter/flutter/issues/133297
912 entity.SetContents(paint.WithFilters(paint.WithMaskBlur(
913 std::move(text_contents), true, GetCurrentTransform())));
914
915 AddRenderEntityToCurrentPass(std::move(entity));
916 }
917
918 static bool UseColorSourceContents(
919 const std::shared_ptr<VerticesGeometry>& vertices,
920 const Paint& paint) {
921 // If there are no vertex color or texture coordinates. Or if there
922 // are vertex coordinates but its just a color.
923 if (vertices->HasVertexColors()) {
924 return false;
925 }
926 if (vertices->HasTextureCoordinates() &&
927 (paint.color_source.GetType() == ColorSource::Type::kColor)) {
928 return true;
929 }
930 return !vertices->HasTextureCoordinates();
931 }
932
933 void Canvas::DrawVertices(const std::shared_ptr<VerticesGeometry>& vertices,
934 BlendMode blend_mode,
935 const Paint& paint) {
936 // Override the blend mode with kDestination in order to match the behavior
937 // of Skia's SK_LEGACY_IGNORE_DRAW_VERTICES_BLEND_WITH_NO_SHADER flag, which
938 // is enabled when the Flutter engine builds Skia.
939 if (paint.color_source.GetType() == ColorSource::Type::kColor) {
940 blend_mode = BlendMode::kDestination;
941 }
942
943 Entity entity;
944 entity.SetTransform(GetCurrentTransform());
945 entity.SetBlendMode(paint.blend_mode);
946
947 // If there are no vertex colors.
948 if (UseColorSourceContents(vertices, paint)) {
949 entity.SetContents(CreateContentsForGeometryWithFilters(paint, vertices));
950 AddRenderEntityToCurrentPass(std::move(entity));
951 return;
952 }
953
954 // If the blend mode is destination don't bother to bind or create a texture.
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);
960 entity.SetContents(paint.WithFilters(std::move(contents)));
961 AddRenderEntityToCurrentPass(std::move(entity));
962 return;
963 }
964
965 // If there is a texture, use this directly. Otherwise render the color
966 // source to a texture.
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);
974 contents->SetEffectTransform(image_data.effect_transform);
975 contents->SetTexture(image_data.texture);
976 contents->SetTileMode(image_data.x_tile_mode, image_data.y_tile_mode);
977
978 entity.SetContents(paint.WithFilters(std::move(contents)));
979 AddRenderEntityToCurrentPass(std::move(entity));
980 return;
981 }
982
983 auto src_paint = paint;
984 src_paint.color = paint.color.WithAlpha(1.0);
985
986 std::shared_ptr<Contents> src_contents =
987 src_paint.CreateContentsForGeometry(vertices);
988
989 // If the color source has an intrinsic size, then we use that to
990 // create the src contents as a simplification. Otherwise we use
991 // the extent of the texture coordinates to determine how large
992 // the src contents should be. If neither has a value we fall back
993 // to using the geometry coverage data.
994 Rect src_coverage;
995 auto size = src_contents->GetColorSourceSize();
996 if (size.has_value()) {
997 src_coverage = Rect::MakeXYWH(0, 0, size->width, size->height);
998 } else {
999 auto cvg = vertices->GetCoverage(Matrix{});
1000 FML_CHECK(cvg.has_value());
1001 src_coverage =
1002 // Covered by FML_CHECK.
1003 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
1004 vertices->GetTextureCoordinateCoverge().value_or(cvg.value());
1005 }
1006 Rect translated_coverage = Rect::MakeSize(src_coverage.GetSize());
1007 src_contents = src_paint.CreateContentsForGeometry(
1008 Geometry::MakeRect(translated_coverage));
1009
1010 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1011 contents->SetBlendMode(blend_mode);
1012 contents->SetAlpha(paint.color.alpha);
1013 contents->SetGeometry(vertices);
1014 contents->SetLazyTextureCoverage(src_coverage);
1015 contents->SetLazyTexture(
1016 [src_contents, translated_coverage](const ContentContext& renderer) {
1017 // Applying the src coverage as the coverage limit prevents the 1px
1018 // coverage pad from adding a border that is picked up by developer
1019 // specified UVs.
1020 return src_contents->RenderToSnapshot(renderer, {}, translated_coverage)
1021 ->texture;
1022 });
1023 entity.SetContents(paint.WithFilters(std::move(contents)));
1024 AddRenderEntityToCurrentPass(std::move(entity));
1025 }
1026
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,
1031 BlendMode blend_mode,
1032 SamplerDescriptor sampler,
1033 std::optional<Rect> cull_rect,
1034 const Paint& paint) {
1035 if (!atlas) {
1036 return;
1037 }
1038
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);
1048
1049 Entity entity;
1050 entity.SetTransform(GetCurrentTransform());
1051 entity.SetBlendMode(paint.blend_mode);
1052 entity.SetContents(paint.WithFilters(contents));
1053
1054 AddRenderEntityToCurrentPass(std::move(entity));
1055 }
1056
1057 } // namespace impeller
text_contents.h
impeller::Matrix::MakeSkew
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
Definition: matrix.h:117
impeller::Paint::stroke_cap
Cap stroke_cap
Definition: paint.h:72
impeller::Entity::ClipOperation::kIntersect
@ kIntersect
impeller::Entity::SetClipDepth
void SetClipDepth(uint32_t clip_depth)
Definition: entity.cc:98
impeller::Picture::pass
std::unique_ptr< EntityPass > pass
Definition: picture.h:18
impeller::ColorSource::GetContents
std::shared_ptr< ColorSourceContents > GetContents(const Paint &paint) const
Definition: color_source.cc:264
impeller::EntityPass::BackdropFilterProc
std::function< std::shared_ptr< FilterContents >(FilterInput::Ref, const Matrix &effect_transform, Entity::RenderingMode rendering_mode)> BackdropFilterProc
Definition: entity_pass.h:59
impeller::Entity::ClipOperation::kDifference
@ kDifference
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::Canvas::RestoreToCount
void RestoreToCount(size_t count)
Definition: canvas.cc:335
image_filter.h
impeller::Entity::SetBlendMode
void SetBlendMode(BlendMode blend_mode)
Definition: entity.cc:115
texture_contents.h
impeller::BlurImageFilter
Definition: image_filter.h:98
impeller::Geometry::MakeStrokePath
static std::shared_ptr< Geometry > MakeStrokePath(const Path &path, Scalar stroke_width=0.0, Scalar miter_limit=4.0, Cap stroke_cap=Cap::kButt, Join stroke_join=Join::kMiter)
Definition: geometry.cc:72
impeller::Geometry::MakeRoundRect
static std::shared_ptr< Geometry > MakeRoundRect(const Rect &rect, const Size &radii)
Definition: geometry.cc:115
impeller::Paint::Style::kStroke
@ kStroke
impeller::CanvasStackEntry
Definition: canvas.h:31
impeller::Paint
Definition: paint.h:23
impeller::CanvasStackEntry::cull_rect
std::optional< Rect > cull_rect
Definition: canvas.h:34
impeller::Canvas::Skew
void Skew(Scalar sx, Scalar sy)
Definition: canvas.cc:323
impeller::BlendMode
BlendMode
Definition: color.h:59
impeller::PathBuilder::SetBounds
PathBuilder & SetBounds(Rect bounds)
Set the bounding box that will be used by Path.GetBoundingBox in place of performing the computation.
Definition: path_builder.cc:458
impeller::kEhCloseEnough
constexpr float kEhCloseEnough
Definition: constants.h:56
impeller::FilterInput::Make
static FilterInput::Ref Make(Variant input, bool msaa_enabled=true)
Definition: filter_input.cc:19
impeller::PointStyle
PointStyle
Definition: canvas.h:43
data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
impeller::Paint::color
Color color
Definition: paint.h:68
paint_pass_delegate.h
impeller::EntityPass::AddSubpass
EntityPass * AddSubpass(std::unique_ptr< EntityPass > pass)
Appends a given pass as a subpass.
Definition: entity_pass.cc:267
impeller::Entity::RenderingMode::kSubpassAppendSnapshotTransform
@ kSubpassAppendSnapshotTransform
impeller::PathBuilder
Definition: path_builder.h:14
impeller::FilterInput::Ref
std::shared_ptr< FilterInput > Ref
Definition: filter_input.h:32
impeller::Canvas::ResetTransform
void ResetTransform()
Definition: canvas.cc:290
impeller::Path::GetBoundingBox
std::optional< Rect > GetBoundingBox() const
Definition: path.cc:405
impeller::Color::alpha
Scalar alpha
Definition: color.h:143
impeller::ContentBoundsPromise
ContentBoundsPromise
Definition: entity_pass.h:28
impeller::PathBuilder::AddRoundedRect
PathBuilder & AddRoundedRect(Rect rect, RoundingRadii radii)
Definition: path_builder.cc:150
impeller::TRect::GetCenter
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:373
impeller::FilterContents::BlurStyle::kNormal
@ kNormal
Blurred inside and outside.
impeller::PathBuilder::SetConvexity
PathBuilder & SetConvexity(Convexity value)
Definition: path_builder.cc:85
impeller::TRect::GetHeight
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
Definition: rect.h:337
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::Paint::color_source
ColorSource color_source
Definition: paint.h:69
impeller::Canvas::initial_cull_rect_
std::optional< Rect > initial_cull_rect_
Definition: canvas.h:182
offset
SeparatedVector2 offset
Definition: stroke_path_geometry.cc:311
impeller::Canvas::GetCurrentTransform
const Matrix & GetCurrentTransform() const
Definition: canvas.cc:298
impeller::EntityPass::SetClipDepth
void SetClipDepth(size_t clip_depth)
Definition: entity_pass.cc:1107
impeller::PathBuilder::AddRect
PathBuilder & AddRect(Rect rect)
Definition: path_builder.cc:117
impeller::Canvas::Concat
void Concat(const Matrix &transform)
Definition: canvas.cc:282
impeller::UseColorSourceContents
static bool UseColorSourceContents(const std::shared_ptr< VerticesGeometry > &vertices, const Paint &paint)
Definition: canvas.cc:918
impeller::Paint::stroke_miter
Scalar stroke_miter
Definition: paint.h:74
impeller::TRect::IsEmpty
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: rect.h:287
impeller::Entity::SetContents
void SetContents(std::shared_ptr< Contents > contents)
Definition: entity.cc:90
vertices_contents.h
path_builder.h
impeller::SamplerDescriptor
Definition: sampler_descriptor.h:15
impeller::Canvas::Initialize
void Initialize(std::optional< Rect > cull_rect)
Definition: canvas.cc:164
impeller::Entity
Definition: entity.h:20
impeller::Picture
Definition: picture.h:17
impeller::Geometry::MakeFillPath
static std::shared_ptr< Geometry > MakeFillPath(const Path &path, std::optional< Rect > inner_rect=std::nullopt)
Definition: geometry.cc:60
impeller::TSize< Scalar >
filter_contents.h
color_source.h
impeller::TRect::GetLeft
constexpr auto GetLeft() const
Definition: rect.h:341
impeller::Canvas::Scale
void Scale(const Vector2 &scale)
Definition: canvas.cc:315
impeller::EntityPass::GetSuperpass
EntityPass * GetSuperpass() const
Definition: entity_pass.cc:263
color_source_contents.h
impeller::FilterContents::BlurStyle::kSolid
@ kSolid
Solid inside, blurred outside.
impeller::Path
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
Definition: path.h:52
impeller::Entity::SetInheritedOpacity
bool SetInheritedOpacity(Scalar alpha)
Definition: entity.cc:134
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:231
impeller::EntityPass
Definition: entity_pass.h:43
impeller::Paint::GetColorFilter
std::shared_ptr< ColorFilter > GetColorFilter() const
Definition: paint.cc:222
impeller::Paint::style
Style style
Definition: paint.h:75
impeller::TRect::GetWidth
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
Definition: rect.h:331
impeller::Color::WithAlpha
constexpr Color WithAlpha(Scalar new_alpha) const
Definition: color.h:280
impeller::Paint::Style::kFill
@ kFill
impeller::EntityPass::GetRequiredMipCount
int32_t GetRequiredMipCount() const
Definition: entity_pass.h:175
impeller::TRect::IsSquare
constexpr bool IsSquare() const
Returns true if width and height are equal and neither is NaN.
Definition: rect.h:294
impeller::ImageData
Definition: color_source.h:67
impeller::ImageData::y_tile_mode
Entity::TileMode y_tile_mode
Definition: color_source.h:70
geometry.h
impeller::Color::White
static constexpr Color White()
Definition: color.h:266
impeller::SourceRectConstraint
SourceRectConstraint
Controls the behavior of the source rectangle given to DrawImageRect.
Definition: canvas.h:52
impeller::Canvas::Restore
virtual bool Restore()
Definition: canvas.cc:257
impeller::Radians
Definition: scalar.h:38
impeller::Entity::RenderingMode::kDirect
@ kDirect
canvas.h
clip_contents.h
impeller::Canvas::DrawPath
void DrawPath(const Path &path, const Paint &paint)
Definition: canvas.cc:343
impeller::PathBuilder::TakePath
Path TakePath(FillType fill=FillType::kNonZero)
Definition: path_builder.cc:22
impeller::Canvas::DrawPaint
void DrawPaint(const Paint &paint)
Definition: canvas.cc:352
impeller::EntityPass::SetTransform
void SetTransform(Matrix transform)
Definition: entity_pass.cc:1095
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:769
impeller::Canvas::GetSaveCount
size_t GetSaveCount() const
Definition: canvas.cc:331
impeller::FilterContents::BlurStyle::kInner
@ kInner
Blurred inside, nothing outside.
impeller::FilterContents::kBlurFilterRequiredMipCount
static const int32_t kBlurFilterRequiredMipCount
Definition: filter_contents.h:24
impeller::Canvas::Canvas
Canvas()
Definition: canvas.cc:149
impeller::TSize::width
Type width
Definition: size.h:22
impeller::Canvas::current_depth_
uint64_t current_depth_
Definition: canvas.h:183
impeller::Canvas::PreConcat
void PreConcat(const Matrix &transform)
Definition: canvas.cc:286
impeller::ImageData::x_tile_mode
Entity::TileMode x_tile_mode
Definition: color_source.h:69
atlas_contents.h
impeller::ColorSource::Type::kImage
@ kImage
content_context.h
impeller::FilterContents::BlurStyle::kOuter
@ kOuter
Nothing inside, blurred outside.
impeller::Entity::SetTransform
void SetTransform(const Matrix &transform)
Set the global transform matrix for this Entity.
Definition: entity.cc:62
impeller::TRect::GetSize
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...
Definition: rect.h:317
impeller::TRect::GetRight
constexpr auto GetRight() const
Definition: rect.h:345
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:213
impeller::Entity::RenderingMode::kSubpassPrependSnapshotTransform
@ kSubpassPrependSnapshotTransform
impeller::ImageData::texture
std::shared_ptr< Texture > texture
Definition: color_source.h:68
impeller::Canvas::Rotate
void Rotate(Radians radians)
Definition: canvas.cc:327
constants.h
impeller::EntityPass::PopClips
void PopClips(size_t num_clips, uint64_t depth)
Definition: entity_pass.cc:117
impeller::TPoint< Scalar >
impeller::Canvas::Transform
void Transform(const Matrix &transform)
Definition: canvas.cc:294
impeller::Canvas::Save
virtual void Save(uint32_t total_content_depth=kMaxDepth)
Definition: canvas.cc:184
impeller::Canvas::GetCurrentLocalCullingBounds
const std::optional< Rect > GetCurrentLocalCullingBounds() const
Definition: canvas.cc:302
scale
const Scalar scale
Definition: stroke_path_geometry.cc:308
paint
const Paint & paint
Definition: color_source.cc:38
impeller::Entity::ClipOperation
ClipOperation
Definition: entity.h:61
impeller::TRect::GetBottom
constexpr auto GetBottom() const
Definition: rect.h:347
color.h
impeller::Paint::HasColorFilter
bool HasColorFilter() const
Whether this paint has a color filter that can apply opacity.
Definition: paint.cc:236
impeller::TSize::height
Type height
Definition: size.h:23
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller::PathBuilder::AddOval
PathBuilder & AddOval(const Rect &rect)
Definition: path_builder.cc:376
impeller::Entity::RenderingMode
RenderingMode
Definition: entity.h:27
impeller::TSize::IsEmpty
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: size.h:105
impeller::EntityPass::SetClipHeight
void SetClipHeight(size_t clip_height)
Definition: entity_pass.cc:1099
impeller::ColorFilterContents::AbsorbOpacity::kYes
@ kYes
impeller::ImageFilterVisitor
Definition: image_filter.h:27
impeller::ContentBoundsPromise::kContainsContents
@ kContainsContents
The caller claims the bounds are a reasonably tight estimate of the coverage of the contents and shou...
impeller
Definition: aiks_blend_unittests.cc:18
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::Canvas::transform_stack_
std::deque< CanvasStackEntry > transform_stack_
Definition: canvas.h:181
impeller::Paint::mask_blur_descriptor
std::optional< MaskBlurDescriptor > mask_blur_descriptor
Definition: paint.h:81
solid_rrect_blur_contents.h
impeller::ContentContext
Definition: content_context.h:366
impeller::TRect::GetTop
constexpr auto GetTop() const
Definition: rect.h:343
impeller::Paint::stroke_width
Scalar stroke_width
Definition: paint.h:71
impeller::ColorSource::Type::kColor
@ kColor
impeller::EntityPass::SetRequiredMipCount
void SetRequiredMipCount(int32_t mip_count)
Definition: entity_pass.h:177
impeller::ColorSource::GetType
Type GetType() const
Definition: color_source.cc:260
impeller::ImageData::effect_transform
Matrix effect_transform
Definition: color_source.h:72
impeller::TRect
Definition: rect.h:122
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Canvas::~Canvas
virtual ~Canvas()
impeller::Vector3
Definition: vector.h:20
impeller::BlendMode::kSourceOver
@ kSourceOver
impeller::Paint::blend_mode
BlendMode blend_mode
Definition: paint.h:76
impeller::TRect::Expand
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition: rect.h:605
impeller::Canvas::Reset
void Reset()
Definition: canvas.cc:177
impeller::Geometry::MakeCover
static std::shared_ptr< Geometry > MakeCover()
Definition: geometry.cc:85
impeller::Paint::image_filter
std::shared_ptr< ImageFilter > image_filter
Definition: paint.h:79
impeller::Paint::stroke_join
Join stroke_join
Definition: paint.h:73
impeller::Canvas::Translate
void Translate(const Vector3 &offset)
Definition: canvas.cc:311
impeller::Canvas::kMaxDepth
static constexpr uint32_t kMaxDepth
Definition: canvas.h:62