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