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"
28 #include "impeller/entity/entity.h"
35 #include "impeller/geometry/path.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  // Nothing to do because AA is implicit.
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;
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 // |flutter::DlOpReceiver|
372  DlScalar mxy,
373  DlScalar mxt,
374  DlScalar myx,
375  DlScalar myy,
376  DlScalar myt) {
377  AUTO_DEPTH_WATCHER(0u);
378 
379  // clang-format off
381  mxx, mxy, 0, mxt,
382  myx, myy, 0, myt,
383  0 , 0, 1, 0,
384  0 , 0, 0, 1
385  );
386  // clang-format on
387 }
388 
389 // |flutter::DlOpReceiver|
391  DlScalar mxy,
392  DlScalar mxz,
393  DlScalar mxt,
394  DlScalar myx,
395  DlScalar myy,
396  DlScalar myz,
397  DlScalar myt,
398  DlScalar mzx,
399  DlScalar mzy,
400  DlScalar mzz,
401  DlScalar mzt,
402  DlScalar mwx,
403  DlScalar mwy,
404  DlScalar mwz,
405  DlScalar mwt) {
406  AUTO_DEPTH_WATCHER(0u);
407 
408  // The order of arguments is row-major but Impeller matrices are
409  // column-major.
410  // clang-format off
411  auto transform = Matrix{
412  mxx, myx, mzx, mwx,
413  mxy, myy, mzy, mwy,
414  mxz, myz, mzz, mwz,
415  mxt, myt, mzt, mwt
416  };
417  // clang-format on
419 }
420 
421 // |flutter::DlOpReceiver|
423  AUTO_DEPTH_WATCHER(0u);
424 
427 }
428 
429 static Entity::ClipOperation ToClipOperation(flutter::DlClipOp clip_op) {
430  switch (clip_op) {
431  case flutter::DlClipOp::kDifference:
433  case flutter::DlClipOp::kIntersect:
435  }
436 }
437 
438 // |flutter::DlOpReceiver|
440  flutter::DlClipOp clip_op,
441  bool is_aa) {
442  AUTO_DEPTH_WATCHER(0u);
443 
444  RectGeometry geom(rect);
445  GetCanvas().ClipGeometry(geom, ToClipOperation(clip_op), /*is_aa=*/is_aa);
446 }
447 
448 // |flutter::DlOpReceiver|
450  flutter::DlClipOp clip_op,
451  bool is_aa) {
452  AUTO_DEPTH_WATCHER(0u);
453 
454  EllipseGeometry geom(bounds);
455  GetCanvas().ClipGeometry(geom, ToClipOperation(clip_op));
456 }
457 
458 // |flutter::DlOpReceiver|
460  flutter::DlClipOp sk_op,
461  bool is_aa) {
462  AUTO_DEPTH_WATCHER(0u);
463 
464  auto clip_op = ToClipOperation(sk_op);
465  if (rrect.IsRect()) {
466  RectGeometry geom(rrect.GetBounds());
467  GetCanvas().ClipGeometry(geom, clip_op, /*is_aa=*/is_aa);
468  } else if (rrect.IsOval()) {
469  EllipseGeometry geom(rrect.GetBounds());
470  GetCanvas().ClipGeometry(geom, clip_op);
471  } else if (rrect.GetRadii().AreAllCornersSame()) {
472  RoundRectGeometry geom(rrect.GetBounds(), rrect.GetRadii().top_left);
473  GetCanvas().ClipGeometry(geom, clip_op);
474  } else {
475  FillPathGeometry geom(PathBuilder{}.AddRoundRect(rrect).TakePath());
476  GetCanvas().ClipGeometry(geom, clip_op);
477  }
478 }
479 
480 // |flutter::DlOpReceiver|
482  flutter::DlClipOp sk_op,
483  bool is_aa) {
484  AUTO_DEPTH_WATCHER(0u);
485 
486  auto clip_op = ToClipOperation(sk_op);
487  if (rse.IsRect()) {
488  RectGeometry geom(rse.GetBounds());
489  GetCanvas().ClipGeometry(geom, clip_op, /*is_aa=*/is_aa);
490  } else if (rse.IsOval()) {
491  EllipseGeometry geom(rse.GetBounds());
492  GetCanvas().ClipGeometry(geom, clip_op);
493  } else {
494  RoundSuperellipseGeometry geom(rse.GetBounds(), rse.GetRadii());
495  GetCanvas().ClipGeometry(geom, clip_op);
496  }
497 }
498 
499 // |flutter::DlOpReceiver|
501  flutter::DlClipOp sk_op,
502  bool is_aa) {
503  AUTO_DEPTH_WATCHER(0u);
504 
505  auto clip_op = ToClipOperation(sk_op);
506 
507  DlRect rect;
508  if (path.IsRect(&rect)) {
509  RectGeometry geom(rect);
510  GetCanvas().ClipGeometry(geom, clip_op, /*is_aa=*/is_aa);
511  } else if (path.IsOval(&rect)) {
512  EllipseGeometry geom(rect);
513  GetCanvas().ClipGeometry(geom, clip_op);
514  } else {
515  SkRRect rrect;
516  if (path.IsSkRRect(&rrect) && rrect.isSimple()) {
517  RoundRectGeometry geom(flutter::ToDlRect(rrect.rect()),
518  flutter::ToDlSize(rrect.getSimpleRadii()));
519  GetCanvas().ClipGeometry(geom, clip_op);
520  } else {
521  FillPathGeometry geom(path.GetPath());
522  GetCanvas().ClipGeometry(geom, clip_op);
523  }
524  }
525 }
526 
527 // |flutter::DlOpReceiver|
528 void DlDispatcherBase::drawColor(flutter::DlColor color,
529  flutter::DlBlendMode dl_mode) {
530  AUTO_DEPTH_WATCHER(1u);
531 
532  Paint paint;
533  paint.color = skia_conversions::ToColor(color);
534  paint.blend_mode = dl_mode;
535  GetCanvas().DrawPaint(paint);
536 }
537 
538 // |flutter::DlOpReceiver|
540  AUTO_DEPTH_WATCHER(1u);
541 
543 }
544 
545 // |flutter::DlOpReceiver|
546 void DlDispatcherBase::drawLine(const DlPoint& p0, const DlPoint& p1) {
547  AUTO_DEPTH_WATCHER(1u);
548 
549  GetCanvas().DrawLine(p0, p1, paint_);
550 }
551 
553  const DlPoint& p1,
554  DlScalar on_length,
555  DlScalar off_length) {
556  AUTO_DEPTH_WATCHER(1u);
557 
558  Scalar length = p0.GetDistance(p1);
559  // Reasons to defer to regular DrawLine:
560  // length is non-positive - drawLine will draw appropriate "dot"
561  // off_length is non-positive - no gaps, drawLine will draw it solid
562  // on_length is negative - invalid dashing
563  // Note that a 0 length "on" dash will draw "dot"s every "off" distance
564  // apart
565  if (length > 0.0f && on_length >= 0.0f && off_length > 0.0f) {
566  Point delta = (p1 - p0) / length; // length > 0 already tested
567  PathBuilder builder;
568 
569  Scalar consumed = 0.0f;
570  while (consumed < length) {
571  builder.MoveTo(p0 + delta * consumed);
572 
573  Scalar dash_end = consumed + on_length;
574  if (dash_end < length) {
575  builder.LineTo(p0 + delta * dash_end);
576  } else {
577  builder.LineTo(p1);
578  // Should happen anyway due to the math, but let's make it explicit
579  // in case of bit errors. We're done with this line.
580  break;
581  }
582 
583  consumed = dash_end + off_length;
584  }
585 
586  Paint stroke_paint = paint_;
587  stroke_paint.style = Paint::Style::kStroke;
588  GetCanvas().DrawPath(builder.TakePath(), stroke_paint);
589  } else {
590  drawLine(p0, p1);
591  }
592 }
593 
594 // |flutter::DlOpReceiver|
596  AUTO_DEPTH_WATCHER(1u);
597 
598  GetCanvas().DrawRect(rect, paint_);
599 }
600 
601 // |flutter::DlOpReceiver|
602 void DlDispatcherBase::drawOval(const DlRect& bounds) {
603  AUTO_DEPTH_WATCHER(1u);
604 
605  GetCanvas().DrawOval(bounds, paint_);
606 }
607 
608 // |flutter::DlOpReceiver|
609 void DlDispatcherBase::drawCircle(const DlPoint& center, DlScalar radius) {
610  AUTO_DEPTH_WATCHER(1u);
611 
612  GetCanvas().DrawCircle(center, radius, paint_);
613 }
614 
615 // |flutter::DlOpReceiver|
617  AUTO_DEPTH_WATCHER(1u);
618 
619  GetCanvas().DrawRoundRect(rrect, paint_);
620 }
621 
622 // |flutter::DlOpReceiver|
624  const DlRoundRect& inner) {
625  AUTO_DEPTH_WATCHER(1u);
626 
627  PathBuilder builder;
628  builder.AddRoundRect(outer);
629  builder.AddRoundRect(inner);
630  builder.SetBounds(outer.GetBounds().Union(inner.GetBounds()));
632 }
633 
634 // |flutter::DlOpReceiver|
636  AUTO_DEPTH_WATCHER(1u);
637 
639 }
640 
641 // |flutter::DlOpReceiver|
643  AUTO_DEPTH_WATCHER(1u);
644 
646 }
647 
649  const DlPath& path,
650  const Paint& paint) {
651  DlRect rect;
652 
653  // We can't "optimize" a path into a rectangle if it's open.
654  bool closed;
655  if (path.IsRect(&rect, &closed) && closed) {
656  canvas.DrawRect(rect, paint);
657  return;
658  }
659 
660  SkRRect rrect;
661  if (path.IsSkRRect(&rrect) && rrect.isSimple()) {
662  canvas.DrawRoundRect(flutter::ToDlRoundRect(rrect), paint);
663  return;
664  }
665 
666  if (path.IsOval(&rect)) {
667  canvas.DrawOval(rect, paint);
668  return;
669  }
670 
671  DlPoint start;
672  DlPoint end;
673  if (path.IsLine(&start, &end)) {
674  canvas.DrawLine(start, end, paint);
675  return;
676  }
677 
678  canvas.DrawPath(path.GetPath(), paint);
679 }
680 
681 // |flutter::DlOpReceiver|
682 void DlDispatcherBase::drawArc(const DlRect& oval_bounds,
683  DlScalar start_degrees,
684  DlScalar sweep_degrees,
685  bool use_center) {
686  AUTO_DEPTH_WATCHER(1u);
687 
688  if (paint_.stroke_width >
689  std::max(oval_bounds.GetWidth(), oval_bounds.GetHeight())) {
690  // This is a special case for rendering arcs whose stroke width is so large
691  // you are effectively drawing a sector of a circle.
692  // https://github.com/flutter/flutter/issues/158567
693  DlRect expanded_rect = oval_bounds.Expand(Size(paint_.stroke_width / 2));
694  PathBuilder builder;
695  Paint fill_paint = paint_;
696  fill_paint.style = Paint::Style::kFill;
697  fill_paint.stroke_width = 1;
698  builder.AddArc(expanded_rect, Degrees(start_degrees),
699  Degrees(sweep_degrees),
700  /*use_center=*/true);
701  GetCanvas().DrawPath(builder.TakePath(), fill_paint);
702  } else {
703  PathBuilder builder;
704  builder.AddArc(oval_bounds, Degrees(start_degrees), Degrees(sweep_degrees),
705  use_center);
706  GetCanvas().DrawPath(builder.TakePath(), paint_);
707  }
708 }
709 
710 // |flutter::DlOpReceiver|
711 void DlDispatcherBase::drawPoints(flutter::DlPointMode mode,
712  uint32_t count,
713  const DlPoint points[]) {
714  AUTO_DEPTH_WATCHER(1u);
715 
716  Paint paint = paint_;
718  switch (mode) {
719  case flutter::DlPointMode::kPoints: {
720  // Cap::kButt is also treated as a square.
721  PointStyle point_style = paint.stroke_cap == Cap::kRound
724  Scalar radius = paint.stroke_width;
725  if (radius > 0) {
726  radius /= 2.0;
727  }
728  GetCanvas().DrawPoints(points, count, radius, paint, point_style);
729  } break;
730  case flutter::DlPointMode::kLines:
731  for (uint32_t i = 1; i < count; i += 2) {
732  Point p0 = points[i - 1];
733  Point p1 = points[i];
734  GetCanvas().DrawLine(p0, p1, paint, /*reuse_depth=*/i > 1);
735  }
736  break;
737  case flutter::DlPointMode::kPolygon:
738  if (count > 1) {
739  Point p0 = points[0];
740  for (uint32_t i = 1; i < count; i++) {
741  Point p1 = points[i];
742  GetCanvas().DrawLine(p0, p1, paint, /*reuse_depth=*/i > 1);
743  p0 = p1;
744  }
745  }
746  break;
747  }
748 }
749 
751  const std::shared_ptr<flutter::DlVertices>& vertices,
752  flutter::DlBlendMode dl_mode) {}
753 
754 // |flutter::DlOpReceiver|
755 void DlDispatcherBase::drawImage(const sk_sp<flutter::DlImage> image,
756  const DlPoint& point,
757  flutter::DlImageSampling sampling,
758  bool render_with_attributes) {
759  AUTO_DEPTH_WATCHER(1u);
760 
761  if (!image) {
762  return;
763  }
764 
765  auto texture = image->impeller_texture();
766  if (!texture) {
767  return;
768  }
769 
770  const auto size = texture->GetSize();
771  const auto src = DlRect::MakeWH(size.width, size.height);
772  const auto dest = DlRect::MakeXYWH(point.x, point.y, size.width, size.height);
773 
774  drawImageRect(image, // image
775  src, // source rect
776  dest, // destination rect
777  sampling, // sampling options
778  render_with_attributes, // render with attributes
779  flutter::DlSrcRectConstraint::kStrict // constraint
780  );
781 }
782 
783 // |flutter::DlOpReceiver|
784 void DlDispatcherBase::drawImageRect(const sk_sp<flutter::DlImage> image,
785  const DlRect& src,
786  const DlRect& dst,
787  flutter::DlImageSampling sampling,
788  bool render_with_attributes,
789  flutter::DlSrcRectConstraint constraint =
790  flutter::DlSrcRectConstraint::kFast) {
791  AUTO_DEPTH_WATCHER(1u);
792 
794  image->impeller_texture(), // image
795  src, // source rect
796  dst, // destination rect
797  render_with_attributes ? paint_ : Paint(), // paint
798  skia_conversions::ToSamplerDescriptor(sampling) // sampling
799  );
800 }
801 
802 // |flutter::DlOpReceiver|
803 void DlDispatcherBase::drawImageNine(const sk_sp<flutter::DlImage> image,
804  const DlIRect& center,
805  const DlRect& dst,
806  flutter::DlFilterMode filter,
807  bool render_with_attributes) {
808  AUTO_DEPTH_WATCHER(9u);
809 
810  NinePatchConverter converter = {};
811  converter.DrawNinePatch(image->impeller_texture(),
812  Rect::MakeLTRB(center.GetLeft(), center.GetTop(),
813  center.GetRight(), center.GetBottom()),
814  dst, ToSamplerDescriptor(filter), &GetCanvas(),
815  &paint_);
816 }
817 
818 // |flutter::DlOpReceiver|
819 void DlDispatcherBase::drawAtlas(const sk_sp<flutter::DlImage> atlas,
820  const RSTransform xform[],
821  const DlRect tex[],
822  const flutter::DlColor colors[],
823  int count,
824  flutter::DlBlendMode mode,
825  flutter::DlImageSampling sampling,
826  const DlRect* cull_rect,
827  bool render_with_attributes) {
828  AUTO_DEPTH_WATCHER(1u);
829 
830  auto geometry =
831  DlAtlasGeometry(atlas->impeller_texture(), //
832  xform, //
833  tex, //
834  colors, //
835  static_cast<size_t>(count), //
836  mode, //
838  ToOptRect(cull_rect) //
839  );
840  auto atlas_contents = std::make_shared<AtlasContents>();
841  atlas_contents->SetGeometry(&geometry);
842 
843  GetCanvas().DrawAtlas(atlas_contents, paint_);
844 }
845 
846 // |flutter::DlOpReceiver|
848  const sk_sp<flutter::DisplayList> display_list,
849  DlScalar opacity) {
850  AUTO_DEPTH_WATCHER(display_list->total_depth());
851 
852  // Save all values that must remain untouched after the operation.
853  Paint saved_paint = paint_;
854  Matrix saved_initial_matrix = initial_matrix_;
855 
856  // Establish a new baseline for interpreting the new DL.
857  // Matrix and clip are left untouched, the current
858  // transform is saved as the new base matrix, and paint
859  // values are reset to defaults.
861  paint_ = Paint();
862 
863  // Handle passed opacity in the most brute-force way by using
864  // a SaveLayer. If the display_list is able to inherit the
865  // opacity, this could also be handled by modulating all of its
866  // attribute settings (for example, color), by the indicated
867  // opacity.
868  int restore_count = GetCanvas().GetSaveCount();
869  if (opacity < SK_Scalar1) {
870  Paint save_paint;
871  save_paint.color = Color(0, 0, 0, opacity);
872  GetCanvas().SaveLayer(save_paint, display_list->GetBounds(), nullptr,
874  display_list->total_depth(),
875  display_list->can_apply_group_opacity());
876  } else {
877  // The display list may alter the clip, which must be restored to the
878  // current clip at the end of playback.
879  GetCanvas().Save(display_list->total_depth());
880  }
881 
882  // TODO(131445): Remove this restriction if we can correctly cull with
883  // perspective transforms.
884  if (display_list->has_rtree() && !initial_matrix_.HasPerspective()) {
885  // The canvas remembers the screen-space culling bounds clipped by
886  // the surface and the history of clip calls. DisplayList can cull
887  // the ops based on a rectangle expressed in its "destination bounds"
888  // so we need the canvas to transform those into the current local
889  // coordinate space into which the DisplayList will be rendered.
890  auto global_culling_bounds = GetCanvas().GetLocalCoverageLimit();
891  if (global_culling_bounds.has_value()) {
892  Rect cull_rect = global_culling_bounds->TransformBounds(
893  GetCanvas().GetCurrentTransform().Invert());
894  display_list->Dispatch(
895  *this, SkRect::MakeLTRB(cull_rect.GetLeft(), cull_rect.GetTop(),
896  cull_rect.GetRight(), cull_rect.GetBottom()));
897  } else {
898  // If the culling bounds are empty, this display list can be skipped
899  // entirely.
900  }
901  } else {
902  display_list->Dispatch(*this);
903  }
904 
905  // Restore all saved state back to what it was before we interpreted
906  // the display_list
908  GetCanvas().RestoreToCount(restore_count);
909  initial_matrix_ = saved_initial_matrix;
910  paint_ = saved_paint;
911 }
912 
913 // |flutter::DlOpReceiver|
914 void DlDispatcherBase::drawTextBlob(const sk_sp<SkTextBlob> blob,
915  DlScalar x,
916  DlScalar y) {
917  // When running with Impeller enabled Skia text blobs are converted to
918  // Impeller text frames in paragraph_skia.cc
920 }
921 
922 // |flutter::DlOpReceiver|
924  const std::shared_ptr<TextFrame>& text_frame,
925  DlScalar x,
926  DlScalar y) {
927  AUTO_DEPTH_WATCHER(1u);
928 
929  GetCanvas().DrawTextFrame(text_frame, //
930  impeller::Point{x, y}, //
931  paint_ //
932  );
933 }
934 
935 // |flutter::DlOpReceiver|
937  const flutter::DlColor color,
938  const DlScalar elevation,
939  bool transparent_occluder,
940  DlScalar dpr) {
941  AUTO_DEPTH_WATCHER(1u);
942 
943  Color spot_color = skia_conversions::ToColor(color);
944  spot_color.alpha *= 0.25;
945 
946  // Compute the spot color -- ported from SkShadowUtils::ComputeTonalColors.
947  {
948  Scalar max =
949  std::max(std::max(spot_color.red, spot_color.green), spot_color.blue);
950  Scalar min =
951  std::min(std::min(spot_color.red, spot_color.green), spot_color.blue);
952  Scalar luminance = (min + max) * 0.5;
953 
954  Scalar alpha_adjust =
955  (2.6f + (-2.66667f + 1.06667f * spot_color.alpha) * spot_color.alpha) *
956  spot_color.alpha;
957  Scalar color_alpha =
958  (3.544762f + (-4.891428f + 2.3466f * luminance) * luminance) *
959  luminance;
960  color_alpha = std::clamp(alpha_adjust * color_alpha, 0.0f, 1.0f);
961 
962  Scalar greyscale_alpha =
963  std::clamp(spot_color.alpha * (1 - 0.4f * luminance), 0.0f, 1.0f);
964 
965  Scalar color_scale = color_alpha * (1 - greyscale_alpha);
966  Scalar tonal_alpha = color_scale + greyscale_alpha;
967  Scalar unpremul_scale = tonal_alpha != 0 ? color_scale / tonal_alpha : 0;
968  spot_color = Color(unpremul_scale * spot_color.red,
969  unpremul_scale * spot_color.green,
970  unpremul_scale * spot_color.blue, tonal_alpha);
971  }
972 
973  Vector3 light_position(0, -1, 1);
974  Scalar occluder_z = dpr * elevation;
975 
976  constexpr Scalar kLightRadius = 800 / 600; // Light radius / light height
977 
978  Paint paint;
979  paint.style = Paint::Style::kFill;
980  paint.color = spot_color;
983  .sigma = Radius{kLightRadius * occluder_z /
985  };
986 
987  GetCanvas().Save(1u);
989  Matrix::MakeTranslation(Vector2(0, -occluder_z * light_position.y)));
990 
991  SimplifyOrDrawPath(GetCanvas(), path, paint);
993 
994  GetCanvas().Restore();
995 }
996 
997 /// Subclasses
998 
1000  const ContentContext& renderer,
1001  flutter::DlBlendMode max_root_blend_mode) {
1002  return !renderer.GetDeviceCapabilities().SupportsFramebufferFetch() &&
1003  max_root_blend_mode > Entity::kLastPipelineBlendMode;
1004 }
1005 
1007  RenderTarget& render_target,
1008  bool is_onscreen,
1009  bool has_root_backdrop_filter,
1010  flutter::DlBlendMode max_root_blend_mode,
1011  IRect cull_rect)
1012  : canvas_(renderer,
1013  render_target,
1014  is_onscreen,
1015  has_root_backdrop_filter ||
1016  RequiresReadbackForBlends(renderer, max_root_blend_mode),
1017  cull_rect),
1018  renderer_(renderer) {}
1019 
1020 Canvas& CanvasDlDispatcher::GetCanvas() {
1021  return canvas_;
1022 }
1023 
1025  const std::shared_ptr<flutter::DlVertices>& vertices,
1026  flutter::DlBlendMode dl_mode) {
1027  AUTO_DEPTH_WATCHER(1u);
1028 
1029  GetCanvas().DrawVertices(
1030  std::make_shared<DlVerticesGeometry>(vertices, renderer_), dl_mode,
1031  paint_);
1032 }
1033 
1035  std::unordered_map<int64_t, BackdropData> backdrop,
1036  size_t backdrop_count) {
1037  GetCanvas().SetBackdropData(std::move(backdrop), backdrop_count);
1038 }
1039 
1040 //// Text Frame Dispatcher
1041 
1043  const Matrix& initial_matrix,
1044  const Rect cull_rect)
1045  : renderer_(renderer), matrix_(initial_matrix) {
1046  cull_rect_state_.push_back(cull_rect);
1047 }
1048 
1050  FML_DCHECK(cull_rect_state_.size() == 1);
1051 }
1052 
1054  stack_.emplace_back(matrix_);
1055  cull_rect_state_.push_back(cull_rect_state_.back());
1056 }
1057 
1059  const flutter::SaveLayerOptions options,
1060  const flutter::DlImageFilter* backdrop,
1061  std::optional<int64_t> backdrop_id) {
1062  save();
1063 
1064  backdrop_count_ += (backdrop == nullptr ? 0 : 1);
1065  if (backdrop != nullptr && backdrop_id.has_value()) {
1066  std::shared_ptr<flutter::DlImageFilter> shared_backdrop =
1067  backdrop->shared();
1068  std::unordered_map<int64_t, BackdropData>::iterator existing =
1069  backdrop_data_.find(backdrop_id.value());
1070  if (existing == backdrop_data_.end()) {
1071  backdrop_data_[backdrop_id.value()] =
1072  BackdropData{.backdrop_count = 1, .last_backdrop = shared_backdrop};
1073  } else {
1074  BackdropData& data = existing->second;
1075  data.backdrop_count++;
1076  if (data.all_filters_equal) {
1077  data.all_filters_equal = (*data.last_backdrop == *shared_backdrop);
1078  data.last_backdrop = shared_backdrop;
1079  }
1080  }
1081  }
1082 
1083  // This dispatcher does not track enough state to accurately compute
1084  // cull rects with image filters.
1085  auto global_cull_rect = cull_rect_state_.back();
1086  if (has_image_filter_ || global_cull_rect.IsMaximum()) {
1087  cull_rect_state_.back() = Rect::MakeMaximum();
1088  } else {
1089  auto global_save_bounds = bounds.TransformBounds(matrix_);
1090  auto new_cull_rect = global_cull_rect.Intersection(global_save_bounds);
1091  if (new_cull_rect.has_value()) {
1092  cull_rect_state_.back() = new_cull_rect.value();
1093  } else {
1094  cull_rect_state_.back() = Rect::MakeLTRB(0, 0, 0, 0);
1095  }
1096  }
1097 }
1098 
1100  matrix_ = stack_.back();
1101  stack_.pop_back();
1102  cull_rect_state_.pop_back();
1103 }
1104 
1106  matrix_ = matrix_.Translate({tx, ty});
1107 }
1108 
1110  matrix_ = matrix_.Scale({sx, sy, 1.0f});
1111 }
1112 
1114  matrix_ = matrix_ * Matrix::MakeRotationZ(Degrees(degrees));
1115 }
1116 
1118  matrix_ = matrix_ * Matrix::MakeSkew(sx, sy);
1119 }
1120 
1121 // clang-format off
1122  // 2x3 2D affine subset of a 4x4 transform in row major order
1124  DlScalar myx, DlScalar myy, DlScalar myt) {
1125  matrix_ = matrix_ * Matrix::MakeColumn(
1126  mxx, myx, 0.0f, 0.0f,
1127  mxy, myy, 0.0f, 0.0f,
1128  0.0f, 0.0f, 1.0f, 0.0f,
1129  mxt, myt, 0.0f, 1.0f
1130  );
1131  }
1132 
1133  // full 4x4 transform in row major order
1135  DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt,
1136  DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt,
1137  DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt,
1138  DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) {
1139  matrix_ = matrix_ * Matrix::MakeColumn(
1140  mxx, myx, mzx, mwx,
1141  mxy, myy, mzy, mwy,
1142  mxz, myz, mzz, mwz,
1143  mxt, myt, mzt, mwt
1144  );
1145  }
1146 // clang-format on
1147 
1149  matrix_ = Matrix();
1150 }
1151 
1153  const std::shared_ptr<impeller::TextFrame>& text_frame,
1154  DlScalar x,
1155  DlScalar y) {
1156  GlyphProperties properties;
1157  if (paint_.style == Paint::Style::kStroke) {
1158  properties.stroke = true;
1159  properties.stroke_cap = paint_.stroke_cap;
1160  properties.stroke_join = paint_.stroke_join;
1161  properties.stroke_miter = paint_.stroke_miter;
1162  properties.stroke_width = paint_.stroke_width;
1163  }
1164  if (text_frame->HasColor()) {
1165  // Alpha is always applied when rendering, remove it here so
1166  // we do not double-apply the alpha.
1167  properties.color = paint_.color.WithAlpha(1.0);
1168  }
1170  (matrix_ * Matrix::MakeTranslation(Point(x, y))).GetMaxBasisLengthXY());
1171 
1172  renderer_.GetLazyGlyphAtlas()->AddTextFrame(
1173  text_frame, //
1174  scale, //
1175  Point(x, y), //
1176  matrix_,
1177  (properties.stroke || text_frame->HasColor()) //
1178  ? std::optional<GlyphProperties>(properties) //
1179  : std::nullopt //
1180  );
1181 }
1182 
1183 const Rect FirstPassDispatcher::GetCurrentLocalCullingBounds() const {
1184  auto cull_rect = cull_rect_state_.back();
1185  if (!cull_rect.IsEmpty() && !cull_rect.IsMaximum()) {
1186  Matrix inverse = matrix_.Invert();
1187  cull_rect = cull_rect.TransformBounds(inverse);
1188  }
1189  return cull_rect;
1190 }
1191 
1193  const sk_sp<flutter::DisplayList> display_list,
1194  DlScalar opacity) {
1195  [[maybe_unused]] size_t stack_depth = stack_.size();
1196  save();
1197  Paint old_paint = paint_;
1198  paint_ = Paint{};
1199  bool old_has_image_filter = has_image_filter_;
1200  has_image_filter_ = false;
1201 
1202  if (matrix_.HasPerspective()) {
1203  display_list->Dispatch(*this);
1204  } else {
1205  Rect local_cull_bounds = GetCurrentLocalCullingBounds();
1206  if (local_cull_bounds.IsMaximum()) {
1207  display_list->Dispatch(*this);
1208  } else if (!local_cull_bounds.IsEmpty()) {
1209  IRect cull_rect = IRect::RoundOut(local_cull_bounds);
1210  display_list->Dispatch(*this,
1211  SkIRect::MakeLTRB(cull_rect.GetLeft(), //
1212  cull_rect.GetTop(), //
1213  cull_rect.GetRight(), //
1214  cull_rect.GetBottom() //
1215  ));
1216  }
1217  }
1218 
1219  restore();
1220  paint_ = old_paint;
1221  has_image_filter_ = old_has_image_filter;
1222  FML_DCHECK(stack_depth == stack_.size());
1223 }
1224 
1225 // |flutter::DlOpReceiver|
1226 void FirstPassDispatcher::setDrawStyle(flutter::DlDrawStyle style) {
1227  paint_.style = ToStyle(style);
1228 }
1229 
1230 // |flutter::DlOpReceiver|
1231 void FirstPassDispatcher::setColor(flutter::DlColor color) {
1232  paint_.color = skia_conversions::ToColor(color);
1233 }
1234 
1235 // |flutter::DlOpReceiver|
1237  paint_.stroke_width = width;
1238 }
1239 
1240 // |flutter::DlOpReceiver|
1242  paint_.stroke_miter = limit;
1243 }
1244 
1245 // |flutter::DlOpReceiver|
1246 void FirstPassDispatcher::setStrokeCap(flutter::DlStrokeCap cap) {
1247  switch (cap) {
1248  case flutter::DlStrokeCap::kButt:
1249  paint_.stroke_cap = Cap::kButt;
1250  break;
1251  case flutter::DlStrokeCap::kRound:
1252  paint_.stroke_cap = Cap::kRound;
1253  break;
1254  case flutter::DlStrokeCap::kSquare:
1255  paint_.stroke_cap = Cap::kSquare;
1256  break;
1257  }
1258 }
1259 
1260 // |flutter::DlOpReceiver|
1261 void FirstPassDispatcher::setStrokeJoin(flutter::DlStrokeJoin join) {
1262  switch (join) {
1263  case flutter::DlStrokeJoin::kMiter:
1264  paint_.stroke_join = Join::kMiter;
1265  break;
1266  case flutter::DlStrokeJoin::kRound:
1267  paint_.stroke_join = Join::kRound;
1268  break;
1269  case flutter::DlStrokeJoin::kBevel:
1270  paint_.stroke_join = Join::kBevel;
1271  break;
1272  }
1273 }
1274 
1275 // |flutter::DlOpReceiver|
1276 void FirstPassDispatcher::setImageFilter(const flutter::DlImageFilter* filter) {
1277  if (filter == nullptr) {
1278  has_image_filter_ = false;
1279  } else {
1280  has_image_filter_ = true;
1281  }
1282 }
1283 
1284 std::pair<std::unordered_map<int64_t, BackdropData>, size_t>
1286  std::unordered_map<int64_t, BackdropData> temp;
1287  std::swap(temp, backdrop_data_);
1288  return std::make_pair(temp, backdrop_count_);
1289 }
1290 
1291 std::shared_ptr<Texture> DisplayListToTexture(
1292  const sk_sp<flutter::DisplayList>& display_list,
1293  ISize size,
1294  AiksContext& context,
1295  bool reset_host_buffer,
1296  bool generate_mips) {
1297  int mip_count = 1;
1298  if (generate_mips) {
1299  mip_count = size.MipCount();
1300  }
1301  // Do not use the render target cache as the lifecycle of this texture
1302  // will outlive a particular frame.
1303  impeller::RenderTargetAllocator render_target_allocator =
1305  context.GetContext()->GetResourceAllocator());
1306  impeller::RenderTarget target;
1307  if (context.GetContext()->GetCapabilities()->SupportsOffscreenMSAA()) {
1308  target = render_target_allocator.CreateOffscreenMSAA(
1309  *context.GetContext(), // context
1310  size, // size
1311  /*mip_count=*/mip_count,
1312  "Picture Snapshot MSAA", // label
1314  kDefaultColorAttachmentConfigMSAA // color_attachment_config
1315  );
1316  } else {
1317  target = render_target_allocator.CreateOffscreen(
1318  *context.GetContext(), // context
1319  size, // size
1320  /*mip_count=*/mip_count,
1321  "Picture Snapshot", // label
1323  kDefaultColorAttachmentConfig // color_attachment_config
1324  );
1325  }
1326  if (!target.IsValid()) {
1327  return nullptr;
1328  }
1329 
1330  SkIRect sk_cull_rect = SkIRect::MakeWH(size.width, size.height);
1332  context.GetContentContext(), impeller::Matrix(), Rect::MakeSize(size));
1333  display_list->Dispatch(collector, sk_cull_rect);
1334  impeller::CanvasDlDispatcher impeller_dispatcher(
1335  context.GetContentContext(), //
1336  target, //
1337  /*is_onscreen=*/false, //
1338  display_list->root_has_backdrop_filter(), //
1339  display_list->max_root_blend_mode(), //
1340  impeller::IRect::MakeSize(size) //
1341  );
1342  const auto& [data, count] = collector.TakeBackdropData();
1343  impeller_dispatcher.SetBackdropData(data, count);
1345  fml::ScopedCleanupClosure cleanup([&] {
1346  if (reset_host_buffer) {
1347  context.GetContentContext().GetTransientsBuffer().Reset();
1348  }
1349  context.GetContentContext().GetTextShadowCache().MarkFrameEnd();
1350  context.GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames();
1351  context.GetContext()->DisposeThreadLocalCachedResources();
1352  });
1353 
1354  display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
1355  impeller_dispatcher.FinishRecording();
1356 
1357  return target.GetRenderTargetTexture();
1358 }
1359 
1361  RenderTarget render_target,
1362  const sk_sp<flutter::DisplayList>& display_list,
1363  SkIRect cull_rect,
1364  bool reset_host_buffer,
1365  bool is_onscreen) {
1366  Rect ip_cull_rect = Rect::MakeLTRB(cull_rect.left(), cull_rect.top(),
1367  cull_rect.right(), cull_rect.bottom());
1368  FirstPassDispatcher collector(context, impeller::Matrix(), ip_cull_rect);
1369  display_list->Dispatch(collector, cull_rect);
1370 
1371  impeller::CanvasDlDispatcher impeller_dispatcher(
1372  context, //
1373  render_target, //
1374  /*is_onscreen=*/is_onscreen, //
1375  display_list->root_has_backdrop_filter(), //
1376  display_list->max_root_blend_mode(), //
1377  IRect::RoundOut(ip_cull_rect) //
1378  );
1379  const auto& [data, count] = collector.TakeBackdropData();
1380  impeller_dispatcher.SetBackdropData(data, count);
1381  context.GetTextShadowCache().MarkFrameStart();
1382  fml::ScopedCleanupClosure cleanup([&] {
1383  if (reset_host_buffer) {
1384  context.GetTransientsBuffer().Reset();
1385  }
1386  context.GetTextShadowCache().MarkFrameEnd();
1387  });
1388 
1389  display_list->Dispatch(impeller_dispatcher, cull_rect);
1390  impeller_dispatcher.FinishRecording();
1391  context.GetLazyGlyphAtlas()->ResetTextFrames();
1392 
1393  return true;
1394 }
1395 
1396 } // namespace impeller
ContentContext & GetContentContext() const
Definition: aiks_context.cc:42
std::shared_ptr< Context > GetContext() const
Definition: aiks_context.cc:38
CanvasDlDispatcher(ContentContext &renderer, RenderTarget &render_target, bool is_onscreen, bool has_root_backdrop_filter, flutter::DlBlendMode max_root_blend_mode, IRect 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:686
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:1742
void DrawRoundSuperellipse(const RoundSuperellipse &rse, const Paint &paint)
Definition: canvas.cc:640
std::optional< Rect > GetLocalCoverageLimit() const
Return the culling bounds of the current render target, or nullopt if there is no coverage.
Definition: canvas.cc:1060
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:1091
const Matrix & GetCurrentTransform() const
Definition: canvas.cc:254
void DrawVertices(const std::shared_ptr< VerticesGeometry > &vertices, BlendMode blend_mode, const Paint &paint)
Definition: canvas.cc:864
void DrawOval(const Rect &rect, const Paint &paint)
Definition: canvas.cc:583
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:799
void RestoreToCount(size_t count)
Definition: canvas.cc:301
bool Restore()
Definition: canvas.cc:1329
size_t GetSaveCount() const
Definition: canvas.cc:293
void Transform(const Matrix &transform)
Definition: canvas.cc:250
uint64_t GetMaxOpDepth() const
Definition: canvas.h:247
void PreConcat(const Matrix &transform)
Definition: canvas.cc:242
void Rotate(Radians radians)
Definition: canvas.cc:274
void DrawPoints(const Point points[], uint32_t count, Scalar radius, const Paint &paint, PointStyle point_style)
Definition: canvas.cc:767
void ResetTransform()
Definition: canvas.cc:246
void DrawTextFrame(const std::shared_ptr< TextFrame > &text_frame, Point position, const Paint &paint)
Definition: canvas.cc:1520
void DrawPaint(const Paint &paint)
Definition: canvas.cc:324
void DrawRoundRect(const RoundRect &rect, const Paint &paint)
Definition: canvas.cc:613
void Skew(Scalar sx, Scalar sy)
Definition: canvas.cc:270
void Scale(const Vector2 &scale)
Definition: canvas.cc:262
uint64_t GetOpDepth() const
Definition: canvas.h:245
void DrawPath(const Path &path, const Paint &paint)
Definition: canvas.cc:309
void Save(uint32_t total_content_depth=kMaxDepth)
Definition: canvas.cc:1043
void DrawRect(const Rect &rect, const Paint &paint)
Definition: canvas.cc:565
void DrawAtlas(const std::shared_ptr< AtlasContents > &atlas_contents, const Paint &paint)
Definition: canvas.cc:977
void DrawLine(const Point &p0, const Point &p1, const Paint &paint, bool reuse_depth=false)
Definition: canvas.cc:542
void Translate(const Vector3 &offset)
Definition: canvas.cc:258
void DrawCircle(const Point &center, Scalar radius, const Paint &paint)
Definition: canvas.cc:663
virtual bool SupportsFramebufferFetch() const =0
Whether the context backend is able to support pipelines with shaders that read from the framebuffer ...
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
const std::shared_ptr< LazyGlyphAtlas > & GetLazyGlyphAtlas() const
const Capabilities & GetDeviceCapabilities() const
TextShadowCache & GetTextShadowCache() const
A wrapper around data provided by a drawAtlas call.
void drawLine(const DlPoint &p0, const DlPoint &p1) 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
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 drawTextBlob(const sk_sp< SkTextBlob > blob, DlScalar x, DlScalar y) 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
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 drawTextFrame(const std::shared_ptr< impeller::TextFrame > &text_frame, DlScalar x, DlScalar y) 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)
static constexpr BlendMode kLastPipelineBlendMode
Definition: entity.h:22
A geometry that is created from a filled path object.
@ 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 drawTextFrame(const std::shared_ptr< impeller::TextFrame > &text_frame, DlScalar x, DlScalar y) 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 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)
Path TakePath(FillType fill=FillType::kNonZero)
Definition: path_builder.cc:30
PathBuilder & AddArc(const Rect &oval_bounds, Radians start, Radians sweep, bool use_center=false)
PathBuilder & AddRoundRect(RoundRect rect)
PathBuilder & LineTo(Point point, bool relative=false)
Insert a line from the current position to point.
Definition: path_builder.cc:66
PathBuilder & MoveTo(Point point, bool relative=false)
Definition: path_builder.cc:47
PathBuilder & SetBounds(Rect bounds)
Set the bounding box that will be used by Path.GetBoundingBox in place of performing the computation.
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)
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::shared_ptr< Texture > GetRenderTargetTexture() const
static Rational RoundScaledFontSize(Scalar scale)
Definition: text_frame.cc:55
void MarkFrameStart()
Mark all glyph textures as unused this frame.
#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)
std::shared_ptr< Texture > DisplayListToTexture(const sk_sp< flutter::DisplayList > &display_list, ISize size, AiksContext &context, bool reset_host_buffer, bool generate_mips)
Render the provided display list to a texture with the given size.
Point Vector2
Definition: point.h:331
flutter::DlRect DlRect
Definition: dl_dispatcher.h:25
float Scalar
Definition: scalar.h:18
flutter::DlIRect DlIRect
Definition: dl_dispatcher.h:26
static Paint::Style ToStyle(flutter::DlDrawStyle style)
flutter::DlRoundRect DlRoundRect
Definition: dl_dispatcher.h:27
static std::optional< const Rect > ToOptRect(const flutter::DlRect *rect)
PointStyle
Definition: canvas.h:61
@ kRound
Points are drawn as squares.
@ kSquare
Points are drawn as circles.
TPoint< Scalar > Point
Definition: point.h:327
static Entity::ClipOperation ToClipOperation(flutter::DlClipOp clip_op)
bool RenderToTarget(ContentContext &context, RenderTarget render_target, const sk_sp< flutter::DisplayList > &display_list, SkIRect cull_rect, bool reset_host_buffer, bool is_onscreen)
Render the provided display list to the render target.
flutter::DlPoint DlPoint
Definition: dl_dispatcher.h:24
flutter::DlRoundSuperellipse DlRoundSuperellipse
Definition: dl_dispatcher.h:28
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:29
@ 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...
TSize< Scalar > Size
Definition: size.h:159
@ kNearest
Select nearest to the sample point. Most widely supported.
flutter::DlScalar DlScalar
Definition: dl_dispatcher.h:23
static FilterContents::BlurStyle ToBlurStyle(flutter::DlBlurStyle blur_style)
size_t backdrop_count
Definition: canvas.h:37
Scalar blue
Definition: color.h:138
Scalar alpha
Definition: color.h:143
constexpr Color WithAlpha(Scalar new_alpha) const
Definition: color.h:278
Scalar red
Definition: color.h:128
Scalar green
Definition: color.h:133
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
constexpr Vector3 GetScale() const
Definition: matrix.h:341
Matrix Invert() const
Definition: matrix.cc:97
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
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:365
FilterContents::BlurStyle style
Definition: paint.h:52
const flutter::DlColorFilter * color_filter
Definition: paint.h:76
const flutter::DlColorSource * color_source
Definition: paint.h:75
const flutter::DlImageFilter * image_filter
Definition: paint.h:77
Cap stroke_cap
Definition: paint.h:80
Join stroke_join
Definition: paint.h:81
Scalar stroke_miter
Definition: paint.h:82
Style style
Definition: paint.h:83
bool invert_colors
Definition: paint.h:85
std::optional< MaskBlurDescriptor > mask_blur_descriptor
Definition: paint.h:87
Color color
Definition: paint.h:74
BlendMode blend_mode
Definition: paint.h:84
Scalar stroke_width
Definition: paint.h:79
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 auto GetBottom() const
Definition: rect.h:361
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition: rect.h:476
constexpr auto GetTop() const
Definition: rect.h:357
constexpr bool IsMaximum() const
Definition: rect.h:318
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: rect.h:301
constexpr auto GetLeft() const
Definition: rect.h:355
RoundOut(const TRect< U > &r)
Definition: rect.h:683
constexpr auto GetRight() const
Definition: rect.h:359
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:188
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
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:67