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 "impeller/core/formats.h"
27 #include "impeller/entity/entity.h"
33 #include "impeller/geometry/path.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 // |flutter::DlOpReceiver|
141  AUTO_DEPTH_WATCHER(0u);
142 
143  // Nothing to do because AA is implicit.
144 }
145 
146 static Paint::Style ToStyle(flutter::DlDrawStyle style) {
147  switch (style) {
148  case flutter::DlDrawStyle::kFill:
149  return Paint::Style::kFill;
150  case flutter::DlDrawStyle::kStroke:
151  return Paint::Style::kStroke;
152  case flutter::DlDrawStyle::kStrokeAndFill:
154  break;
155  }
156  return Paint::Style::kFill;
157 }
158 
159 // |flutter::DlOpReceiver|
160 void DlDispatcherBase::setDrawStyle(flutter::DlDrawStyle style) {
161  AUTO_DEPTH_WATCHER(0u);
162 
163  paint_.style = ToStyle(style);
164 }
165 
166 // |flutter::DlOpReceiver|
167 void DlDispatcherBase::setColor(flutter::DlColor color) {
168  AUTO_DEPTH_WATCHER(0u);
169 
171 }
172 
173 // |flutter::DlOpReceiver|
175  AUTO_DEPTH_WATCHER(0u);
176 
177  paint_.stroke_width = width;
178 }
179 
180 // |flutter::DlOpReceiver|
182  AUTO_DEPTH_WATCHER(0u);
183 
184  paint_.stroke_miter = limit;
185 }
186 
187 // |flutter::DlOpReceiver|
188 void DlDispatcherBase::setStrokeCap(flutter::DlStrokeCap cap) {
189  AUTO_DEPTH_WATCHER(0u);
190 
191  switch (cap) {
192  case flutter::DlStrokeCap::kButt:
194  break;
195  case flutter::DlStrokeCap::kRound:
197  break;
198  case flutter::DlStrokeCap::kSquare:
200  break;
201  }
202 }
203 
204 // |flutter::DlOpReceiver|
205 void DlDispatcherBase::setStrokeJoin(flutter::DlStrokeJoin join) {
206  AUTO_DEPTH_WATCHER(0u);
207 
208  switch (join) {
209  case flutter::DlStrokeJoin::kMiter:
211  break;
212  case flutter::DlStrokeJoin::kRound:
214  break;
215  case flutter::DlStrokeJoin::kBevel:
217  break;
218  }
219 }
220 
221 // |flutter::DlOpReceiver|
222 void DlDispatcherBase::setColorSource(const flutter::DlColorSource* source) {
223  AUTO_DEPTH_WATCHER(0u);
224 
225  paint_.color_source = source;
226 }
227 
228 // |flutter::DlOpReceiver|
229 void DlDispatcherBase::setColorFilter(const flutter::DlColorFilter* filter) {
230  AUTO_DEPTH_WATCHER(0u);
231 
232  paint_.color_filter = filter;
233 }
234 
235 // |flutter::DlOpReceiver|
237  AUTO_DEPTH_WATCHER(0u);
238 
239  paint_.invert_colors = invert;
240 }
241 
242 // |flutter::DlOpReceiver|
243 void DlDispatcherBase::setBlendMode(flutter::DlBlendMode dl_mode) {
244  AUTO_DEPTH_WATCHER(0u);
245 
247 }
248 
249 static FilterContents::BlurStyle ToBlurStyle(flutter::DlBlurStyle blur_style) {
250  switch (blur_style) {
251  case flutter::DlBlurStyle::kNormal:
253  case flutter::DlBlurStyle::kSolid:
255  case flutter::DlBlurStyle::kOuter:
257  case flutter::DlBlurStyle::kInner:
259  }
260 }
261 
262 // |flutter::DlOpReceiver|
263 void DlDispatcherBase::setMaskFilter(const flutter::DlMaskFilter* filter) {
264  AUTO_DEPTH_WATCHER(0u);
265 
266  // Needs https://github.com/flutter/flutter/issues/95434
267  if (filter == nullptr) {
268  paint_.mask_blur_descriptor = std::nullopt;
269  return;
270  }
271  switch (filter->type()) {
272  case flutter::DlMaskFilterType::kBlur: {
273  auto blur = filter->asBlur();
274 
276  .style = ToBlurStyle(blur->style()),
277  .sigma = Sigma(blur->sigma()),
278  .respect_ctm = blur->respectCTM(),
279  };
280  break;
281  }
282  }
283 }
284 
285 // |flutter::DlOpReceiver|
286 void DlDispatcherBase::setImageFilter(const flutter::DlImageFilter* filter) {
287  AUTO_DEPTH_WATCHER(0u);
288 
289  paint_.image_filter = filter;
290 }
291 
292 // |flutter::DlOpReceiver|
293 void DlDispatcherBase::save(uint32_t total_content_depth) {
294  AUTO_DEPTH_WATCHER(1u);
295 
296  GetCanvas().Save(total_content_depth);
297 }
298 
299 // |flutter::DlOpReceiver|
301  const flutter::SaveLayerOptions& options,
302  uint32_t total_content_depth,
303  flutter::DlBlendMode max_content_mode,
304  const flutter::DlImageFilter* backdrop,
305  std::optional<int64_t> backdrop_id) {
306  AUTO_DEPTH_WATCHER(1u);
307 
308  auto paint = options.renders_with_attributes() ? paint_ : Paint{};
309  auto promise = options.content_is_clipped()
312  std::optional<Rect> impeller_bounds;
313  // If the content is unbounded but has developer specified bounds, we take
314  // the original bounds so that we clip the content as expected.
315  if (!options.content_is_unbounded() || options.bounds_from_caller()) {
316  impeller_bounds = bounds;
317  }
318 
320  paint, impeller_bounds, backdrop, promise, total_content_depth,
321  // Unbounded content can still have user specified bounds that require a
322  // saveLayer to be created to perform the clip.
323  options.can_distribute_opacity() && !options.content_is_unbounded(),
324  backdrop_id //
325  );
326 }
327 
328 // |flutter::DlOpReceiver|
330  GetCanvas().Restore();
331 }
332 
333 // |flutter::DlOpReceiver|
335  AUTO_DEPTH_WATCHER(0u);
336 
337  GetCanvas().Translate({tx, ty, 0.0});
338 }
339 
340 // |flutter::DlOpReceiver|
342  AUTO_DEPTH_WATCHER(0u);
343 
344  GetCanvas().Scale({sx, sy, 1.0});
345 }
346 
347 // |flutter::DlOpReceiver|
349  AUTO_DEPTH_WATCHER(0u);
350 
351  GetCanvas().Rotate(Degrees{degrees});
352 }
353 
354 // |flutter::DlOpReceiver|
356  AUTO_DEPTH_WATCHER(0u);
357 
358  GetCanvas().Skew(sx, sy);
359 }
360 
361 // |flutter::DlOpReceiver|
363  DlScalar mxy,
364  DlScalar mxt,
365  DlScalar myx,
366  DlScalar myy,
367  DlScalar myt) {
368  AUTO_DEPTH_WATCHER(0u);
369 
370  // clang-format off
372  mxx, mxy, 0, mxt,
373  myx, myy, 0, myt,
374  0 , 0, 1, 0,
375  0 , 0, 0, 1
376  );
377  // clang-format on
378 }
379 
380 // |flutter::DlOpReceiver|
382  DlScalar mxy,
383  DlScalar mxz,
384  DlScalar mxt,
385  DlScalar myx,
386  DlScalar myy,
387  DlScalar myz,
388  DlScalar myt,
389  DlScalar mzx,
390  DlScalar mzy,
391  DlScalar mzz,
392  DlScalar mzt,
393  DlScalar mwx,
394  DlScalar mwy,
395  DlScalar mwz,
396  DlScalar mwt) {
397  AUTO_DEPTH_WATCHER(0u);
398 
399  // The order of arguments is row-major but Impeller matrices are
400  // column-major.
401  // clang-format off
402  auto transform = Matrix{
403  mxx, myx, mzx, mwx,
404  mxy, myy, mzy, mwy,
405  mxz, myz, mzz, mwz,
406  mxt, myt, mzt, mwt
407  };
408  // clang-format on
410 }
411 
412 // |flutter::DlOpReceiver|
414  AUTO_DEPTH_WATCHER(0u);
415 
418 }
419 
421  flutter::DlCanvas::ClipOp clip_op) {
422  switch (clip_op) {
423  case flutter::DlCanvas::ClipOp::kDifference:
425  case flutter::DlCanvas::ClipOp::kIntersect:
427  }
428 }
429 
430 // |flutter::DlOpReceiver|
432  ClipOp clip_op,
433  bool is_aa) {
434  AUTO_DEPTH_WATCHER(0u);
435 
436  RectGeometry geom(rect);
437  GetCanvas().ClipGeometry(geom, ToClipOperation(clip_op), /*is_aa=*/is_aa);
438 }
439 
440 // |flutter::DlOpReceiver|
442  ClipOp clip_op,
443  bool is_aa) {
444  AUTO_DEPTH_WATCHER(0u);
445 
446  EllipseGeometry geom(bounds);
447  GetCanvas().ClipGeometry(geom, ToClipOperation(clip_op));
448 }
449 
450 // |flutter::DlOpReceiver|
452  ClipOp sk_op,
453  bool is_aa) {
454  AUTO_DEPTH_WATCHER(0u);
455 
456  auto clip_op = ToClipOperation(sk_op);
457  if (rrect.IsRect()) {
458  RectGeometry geom(rrect.GetBounds());
459  GetCanvas().ClipGeometry(geom, clip_op, /*is_aa=*/is_aa);
460  } else if (rrect.IsOval()) {
461  EllipseGeometry geom(rrect.GetBounds());
462  GetCanvas().ClipGeometry(geom, clip_op);
463  } else if (rrect.GetRadii().AreAllCornersSame()) {
464  RoundRectGeometry geom(rrect.GetBounds(), rrect.GetRadii().top_left);
465  GetCanvas().ClipGeometry(geom, clip_op);
466  } else {
467  FillPathGeometry geom(PathBuilder{}.AddRoundRect(rrect).TakePath());
468  GetCanvas().ClipGeometry(geom, clip_op);
469  }
470 }
471 
472 // |flutter::DlOpReceiver|
473 void DlDispatcherBase::clipPath(const DlPath& path, ClipOp sk_op, bool is_aa) {
474  AUTO_DEPTH_WATCHER(0u);
475 
476  auto clip_op = ToClipOperation(sk_op);
477 
478  DlRect rect;
479  if (path.IsRect(&rect)) {
480  RectGeometry geom(rect);
481  GetCanvas().ClipGeometry(geom, clip_op, /*is_aa=*/is_aa);
482  } else if (path.IsOval(&rect)) {
483  EllipseGeometry geom(rect);
484  GetCanvas().ClipGeometry(geom, clip_op);
485  } else {
486  SkRRect rrect;
487  if (path.IsSkRRect(&rrect) && rrect.isSimple()) {
488  RoundRectGeometry geom(skia_conversions::ToRect(rrect.rect()),
489  skia_conversions::ToSize(rrect.getSimpleRadii()));
490  GetCanvas().ClipGeometry(geom, clip_op);
491  } else {
492  FillPathGeometry geom(path.GetPath());
493  GetCanvas().ClipGeometry(geom, clip_op);
494  }
495  }
496 }
497 
498 // |flutter::DlOpReceiver|
499 void DlDispatcherBase::drawColor(flutter::DlColor color,
500  flutter::DlBlendMode dl_mode) {
501  AUTO_DEPTH_WATCHER(1u);
502 
503  Paint paint;
504  paint.color = skia_conversions::ToColor(color);
505  paint.blend_mode = skia_conversions::ToBlendMode(dl_mode);
506  GetCanvas().DrawPaint(paint);
507 }
508 
509 // |flutter::DlOpReceiver|
511  AUTO_DEPTH_WATCHER(1u);
512 
514 }
515 
516 // |flutter::DlOpReceiver|
517 void DlDispatcherBase::drawLine(const DlPoint& p0, const DlPoint& p1) {
518  AUTO_DEPTH_WATCHER(1u);
519 
520  GetCanvas().DrawLine(p0, p1, paint_);
521 }
522 
524  const DlPoint& p1,
525  DlScalar on_length,
526  DlScalar off_length) {
527  AUTO_DEPTH_WATCHER(1u);
528 
529  Scalar length = p0.GetDistance(p1);
530  // Reasons to defer to regular DrawLine:
531  // length is non-positive - drawLine will draw appropriate "dot"
532  // off_length is non-positive - no gaps, drawLine will draw it solid
533  // on_length is negative - invalid dashing
534  // Note that a 0 length "on" dash will draw "dot"s every "off" distance
535  // apart
536  if (length > 0.0f && on_length >= 0.0f && off_length > 0.0f) {
537  Point delta = (p1 - p0) / length; // length > 0 already tested
538  PathBuilder builder;
539 
540  Scalar consumed = 0.0f;
541  while (consumed < length) {
542  builder.MoveTo(p0 + delta * consumed);
543 
544  Scalar dash_end = consumed + on_length;
545  if (dash_end < length) {
546  builder.LineTo(p0 + delta * dash_end);
547  } else {
548  builder.LineTo(p1);
549  // Should happen anyway due to the math, but let's make it explicit
550  // in case of bit errors. We're done with this line.
551  break;
552  }
553 
554  consumed = dash_end + off_length;
555  }
556 
557  Paint stroke_paint = paint_;
558  stroke_paint.style = Paint::Style::kStroke;
559  GetCanvas().DrawPath(builder.TakePath(), stroke_paint);
560  } else {
561  drawLine(p0, p1);
562  }
563 }
564 
565 // |flutter::DlOpReceiver|
567  AUTO_DEPTH_WATCHER(1u);
568 
569  GetCanvas().DrawRect(rect, paint_);
570 }
571 
572 // |flutter::DlOpReceiver|
573 void DlDispatcherBase::drawOval(const DlRect& bounds) {
574  AUTO_DEPTH_WATCHER(1u);
575 
576  GetCanvas().DrawOval(bounds, paint_);
577 }
578 
579 // |flutter::DlOpReceiver|
580 void DlDispatcherBase::drawCircle(const DlPoint& center, DlScalar radius) {
581  AUTO_DEPTH_WATCHER(1u);
582 
583  GetCanvas().DrawCircle(center, radius, paint_);
584 }
585 
586 // |flutter::DlOpReceiver|
588  AUTO_DEPTH_WATCHER(1u);
589 
590  GetCanvas().DrawRoundRect(rrect, paint_);
591 }
592 
593 // |flutter::DlOpReceiver|
595  const DlRoundRect& inner) {
596  AUTO_DEPTH_WATCHER(1u);
597 
598  PathBuilder builder;
599  builder.AddRoundRect(outer);
600  builder.AddRoundRect(inner);
601  builder.SetBounds(outer.GetBounds().Union(inner.GetBounds()));
603 }
604 
605 // |flutter::DlOpReceiver|
607  AUTO_DEPTH_WATCHER(1u);
608 
610 }
611 
613  const DlPath& path,
614  const Paint& paint) {
615  DlRect rect;
616 
617  // We can't "optimize" a path into a rectangle if it's open.
618  bool closed;
619  if (path.IsRect(&rect, &closed) && closed) {
620  canvas.DrawRect(rect, paint);
621  return;
622  }
623 
624  SkRRect rrect;
625  if (path.IsSkRRect(&rrect) && rrect.isSimple()) {
626  canvas.DrawRoundRect(flutter::ToDlRoundRect(rrect), paint);
627  return;
628  }
629 
630  if (path.IsOval(&rect)) {
631  canvas.DrawOval(rect, paint);
632  return;
633  }
634 
635  canvas.DrawPath(path.GetPath(), paint);
636 }
637 
638 // |flutter::DlOpReceiver|
639 void DlDispatcherBase::drawArc(const DlRect& oval_bounds,
640  DlScalar start_degrees,
641  DlScalar sweep_degrees,
642  bool use_center) {
643  AUTO_DEPTH_WATCHER(1u);
644 
645  if (paint_.stroke_width >
646  std::max(oval_bounds.GetWidth(), oval_bounds.GetHeight())) {
647  // This is a special case for rendering arcs whose stroke width is so large
648  // you are effectively drawing a sector of a circle.
649  // https://github.com/flutter/flutter/issues/158567
650  DlRect expanded_rect = oval_bounds.Expand(Size(paint_.stroke_width / 2));
651  PathBuilder builder;
652  Paint fill_paint = paint_;
653  fill_paint.style = Paint::Style::kFill;
654  fill_paint.stroke_width = 1;
655  builder.AddArc(expanded_rect, Degrees(start_degrees),
656  Degrees(sweep_degrees),
657  /*use_center=*/true);
658  GetCanvas().DrawPath(builder.TakePath(), fill_paint);
659  } else {
660  PathBuilder builder;
661  builder.AddArc(oval_bounds, Degrees(start_degrees), Degrees(sweep_degrees),
662  use_center);
663  GetCanvas().DrawPath(builder.TakePath(), paint_);
664  }
665 }
666 
667 // |flutter::DlOpReceiver|
668 void DlDispatcherBase::drawPoints(PointMode mode,
669  uint32_t count,
670  const DlPoint points[]) {
671  AUTO_DEPTH_WATCHER(1u);
672 
673  Paint paint = paint_;
675  switch (mode) {
676  case flutter::DlCanvas::PointMode::kPoints: {
677  // Cap::kButt is also treated as a square.
678  PointStyle point_style = paint.stroke_cap == Cap::kRound
681  Scalar radius = paint.stroke_width;
682  if (radius > 0) {
683  radius /= 2.0;
684  }
685  GetCanvas().DrawPoints(points, count, radius, paint, point_style);
686  } break;
687  case flutter::DlCanvas::PointMode::kLines:
688  for (uint32_t i = 1; i < count; i += 2) {
689  Point p0 = points[i - 1];
690  Point p1 = points[i];
691  GetCanvas().DrawLine(p0, p1, paint, /*reuse_depth=*/i > 1);
692  }
693  break;
694  case flutter::DlCanvas::PointMode::kPolygon:
695  if (count > 1) {
696  Point p0 = points[0];
697  for (uint32_t i = 1; i < count; i++) {
698  Point p1 = points[i];
699  GetCanvas().DrawLine(p0, p1, paint, /*reuse_depth=*/i > 1);
700  p0 = p1;
701  }
702  }
703  break;
704  }
705 }
706 
708  const std::shared_ptr<flutter::DlVertices>& vertices,
709  flutter::DlBlendMode dl_mode) {}
710 
711 // |flutter::DlOpReceiver|
712 void DlDispatcherBase::drawImage(const sk_sp<flutter::DlImage> image,
713  const DlPoint& point,
714  flutter::DlImageSampling sampling,
715  bool render_with_attributes) {
716  AUTO_DEPTH_WATCHER(1u);
717 
718  if (!image) {
719  return;
720  }
721 
722  auto texture = image->impeller_texture();
723  if (!texture) {
724  return;
725  }
726 
727  const auto size = texture->GetSize();
728  const auto src = DlRect::MakeWH(size.width, size.height);
729  const auto dest = DlRect::MakeXYWH(point.x, point.y, size.width, size.height);
730 
731  drawImageRect(image, // image
732  src, // source rect
733  dest, // destination rect
734  sampling, // sampling options
735  render_with_attributes, // render with attributes
736  SrcRectConstraint::kStrict // constraint
737  );
738 }
739 
740 // |flutter::DlOpReceiver|
742  const sk_sp<flutter::DlImage> image,
743  const DlRect& src,
744  const DlRect& dst,
745  flutter::DlImageSampling sampling,
746  bool render_with_attributes,
747  SrcRectConstraint constraint = SrcRectConstraint::kFast) {
748  AUTO_DEPTH_WATCHER(1u);
749 
751  image->impeller_texture(), // image
752  src, // source rect
753  dst, // destination rect
754  render_with_attributes ? paint_ : Paint(), // paint
755  skia_conversions::ToSamplerDescriptor(sampling) // sampling
756  );
757 }
758 
759 // |flutter::DlOpReceiver|
760 void DlDispatcherBase::drawImageNine(const sk_sp<flutter::DlImage> image,
761  const DlIRect& center,
762  const DlRect& dst,
763  flutter::DlFilterMode filter,
764  bool render_with_attributes) {
765  AUTO_DEPTH_WATCHER(9u);
766 
767  NinePatchConverter converter = {};
768  converter.DrawNinePatch(image->impeller_texture(),
769  Rect::MakeLTRB(center.GetLeft(), center.GetTop(),
770  center.GetRight(), center.GetBottom()),
771  dst, ToSamplerDescriptor(filter), &GetCanvas(),
772  &paint_);
773 }
774 
775 // |flutter::DlOpReceiver|
776 void DlDispatcherBase::drawAtlas(const sk_sp<flutter::DlImage> atlas,
777  const RSTransform xform[],
778  const DlRect tex[],
779  const flutter::DlColor colors[],
780  int count,
781  flutter::DlBlendMode mode,
782  flutter::DlImageSampling sampling,
783  const DlRect* cull_rect,
784  bool render_with_attributes) {
785  AUTO_DEPTH_WATCHER(1u);
786 
787  auto geometry =
788  DlAtlasGeometry(atlas->impeller_texture(), //
789  xform, //
790  tex, //
791  colors, //
792  static_cast<size_t>(count), //
795  skia_conversions::ToRect(cull_rect) //
796  );
797  auto atlas_contents = std::make_shared<AtlasContents>();
798  atlas_contents->SetGeometry(&geometry);
799 
800  GetCanvas().DrawAtlas(atlas_contents, paint_);
801 }
802 
803 // |flutter::DlOpReceiver|
805  const sk_sp<flutter::DisplayList> display_list,
806  DlScalar opacity) {
807  AUTO_DEPTH_WATCHER(display_list->total_depth());
808 
809  // Save all values that must remain untouched after the operation.
810  Paint saved_paint = paint_;
811  Matrix saved_initial_matrix = initial_matrix_;
812 
813  // Establish a new baseline for interpreting the new DL.
814  // Matrix and clip are left untouched, the current
815  // transform is saved as the new base matrix, and paint
816  // values are reset to defaults.
818  paint_ = Paint();
819 
820  // Handle passed opacity in the most brute-force way by using
821  // a SaveLayer. If the display_list is able to inherit the
822  // opacity, this could also be handled by modulating all of its
823  // attribute settings (for example, color), by the indicated
824  // opacity.
825  int restore_count = GetCanvas().GetSaveCount();
826  if (opacity < SK_Scalar1) {
827  Paint save_paint;
828  save_paint.color = Color(0, 0, 0, opacity);
830  save_paint, skia_conversions::ToRect(display_list->bounds()), nullptr,
831  ContentBoundsPromise::kContainsContents, display_list->total_depth(),
832  display_list->can_apply_group_opacity());
833  } else {
834  // The display list may alter the clip, which must be restored to the
835  // current clip at the end of playback.
836  GetCanvas().Save(display_list->total_depth());
837  }
838 
839  // TODO(131445): Remove this restriction if we can correctly cull with
840  // perspective transforms.
841  if (display_list->has_rtree() && !initial_matrix_.HasPerspective()) {
842  // The canvas remembers the screen-space culling bounds clipped by
843  // the surface and the history of clip calls. DisplayList can cull
844  // the ops based on a rectangle expressed in its "destination bounds"
845  // so we need the canvas to transform those into the current local
846  // coordinate space into which the DisplayList will be rendered.
847  auto global_culling_bounds = GetCanvas().GetLocalCoverageLimit();
848  if (global_culling_bounds.has_value()) {
849  Rect cull_rect = global_culling_bounds->TransformBounds(
850  GetCanvas().GetCurrentTransform().Invert());
851  display_list->Dispatch(
852  *this, SkRect::MakeLTRB(cull_rect.GetLeft(), cull_rect.GetTop(),
853  cull_rect.GetRight(), cull_rect.GetBottom()));
854  } else {
855  // If the culling bounds are empty, this display list can be skipped
856  // entirely.
857  }
858  } else {
859  display_list->Dispatch(*this);
860  }
861 
862  // Restore all saved state back to what it was before we interpreted
863  // the display_list
865  GetCanvas().RestoreToCount(restore_count);
866  initial_matrix_ = saved_initial_matrix;
867  paint_ = saved_paint;
868 }
869 
870 // |flutter::DlOpReceiver|
871 void DlDispatcherBase::drawTextBlob(const sk_sp<SkTextBlob> blob,
872  DlScalar x,
873  DlScalar y) {
874  // When running with Impeller enabled Skia text blobs are converted to
875  // Impeller text frames in paragraph_skia.cc
877 }
878 
879 // |flutter::DlOpReceiver|
881  const std::shared_ptr<TextFrame>& text_frame,
882  DlScalar x,
883  DlScalar y) {
884  AUTO_DEPTH_WATCHER(1u);
885 
886  GetCanvas().DrawTextFrame(text_frame, //
887  impeller::Point{x, y}, //
888  paint_ //
889  );
890 }
891 
892 // |flutter::DlOpReceiver|
894  const flutter::DlColor color,
895  const DlScalar elevation,
896  bool transparent_occluder,
897  DlScalar dpr) {
898  AUTO_DEPTH_WATCHER(1u);
899 
900  Color spot_color = skia_conversions::ToColor(color);
901  spot_color.alpha *= 0.25;
902 
903  // Compute the spot color -- ported from SkShadowUtils::ComputeTonalColors.
904  {
905  Scalar max =
906  std::max(std::max(spot_color.red, spot_color.green), spot_color.blue);
907  Scalar min =
908  std::min(std::min(spot_color.red, spot_color.green), spot_color.blue);
909  Scalar luminance = (min + max) * 0.5;
910 
911  Scalar alpha_adjust =
912  (2.6f + (-2.66667f + 1.06667f * spot_color.alpha) * spot_color.alpha) *
913  spot_color.alpha;
914  Scalar color_alpha =
915  (3.544762f + (-4.891428f + 2.3466f * luminance) * luminance) *
916  luminance;
917  color_alpha = std::clamp(alpha_adjust * color_alpha, 0.0f, 1.0f);
918 
919  Scalar greyscale_alpha =
920  std::clamp(spot_color.alpha * (1 - 0.4f * luminance), 0.0f, 1.0f);
921 
922  Scalar color_scale = color_alpha * (1 - greyscale_alpha);
923  Scalar tonal_alpha = color_scale + greyscale_alpha;
924  Scalar unpremul_scale = tonal_alpha != 0 ? color_scale / tonal_alpha : 0;
925  spot_color = Color(unpremul_scale * spot_color.red,
926  unpremul_scale * spot_color.green,
927  unpremul_scale * spot_color.blue, tonal_alpha);
928  }
929 
930  Vector3 light_position(0, -1, 1);
931  Scalar occluder_z = dpr * elevation;
932 
933  constexpr Scalar kLightRadius = 800 / 600; // Light radius / light height
934 
935  Paint paint;
936  paint.style = Paint::Style::kFill;
937  paint.color = spot_color;
940  .sigma = Radius{kLightRadius * occluder_z /
942  };
943 
944  GetCanvas().Save(1u);
946  Matrix::MakeTranslation(Vector2(0, -occluder_z * light_position.y)));
947 
948  SimplifyOrDrawPath(GetCanvas(), path, paint);
950 
951  GetCanvas().Restore();
952 }
953 
954 /// Subclasses
955 
957  const ContentContext& renderer,
958  flutter::DlBlendMode max_root_blend_mode) {
959  return !renderer.GetDeviceCapabilities().SupportsFramebufferFetch() &&
960  skia_conversions::ToBlendMode(max_root_blend_mode) >
962 }
963 
965  RenderTarget& render_target,
966  bool is_onscreen,
967  bool has_root_backdrop_filter,
968  flutter::DlBlendMode max_root_blend_mode,
969  IRect cull_rect)
970  : canvas_(renderer,
971  render_target,
972  is_onscreen,
973  has_root_backdrop_filter ||
974  RequiresReadbackForBlends(renderer, max_root_blend_mode),
975  cull_rect),
976  renderer_(renderer) {}
977 
978 Canvas& CanvasDlDispatcher::GetCanvas() {
979  return canvas_;
980 }
981 
983  const std::shared_ptr<flutter::DlVertices>& vertices,
984  flutter::DlBlendMode dl_mode) {
985  AUTO_DEPTH_WATCHER(1u);
986 
987  GetCanvas().DrawVertices(
988  std::make_shared<DlVerticesGeometry>(vertices, renderer_),
990 }
991 
993  std::unordered_map<int64_t, BackdropData> backdrop,
994  size_t backdrop_count) {
995  GetCanvas().SetBackdropData(std::move(backdrop), backdrop_count);
996 }
997 
998 //// Text Frame Dispatcher
999 
1001  const Matrix& initial_matrix,
1002  const Rect cull_rect)
1003  : renderer_(renderer), matrix_(initial_matrix) {
1004  cull_rect_state_.push_back(cull_rect);
1005 }
1006 
1008  FML_DCHECK(cull_rect_state_.size() == 1);
1009 }
1010 
1012  stack_.emplace_back(matrix_);
1013  cull_rect_state_.push_back(cull_rect_state_.back());
1014 }
1015 
1017  const flutter::SaveLayerOptions options,
1018  const flutter::DlImageFilter* backdrop,
1019  std::optional<int64_t> backdrop_id) {
1020  save();
1021 
1022  backdrop_count_ += (backdrop == nullptr ? 0 : 1);
1023  if (backdrop != nullptr && backdrop_id.has_value()) {
1024  std::shared_ptr<flutter::DlImageFilter> shared_backdrop =
1025  backdrop->shared();
1026  std::unordered_map<int64_t, BackdropData>::iterator existing =
1027  backdrop_data_.find(backdrop_id.value());
1028  if (existing == backdrop_data_.end()) {
1029  backdrop_data_[backdrop_id.value()] =
1030  BackdropData{.backdrop_count = 1, .last_backdrop = shared_backdrop};
1031  } else {
1032  BackdropData& data = existing->second;
1033  data.backdrop_count++;
1034  if (data.all_filters_equal) {
1035  data.all_filters_equal = (*data.last_backdrop == *shared_backdrop);
1036  data.last_backdrop = shared_backdrop;
1037  }
1038  }
1039  }
1040 
1041  // This dispatcher does not track enough state to accurately compute
1042  // cull rects with image filters.
1043  auto global_cull_rect = cull_rect_state_.back();
1044  if (has_image_filter_ || global_cull_rect.IsMaximum()) {
1045  cull_rect_state_.back() = Rect::MakeMaximum();
1046  } else {
1047  auto global_save_bounds = bounds.TransformBounds(matrix_);
1048  auto new_cull_rect = global_cull_rect.Intersection(global_save_bounds);
1049  if (new_cull_rect.has_value()) {
1050  cull_rect_state_.back() = new_cull_rect.value();
1051  } else {
1052  cull_rect_state_.back() = Rect::MakeLTRB(0, 0, 0, 0);
1053  }
1054  }
1055 }
1056 
1058  matrix_ = stack_.back();
1059  stack_.pop_back();
1060  cull_rect_state_.pop_back();
1061 }
1062 
1064  matrix_ = matrix_.Translate({tx, ty});
1065 }
1066 
1068  matrix_ = matrix_.Scale({sx, sy, 1.0f});
1069 }
1070 
1072  matrix_ = matrix_ * Matrix::MakeRotationZ(Degrees(degrees));
1073 }
1074 
1076  matrix_ = matrix_ * Matrix::MakeSkew(sx, sy);
1077 }
1078 
1079 // clang-format off
1080  // 2x3 2D affine subset of a 4x4 transform in row major order
1082  DlScalar myx, DlScalar myy, DlScalar myt) {
1083  matrix_ = matrix_ * Matrix::MakeColumn(
1084  mxx, myx, 0.0f, 0.0f,
1085  mxy, myy, 0.0f, 0.0f,
1086  0.0f, 0.0f, 1.0f, 0.0f,
1087  mxt, myt, 0.0f, 1.0f
1088  );
1089  }
1090 
1091  // full 4x4 transform in row major order
1093  DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt,
1094  DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt,
1095  DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt,
1096  DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) {
1097  matrix_ = matrix_ * Matrix::MakeColumn(
1098  mxx, myx, mzx, mwx,
1099  mxy, myy, mzy, mwy,
1100  mxz, myz, mzz, mwz,
1101  mxt, myt, mzt, mwt
1102  );
1103  }
1104 // clang-format on
1105 
1107  matrix_ = Matrix();
1108 }
1109 
1111  const std::shared_ptr<impeller::TextFrame>& text_frame,
1112  DlScalar x,
1113  DlScalar y) {
1114  GlyphProperties properties;
1115  if (paint_.style == Paint::Style::kStroke) {
1116  properties.stroke = true;
1117  properties.stroke_cap = paint_.stroke_cap;
1118  properties.stroke_join = paint_.stroke_join;
1119  properties.stroke_miter = paint_.stroke_miter;
1120  properties.stroke_width = paint_.stroke_width;
1121  }
1122  if (text_frame->HasColor()) {
1123  // Alpha is always applied when rendering, remove it here so
1124  // we do not double-apply the alpha.
1125  properties.color = paint_.color.WithAlpha(1.0);
1126  }
1128  (matrix_ * Matrix::MakeTranslation(Point(x, y))).GetMaxBasisLengthXY());
1129 
1130  renderer_.GetLazyGlyphAtlas()->AddTextFrame(
1131  text_frame, //
1132  scale, //
1133  Point(x, y), //
1134  matrix_,
1135  (properties.stroke || text_frame->HasColor()) //
1136  ? std::optional<GlyphProperties>(properties) //
1137  : std::nullopt //
1138  );
1139 }
1140 
1141 const Rect FirstPassDispatcher::GetCurrentLocalCullingBounds() const {
1142  auto cull_rect = cull_rect_state_.back();
1143  if (!cull_rect.IsEmpty() && !cull_rect.IsMaximum()) {
1144  Matrix inverse = matrix_.Invert();
1145  cull_rect = cull_rect.TransformBounds(inverse);
1146  }
1147  return cull_rect;
1148 }
1149 
1151  const sk_sp<flutter::DisplayList> display_list,
1152  DlScalar opacity) {
1153  [[maybe_unused]] size_t stack_depth = stack_.size();
1154  save();
1155  Paint old_paint = paint_;
1156  paint_ = Paint{};
1157  bool old_has_image_filter = has_image_filter_;
1158  has_image_filter_ = false;
1159 
1160  if (matrix_.HasPerspective()) {
1161  display_list->Dispatch(*this);
1162  } else {
1163  Rect local_cull_bounds = GetCurrentLocalCullingBounds();
1164  if (local_cull_bounds.IsMaximum()) {
1165  display_list->Dispatch(*this);
1166  } else if (!local_cull_bounds.IsEmpty()) {
1167  IRect cull_rect = IRect::RoundOut(local_cull_bounds);
1168  display_list->Dispatch(*this,
1169  SkIRect::MakeLTRB(cull_rect.GetLeft(), //
1170  cull_rect.GetTop(), //
1171  cull_rect.GetRight(), //
1172  cull_rect.GetBottom() //
1173  ));
1174  }
1175  }
1176 
1177  restore();
1178  paint_ = old_paint;
1179  has_image_filter_ = old_has_image_filter;
1180  FML_DCHECK(stack_depth == stack_.size());
1181 }
1182 
1183 // |flutter::DlOpReceiver|
1184 void FirstPassDispatcher::setDrawStyle(flutter::DlDrawStyle style) {
1185  paint_.style = ToStyle(style);
1186 }
1187 
1188 // |flutter::DlOpReceiver|
1189 void FirstPassDispatcher::setColor(flutter::DlColor color) {
1190  paint_.color = skia_conversions::ToColor(color);
1191 }
1192 
1193 // |flutter::DlOpReceiver|
1195  paint_.stroke_width = width;
1196 }
1197 
1198 // |flutter::DlOpReceiver|
1200  paint_.stroke_miter = limit;
1201 }
1202 
1203 // |flutter::DlOpReceiver|
1204 void FirstPassDispatcher::setStrokeCap(flutter::DlStrokeCap cap) {
1205  switch (cap) {
1206  case flutter::DlStrokeCap::kButt:
1207  paint_.stroke_cap = Cap::kButt;
1208  break;
1209  case flutter::DlStrokeCap::kRound:
1210  paint_.stroke_cap = Cap::kRound;
1211  break;
1212  case flutter::DlStrokeCap::kSquare:
1213  paint_.stroke_cap = Cap::kSquare;
1214  break;
1215  }
1216 }
1217 
1218 // |flutter::DlOpReceiver|
1219 void FirstPassDispatcher::setStrokeJoin(flutter::DlStrokeJoin join) {
1220  switch (join) {
1221  case flutter::DlStrokeJoin::kMiter:
1222  paint_.stroke_join = Join::kMiter;
1223  break;
1224  case flutter::DlStrokeJoin::kRound:
1225  paint_.stroke_join = Join::kRound;
1226  break;
1227  case flutter::DlStrokeJoin::kBevel:
1228  paint_.stroke_join = Join::kBevel;
1229  break;
1230  }
1231 }
1232 
1233 // |flutter::DlOpReceiver|
1234 void FirstPassDispatcher::setImageFilter(const flutter::DlImageFilter* filter) {
1235  if (filter == nullptr) {
1236  has_image_filter_ = false;
1237  } else {
1238  has_image_filter_ = true;
1239  }
1240 }
1241 
1242 std::pair<std::unordered_map<int64_t, BackdropData>, size_t>
1244  std::unordered_map<int64_t, BackdropData> temp;
1245  std::swap(temp, backdrop_data_);
1246  return std::make_pair(temp, backdrop_count_);
1247 }
1248 
1249 std::shared_ptr<Texture> DisplayListToTexture(
1250  const sk_sp<flutter::DisplayList>& display_list,
1251  ISize size,
1252  AiksContext& context,
1253  bool reset_host_buffer,
1254  bool generate_mips) {
1255  int mip_count = 1;
1256  if (generate_mips) {
1257  mip_count = size.MipCount();
1258  }
1259  // Do not use the render target cache as the lifecycle of this texture
1260  // will outlive a particular frame.
1261  impeller::RenderTargetAllocator render_target_allocator =
1263  context.GetContext()->GetResourceAllocator());
1264  impeller::RenderTarget target;
1265  if (context.GetContext()->GetCapabilities()->SupportsOffscreenMSAA()) {
1266  target = render_target_allocator.CreateOffscreenMSAA(
1267  *context.GetContext(), // context
1268  size, // size
1269  /*mip_count=*/mip_count,
1270  "Picture Snapshot MSAA", // label
1272  kDefaultColorAttachmentConfigMSAA // color_attachment_config
1273  );
1274  } else {
1275  target = render_target_allocator.CreateOffscreen(
1276  *context.GetContext(), // context
1277  size, // size
1278  /*mip_count=*/mip_count,
1279  "Picture Snapshot", // label
1281  kDefaultColorAttachmentConfig // color_attachment_config
1282  );
1283  }
1284  if (!target.IsValid()) {
1285  return nullptr;
1286  }
1287 
1288  SkIRect sk_cull_rect = SkIRect::MakeWH(size.width, size.height);
1290  context.GetContentContext(), impeller::Matrix(), Rect::MakeSize(size));
1291  display_list->Dispatch(collector, sk_cull_rect);
1292  impeller::CanvasDlDispatcher impeller_dispatcher(
1293  context.GetContentContext(), //
1294  target, //
1295  /*is_onscreen=*/false, //
1296  display_list->root_has_backdrop_filter(), //
1297  display_list->max_root_blend_mode(), //
1298  impeller::IRect::MakeSize(size) //
1299  );
1300  const auto& [data, count] = collector.TakeBackdropData();
1301  impeller_dispatcher.SetBackdropData(data, count);
1302  display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
1303  impeller_dispatcher.FinishRecording();
1304 
1305  if (reset_host_buffer) {
1307  }
1308  context.GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames();
1309  context.GetContext()->DisposeThreadLocalCachedResources();
1310 
1311  return target.GetRenderTargetTexture();
1312 }
1313 
1315  RenderTarget render_target,
1316  const sk_sp<flutter::DisplayList>& display_list,
1317  SkIRect cull_rect,
1318  bool reset_host_buffer,
1319  bool is_onscreen) {
1320  Rect ip_cull_rect = Rect::MakeLTRB(cull_rect.left(), cull_rect.top(),
1321  cull_rect.right(), cull_rect.bottom());
1322  FirstPassDispatcher collector(context, impeller::Matrix(), ip_cull_rect);
1323  display_list->Dispatch(collector, cull_rect);
1324 
1325  impeller::CanvasDlDispatcher impeller_dispatcher(
1326  context, //
1327  render_target, //
1328  /*is_onscreen=*/is_onscreen, //
1329  display_list->root_has_backdrop_filter(), //
1330  display_list->max_root_blend_mode(), //
1331  IRect::RoundOut(ip_cull_rect) //
1332  );
1333  const auto& [data, count] = collector.TakeBackdropData();
1334  impeller_dispatcher.SetBackdropData(data, count);
1335  display_list->Dispatch(impeller_dispatcher, cull_rect);
1336  impeller_dispatcher.FinishRecording();
1337  if (reset_host_buffer) {
1338  context.GetTransientsBuffer().Reset();
1339  }
1340  context.GetLazyGlyphAtlas()->ResetTextFrames();
1341 
1342  return true;
1343 }
1344 
1345 } // 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:566
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:1558
std::optional< Rect > GetLocalCoverageLimit() const
Return the culling bounds of the current render target, or nullopt if there is no coverage.
Definition: canvas.cc:935
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:966
const Matrix & GetCurrentTransform() const
Definition: canvas.cc:238
void DrawVertices(const std::shared_ptr< VerticesGeometry > &vertices, BlendMode blend_mode, const Paint &paint)
Definition: canvas.cc:739
void DrawOval(const Rect &rect, const Paint &paint)
Definition: canvas.cc:486
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:679
void RestoreToCount(size_t count)
Definition: canvas.cc:285
bool Restore()
Definition: canvas.cc:1204
size_t GetSaveCount() const
Definition: canvas.cc:277
void Transform(const Matrix &transform)
Definition: canvas.cc:234
uint64_t GetMaxOpDepth() const
Definition: canvas.h:244
void PreConcat(const Matrix &transform)
Definition: canvas.cc:226
void Rotate(Radians radians)
Definition: canvas.cc:258
void DrawPoints(const Point points[], uint32_t count, Scalar radius, const Paint &paint, PointStyle point_style)
Definition: canvas.cc:647
void ResetTransform()
Definition: canvas.cc:230
void DrawTextFrame(const std::shared_ptr< TextFrame > &text_frame, Point position, const Paint &paint)
Definition: canvas.cc:1346
void DrawPaint(const Paint &paint)
Definition: canvas.cc:308
void DrawRoundRect(const RoundRect &rect, const Paint &paint)
Definition: canvas.cc:516
void Skew(Scalar sx, Scalar sy)
Definition: canvas.cc:254
void Scale(const Vector2 &scale)
Definition: canvas.cc:246
uint64_t GetOpDepth() const
Definition: canvas.h:242
void DrawPath(const Path &path, const Paint &paint)
Definition: canvas.cc:293
void Save(uint32_t total_content_depth=kMaxDepth)
Definition: canvas.cc:918
void DrawRect(const Rect &rect, const Paint &paint)
Definition: canvas.cc:468
void DrawAtlas(const std::shared_ptr< AtlasContents > &atlas_contents, const Paint &paint)
Definition: canvas.cc:852
void DrawLine(const Point &p0, const Point &p1, const Paint &paint, bool reuse_depth=false)
Definition: canvas.cc:455
void Translate(const Vector3 &offset)
Definition: canvas.cc:242
void DrawCircle(const Point &center, Scalar radius, const Paint &paint)
Definition: canvas.cc:543
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
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 clipRoundRect(const DlRoundRect &rrect, ClipOp clip_op, bool is_aa) 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 clipRect(const DlRect &rect, ClipOp clip_op, bool is_aa) 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, ClipOp clip_op, bool is_aa) override
void skew(DlScalar sx, DlScalar sy) 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 drawPoints(PointMode mode, uint32_t count, const DlPoint points[]) override
void drawImageRect(const sk_sp< flutter::DlImage > image, const DlRect &src, const DlRect &dst, flutter::DlImageSampling sampling, bool render_with_attributes, SrcRectConstraint constraint) 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 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 clipPath(const DlPath &path, ClipOp clip_op, bool is_aa) 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 Reset()
Resets the contents of the HostBuffer to nothing so it can be reused.
Definition: host_buffer.cc:224
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:28
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:64
PathBuilder & MoveTo(Point point, bool relative=false)
Definition: path_builder.cc:45
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 Scalar RoundScaledFontSize(Scalar scale)
Definition: text_frame.cc:41
#define AUTO_DEPTH_WATCHER(d)
#define UNIMPLEMENTED
#define AUTO_DEPTH_CHECK()
int32_t x
BlendMode ToBlendMode(flutter::DlBlendMode mode)
Size ToSize(const SkPoint &point)
impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlImageSampling options)
Rect ToRect(const SkRect &rect)
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
PointStyle
Definition: canvas.h:60
@ kRound
Points are drawn as squares.
@ kSquare
Points are drawn as circles.
TPoint< Scalar > Point
Definition: point.h:327
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
static bool RequiresReadbackForBlends(const ContentContext &renderer, flutter::DlBlendMode max_root_blend_mode)
Subclasses.
static Entity::ClipOperation ToClipOperation(flutter::DlCanvas::ClipOp clip_op)
static impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlFilterMode options)
flutter::DlPath DlPath
Definition: dl_dispatcher.h:28
@ 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:171
@ 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:36
Scalar blue
Definition: color.h:137
Scalar alpha
Definition: color.h:142
constexpr Color WithAlpha(Scalar new_alpha) const
Definition: color.h:277
Scalar red
Definition: color.h:127
Scalar green
Definition: color.h:132
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:250
constexpr Vector3 GetScale() const
Definition: matrix.h:328
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:262
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:223
constexpr bool HasPerspective() const
Definition: matrix.h:352
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
Definition: size.h:140
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:64