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