| 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 <algorithm>
8 #include <optional>
9 #include <utility>
10
11 #include "flutter/fml/logging.h"
12 #include "impeller/aiks/image_filter.h"
13 #include "impeller/aiks/paint_pass_delegate.h"
14 #include "impeller/entity/contents/atlas_contents.h"
15 #include "impeller/entity/contents/clip_contents.h"
16 #include "impeller/entity/contents/solid_rrect_blur_contents.h"
17 #include "impeller/entity/contents/text_contents.h"
18 #include "impeller/entity/contents/texture_contents.h"
19 #include "impeller/entity/contents/vertices_contents.h"
20 #include "impeller/entity/geometry/geometry.h"
21 #include "impeller/geometry/constants.h"
22 #include "impeller/geometry/path_builder.h"
23
24 namespace impeller {
25
26 Canvas::Canvas() {
27 Initialize(std::nullopt);
28 }
29
30 Canvas::Canvas(Rect cull_rect) {
31 Initialize(cull_rect);
32 }
33
34 Canvas::Canvas(IRect cull_rect) {
35 Initialize(Rect::MakeLTRB(cull_rect.GetLeft(), cull_rect.GetTop(),
36 cull_rect.GetRight(), cull_rect.GetBottom()));
37 }
38
39 Canvas::~Canvas() = default;
40
41 void Canvas::Initialize(std::optional<Rect> cull_rect) {
42 initial_cull_rect_ = cull_rect;
43 base_pass_ = std::make_unique<EntityPass>();
44 current_pass_ = base_pass_.get();
45 xformation_stack_.emplace_back(CanvasStackEntry{.cull_rect = cull_rect});
46 FML_DCHECK(GetSaveCount() == 1u);
47 FML_DCHECK(base_pass_->GetSubpassesDepth() == 1u);
48 }
49
50 void Canvas::Reset() {
51 base_pass_ = nullptr;
52 current_pass_ = nullptr;
53 xformation_stack_ = {};
54 }
55
56 void Canvas::Save() {
57 Save(false);
58 }
59
60 void Canvas::Save(bool create_subpass,
61 BlendMode blend_mode,
62 const std::shared_ptr<ImageFilter>& backdrop_filter) {
63 auto entry = CanvasStackEntry{};
64 entry.xformation = xformation_stack_.back().xformation;
65 entry.cull_rect = xformation_stack_.back().cull_rect;
66 entry.stencil_depth = xformation_stack_.back().stencil_depth;
67 if (create_subpass) {
68 entry.rendering_mode = Entity::RenderingMode::kSubpass;
69 auto subpass = std::make_unique<EntityPass>();
70 subpass->SetEnableOffscreenCheckerboard(
71 debug_options.offscreen_texture_checkerboard);
72 if (backdrop_filter) {
73 EntityPass::BackdropFilterProc backdrop_filter_proc =
74 [backdrop_filter = backdrop_filter->Clone()](
75 const FilterInput::Ref& input, const Matrix& effect_transform,
76 Entity::RenderingMode rendering_mode) {
77 auto filter = backdrop_filter->WrapInput(input);
78 filter->SetEffectTransform(effect_transform);
79 filter->SetRenderingMode(rendering_mode);
80 return filter;
81 };
82 subpass->SetBackdropFilter(backdrop_filter_proc);
83 }
84 subpass->SetBlendMode(blend_mode);
85 current_pass_ = GetCurrentPass().AddSubpass(std::move(subpass));
86 current_pass_->SetTransformation(xformation_stack_.back().xformation);
87 current_pass_->SetStencilDepth(xformation_stack_.back().stencil_depth);
88 }
89 xformation_stack_.emplace_back(entry);
90 }
91
92 bool Canvas::Restore() {
93 FML_DCHECK(xformation_stack_.size() > 0);
94 if (xformation_stack_.size() == 1) {
95 return false;
96 }
97 if (xformation_stack_.back().rendering_mode ==
98 Entity::RenderingMode::kSubpass) {
99 current_pass_ = GetCurrentPass().GetSuperpass();
100 FML_DCHECK(current_pass_);
101 }
102
103 bool contains_clips = xformation_stack_.back().contains_clips;
104 xformation_stack_.pop_back();
105
106 if (contains_clips) {
107 RestoreClip();
108 }
109
110 return true;
111 }
112
113 void Canvas::Concat(const Matrix& xformation) {
114 xformation_stack_.back().xformation = GetCurrentTransformation() * xformation;
115 }
116
117 void Canvas::PreConcat(const Matrix& xformation) {
118 xformation_stack_.back().xformation = xformation * GetCurrentTransformation();
119 }
120
121 void Canvas::ResetTransform() {
122 xformation_stack_.back().xformation = {};
123 }
124
125 void Canvas::Transform(const Matrix& xformation) {
126 Concat(xformation);
127 }
128
129 const Matrix& Canvas::GetCurrentTransformation() const {
130 return xformation_stack_.back().xformation;
131 }
132
133 const std::optional<Rect> Canvas::GetCurrentLocalCullingBounds() const {
134 auto cull_rect = xformation_stack_.back().cull_rect;
135 if (cull_rect.has_value()) {
136 Matrix inverse = xformation_stack_.back().xformation.Invert();
137 cull_rect = cull_rect.value().TransformBounds(inverse);
138 }
139 return cull_rect;
140 }
141
142 void Canvas::Translate(const Vector3& offset) {
143 Concat(Matrix::MakeTranslation(offset));
144 }
145
146 void Canvas::Scale(const Vector2& scale) {
147 Concat(Matrix::MakeScale(scale));
148 }
149
150 void Canvas::Scale(const Vector3& scale) {
151 Concat(Matrix::MakeScale(scale));
152 }
153
154 void Canvas::Skew(Scalar sx, Scalar sy) {
155 Concat(Matrix::MakeSkew(sx, sy));
156 }
157
158 void Canvas::Rotate(Radians radians) {
159 Concat(Matrix::MakeRotationZ(radians));
160 }
161
162 size_t Canvas::GetSaveCount() const {
163 return xformation_stack_.size();
164 }
165
166 void Canvas::RestoreToCount(size_t count) {
167 while (GetSaveCount() > count) {
168 if (!Restore()) {
169 return;
170 }
171 }
172 }
173
174 void Canvas::DrawPath(const Path& path, const Paint& paint) {
175 Entity entity;
176 entity.SetTransformation(GetCurrentTransformation());
177 entity.SetStencilDepth(GetStencilDepth());
178 entity.SetBlendMode(paint.blend_mode);
179 entity.SetContents(paint.WithFilters(paint.CreateContentsForEntity(path)));
180
181 GetCurrentPass().AddEntity(entity);
182 }
183
184 void Canvas::DrawPaint(const Paint& paint) {
185 Entity entity;
186 entity.SetTransformation(GetCurrentTransformation());
187 entity.SetStencilDepth(GetStencilDepth());
188 entity.SetBlendMode(paint.blend_mode);
189 entity.SetContents(paint.CreateContentsForEntity({}, true));
190
191 GetCurrentPass().AddEntity(entity);
192 }
193
194 bool Canvas::AttemptDrawBlurredRRect(const Rect& rect,
195 Scalar corner_radius,
196 const Paint& paint) {
197 Paint new_paint = paint;
198 if (new_paint.color_source.GetType() != ColorSource::Type::kColor ||
199 new_paint.style != Paint::Style::kFill) {
200 return false;
201 }
202
203 if (!new_paint.mask_blur_descriptor.has_value() ||
204 new_paint.mask_blur_descriptor->style !=
205 FilterContents::BlurStyle::kNormal) {
206 return false;
207 }
208
209 if (std::fabs(new_paint.mask_blur_descriptor->sigma.sigma) <=
210 kEhCloseEnough) {
211 return true;
212 }
213
214 // For symmetrically mask blurred solid RRects, absorb the mask blur and use
215 // a faster SDF approximation.
216
217 auto contents = std::make_shared<SolidRRectBlurContents>();
218 contents->SetColor(new_paint.color);
219 contents->SetSigma(new_paint.mask_blur_descriptor->sigma);
220 contents->SetRRect(rect, corner_radius);
221
222 new_paint.mask_blur_descriptor = std::nullopt;
223
224 Entity entity;
225 entity.SetTransformation(GetCurrentTransformation());
226 entity.SetStencilDepth(GetStencilDepth());
227 entity.SetBlendMode(new_paint.blend_mode);
228 entity.SetContents(new_paint.WithFilters(std::move(contents)));
229
230 GetCurrentPass().AddEntity(entity);
231
232 return true;
233 }
234
235 void Canvas::DrawRect(Rect rect, const Paint& paint) {
236 if (paint.style == Paint::Style::kStroke) {
237 DrawPath(PathBuilder{}.AddRect(rect).TakePath(), paint);
238 return;
239 }
240
241 if (AttemptDrawBlurredRRect(rect, 0, paint)) {
242 return;
243 }
244
245 Entity entity;
246 entity.SetTransformation(GetCurrentTransformation());
247 entity.SetStencilDepth(GetStencilDepth());
248 entity.SetBlendMode(paint.blend_mode);
249 entity.SetContents(paint.WithFilters(
250 paint.CreateContentsForGeometry(Geometry::MakeRect(rect))));
251
252 GetCurrentPass().AddEntity(entity);
253 }
254
255 void Canvas::DrawRRect(Rect rect, Scalar corner_radius, const Paint& paint) {
256 if (AttemptDrawBlurredRRect(rect, corner_radius, paint)) {
257 return;
258 }
259 auto path = PathBuilder{}
260 .SetConvexity(Convexity::kConvex)
261 .AddRoundedRect(rect, corner_radius)
262 .TakePath();
263 if (paint.style == Paint::Style::kFill) {
264 Entity entity;
265 entity.SetTransformation(GetCurrentTransformation());
266 entity.SetStencilDepth(GetStencilDepth());
267 entity.SetBlendMode(paint.blend_mode);
268 entity.SetContents(paint.WithFilters(
269 paint.CreateContentsForGeometry(Geometry::MakeFillPath(path))));
270
271 GetCurrentPass().AddEntity(entity);
272 return;
273 }
274 DrawPath(path, paint);
275 }
276
277 void Canvas::DrawCircle(Point center, Scalar radius, const Paint& paint) {
278 Size half_size(radius, radius);
279 if (AttemptDrawBlurredRRect(Rect(center - half_size, half_size * 2), radius,
280 paint)) {
281 return;
282 }
283 auto circle_path = PathBuilder{}
284 .AddCircle(center, radius)
285 .SetConvexity(Convexity::kConvex)
286 .TakePath();
287 DrawPath(circle_path, paint);
288 }
289
290 void Canvas::ClipPath(const Path& path, Entity::ClipOperation clip_op) {
291 ClipGeometry(Geometry::MakeFillPath(path), clip_op);
292 if (clip_op == Entity::ClipOperation::kIntersect) {
293 auto bounds = path.GetBoundingBox();
294 if (bounds.has_value()) {
295 IntersectCulling(bounds.value());
296 }
297 }
298 }
299
300 void Canvas::ClipRect(const Rect& rect, Entity::ClipOperation clip_op) {
301 auto geometry = Geometry::MakeRect(rect);
302 auto& cull_rect = xformation_stack_.back().cull_rect;
303 if (clip_op == Entity::ClipOperation::kIntersect && //
304 cull_rect.has_value() && //
305 geometry->CoversArea(xformation_stack_.back().xformation, *cull_rect) //
306 ) {
307 return; // This clip will do nothing, so skip it.
308 }
309
310 ClipGeometry(std::move(geometry), clip_op);
311 switch (clip_op) {
312 case Entity::ClipOperation::kIntersect:
313 IntersectCulling(rect);
314 break;
315 case Entity::ClipOperation::kDifference:
316 SubtractCulling(rect);
317 break;
318 }
319 }
320
321 void Canvas::ClipRRect(const Rect& rect,
322 Scalar corner_radius,
323 Entity::ClipOperation clip_op) {
324 auto path = PathBuilder{}
325 .SetConvexity(Convexity::kConvex)
326 .AddRoundedRect(rect, corner_radius)
327 .TakePath();
328
329 std::optional<Rect> inner_rect = (corner_radius * 2 < rect.size.width &&
330 corner_radius * 2 < rect.size.height)
331 ? rect.Expand(-corner_radius)
332 : std::make_optional<Rect>();
333 auto geometry = Geometry::MakeFillPath(path, inner_rect);
334 auto& cull_rect = xformation_stack_.back().cull_rect;
335 if (clip_op == Entity::ClipOperation::kIntersect && //
336 cull_rect.has_value() && //
337 geometry->CoversArea(xformation_stack_.back().xformation, *cull_rect) //
338 ) {
339 return; // This clip will do nothing, so skip it.
340 }
341
342 ClipGeometry(std::move(geometry), clip_op);
343 switch (clip_op) {
344 case Entity::ClipOperation::kIntersect:
345 IntersectCulling(rect);
346 break;
347 case Entity::ClipOperation::kDifference:
348 if (corner_radius <= 0) {
349 SubtractCulling(rect);
350 } else {
351 // We subtract the inner "tall" and "wide" rectangle pieces
352 // that fit inside the corners which cover the greatest area
353 // without involving the curved corners
354 // Since this is a subtract operation, we can subtract each
355 // rectangle piece individually without fear of interference.
356 if (corner_radius * 2 < rect.size.width) {
357 SubtractCulling(Rect::MakeLTRB(
358 rect.GetLeft() + corner_radius, rect.GetTop(),
359 rect.GetRight() - corner_radius, rect.GetBottom()));
360 }
361 if (corner_radius * 2 < rect.size.height) {
362 SubtractCulling(Rect::MakeLTRB(
363 rect.GetLeft(), rect.GetTop() + corner_radius, //
364 rect.GetRight(), rect.GetBottom() - corner_radius));
365 }
366 }
367 break;
368 }
369 }
370
371 void Canvas::ClipGeometry(std::unique_ptr<Geometry> geometry,
372 Entity::ClipOperation clip_op) {
373 auto contents = std::make_shared<ClipContents>();
374 contents->SetGeometry(std::move(geometry));
375 contents->SetClipOperation(clip_op);
376
377 Entity entity;
378 entity.SetTransformation(GetCurrentTransformation());
379 entity.SetContents(std::move(contents));
380 entity.SetStencilDepth(GetStencilDepth());
381
382 GetCurrentPass().AddEntity(entity);
383
384 ++xformation_stack_.back().stencil_depth;
385 xformation_stack_.back().contains_clips = true;
386 }
387
388 void Canvas::IntersectCulling(Rect clip_rect) {
389 clip_rect = clip_rect.TransformBounds(GetCurrentTransformation());
390 std::optional<Rect>& cull_rect = xformation_stack_.back().cull_rect;
391 if (cull_rect.has_value()) {
392 cull_rect = cull_rect
393 .value() //
394 .Intersection(clip_rect) //
395 .value_or(Rect{});
396 } else {
397 cull_rect = clip_rect;
398 }
399 }
400
401 void Canvas::SubtractCulling(Rect clip_rect) {
402 std::optional<Rect>& cull_rect = xformation_stack_.back().cull_rect;
403 if (cull_rect.has_value()) {
404 clip_rect = clip_rect.TransformBounds(GetCurrentTransformation());
405 cull_rect = cull_rect
406 .value() //
407 .Cutout(clip_rect) //
408 .value_or(Rect{});
409 }
410 // else (no cull) diff (any clip) is non-rectangular
411 }
412
413 void Canvas::RestoreClip() {
414 Entity entity;
415 entity.SetTransformation(GetCurrentTransformation());
416 // This path is empty because ClipRestoreContents just generates a quad that
417 // takes up the full render target.
418 entity.SetContents(std::make_shared<ClipRestoreContents>());
419 entity.SetStencilDepth(GetStencilDepth());
420
421 GetCurrentPass().AddEntity(entity);
422 }
423
424 void Canvas::DrawPoints(std::vector<Point> points,
425 Scalar radius,
426 const Paint& paint,
427 PointStyle point_style) {
428 if (radius <= 0) {
429 return;
430 }
431
432 Entity entity;
433 entity.SetTransformation(GetCurrentTransformation());
434 entity.SetStencilDepth(GetStencilDepth());
435 entity.SetBlendMode(paint.blend_mode);
436 entity.SetContents(paint.WithFilters(paint.CreateContentsForGeometry(
437 Geometry::MakePointField(std::move(points), radius,
438 /*round=*/point_style == PointStyle::kRound))));
439
440 GetCurrentPass().AddEntity(entity);
441 }
442
443 void Canvas::DrawPicture(const Picture& picture) {
444 if (!picture.pass) {
445 return;
446 }
447
448 // Clone the base pass and account for the CTM updates.
449 auto pass = picture.pass->Clone();
450
451 pass->IterateAllElements([&](auto& element) -> bool {
452 if (auto entity = std::get_if<Entity>(&element)) {
453 entity->IncrementStencilDepth(GetStencilDepth());
454 entity->SetTransformation(GetCurrentTransformation() *
455 entity->GetTransformation());
456 return true;
457 }
458
459 if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
460 subpass->get()->SetStencilDepth(subpass->get()->GetStencilDepth() +
461 GetStencilDepth());
462 return true;
463 }
464
465 FML_UNREACHABLE();
466 });
467
468 GetCurrentPass().AddSubpassInline(std::move(pass));
469
470 RestoreClip();
471 }
472
473 void Canvas::DrawImage(const std::shared_ptr<Image>& image,
474 Point offset,
475 const Paint& paint,
476 SamplerDescriptor sampler) {
477 if (!image) {
478 return;
479 }
480
481 const auto source = Rect::MakeSize(image->GetSize());
482 const auto dest =
483 Rect::MakeXYWH(offset.x, offset.y, source.size.width, source.size.height);
484
485 DrawImageRect(image, source, dest, paint, std::move(sampler));
486 }
487
488 void Canvas::DrawImageRect(const std::shared_ptr<Image>& image,
489 Rect source,
490 Rect dest,
491 const Paint& paint,
492 SamplerDescriptor sampler) {
493 if (!image || source.size.IsEmpty() || dest.size.IsEmpty()) {
494 return;
495 }
496
497 auto size = image->GetSize();
498
499 if (size.IsEmpty()) {
500 return;
501 }
502
503 auto contents = TextureContents::MakeRect(dest);
504 contents->SetTexture(image->GetTexture());
505 contents->SetSourceRect(source);
506 contents->SetSamplerDescriptor(std::move(sampler));
507 contents->SetOpacity(paint.color.alpha);
508 contents->SetDeferApplyingOpacity(paint.HasColorFilter());
509
510 Entity entity;
511 entity.SetBlendMode(paint.blend_mode);
512 entity.SetStencilDepth(GetStencilDepth());
513 entity.SetContents(paint.WithFilters(contents));
514 entity.SetTransformation(GetCurrentTransformation());
515
516 GetCurrentPass().AddEntity(entity);
517 }
518
519 Picture Canvas::EndRecordingAsPicture() {
520 Picture picture;
521 picture.pass = std::move(base_pass_);
522
523 Reset();
524 Initialize(initial_cull_rect_);
525
526 return picture;
527 }
528
529 EntityPass& Canvas::GetCurrentPass() {
530 FML_DCHECK(current_pass_ != nullptr);
531 return *current_pass_;
532 }
533
534 size_t Canvas::GetStencilDepth() const {
535 return xformation_stack_.back().stencil_depth;
536 }
537
538 void Canvas::SaveLayer(const Paint& paint,
539 std::optional<Rect> bounds,
540 const std::shared_ptr<ImageFilter>& backdrop_filter) {
541 Save(true, paint.blend_mode, backdrop_filter);
542
543 // The DisplayList bounds/rtree doesn't account for filters applied to parent
544 // layers, and so sub-DisplayLists are getting culled as if no filters are
545 // applied.
546 // See also: https://github.com/flutter/flutter/issues/139294
547 if (paint.image_filter) {
548 xformation_stack_.back().cull_rect = std::nullopt;
549 }
550
551 auto& new_layer_pass = GetCurrentPass();
552 new_layer_pass.SetBoundsLimit(bounds);
553
554 // Only apply opacity peephole on default blending.
555 if (paint.blend_mode == BlendMode::kSourceOver) {
556 new_layer_pass.SetDelegate(
557 std::make_shared<OpacityPeepholePassDelegate>(paint));
558 } else {
559 new_layer_pass.SetDelegate(std::make_shared<PaintPassDelegate>(paint));
560 }
561 }
562
563 void Canvas::DrawTextFrame(const std::shared_ptr<TextFrame>& text_frame,
564 Point position,
565 const Paint& paint) {
566 Entity entity;
567 entity.SetStencilDepth(GetStencilDepth());
568 entity.SetBlendMode(paint.blend_mode);
569
570 auto text_contents = std::make_shared<TextContents>();
571 text_contents->SetTextFrame(text_frame);
572 text_contents->SetColor(paint.color);
573
574 entity.SetTransformation(GetCurrentTransformation() *
575 Matrix::MakeTranslation(position));
576
577 // TODO(bdero): This mask blur application is a hack. It will always wind up
578 // doing a gaussian blur that affects the color source itself
579 // instead of just the mask. The color filter text support
580 // needs to be reworked in order to interact correctly with
581 // mask filters.
582 // https://github.com/flutter/flutter/issues/133297
583 entity.SetContents(
584 paint.WithFilters(paint.WithMaskBlur(std::move(text_contents), true)));
585
586 GetCurrentPass().AddEntity(entity);
587 }
588
589 static bool UseColorSourceContents(
590 const std::shared_ptr<VerticesGeometry>& vertices,
591 const Paint& paint) {
592 // If there are no vertex color or texture coordinates. Or if there
593 // are vertex coordinates then only if the contents are an image or
594 // a solid color.
595 if (vertices->HasVertexColors()) {
596 return false;
597 }
598 if (vertices->HasTextureCoordinates() &&
599 (paint.color_source.GetType() == ColorSource::Type::kImage ||
600 paint.color_source.GetType() == ColorSource::Type::kColor)) {
601 return true;
602 }
603 return !vertices->HasTextureCoordinates();
604 }
605
606 void Canvas::DrawVertices(const std::shared_ptr<VerticesGeometry>& vertices,
607 BlendMode blend_mode,
608 const Paint& paint) {
609 // Override the blend mode with kDestination in order to match the behavior
610 // of Skia's SK_LEGACY_IGNORE_DRAW_VERTICES_BLEND_WITH_NO_SHADER flag, which
611 // is enabled when the Flutter engine builds Skia.
612 if (paint.color_source.GetType() == ColorSource::Type::kColor) {
613 blend_mode = BlendMode::kDestination;
614 }
615
616 Entity entity;
617 entity.SetTransformation(GetCurrentTransformation());
618 entity.SetStencilDepth(GetStencilDepth());
619 entity.SetBlendMode(paint.blend_mode);
620
621 // If there are no vertex color or texture coordinates. Or if there
622 // are vertex coordinates then only if the contents are an image.
623 if (UseColorSourceContents(vertices, paint)) {
624 auto contents = paint.CreateContentsForGeometry(vertices);
625 entity.SetContents(paint.WithFilters(std::move(contents)));
626 GetCurrentPass().AddEntity(entity);
627 return;
628 }
629
630 auto src_paint = paint;
631 src_paint.color = paint.color.WithAlpha(1.0);
632
633 std::shared_ptr<Contents> src_contents =
634 src_paint.CreateContentsForGeometry(vertices);
635 if (vertices->HasTextureCoordinates()) {
636 // If the color source has an intrinsic size, then we use that to
637 // create the src contents as a simplification. Otherwise we use
638 // the extent of the texture coordinates to determine how large
639 // the src contents should be. If neither has a value we fall back
640 // to using the geometry coverage data.
641 Rect src_coverage;
642 auto size = src_contents->GetColorSourceSize();
643 if (size.has_value()) {
644 src_coverage = Rect::MakeXYWH(0, 0, size->width, size->height);
645 } else {
646 auto cvg = vertices->GetCoverage(Matrix{});
647 FML_CHECK(cvg.has_value());
648 src_coverage =
649 // Covered by FML_CHECK.
650 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
651 vertices->GetTextureCoordinateCoverge().value_or(cvg.value());
652 }
653 src_contents =
654 src_paint.CreateContentsForGeometry(Geometry::MakeRect(src_coverage));
655 }
656
657 auto contents = std::make_shared<VerticesContents>();
658 contents->SetAlpha(paint.color.alpha);
659 contents->SetBlendMode(blend_mode);
660 contents->SetGeometry(vertices);
661 contents->SetSourceContents(std::move(src_contents));
662 entity.SetContents(paint.WithFilters(std::move(contents)));
663
664 GetCurrentPass().AddEntity(entity);
665 }
666
667 void Canvas::DrawAtlas(const std::shared_ptr<Image>& atlas,
668 std::vector<Matrix> transforms,
669 std::vector<Rect> texture_coordinates,
670 std::vector<Color> colors,
671 BlendMode blend_mode,
672 SamplerDescriptor sampler,
673 std::optional<Rect> cull_rect,
674 const Paint& paint) {
675 if (!atlas) {
676 return;
677 }
678
679 std::shared_ptr<AtlasContents> contents = std::make_shared<AtlasContents>();
680 contents->SetColors(std::move(colors));
681 contents->SetTransforms(std::move(transforms));
682 contents->SetTextureCoordinates(std::move(texture_coordinates));
683 contents->SetTexture(atlas->GetTexture());
684 contents->SetSamplerDescriptor(std::move(sampler));
685 contents->SetBlendMode(blend_mode);
686 contents->SetCullRect(cull_rect);
687 contents->SetAlpha(paint.color.alpha);
688
689 Entity entity;
690 entity.SetTransformation(GetCurrentTransformation());
691 entity.SetStencilDepth(GetStencilDepth());
692 entity.SetBlendMode(paint.blend_mode);
693 entity.SetContents(paint.WithFilters(contents));
694
695 GetCurrentPass().AddEntity(entity);
696 }
697
698 } // namespace impeller
text_contents.h
impeller::Matrix::MakeSkew
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
Definition: matrix.h:116
impeller::EntityPass::AddSubpassInline
void AddSubpassInline(std::unique_ptr< EntityPass > pass)
Merges a given pass into this pass. Useful for drawing pre-recorded pictures that don't require rende...
Definition: entity_pass.cc:245
impeller::BlendMode
BlendMode
Definition: color.h:57
impeller::Entity::ClipOperation::kIntersect
@ kIntersect
impeller::Canvas::EndRecordingAsPicture
Picture EndRecordingAsPicture()
Definition: canvas.cc:519
impeller::Picture::pass
std::unique_ptr< EntityPass > pass
Definition: picture.h:20
impeller::Entity::SetTransformation
void SetTransformation(const Matrix &transformation)
Definition: entity.cc:53
impeller::EntityPass::SetTransformation
void SetTransformation(Matrix xformation)
Definition: entity_pass.cc:1126
impeller::Paint::WithMaskBlur
std::shared_ptr< Contents > WithMaskBlur(std::shared_ptr< Contents > input, bool is_solid_color) const
Definition: paint.cc:83
impeller::TRect::size
TSize< Type > size
Definition: rect.h:24
impeller::EntityPass::BackdropFilterProc
std::function< std::shared_ptr< FilterContents >(FilterInput::Ref, const Matrix &effect_transform, Entity::RenderingMode rendering_mode)> BackdropFilterProc
Definition: entity_pass.h:44
impeller::TPoint::y
Type y
Definition: point.h:24
impeller::Entity::ClipOperation::kDifference
@ kDifference
impeller::Scalar
float Scalar
Definition: scalar.h:15
impeller::Canvas::RestoreToCount
void RestoreToCount(size_t count)
Definition: canvas.cc:166
image_filter.h
impeller::Entity::SetBlendMode
void SetBlendMode(BlendMode blend_mode)
Definition: entity.cc:101
texture_contents.h
impeller::Paint::Style::kStroke
@ kStroke
impeller::CanvasStackEntry
Definition: canvas.h:33
impeller::Paint
Definition: paint.h:25
impeller::CanvasStackEntry::cull_rect
std::optional< Rect > cull_rect
Definition: canvas.h:36
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:47
impeller::Canvas::Skew
void Skew(Scalar sx, Scalar sy)
Definition: canvas.cc:154
impeller::kEhCloseEnough
constexpr float kEhCloseEnough
Definition: constants.h:55
impeller::Paint::CreateContentsForEntity
std::shared_ptr< Contents > CreateContentsForEntity(const Path &path={}, bool cover=false) const
Definition: paint.cc:17
impeller::PointStyle
PointStyle
Definition: canvas.h:42
impeller::Paint::color
Color color
Definition: paint.h:54
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:226
impeller::Canvas::DrawTextFrame
void DrawTextFrame(const std::shared_ptr< TextFrame > &text_frame, Point position, const Paint &paint)
Definition: canvas.cc:563
impeller::PathBuilder
Definition: path_builder.h:13
impeller::PointStyle::kRound
@ kRound
Points are drawn as squares.
impeller::FilterInput::Ref
std::shared_ptr< FilterInput > Ref
Definition: filter_input.h:31
impeller::Canvas::ResetTransform
void ResetTransform()
Definition: canvas.cc:121
impeller::Canvas::DrawVertices
void DrawVertices(const std::shared_ptr< VerticesGeometry > &vertices, BlendMode blend_mode, const Paint &paint)
Definition: canvas.cc:606
impeller::Path::GetBoundingBox
std::optional< Rect > GetBoundingBox() const
Definition: path.cc:399
impeller::Geometry::MakeRect
static std::unique_ptr< Geometry > MakeRect(Rect rect)
Definition: geometry.cc:142
impeller::Color::alpha
Scalar alpha
Definition: color.h:141
impeller::Canvas::DebugOptions::offscreen_texture_checkerboard
bool offscreen_texture_checkerboard
Definition: canvas.h:57
impeller::PathBuilder::AddRoundedRect
PathBuilder & AddRoundedRect(Rect rect, RoundingRadii radii)
Definition: path_builder.cc:207
impeller::Canvas::debug_options
struct impeller::Canvas::DebugOptions debug_options
impeller::FilterContents::BlurStyle::kNormal
@ kNormal
Blurred inside and outside.
impeller::PathBuilder::SetConvexity
PathBuilder & SetConvexity(Convexity value)
Definition: path_builder.cc:111
impeller::Canvas::SaveLayer
void SaveLayer(const Paint &paint, std::optional< Rect > bounds=std::nullopt, const std::shared_ptr< ImageFilter > &backdrop_filter=nullptr)
Definition: canvas.cc:538
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:94
impeller::Paint::color_source
ColorSource color_source
Definition: paint.h:55
impeller::EntityPass::SetStencilDepth
void SetStencilDepth(size_t stencil_depth)
Definition: entity_pass.cc:1130
impeller::PathBuilder::AddRect
PathBuilder & AddRect(Rect rect)
Definition: path_builder.cc:181
impeller::UseColorSourceContents
static bool UseColorSourceContents(const std::shared_ptr< VerticesGeometry > &vertices, const Paint &paint)
Definition: canvas.cc:589
impeller::Canvas::DrawImage
void DrawImage(const std::shared_ptr< Image > &image, Point offset, const Paint &paint, SamplerDescriptor sampler={})
Definition: canvas.cc:473
impeller::Canvas::DrawPicture
void DrawPicture(const Picture &picture)
Definition: canvas.cc:443
impeller::Entity::SetContents
void SetContents(std::shared_ptr< Contents > contents)
Definition: entity.cc:81
vertices_contents.h
path_builder.h
impeller::SamplerDescriptor
Definition: sampler_descriptor.h:18
impeller::Entity
Definition: entity.h:21
impeller::Picture
Definition: picture.h:19
impeller::TSize
Definition: size.h:18
impeller::Canvas::DrawImageRect
void DrawImageRect(const std::shared_ptr< Image > &image, Rect source, Rect dest, const Paint &paint, SamplerDescriptor sampler={})
Definition: canvas.cc:488
impeller::BlendMode::kSourceOver
@ kSourceOver
impeller::TRect::GetLeft
constexpr auto GetLeft() const
Definition: rect.h:137
impeller::Canvas::Scale
void Scale(const Vector2 &scale)
Definition: canvas.cc:146
impeller::EntityPass::GetSuperpass
EntityPass * GetSuperpass() const
Definition: entity_pass.cc:222
impeller::Path
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
Definition: path.h:54
impeller::BlendMode::kDestination
@ kDestination
impeller::Canvas::Save
void Save()
Definition: canvas.cc:56
impeller::EntityPass
Definition: entity_pass.h:26
impeller::Paint::style
Style style
Definition: paint.h:62
impeller::Canvas::DrawCircle
void DrawCircle(Point center, Scalar radius, const Paint &paint)
Definition: canvas.cc:277
impeller::Color::WithAlpha
constexpr Color WithAlpha(Scalar new_alpha) const
Definition: color.h:268
impeller::Paint::Style::kFill
@ kFill
impeller::Canvas::DrawRRect
void DrawRRect(Rect rect, Scalar corner_radius, const Paint &paint)
Definition: canvas.cc:255
geometry.h
impeller::Canvas::Restore
bool Restore()
Definition: canvas.cc:92
impeller::Radians
Definition: scalar.h:35
impeller::Canvas::DrawAtlas
void DrawAtlas(const std::shared_ptr< Image > &atlas, std::vector< Matrix > transforms, std::vector< Rect > texture_coordinates, std::vector< Color > colors, BlendMode blend_mode, SamplerDescriptor sampler, std::optional< Rect > cull_rect, const Paint &paint)
Definition: canvas.cc:667
canvas.h
clip_contents.h
impeller::Canvas::DrawPath
void DrawPath(const Path &path, const Paint &paint)
Definition: canvas.cc:174
impeller::PathBuilder::TakePath
Path TakePath(FillType fill=FillType::kNonZero)
Definition: path_builder.cc:21
impeller::Canvas::DrawPaint
void DrawPaint(const Paint &paint)
Definition: canvas.cc:184
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:306
impeller::Canvas::GetSaveCount
size_t GetSaveCount() const
Definition: canvas.cc:162
impeller::Canvas::PreConcat
void PreConcat(const Matrix &xformation)
Definition: canvas.cc:117
impeller::Canvas::Canvas
Canvas()
Definition: canvas.cc:26
impeller::TSize::width
Type width
Definition: size.h:21
impeller::Entity::RenderingMode::kSubpass
@ kSubpass
impeller::TPoint::x
Type x
Definition: point.h:23
impeller::Canvas::Transform
void Transform(const Matrix &xformation)
Definition: canvas.cc:125
atlas_contents.h
impeller::ColorSource::Type::kImage
@ kImage
impeller::Canvas::ClipRRect
void ClipRRect(const Rect &rect, Scalar corner_radius, Entity::ClipOperation clip_op=Entity::ClipOperation::kIntersect)
Definition: canvas.cc:321
impeller::TRect::GetRight
constexpr auto GetRight() const
Definition: rect.h:151
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:208
impeller::Canvas::Rotate
void Rotate(Radians radians)
Definition: canvas.cc:158
impeller::Geometry::MakePointField
static std::unique_ptr< Geometry > MakePointField(std::vector< Point > points, Scalar radius, bool round)
Definition: geometry.cc:119
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:52
impeller::Canvas::GetCurrentTransformation
const Matrix & GetCurrentTransformation() const
Definition: canvas.cc:129
constants.h
impeller::TPoint< Scalar >
impeller::Geometry::MakeFillPath
static std::unique_ptr< Geometry > MakeFillPath(const Path &path, std::optional< Rect > inner_rect=std::nullopt)
Definition: geometry.cc:113
impeller::Paint::CreateContentsForGeometry
std::shared_ptr< Contents > CreateContentsForGeometry(std::shared_ptr< Geometry > geometry) const
Definition: paint.cc:34
impeller::Canvas::GetCurrentLocalCullingBounds
const std::optional< Rect > GetCurrentLocalCullingBounds() const
Definition: canvas.cc:133
impeller::Canvas::Concat
void Concat(const Matrix &xformation)
Definition: canvas.cc:113
impeller::Entity::ClipOperation
ClipOperation
Definition: entity.h:59
impeller::Canvas::DrawRect
void DrawRect(Rect rect, const Paint &paint)
Definition: canvas.cc:235
impeller::TRect::GetBottom
constexpr auto GetBottom() const
Definition: rect.h:158
impeller::Paint::HasColorFilter
bool HasColorFilter() const
Whether this paint has a color filter that can apply opacity.
Definition: paint.cc:211
impeller::Entity::SetStencilDepth
void SetStencilDepth(uint32_t stencil_depth)
Definition: entity.cc:89
impeller::PathBuilder::AddCircle
PathBuilder & AddCircle(const Point &center, Scalar radius)
Definition: path_builder.cc:198
impeller::Canvas::DrawPoints
void DrawPoints(std::vector< Point >, Scalar radius, const Paint &paint, PointStyle point_style)
Definition: canvas.cc:424
impeller::TSize::height
Type height
Definition: size.h:22
impeller::Canvas::ClipRect
void ClipRect(const Rect &rect, Entity::ClipOperation clip_op=Entity::ClipOperation::kIntersect)
Definition: canvas.cc:300
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:40
impeller::Entity::RenderingMode
RenderingMode
Definition: entity.h:26
impeller::TSize::IsEmpty
constexpr bool IsEmpty() const
Definition: size.h:105
impeller::Convexity::kConvex
@ kConvex
impeller::TextureContents::MakeRect
static std::shared_ptr< TextureContents > MakeRect(Rect destination)
A common case factory that marks the texture contents as having a destination rectangle....
Definition: texture_contents.cc:28
impeller
Definition: aiks_context.cc:10
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:103
impeller::Paint::mask_blur_descriptor
std::optional< MaskBlurDescriptor > mask_blur_descriptor
Definition: paint.h:68
solid_rrect_blur_contents.h
impeller::TRect::GetTop
constexpr auto GetTop() const
Definition: rect.h:144
impeller::ColorSource::Type::kColor
@ kColor
impeller::Paint::WithFilters
std::shared_ptr< Contents > WithFilters(std::shared_ptr< Contents > input) const
Wrap this paint's configured filters to the given contents.
Definition: paint.cc:59
impeller::ColorSource::GetType
Type GetType() const
Definition: color_source.cc:234
impeller::TRect
Definition: rect.h:20
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:36
impeller::Canvas::~Canvas
~Canvas()
impeller::Vector3
Definition: vector.h:17
impeller::Paint::blend_mode
BlendMode blend_mode
Definition: paint.h:63
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:279
impeller::Paint::image_filter
std::shared_ptr< ImageFilter > image_filter
Definition: paint.h:66
impeller::EntityPass::AddEntity
void AddEntity(Entity entity)
Definition: entity_pass.cc:77
impeller::CanvasStackEntry::xformation
Matrix xformation
Definition: canvas.h:34
impeller::Canvas::Translate
void Translate(const Vector3 &offset)
Definition: canvas.cc:142
impeller::Canvas::ClipPath
void ClipPath(const Path &path, Entity::ClipOperation clip_op=Entity::ClipOperation::kIntersect)
Definition: canvas.cc:290