Flutter Impeller
dl_dispatcher.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 
6 
7 #include <algorithm>
8 #include <cstring>
9 #include <memory>
10 #include <optional>
11 #include <vector>
12 
13 #include "display_list/dl_sampling_options.h"
14 #include "display_list/effects/dl_image_filter.h"
15 #include "flutter/fml/logging.h"
16 #include "fml/closure.h"
17 #include "impeller/core/formats.h"
30 #include "impeller/entity/entity.h"
40 
41 namespace impeller {
42 
43 #if !defined(NDEBUG)
44 #define USE_DEPTH_WATCHER true
45 #else
46 #define USE_DEPTH_WATCHER false
47 #endif // !defined(NDEBUG)
48 
49 #if USE_DEPTH_WATCHER
50 
51 // Invoke this macro at the top of any DlOpReceiver dispatch function
52 // using a number indicating the maximum depth that the operation is
53 // expected to consume in the Canvas. Most rendering ops consume 1
54 // except for DrawImageNine that currently consumes 1 per section (i.e. 9).
55 // Attribute, clip and transform ops do not consume depth but this
56 // macro can still be used with an argument of 0 to verify that expectation.
57 //
58 // The watchdog object allocated here will automatically double-check
59 // the depth usage at any exit point to the function, or any other
60 // point at which it falls out of scope.
61 #define AUTO_DEPTH_WATCHER(d) \
62  DepthWatcher _watcher(__FILE__, __LINE__, GetCanvas(), \
63  paint_.mask_blur_descriptor.has_value(), d)
64 
65 // While the AUTO_DEPTH_WATCHER macro will check the depth usage at
66 // any exit point from the dispatch function, sometimes the dispatch
67 // functions are somewhat compounded and result in multiple Canvas
68 // calls.
69 //
70 // Invoke this macro at any key points in the middle of a dispatch
71 // function to verify that you still haven't exceeded the maximum
72 // allowed depth. This is especially useful if the function does
73 // an implicit save/restore where the restore call might assert the
74 // depth constraints in a function in Canvas that can't be as easily
75 // traced back to a given dispatch function as these macros can.
76 #define AUTO_DEPTH_CHECK() _watcher.check(__FILE__, __LINE__)
77 
78 // Helper class, use the AUTO_DEPTH_WATCHER macros to access it
79 struct DepthWatcher {
80  DepthWatcher(const std::string& file,
81  int line,
82  const impeller::Canvas& canvas,
83  bool has_mask_blur,
84  int allowed)
85  : file_(file),
86  line_(line),
87  canvas_(canvas),
88  allowed_(has_mask_blur ? allowed + 1 : allowed),
89  old_depth_(canvas.GetOpDepth()),
90  old_max_(canvas.GetMaxOpDepth()) {}
91 
92  ~DepthWatcher() { check(file_, line_); }
93 
94  void check(const std::string& file, int line) {
95  FML_CHECK(canvas_.GetOpDepth() <= (old_depth_ + allowed_) &&
96  canvas_.GetOpDepth() <= old_max_)
97  << std::endl
98  << "from " << file << ":" << line << std::endl
99  << "old/allowed/current/max = " << old_depth_ << "/" << allowed_ << "/"
100  << canvas_.GetOpDepth() << "/" << old_max_;
101  }
102 
103  private:
104  const std::string file_;
105  const int line_;
106 
107  const impeller::Canvas& canvas_;
108  const uint64_t allowed_;
109  const uint64_t old_depth_;
110  const uint64_t old_max_;
111 };
112 
113 #else // USE_DEPTH_WATCHER
114 
115 #define AUTO_DEPTH_WATCHER(d)
116 #define AUTO_DEPTH_CHECK()
117 
118 #endif // USE_DEPTH_WATCHER
119 
120 #define UNIMPLEMENTED \
121  FML_DLOG(ERROR) << "Unimplemented detail in " << __FUNCTION__;
122 
124  const flutter::DlFilterMode options) {
126  switch (options) {
127  case flutter::DlFilterMode::kNearest:
129  desc.label = "Nearest Sampler";
130  break;
131  case flutter::DlFilterMode::kLinear:
133  desc.label = "Linear Sampler";
134  break;
135  default:
136  break;
137  }
138  return desc;
139 }
140 
141 static std::optional<const Rect> ToOptRect(const flutter::DlRect* rect) {
142  if (rect == nullptr) {
143  return std::nullopt;
144  }
145  return *rect;
146 }
147 
148 // |flutter::DlOpReceiver|
150  AUTO_DEPTH_WATCHER(0u);
151 
152  paint_.anti_alias = aa;
153 }
154 
155 static Paint::Style ToStyle(flutter::DlDrawStyle style) {
156  switch (style) {
157  case flutter::DlDrawStyle::kFill:
158  return Paint::Style::kFill;
159  case flutter::DlDrawStyle::kStroke:
160  return Paint::Style::kStroke;
161  case flutter::DlDrawStyle::kStrokeAndFill:
163  break;
164  }
165  return Paint::Style::kFill;
166 }
167 
168 // |flutter::DlOpReceiver|
169 void DlDispatcherBase::setDrawStyle(flutter::DlDrawStyle style) {
170  AUTO_DEPTH_WATCHER(0u);
171 
172  paint_.style = ToStyle(style);
173 }
174 
175 // |flutter::DlOpReceiver|
176 void DlDispatcherBase::setColor(flutter::DlColor color) {
177  AUTO_DEPTH_WATCHER(0u);
178 
180 }
181 
182 // |flutter::DlOpReceiver|
184  AUTO_DEPTH_WATCHER(0u);
185 
186  paint_.stroke.width = width;
187 }
188 
189 // |flutter::DlOpReceiver|
191  AUTO_DEPTH_WATCHER(0u);
192 
193  paint_.stroke.miter_limit = limit;
194 }
195 
196 // |flutter::DlOpReceiver|
197 void DlDispatcherBase::setStrokeCap(flutter::DlStrokeCap cap) {
198  AUTO_DEPTH_WATCHER(0u);
199 
200  switch (cap) {
201  case flutter::DlStrokeCap::kButt:
203  break;
204  case flutter::DlStrokeCap::kRound:
206  break;
207  case flutter::DlStrokeCap::kSquare:
209  break;
210  }
211 }
212 
213 // |flutter::DlOpReceiver|
214 void DlDispatcherBase::setStrokeJoin(flutter::DlStrokeJoin join) {
215  AUTO_DEPTH_WATCHER(0u);
216 
217  switch (join) {
218  case flutter::DlStrokeJoin::kMiter:
220  break;
221  case flutter::DlStrokeJoin::kRound:
223  break;
224  case flutter::DlStrokeJoin::kBevel:
226  break;
227  }
228 }
229 
230 // |flutter::DlOpReceiver|
231 void DlDispatcherBase::setColorSource(const flutter::DlColorSource* source) {
232  AUTO_DEPTH_WATCHER(0u);
233 
234  paint_.color_source = source;
235 }
236 
237 // |flutter::DlOpReceiver|
238 void DlDispatcherBase::setColorFilter(const flutter::DlColorFilter* filter) {
239  AUTO_DEPTH_WATCHER(0u);
240 
241  paint_.color_filter = filter;
242 }
243 
244 // |flutter::DlOpReceiver|
246  AUTO_DEPTH_WATCHER(0u);
247 
248  paint_.invert_colors = invert;
249 }
250 
251 // |flutter::DlOpReceiver|
252 void DlDispatcherBase::setBlendMode(flutter::DlBlendMode dl_mode) {
253  AUTO_DEPTH_WATCHER(0u);
254 
255  paint_.blend_mode = dl_mode;
256 }
257 
258 static FilterContents::BlurStyle ToBlurStyle(flutter::DlBlurStyle blur_style) {
259  switch (blur_style) {
260  case flutter::DlBlurStyle::kNormal:
262  case flutter::DlBlurStyle::kSolid:
264  case flutter::DlBlurStyle::kOuter:
266  case flutter::DlBlurStyle::kInner:
268  }
269 }
270 
271 // |flutter::DlOpReceiver|
272 void DlDispatcherBase::setMaskFilter(const flutter::DlMaskFilter* filter) {
273  AUTO_DEPTH_WATCHER(0u);
274 
275  // Needs https://github.com/flutter/flutter/issues/95434
276  if (filter == nullptr) {
277  paint_.mask_blur_descriptor = std::nullopt;
278  return;
279  }
280  switch (filter->type()) {
281  case flutter::DlMaskFilterType::kBlur: {
282  auto blur = filter->asBlur();
283 
285  .style = ToBlurStyle(blur->style()),
286  .sigma = Sigma(blur->sigma()),
287  .respect_ctm = blur->respectCTM(),
288  };
289  break;
290  }
291  }
292 }
293 
294 // |flutter::DlOpReceiver|
295 void DlDispatcherBase::setImageFilter(const flutter::DlImageFilter* filter) {
296  AUTO_DEPTH_WATCHER(0u);
297 
298  paint_.image_filter = filter;
299 }
300 
301 // |flutter::DlOpReceiver|
302 void DlDispatcherBase::save(uint32_t total_content_depth) {
303  AUTO_DEPTH_WATCHER(1u);
304 
305  GetCanvas().Save(total_content_depth);
306 }
307 
308 // |flutter::DlOpReceiver|
310  const flutter::SaveLayerOptions& options,
311  uint32_t total_content_depth,
312  flutter::DlBlendMode max_content_mode,
313  const flutter::DlImageFilter* backdrop,
314  std::optional<int64_t> backdrop_id) {
315  AUTO_DEPTH_WATCHER(1u);
316 
317  auto paint = options.renders_with_attributes() ? paint_ : Paint{};
318  auto promise = options.content_is_clipped()
321  std::optional<Rect> impeller_bounds;
322  // If the content is unbounded but has developer specified bounds, we take
323  // the original bounds so that we clip the content as expected.
324  if (!options.content_is_unbounded() || options.bounds_from_caller()) {
325  impeller_bounds = bounds;
326  }
327 
329  paint, impeller_bounds, backdrop, promise, total_content_depth,
330  // Unbounded content can still have user specified bounds that require a
331  // saveLayer to be created to perform the clip.
332  options.can_distribute_opacity() && !options.content_is_unbounded(),
333  backdrop_id //
334  );
335 }
336 
337 // |flutter::DlOpReceiver|
339  GetCanvas().Restore();
340 }
341 
342 // |flutter::DlOpReceiver|
344  AUTO_DEPTH_WATCHER(0u);
345 
346  GetCanvas().Translate({tx, ty, 0.0});
347 }
348 
349 // |flutter::DlOpReceiver|
351  AUTO_DEPTH_WATCHER(0u);
352 
353  GetCanvas().Scale({sx, sy, 1.0});
354 }
355 
356 // |flutter::DlOpReceiver|
358  AUTO_DEPTH_WATCHER(0u);
359 
360  GetCanvas().Rotate(Degrees{degrees});
361 }
362 
363 // |flutter::DlOpReceiver|
365  AUTO_DEPTH_WATCHER(0u);
366 
367  GetCanvas().Skew(sx, sy);
368 }
369 
370 // clang-format off
371 // |flutter::DlOpReceiver|
373  DlScalar mxx, DlScalar mxy, DlScalar mxt,
374  DlScalar myx, DlScalar myy, DlScalar myt) {
375  AUTO_DEPTH_WATCHER(0u);
376 
378  mxx, mxy, 0, mxt,
379  myx, myy, 0, myt,
380  0 , 0, 1, 0,
381  0 , 0, 0, 1
382  );
383 }
384 // clang-format on
385 
386 // clang-format off
387 // |flutter::DlOpReceiver|
389  DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt,
390  DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt,
391  DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt,
392  DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) {
393  AUTO_DEPTH_WATCHER(0u);
394 
395  // The order of arguments is row-major but Impeller matrices are
396  // column-major.
397  auto transform = Matrix{
398  mxx, myx, mzx, mwx,
399  mxy, myy, mzy, mwy,
400  mxz, myz, mzz, mwz,
401  mxt, myt, mzt, mwt
402  };
404 }
405 // clang-format on
406 
407 // |flutter::DlOpReceiver|
409  AUTO_DEPTH_WATCHER(0u);
410 
413 }
414 
415 static Entity::ClipOperation ToClipOperation(flutter::DlClipOp clip_op) {
416  switch (clip_op) {
417  case flutter::DlClipOp::kDifference:
419  case flutter::DlClipOp::kIntersect:
421  }
422 }
423 
424 // |flutter::DlOpReceiver|
426  flutter::DlClipOp clip_op,
427  bool is_aa) {
428  AUTO_DEPTH_WATCHER(0u);
429 
430  FillRectGeometry geom(rect);
431  GetCanvas().ClipGeometry(geom, ToClipOperation(clip_op), /*is_aa=*/is_aa);
432 }
433 
434 // |flutter::DlOpReceiver|
436  flutter::DlClipOp clip_op,
437  bool is_aa) {
438  AUTO_DEPTH_WATCHER(0u);
439 
440  EllipseGeometry geom(bounds);
441  GetCanvas().ClipGeometry(geom, ToClipOperation(clip_op));
442 }
443 
444 // |flutter::DlOpReceiver|
446  flutter::DlClipOp sk_op,
447  bool is_aa) {
448  AUTO_DEPTH_WATCHER(0u);
449 
450  auto clip_op = ToClipOperation(sk_op);
451  if (rrect.IsRect()) {
452  FillRectGeometry geom(rrect.GetBounds());
453  GetCanvas().ClipGeometry(geom, clip_op, /*is_aa=*/is_aa);
454  } else if (rrect.IsOval()) {
455  EllipseGeometry geom(rrect.GetBounds());
456  GetCanvas().ClipGeometry(geom, clip_op);
457  } else if (rrect.GetRadii().AreAllCornersSame()) {
458  RoundRectGeometry geom(rrect.GetBounds(), rrect.GetRadii().top_left);
459  GetCanvas().ClipGeometry(geom, clip_op);
460  } else {
461  FillRoundRectGeometry geom(rrect);
462  GetCanvas().ClipGeometry(geom, clip_op);
463  }
464 }
465 
466 // |flutter::DlOpReceiver|
468  flutter::DlClipOp sk_op,
469  bool is_aa) {
470  AUTO_DEPTH_WATCHER(0u);
471 
472  auto clip_op = ToClipOperation(sk_op);
473  if (rse.IsRect()) {
474  FillRectGeometry geom(rse.GetBounds());
475  GetCanvas().ClipGeometry(geom, clip_op, /*is_aa=*/is_aa);
476  } else if (rse.IsOval()) {
477  EllipseGeometry geom(rse.GetBounds());
478  GetCanvas().ClipGeometry(geom, clip_op);
479  } else {
480  RoundSuperellipseGeometry geom(rse.GetBounds(), rse.GetRadii());
481  GetCanvas().ClipGeometry(geom, clip_op);
482  }
483 }
484 
485 // |flutter::DlOpReceiver|
487  flutter::DlClipOp sk_op,
488  bool is_aa) {
489  AUTO_DEPTH_WATCHER(0u);
490 
491  auto clip_op = ToClipOperation(sk_op);
492 
493  DlRect rect;
494  if (path.IsRect(&rect)) {
495  FillRectGeometry geom(rect);
496  GetCanvas().ClipGeometry(geom, clip_op, /*is_aa=*/is_aa);
497  } else if (path.IsOval(&rect)) {
498  EllipseGeometry geom(rect);
499  GetCanvas().ClipGeometry(geom, clip_op);
500  } else {
501  DlRoundRect rrect;
502  if (path.IsRoundRect(&rrect) && rrect.GetRadii().AreAllCornersSame()) {
503  RoundRectGeometry geom(rrect.GetBounds(), rrect.GetRadii().top_left);
504  GetCanvas().ClipGeometry(geom, clip_op);
505  } else {
506  FillPathGeometry geom(path);
507  GetCanvas().ClipGeometry(geom, clip_op);
508  }
509  }
510 }
511 
512 // |flutter::DlOpReceiver|
513 void DlDispatcherBase::drawColor(flutter::DlColor color,
514  flutter::DlBlendMode dl_mode) {
515  AUTO_DEPTH_WATCHER(1u);
516 
517  Paint paint;
518  paint.color = skia_conversions::ToColor(color);
519  paint.blend_mode = dl_mode;
520  GetCanvas().DrawPaint(paint);
521 }
522 
523 // |flutter::DlOpReceiver|
525  AUTO_DEPTH_WATCHER(1u);
526 
528 }
529 
530 // |flutter::DlOpReceiver|
531 void DlDispatcherBase::drawLine(const DlPoint& p0, const DlPoint& p1) {
532  AUTO_DEPTH_WATCHER(1u);
533 
534  GetCanvas().DrawLine(p0, p1, paint_);
535 }
536 
537 // |flutter::DlOpReceiver|
539  const DlPoint& p1,
540  DlScalar on_length,
541  DlScalar off_length) {
542  AUTO_DEPTH_WATCHER(1u);
543 
544  GetCanvas().DrawDashedLine(p0, p1, on_length, off_length, paint_);
545 }
546 
547 // |flutter::DlOpReceiver|
549  AUTO_DEPTH_WATCHER(1u);
550 
551  GetCanvas().DrawRect(rect, paint_);
552 }
553 
554 // |flutter::DlOpReceiver|
555 void DlDispatcherBase::drawOval(const DlRect& bounds) {
556  AUTO_DEPTH_WATCHER(1u);
557 
558  GetCanvas().DrawOval(bounds, paint_);
559 }
560 
561 // |flutter::DlOpReceiver|
562 void DlDispatcherBase::drawCircle(const DlPoint& center, DlScalar radius) {
563  AUTO_DEPTH_WATCHER(1u);
564 
565  GetCanvas().DrawCircle(center, radius, paint_);
566 }
567 
568 // |flutter::DlOpReceiver|
570  AUTO_DEPTH_WATCHER(1u);
571 
572  GetCanvas().DrawRoundRect(rrect, paint_);
573 }
574 
575 // |flutter::DlOpReceiver|
577  const DlRoundRect& inner) {
578  AUTO_DEPTH_WATCHER(1u);
579 
580  GetCanvas().DrawDiffRoundRect(outer, inner, paint_);
581 }
582 
583 // |flutter::DlOpReceiver|
585  AUTO_DEPTH_WATCHER(1u);
586 
588 }
589 
590 // |flutter::DlOpReceiver|
592  AUTO_DEPTH_WATCHER(1u);
593 
594  GetCanvas().DrawPath(path, paint_);
595 }
596 
598  const DlPath& path,
599  const Paint& paint) {
600  DlRect rect;
601 
602  // We can't "optimize" a path into a rectangle if it's open.
603  bool closed;
604  if (path.IsRect(&rect, &closed) && closed) {
605  canvas.DrawRect(rect, paint);
606  return;
607  }
608 
609  DlRoundRect rrect;
610  if (path.IsRoundRect(&rrect) && rrect.GetRadii().AreAllCornersSame()) {
611  canvas.DrawRoundRect(rrect, paint);
612  return;
613  }
614 
615  if (path.IsOval(&rect)) {
616  canvas.DrawOval(rect, paint);
617  return;
618  }
619 
620  DlPoint start;
621  DlPoint end;
622  if (path.IsLine(&start, &end)) {
623  canvas.DrawLine(start, end, paint);
624  return;
625  }
626 
627  canvas.DrawPath(path, paint);
628 }
629 
630 // |flutter::DlOpReceiver|
631 void DlDispatcherBase::drawArc(const DlRect& oval_bounds,
632  DlScalar start_degrees,
633  DlScalar sweep_degrees,
634  bool use_center) {
635  AUTO_DEPTH_WATCHER(1u);
636 
637  GetCanvas().DrawArc(Arc(oval_bounds, Degrees(start_degrees),
638  Degrees(sweep_degrees), use_center),
639  paint_);
640 }
641 
642 // |flutter::DlOpReceiver|
643 void DlDispatcherBase::drawPoints(flutter::DlPointMode mode,
644  uint32_t count,
645  const DlPoint points[]) {
646  AUTO_DEPTH_WATCHER(1u);
647 
648  Paint paint = paint_;
650  switch (mode) {
651  case flutter::DlPointMode::kPoints: {
652  // Cap::kButt is also treated as a square.
653  PointStyle point_style = paint.stroke.cap == Cap::kRound
656  Scalar radius = paint.stroke.width;
657  if (radius > 0) {
658  radius /= 2.0;
659  }
660  GetCanvas().DrawPoints(points, count, radius, paint, point_style);
661  } break;
662  case flutter::DlPointMode::kLines:
663  for (uint32_t i = 1; i < count; i += 2) {
664  Point p0 = points[i - 1];
665  Point p1 = points[i];
666  GetCanvas().DrawLine(p0, p1, paint, /*reuse_depth=*/i > 1);
667  }
668  break;
669  case flutter::DlPointMode::kPolygon:
670  if (count > 1) {
671  Point p0 = points[0];
672  for (uint32_t i = 1; i < count; i++) {
673  Point p1 = points[i];
674  GetCanvas().DrawLine(p0, p1, paint, /*reuse_depth=*/i > 1);
675  p0 = p1;
676  }
677  }
678  break;
679  }
680 }
681 
682 std::shared_ptr<Texture> DlDispatcherBase::GetTexture(
683  const sk_sp<flutter::DlImage>& image) {
684  if (!image) {
685  return nullptr;
686  }
687  return image->asImpellerImage()->GetCachedTexture(GetContentContext());
688 }
689 
691  const std::shared_ptr<flutter::DlVertices>& vertices,
692  flutter::DlBlendMode dl_mode) {}
693 
694 // |flutter::DlOpReceiver|
695 void DlDispatcherBase::drawImage(const sk_sp<flutter::DlImage> image,
696  const DlPoint& point,
697  flutter::DlImageSampling sampling,
698  bool render_with_attributes) {
699  AUTO_DEPTH_WATCHER(1u);
700 
701  if (!image) {
702  return;
703  }
704 
705  auto texture = GetTexture(image);
706  if (!texture) {
707  return;
708  }
709 
710  const auto size = texture->GetSize();
711  const auto src = DlRect::MakeWH(size.width, size.height);
712  const auto dest = DlRect::MakeXYWH(point.x, point.y, size.width, size.height);
713 
714  drawImageRect(image, // image
715  src, // source rect
716  dest, // destination rect
717  sampling, // sampling options
718  render_with_attributes, // render with attributes
719  flutter::DlSrcRectConstraint::kStrict // constraint
720  );
721 }
722 
723 // |flutter::DlOpReceiver|
724 void DlDispatcherBase::drawImageRect(const sk_sp<flutter::DlImage> image,
725  const DlRect& src,
726  const DlRect& dst,
727  flutter::DlImageSampling sampling,
728  bool render_with_attributes,
729  flutter::DlSrcRectConstraint constraint =
730  flutter::DlSrcRectConstraint::kFast) {
731  AUTO_DEPTH_WATCHER(1u);
732 
734  GetTexture(image), // image
735  src, // source rect
736  dst, // destination rect
737  render_with_attributes ? paint_ : Paint(), // paint
738  skia_conversions::ToSamplerDescriptor(sampling) // sampling
739  );
740 }
741 
742 // |flutter::DlOpReceiver|
743 void DlDispatcherBase::drawImageNine(const sk_sp<flutter::DlImage> image,
744  const DlIRect& center,
745  const DlRect& dst,
746  flutter::DlFilterMode filter,
747  bool render_with_attributes) {
748  AUTO_DEPTH_WATCHER(9u);
749 
750  NinePatchConverter converter = {};
751  converter.DrawNinePatch(GetTexture(image),
752  Rect::MakeLTRB(center.GetLeft(), center.GetTop(),
753  center.GetRight(), center.GetBottom()),
754  dst, ToSamplerDescriptor(filter), &GetCanvas(),
755  &paint_);
756 }
757 
758 // |flutter::DlOpReceiver|
759 void DlDispatcherBase::drawAtlas(const sk_sp<flutter::DlImage> atlas,
760  const RSTransform xform[],
761  const DlRect tex[],
762  const flutter::DlColor colors[],
763  int count,
764  flutter::DlBlendMode mode,
765  flutter::DlImageSampling sampling,
766  const DlRect* cull_rect,
767  bool render_with_attributes) {
768  AUTO_DEPTH_WATCHER(1u);
769 
770  auto geometry =
771  DlAtlasGeometry(GetTexture(atlas), //
772  xform, //
773  tex, //
774  colors, //
775  static_cast<size_t>(count), //
776  mode, //
778  ToOptRect(cull_rect) //
779  );
780  auto atlas_contents = std::make_shared<AtlasContents>();
781  atlas_contents->SetGeometry(&geometry);
782 
783  GetCanvas().DrawAtlas(atlas_contents, paint_);
784 }
785 
786 // |flutter::DlOpReceiver|
788  const sk_sp<flutter::DisplayList> display_list,
789  DlScalar opacity) {
790  AUTO_DEPTH_WATCHER(display_list->total_depth());
791 
792  // Save all values that must remain untouched after the operation.
793  Paint saved_paint = paint_;
794  Matrix saved_initial_matrix = initial_matrix_;
795 
796  // Establish a new baseline for interpreting the new DL.
797  // Matrix and clip are left untouched, the current
798  // transform is saved as the new base matrix, and paint
799  // values are reset to defaults.
801  paint_ = Paint();
802 
803  // Handle passed opacity in the most brute-force way by using
804  // a SaveLayer. If the display_list is able to inherit the
805  // opacity, this could also be handled by modulating all of its
806  // attribute settings (for example, color), by the indicated
807  // opacity.
808  int restore_count = GetCanvas().GetSaveCount();
809  if (opacity < SK_Scalar1) {
810  Paint save_paint;
811  save_paint.color = Color(0, 0, 0, opacity);
812  GetCanvas().SaveLayer(save_paint, display_list->GetBounds(), nullptr,
814  display_list->total_depth(),
815  display_list->can_apply_group_opacity());
816  } else {
817  // The display list may alter the clip, which must be restored to the
818  // current clip at the end of playback.
819  GetCanvas().Save(display_list->total_depth());
820  }
821 
822  // TODO(131445): Remove this restriction if we can correctly cull with
823  // perspective transforms.
824  if (display_list->has_rtree() && !initial_matrix_.HasPerspective()) {
825  // The canvas remembers the screen-space culling bounds clipped by
826  // the surface and the history of clip calls. DisplayList can cull
827  // the ops based on a rectangle expressed in its "destination bounds"
828  // so we need the canvas to transform those into the current local
829  // coordinate space into which the DisplayList will be rendered.
830  auto global_culling_bounds = GetCanvas().GetLocalCoverageLimit();
831  if (global_culling_bounds.has_value()) {
832  Rect cull_rect = global_culling_bounds->TransformBounds(
833  GetCanvas().GetCurrentTransform().Invert());
834  display_list->Dispatch(*this, cull_rect);
835  } else {
836  // If the culling bounds are empty, this display list can be skipped
837  // entirely.
838  }
839  } else {
840  display_list->Dispatch(*this);
841  }
842 
843  // Restore all saved state back to what it was before we interpreted
844  // the display_list
846  GetCanvas().RestoreToCount(restore_count);
847  initial_matrix_ = saved_initial_matrix;
848  paint_ = saved_paint;
849 }
850 
851 // |flutter::DlOpReceiver|
852 void DlDispatcherBase::drawText(const std::shared_ptr<flutter::DlText>& text,
853  DlScalar x,
854  DlScalar y) {
855  AUTO_DEPTH_WATCHER(1u);
856 
857  auto text_frame = text->GetTextFrame();
858 
859  // When running with Impeller enabled Skia text blobs are converted to
860  // Impeller text frames in paragraph_skia.cc
861  FML_CHECK(text_frame != nullptr);
862  GetCanvas().DrawTextFrame(text_frame, //
863  impeller::Point{x, y}, //
864  paint_ //
865  );
866 }
867 
868 // |flutter::DlOpReceiver|
870  const flutter::DlColor color,
871  const DlScalar elevation,
872  bool transparent_occluder,
873  DlScalar dpr) {
874  AUTO_DEPTH_WATCHER(1u);
875 
876  Color spot_color = skia_conversions::ToColor(color);
877  spot_color.alpha *= 0.25;
878 
879  // Compute the spot color -- ported from SkShadowUtils::ComputeTonalColors.
880  {
881  Scalar max =
882  std::max(std::max(spot_color.red, spot_color.green), spot_color.blue);
883  Scalar min =
884  std::min(std::min(spot_color.red, spot_color.green), spot_color.blue);
885  Scalar luminance = (min + max) * 0.5;
886 
887  Scalar alpha_adjust =
888  (2.6f + (-2.66667f + 1.06667f * spot_color.alpha) * spot_color.alpha) *
889  spot_color.alpha;
890  Scalar color_alpha =
891  (3.544762f + (-4.891428f + 2.3466f * luminance) * luminance) *
892  luminance;
893  color_alpha = std::clamp(alpha_adjust * color_alpha, 0.0f, 1.0f);
894 
895  Scalar greyscale_alpha =
896  std::clamp(spot_color.alpha * (1 - 0.4f * luminance), 0.0f, 1.0f);
897 
898  Scalar color_scale = color_alpha * (1 - greyscale_alpha);
899  Scalar tonal_alpha = color_scale + greyscale_alpha;
900  Scalar unpremul_scale = tonal_alpha != 0 ? color_scale / tonal_alpha : 0;
901  spot_color = Color(unpremul_scale * spot_color.red,
902  unpremul_scale * spot_color.green,
903  unpremul_scale * spot_color.blue, tonal_alpha);
904  }
905 
906  Vector3 light_position(0, -1, 1);
907  Scalar occluder_z = dpr * elevation;
908 
909  constexpr Scalar kLightRadius = 800 / 600; // Light radius / light height
910 
911  Paint paint;
912  paint.style = Paint::Style::kFill;
913  paint.color = spot_color;
916  .sigma = Radius{kLightRadius * occluder_z /
918  };
919 
920  GetCanvas().Save(1u);
922  Matrix::MakeTranslation(Vector2(0, -occluder_z * light_position.y)));
923 
924  SimplifyOrDrawPath(GetCanvas(), path, paint);
926 
927  GetCanvas().Restore();
928 }
929 
930 /// Subclasses
931 
933  const ContentContext& renderer,
934  flutter::DlBlendMode max_root_blend_mode) {
935  return !renderer.GetDeviceCapabilities().SupportsFramebufferFetch() &&
936  max_root_blend_mode > Entity::kLastPipelineBlendMode;
937 }
938 
940  RenderTarget& render_target,
941  bool is_onscreen,
942  bool has_root_backdrop_filter,
943  flutter::DlBlendMode max_root_blend_mode,
944  IRect32 cull_rect)
945  : DlDispatcherBase(),
946  canvas_(renderer,
947  render_target,
948  is_onscreen,
949  has_root_backdrop_filter ||
950  RequiresReadbackForBlends(renderer, max_root_blend_mode),
951  cull_rect),
952  renderer_(renderer) {}
953 
954 Canvas& CanvasDlDispatcher::GetCanvas() {
955  return canvas_;
956 }
957 
958 const ContentContext& CanvasDlDispatcher::GetContentContext() const {
959  return renderer_;
960 }
961 
963  const std::shared_ptr<flutter::DlVertices>& vertices,
964  flutter::DlBlendMode dl_mode) {
965  AUTO_DEPTH_WATCHER(1u);
966 
967  GetCanvas().DrawVertices(
968  std::make_shared<DlVerticesGeometry>(vertices, renderer_), dl_mode,
969  paint_);
970 }
971 
973  std::unordered_map<int64_t, BackdropData> backdrop,
974  size_t backdrop_count) {
975  GetCanvas().SetBackdropData(std::move(backdrop), backdrop_count);
976 }
977 
978 //// Text Frame Dispatcher
979 
981  const Matrix& initial_matrix,
982  const Rect cull_rect)
983  : renderer_(renderer), matrix_(initial_matrix) {
984  cull_rect_state_.push_back(cull_rect);
985 }
986 
988  FML_DCHECK(cull_rect_state_.size() == 1);
989 }
990 
992  stack_.emplace_back(matrix_);
993  cull_rect_state_.push_back(cull_rect_state_.back());
994 }
995 
997  const flutter::SaveLayerOptions options,
998  const flutter::DlImageFilter* backdrop,
999  std::optional<int64_t> backdrop_id) {
1000  save();
1001 
1002  backdrop_count_ += (backdrop == nullptr ? 0 : 1);
1003  if (backdrop != nullptr && backdrop_id.has_value()) {
1004  std::shared_ptr<flutter::DlImageFilter> shared_backdrop =
1005  backdrop->shared();
1006  std::unordered_map<int64_t, BackdropData>::iterator existing =
1007  backdrop_data_.find(backdrop_id.value());
1008  if (existing == backdrop_data_.end()) {
1009  backdrop_data_[backdrop_id.value()] =
1010  BackdropData{.backdrop_count = 1, .last_backdrop = shared_backdrop};
1011  } else {
1012  BackdropData& data = existing->second;
1013  data.backdrop_count++;
1014  if (data.all_filters_equal) {
1015  data.all_filters_equal = (*data.last_backdrop == *shared_backdrop);
1016  data.last_backdrop = shared_backdrop;
1017  }
1018  }
1019  }
1020 
1021  // This dispatcher does not track enough state to accurately compute
1022  // cull rects with image filters.
1023  auto global_cull_rect = cull_rect_state_.back();
1024  if (has_image_filter_ || global_cull_rect.IsMaximum()) {
1025  cull_rect_state_.back() = Rect::MakeMaximum();
1026  } else {
1027  auto global_save_bounds = bounds.TransformBounds(matrix_);
1028  auto new_cull_rect = global_cull_rect.Intersection(global_save_bounds);
1029  if (new_cull_rect.has_value()) {
1030  cull_rect_state_.back() = new_cull_rect.value();
1031  } else {
1032  cull_rect_state_.back() = Rect::MakeLTRB(0, 0, 0, 0);
1033  }
1034  }
1035 }
1036 
1038  matrix_ = stack_.back();
1039  stack_.pop_back();
1040  cull_rect_state_.pop_back();
1041 }
1042 
1044  matrix_ = matrix_.Translate({tx, ty});
1045 }
1046 
1048  matrix_ = matrix_.Scale({sx, sy, 1.0f});
1049 }
1050 
1052  matrix_ = matrix_ * Matrix::MakeRotationZ(Degrees(degrees));
1053 }
1054 
1056  matrix_ = matrix_ * Matrix::MakeSkew(sx, sy);
1057 }
1058 
1059 // clang-format off
1060 // 2x3 2D affine subset of a 4x4 transform in row major order
1062  DlScalar mxx, DlScalar mxy, DlScalar mxt,
1063  DlScalar myx, DlScalar myy, DlScalar myt) {
1064  matrix_ = matrix_ * Matrix::MakeColumn(
1065  mxx, myx, 0.0f, 0.0f,
1066  mxy, myy, 0.0f, 0.0f,
1067  0.0f, 0.0f, 1.0f, 0.0f,
1068  mxt, myt, 0.0f, 1.0f
1069  );
1070 }
1071 // clang-format on
1072 
1073 // clang-format off
1074 // full 4x4 transform in row major order
1076  DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt,
1077  DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt,
1078  DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt,
1079  DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) {
1080  matrix_ = matrix_ * Matrix::MakeColumn(
1081  mxx, myx, mzx, mwx,
1082  mxy, myy, mzy, mwy,
1083  mxz, myz, mzz, mwz,
1084  mxt, myt, mzt, mwt
1085  );
1086 }
1087 // clang-format on
1088 
1090  matrix_ = Matrix();
1091 }
1092 
1093 void FirstPassDispatcher::drawText(const std::shared_ptr<flutter::DlText>& text,
1094  DlScalar x,
1095  DlScalar y) {
1096  GlyphProperties properties;
1097  auto text_frame = text->GetTextFrame();
1098  if (text_frame == nullptr) {
1099  return;
1100  }
1101 
1102  properties.stroke = paint_.GetStroke();
1103 
1104  if (text_frame->HasColor()) {
1105  // Alpha is always applied when rendering, remove it here so
1106  // we do not double-apply the alpha.
1107  properties.tone_or_color = paint_.color.WithAlpha(1.0);
1108  } else {
1109  properties.tone_or_color = GlyphProperties::ComputeTone(paint_.color);
1110  }
1111 
1112  renderer_.GetLazyGlyphAtlas()->AddTextFrame(text_frame, //
1113  Point(x, y), //
1114  matrix_, //
1115  properties //
1116  );
1117 }
1118 
1119 const Rect FirstPassDispatcher::GetCurrentLocalCullingBounds() const {
1120  auto cull_rect = cull_rect_state_.back();
1121  if (!cull_rect.IsEmpty() && !cull_rect.IsMaximum()) {
1122  Matrix inverse = matrix_.Invert();
1123  cull_rect = cull_rect.TransformBounds(inverse);
1124  }
1125  return cull_rect;
1126 }
1127 
1129  const sk_sp<flutter::DisplayList> display_list,
1130  DlScalar opacity) {
1131  [[maybe_unused]] size_t stack_depth = stack_.size();
1132  save();
1133  Paint old_paint = paint_;
1134  paint_ = Paint{};
1135  bool old_has_image_filter = has_image_filter_;
1136  has_image_filter_ = false;
1137 
1138  if (matrix_.HasPerspective()) {
1139  display_list->Dispatch(*this);
1140  } else {
1141  Rect local_cull_bounds = GetCurrentLocalCullingBounds();
1142  if (local_cull_bounds.IsMaximum()) {
1143  display_list->Dispatch(*this);
1144  } else if (!local_cull_bounds.IsEmpty()) {
1145  DlIRect cull_rect = DlIRect::RoundOut(local_cull_bounds);
1146  display_list->Dispatch(*this, cull_rect);
1147  }
1148  }
1149 
1150  restore();
1151  paint_ = old_paint;
1152  has_image_filter_ = old_has_image_filter;
1153  FML_DCHECK(stack_depth == stack_.size());
1154 }
1155 
1156 // |flutter::DlOpReceiver|
1157 void FirstPassDispatcher::setDrawStyle(flutter::DlDrawStyle style) {
1158  paint_.style = ToStyle(style);
1159 }
1160 
1161 // |flutter::DlOpReceiver|
1162 void FirstPassDispatcher::setColor(flutter::DlColor color) {
1163  paint_.color = skia_conversions::ToColor(color);
1164 }
1165 
1166 // |flutter::DlOpReceiver|
1168  paint_.stroke.width = width;
1169 }
1170 
1171 // |flutter::DlOpReceiver|
1173  paint_.stroke.miter_limit = limit;
1174 }
1175 
1176 // |flutter::DlOpReceiver|
1177 void FirstPassDispatcher::setStrokeCap(flutter::DlStrokeCap cap) {
1178  switch (cap) {
1179  case flutter::DlStrokeCap::kButt:
1180  paint_.stroke.cap = Cap::kButt;
1181  break;
1182  case flutter::DlStrokeCap::kRound:
1183  paint_.stroke.cap = Cap::kRound;
1184  break;
1185  case flutter::DlStrokeCap::kSquare:
1186  paint_.stroke.cap = Cap::kSquare;
1187  break;
1188  }
1189 }
1190 
1191 // |flutter::DlOpReceiver|
1192 void FirstPassDispatcher::setStrokeJoin(flutter::DlStrokeJoin join) {
1193  switch (join) {
1194  case flutter::DlStrokeJoin::kMiter:
1195  paint_.stroke.join = Join::kMiter;
1196  break;
1197  case flutter::DlStrokeJoin::kRound:
1198  paint_.stroke.join = Join::kRound;
1199  break;
1200  case flutter::DlStrokeJoin::kBevel:
1201  paint_.stroke.join = Join::kBevel;
1202  break;
1203  }
1204 }
1205 
1206 // |flutter::DlOpReceiver|
1207 void FirstPassDispatcher::setImageFilter(const flutter::DlImageFilter* filter) {
1208  if (filter == nullptr) {
1209  has_image_filter_ = false;
1210  } else {
1211  has_image_filter_ = true;
1212  }
1213 }
1214 
1215 namespace {
1216 bool PixelFormatSupportsMSAA(std::optional<PixelFormat> pixel_format) {
1217  return !pixel_format.has_value();
1218 }
1219 } // namespace
1220 
1221 std::pair<std::unordered_map<int64_t, BackdropData>, size_t>
1223  std::unordered_map<int64_t, BackdropData> temp;
1224  std::swap(temp, backdrop_data_);
1225  return std::make_pair(temp, backdrop_count_);
1226 }
1227 
1228 std::shared_ptr<Texture> DisplayListToTexture(
1229  const sk_sp<flutter::DisplayList>& display_list,
1230  ISize size,
1232  bool reset_host_buffer,
1233  bool generate_mips,
1234  std::optional<PixelFormat> target_pixel_format) {
1235  int mip_count = 1;
1236  if (generate_mips) {
1237  mip_count = size.MipCount();
1238  }
1239  // Do not use the render target cache as the lifecycle of this texture
1240  // will outlive a particular frame.
1241  impeller::RenderTargetAllocator render_target_allocator =
1243  context.GetContext()->GetResourceAllocator());
1244  impeller::RenderTarget target;
1245  if (context.GetContext()->GetCapabilities()->SupportsOffscreenMSAA() &&
1246  PixelFormatSupportsMSAA(target_pixel_format)) {
1247  target = render_target_allocator.CreateOffscreenMSAA(
1248  *context.GetContext(), // context
1249  size, // size
1250  /*mip_count=*/mip_count,
1251  "Picture Snapshot MSAA", // label
1253  kDefaultColorAttachmentConfigMSAA, // color_attachment_config
1254  std::nullopt, // stencil_attachment_config
1255  nullptr, // existing_color_msaa_texture
1256  nullptr, // existing_color_resolve_texture
1257  nullptr, // existing_depth_stencil_texture
1258  target_pixel_format // target_format
1259  );
1260  } else {
1261  target = render_target_allocator.CreateOffscreen(
1262  *context.GetContext(), // context
1263  size, // size
1264  /*mip_count=*/mip_count,
1265  "Picture Snapshot", // label
1267  kDefaultColorAttachmentConfig, // color_attachment_config
1268  std::nullopt, // stencil_attachment_config
1269  nullptr, // existing_color_texture
1270  nullptr, // existing_depth_stencil_texture
1271  target_pixel_format // target_format
1272  );
1273  }
1274  if (!target.IsValid()) {
1275  return nullptr;
1276  }
1277 
1278  DlIRect cull_rect = DlIRect::MakeWH(size.width, size.height);
1280  context.GetContentContext(), impeller::Matrix(), Rect::MakeSize(size));
1281  display_list->Dispatch(collector, cull_rect);
1282  impeller::CanvasDlDispatcher impeller_dispatcher(
1283  context.GetContentContext(), //
1284  target, //
1285  /*is_onscreen=*/false, //
1286  display_list->root_has_backdrop_filter(), //
1287  display_list->max_root_blend_mode(), //
1289  );
1290  const auto& [data, count] = collector.TakeBackdropData();
1291  impeller_dispatcher.SetBackdropData(data, count);
1292  context.GetContentContext().GetTextShadowCache().MarkFrameStart();
1293  fml::ScopedCleanupClosure cleanup([&] {
1294  if (reset_host_buffer) {
1295  context.GetContentContext().GetTransientsDataBuffer().Reset();
1296  context.GetContentContext().GetTransientsIndexesBuffer().Reset();
1297  }
1298  context.GetContentContext().GetTextShadowCache().MarkFrameEnd();
1299  context.GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames();
1300  context.GetContext()->DisposeThreadLocalCachedResources();
1301  });
1302 
1303  display_list->Dispatch(impeller_dispatcher, cull_rect);
1304  impeller_dispatcher.FinishRecording();
1305 
1306  return target.GetRenderTargetTexture();
1307 }
1308 
1310  RenderTarget render_target,
1311  const sk_sp<flutter::DisplayList>& display_list,
1312  Rect cull_rect,
1313  bool reset_host_buffer,
1314  bool is_onscreen) {
1315  FirstPassDispatcher collector(context, impeller::Matrix(), cull_rect);
1316  display_list->Dispatch(collector, cull_rect);
1317 
1318  impeller::CanvasDlDispatcher impeller_dispatcher(
1319  context, //
1320  render_target, //
1321  /*is_onscreen=*/is_onscreen, //
1322  display_list->root_has_backdrop_filter(), //
1323  display_list->max_root_blend_mode(), //
1324  IRect32::RoundOut(cull_rect) //
1325  );
1326  const auto& [data, count] = collector.TakeBackdropData();
1327  impeller_dispatcher.SetBackdropData(data, count);
1328  context.GetTextShadowCache().MarkFrameStart();
1329  fml::ScopedCleanupClosure cleanup([&] {
1330  if (reset_host_buffer) {
1331  context.ResetTransientsBuffers();
1332  }
1333  context.GetTextShadowCache().MarkFrameEnd();
1334  });
1335 
1336  display_list->Dispatch(impeller_dispatcher, cull_rect);
1337  impeller_dispatcher.FinishRecording();
1338  context.GetLazyGlyphAtlas()->ResetTextFrames();
1339 
1340  return true;
1341 }
1342 
1343 } // namespace impeller
CanvasDlDispatcher(ContentContext &renderer, RenderTarget &render_target, bool is_onscreen, bool has_root_backdrop_filter, flutter::DlBlendMode max_root_blend_mode, IRect32 cull_rect)
void drawVertices(const std::shared_ptr< flutter::DlVertices > &vertices, flutter::DlBlendMode dl_mode) override
void SetBackdropData(std::unordered_map< int64_t, BackdropData > backdrop, size_t backdrop_count)
void ClipGeometry(const Geometry &geometry, Entity::ClipOperation clip_op, bool is_aa=true)
Definition: canvas.cc:1292
void SetBackdropData(std::unordered_map< int64_t, BackdropData > backdrop_data, size_t backdrop_count)
Update the backdrop data used to group together backdrop filters within the same layer.
Definition: canvas.cc:2408
void DrawRoundSuperellipse(const RoundSuperellipse &rse, const Paint &paint)
Definition: canvas.cc:1186
std::optional< Rect > GetLocalCoverageLimit() const
Return the culling bounds of the current render target, or nullopt if there is no coverage.
Definition: canvas.cc:1673
void SaveLayer(const Paint &paint, std::optional< Rect > bounds=std::nullopt, const flutter::DlImageFilter *backdrop_filter=nullptr, ContentBoundsPromise bounds_promise=ContentBoundsPromise::kUnknown, uint32_t total_content_depth=kMaxDepth, bool can_distribute_opacity=false, std::optional< int64_t > backdrop_id=std::nullopt)
Definition: canvas.cc:1710
const Matrix & GetCurrentTransform() const
Definition: canvas.cc:404
void DrawVertices(const std::shared_ptr< VerticesGeometry > &vertices, BlendMode blend_mode, const Paint &paint)
Definition: canvas.cc:1473
void DrawOval(const Rect &rect, const Paint &paint)
Definition: canvas.cc:994
void DrawImageRect(const std::shared_ptr< Texture > &image, Rect source, Rect dest, const Paint &paint, const SamplerDescriptor &sampler={}, SourceRectConstraint src_rect_constraint=SourceRectConstraint::kFast)
Definition: canvas.cc:1406
void RestoreToCount(size_t count)
Definition: canvas.cc:451
bool Restore()
Definition: canvas.cc:1940
size_t GetSaveCount() const
Definition: canvas.cc:443
void Transform(const Matrix &transform)
Definition: canvas.cc:400
uint64_t GetMaxOpDepth() const
Definition: canvas.h:257
void DrawDashedLine(const Point &p0, const Point &p1, Scalar on_length, Scalar off_length, const Paint &paint)
Definition: canvas.cc:915
void DrawDiffRoundRect(const RoundRect &outer, const RoundRect &inner, const Paint &paint)
Definition: canvas.cc:1170
void DrawPath(const flutter::DlPath &path, const Paint &paint)
Definition: canvas.cc:459
void PreConcat(const Matrix &transform)
Definition: canvas.cc:392
void Rotate(Radians radians)
Definition: canvas.cc:424
void DrawPoints(const Point points[], uint32_t count, Scalar radius, const Paint &paint, PointStyle point_style)
Definition: canvas.cc:1374
void ResetTransform()
Definition: canvas.cc:396
void DrawTextFrame(const std::shared_ptr< TextFrame > &text_frame, Point position, const Paint &paint)
Definition: canvas.cc:2132
void DrawPaint(const Paint &paint)
Definition: canvas.cc:479
void DrawRoundRect(const RoundRect &rect, const Paint &paint)
Definition: canvas.cc:1101
void Skew(Scalar sx, Scalar sy)
Definition: canvas.cc:420
void Scale(const Vector2 &scale)
Definition: canvas.cc:412
uint64_t GetOpDepth() const
Definition: canvas.h:255
void Save(uint32_t total_content_depth=kMaxDepth)
Definition: canvas.cc:1656
void DrawRect(const Rect &rect, const Paint &paint)
Definition: canvas.cc:941
void DrawAtlas(const std::shared_ptr< AtlasContents > &atlas_contents, const Paint &paint)
Definition: canvas.cc:1588
void DrawLine(const Point &p0, const Point &p1, const Paint &paint, bool reuse_depth=false)
Definition: canvas.cc:897
void Translate(const Vector3 &offset)
Definition: canvas.cc:408
void DrawCircle(const Point &center, Scalar radius, const Paint &paint)
Definition: canvas.cc:1255
void DrawArc(const Arc &arc, const Paint &paint)
Definition: canvas.cc:1049
virtual bool SupportsFramebufferFetch() const =0
Whether the context backend is able to support pipelines with shaders that read from the framebuffer ...
const std::shared_ptr< LazyGlyphAtlas > & GetLazyGlyphAtlas() const
const Capabilities & GetDeviceCapabilities() const
A wrapper around data provided by a drawAtlas call.
void drawLine(const DlPoint &p0, const DlPoint &p1) override
void drawText(const std::shared_ptr< flutter::DlText > &text, DlScalar x, DlScalar y) override
void drawAtlas(const sk_sp< flutter::DlImage > atlas, const RSTransform xform[], const DlRect tex[], const flutter::DlColor colors[], int count, flutter::DlBlendMode mode, flutter::DlImageSampling sampling, const DlRect *cull_rect, bool render_with_attributes) override
void drawPoints(flutter::DlPointMode mode, uint32_t count, const DlPoint points[]) override
virtual Canvas & GetCanvas()=0
void drawDashedLine(const DlPoint &p0, const DlPoint &p1, DlScalar on_length, DlScalar off_length) override
void drawOval(const DlRect &bounds) override
void setImageFilter(const flutter::DlImageFilter *filter) override
void drawPath(const DlPath &path) override
void setStrokeCap(flutter::DlStrokeCap cap) override
void clipOval(const DlRect &bounds, flutter::DlClipOp clip_op, bool is_aa) override
std::shared_ptr< Texture > GetTexture(const sk_sp< flutter::DlImage > &image)
void drawRoundSuperellipse(const DlRoundSuperellipse &rse) override
void clipRoundRect(const DlRoundRect &rrect, flutter::DlClipOp clip_op, bool is_aa) override
void skew(DlScalar sx, DlScalar sy) override
void clipRect(const DlRect &rect, flutter::DlClipOp clip_op, bool is_aa) override
void setAntiAlias(bool aa) override
void transformFullPerspective(DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt, DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt, DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) override
void setStrokeWidth(DlScalar width) override
void drawDiffRoundRect(const DlRoundRect &outer, const DlRoundRect &inner) override
void drawRoundRect(const DlRoundRect &rrect) override
void setStrokeJoin(flutter::DlStrokeJoin join) override
void rotate(DlScalar degrees) override
void setColorFilter(const flutter::DlColorFilter *filter) override
void scale(DlScalar sx, DlScalar sy) override
void setDrawStyle(flutter::DlDrawStyle style) override
void drawShadow(const DlPath &path, const flutter::DlColor color, const DlScalar elevation, bool transparent_occluder, DlScalar dpr) override
void drawImage(const sk_sp< flutter::DlImage > image, const DlPoint &point, flutter::DlImageSampling sampling, bool render_with_attributes) override
void clipPath(const DlPath &path, flutter::DlClipOp clip_op, bool is_aa) override
void drawImageRect(const sk_sp< flutter::DlImage > image, const DlRect &src, const DlRect &dst, flutter::DlImageSampling sampling, bool render_with_attributes, flutter::DlSrcRectConstraint constraint) override
void clipRoundSuperellipse(const DlRoundSuperellipse &rse, flutter::DlClipOp clip_op, bool is_aa) override
void drawArc(const DlRect &oval_bounds, DlScalar start_degrees, DlScalar sweep_degrees, bool use_center) override
void saveLayer(const DlRect &bounds, const flutter::SaveLayerOptions &options, uint32_t total_content_depth, flutter::DlBlendMode max_content_mode, const flutter::DlImageFilter *backdrop, std::optional< int64_t > backdrop_id) override
void drawDisplayList(const sk_sp< flutter::DisplayList > display_list, DlScalar opacity) override
void transform2DAffine(DlScalar mxx, DlScalar mxy, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myt) override
void setInvertColors(bool invert) override
virtual const ContentContext & GetContentContext() const =0
void setColor(flutter::DlColor color) override
void save(uint32_t total_content_depth) override
void setStrokeMiter(DlScalar limit) override
void translate(DlScalar tx, DlScalar ty) override
void drawVertices(const std::shared_ptr< flutter::DlVertices > &vertices, flutter::DlBlendMode dl_mode) override
void drawCircle(const DlPoint &center, DlScalar radius) override
void setMaskFilter(const flutter::DlMaskFilter *filter) override
void setColorSource(const flutter::DlColorSource *source) override
void drawImageNine(const sk_sp< flutter::DlImage > image, const DlIRect &center, const DlRect &dst, flutter::DlFilterMode filter, bool render_with_attributes) override
void transformReset() override
void setBlendMode(flutter::DlBlendMode mode) override
void drawColor(flutter::DlColor color, flutter::DlBlendMode mode) override
void drawRect(const DlRect &rect) override
static void SimplifyOrDrawPath(Canvas &canvas, const DlPath &cache, const Paint &paint)
A Geometry class that can directly generate vertices (with or without texture coordinates) for filled...
static constexpr BlendMode kLastPipelineBlendMode
Definition: entity.h:28
A Geometry that produces fillable vertices from a |DlPath| object using the |FillPathSourceGeometry| ...
A Geometry class that produces fillable vertices from any |RoundRect| object regardless of radii unif...
@ kNormal
Blurred inside and outside.
@ kOuter
Nothing inside, blurred outside.
@ kInner
Blurred inside, nothing outside.
@ kSolid
Solid inside, blurred outside.
void setColor(flutter::DlColor color) override
void setStrokeCap(flutter::DlStrokeCap cap) override
void saveLayer(const DlRect &bounds, const flutter::SaveLayerOptions options, const flutter::DlImageFilter *backdrop, std::optional< int64_t > backdrop_id) override
void setDrawStyle(flutter::DlDrawStyle style) override
std::pair< std::unordered_map< int64_t, BackdropData >, size_t > TakeBackdropData()
void rotate(DlScalar degrees) override
void setImageFilter(const flutter::DlImageFilter *filter) override
void setStrokeMiter(DlScalar limit) override
void transformFullPerspective(DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt, DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt, DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) override
void drawText(const std::shared_ptr< flutter::DlText > &text, DlScalar x, DlScalar y) override
void scale(DlScalar sx, DlScalar sy) override
void translate(DlScalar tx, DlScalar ty) override
void skew(DlScalar sx, DlScalar sy) override
FirstPassDispatcher(const ContentContext &renderer, const Matrix &initial_matrix, const Rect cull_rect)
void drawDisplayList(const sk_sp< flutter::DisplayList > display_list, DlScalar opacity) override
void setStrokeWidth(DlScalar width) override
void setStrokeJoin(flutter::DlStrokeJoin join) override
void transform2DAffine(DlScalar mxx, DlScalar mxy, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myt) override
void DrawNinePatch(const std::shared_ptr< Texture > &image, Rect center, Rect dst, const SamplerDescriptor &sampler, Canvas *canvas, Paint *paint)
a wrapper around the impeller [Allocator] instance that can be used to provide caching of allocated r...
virtual RenderTarget CreateOffscreenMSAA(const Context &context, ISize size, int mip_count, std::string_view label="Offscreen MSAA", RenderTarget::AttachmentConfigMSAA color_attachment_config=RenderTarget::kDefaultColorAttachmentConfigMSAA, std::optional< RenderTarget::AttachmentConfig > stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &existing_color_msaa_texture=nullptr, const std::shared_ptr< Texture > &existing_color_resolve_texture=nullptr, const std::shared_ptr< Texture > &existing_depth_stencil_texture=nullptr, std::optional< PixelFormat > target_pixel_format=std::nullopt)
virtual RenderTarget CreateOffscreen(const Context &context, ISize size, int mip_count, std::string_view label="Offscreen", RenderTarget::AttachmentConfig color_attachment_config=RenderTarget::kDefaultColorAttachmentConfig, std::optional< RenderTarget::AttachmentConfig > stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &existing_color_texture=nullptr, const std::shared_ptr< Texture > &existing_depth_stencil_texture=nullptr, std::optional< PixelFormat > target_pixel_format=std::nullopt)
std::shared_ptr< Texture > GetRenderTargetTexture() const
A Geometry class that generates fillable vertices (with or without texture coordinates) directly from...
A Geometry class that generates fillable vertices (with or without texture coordinates) directly from...
#define AUTO_DEPTH_WATCHER(d)
#define UNIMPLEMENTED
#define AUTO_DEPTH_CHECK()
int32_t x
impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlImageSampling options)
Color ToColor(const flutter::DlColor &color)
Point Vector2
Definition: point.h:430
flutter::DlRect DlRect
Definition: dl_dispatcher.h:30
float Scalar
Definition: scalar.h:19
flutter::DlIRect DlIRect
Definition: dl_dispatcher.h:31
static Paint::Style ToStyle(flutter::DlDrawStyle style)
std::shared_ptr< Texture > DisplayListToTexture(const sk_sp< flutter::DisplayList > &display_list, ISize size, AiksContext &context, bool reset_host_buffer, bool generate_mips, std::optional< PixelFormat > target_pixel_format)
Render the provided display list to a texture with the given size.
flutter::DlRoundRect DlRoundRect
Definition: dl_dispatcher.h:32
static std::optional< const Rect > ToOptRect(const flutter::DlRect *rect)
PointStyle
Definition: canvas.h:66
@ kRound
Points are drawn as squares.
@ kSquare
Points are drawn as circles.
TPoint< Scalar > Point
Definition: point.h:426
static Entity::ClipOperation ToClipOperation(flutter::DlClipOp clip_op)
flutter::DlPoint DlPoint
Definition: dl_dispatcher.h:29
flutter::DlRoundSuperellipse DlRoundSuperellipse
Definition: dl_dispatcher.h:33
static bool RequiresReadbackForBlends(const ContentContext &renderer, flutter::DlBlendMode max_root_blend_mode)
Subclasses.
static impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlFilterMode options)
flutter::DlPath DlPath
Definition: dl_dispatcher.h:34
@ kMayClipContents
The caller claims the bounds are a subset of an estimate of the reasonably tight bounds but likely cl...
@ kContainsContents
The caller claims the bounds are a reasonably tight estimate of the coverage of the contents and shou...
bool RenderToTarget(ContentContext &context, RenderTarget render_target, const sk_sp< flutter::DisplayList > &display_list, Rect cull_rect, bool reset_host_buffer, bool is_onscreen)
Render the provided display list to the render target.
@ kNearest
Select nearest to the sample point. Most widely supported.
flutter::DlScalar DlScalar
Definition: dl_dispatcher.h:28
static FilterContents::BlurStyle ToBlurStyle(flutter::DlBlurStyle blur_style)
std::shared_ptr< ContextGLES > context
std::shared_ptr< flutter::DlImageFilter > last_backdrop
Definition: canvas.h:48
size_t backdrop_count
Definition: canvas.h:42
Scalar blue
Definition: color.h:138
Scalar alpha
Definition: color.h:143
constexpr Color WithAlpha(Scalar new_alpha) const
Definition: color.h:283
Scalar red
Definition: color.h:128
Scalar green
Definition: color.h:133
static Tone ComputeTone(const Color &c)
std::optional< StrokeParameters > stroke
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
constexpr Matrix Translate(const Vector3 &t) const
Definition: matrix.h:263
Matrix Invert() const
Definition: matrix.cc:99
static constexpr Matrix MakeColumn(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition: matrix.h:69
Vector3 GetScale() const
Definition: matrix.h:394
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
Definition: matrix.h:127
constexpr Matrix Scale(const Vector3 &s) const
Definition: matrix.h:275
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:223
constexpr bool HasPerspective() const
Definition: matrix.h:426
FilterContents::BlurStyle style
Definition: paint.h:55
std::optional< StrokeParameters > GetStroke() const
Return an optional StrokeParameters if this Paint is a stroked Paint, otherwise return a nullopt.
Definition: paint.h:95
const flutter::DlColorFilter * color_filter
Definition: paint.h:81
const flutter::DlColorSource * color_source
Definition: paint.h:80
bool anti_alias
Definition: paint.h:88
const flutter::DlImageFilter * image_filter
Definition: paint.h:82
Style style
Definition: paint.h:85
bool invert_colors
Definition: paint.h:87
std::optional< MaskBlurDescriptor > mask_blur_descriptor
Definition: paint.h:90
Color color
Definition: paint.h:79
BlendMode blend_mode
Definition: paint.h:86
StrokeParameters stroke
Definition: paint.h:84
For convolution filters, the "radius" is the size of the convolution kernel to use on the local space...
Definition: sigma.h:48
In filters that use Gaussian distributions, "sigma" is a size of one standard deviation in terms of t...
Definition: sigma.h:32
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition: rect.h:506
constexpr bool IsMaximum() const
Definition: rect.h:348
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: rect.h:331
RoundOut(const TRect< U > &r)
Definition: rect.h:748
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
constexpr static TRect MakeMaximum()
Definition: rect.h:212
Type height
Definition: size.h:29
Type width
Definition: size.h:28
constexpr size_t MipCount() const
Return the mip count of the texture.
Definition: size.h:137
const size_t start
const size_t end
std::vector< Point > points