Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
dl_dispatcher.cc File Reference

Go to the source code of this file.

Namespaces

namespace  impeller
 

Macros

#define USE_DEPTH_WATCHER   true
 
#define AUTO_DEPTH_WATCHER(d)
 
#define AUTO_DEPTH_CHECK()
 
#define UNIMPLEMENTED    FML_DLOG(ERROR) << "Unimplemented detail in " << __FUNCTION__;
 

Functions

static impeller::SamplerDescriptor impeller::ToSamplerDescriptor (const flutter::DlFilterMode options)
 
static std::optional< const Rectimpeller::ToOptRect (const flutter::DlRect *rect)
 
static Paint::Style impeller::ToStyle (flutter::DlDrawStyle style)
 
static FilterContents::BlurStyle impeller::ToBlurStyle (flutter::DlBlurStyle blur_style)
 
static Entity::ClipOperation impeller::ToClipOperation (flutter::DlClipOp clip_op)
 
static bool impeller::RequiresReadbackForBlends (const ContentContext &renderer, flutter::DlBlendMode max_root_blend_mode)
 Subclasses.
 
std::shared_ptr< Textureimpeller::DisplayListToTexture (const sk_sp< flutter::DisplayList > &display_list, ISize size, AiksContext &context, bool reset_host_buffer=true, bool generate_mips=false, std::optional< PixelFormat > target_pixel_format=std::nullopt)
 Render the provided display list to a texture with the given size.
 
bool impeller::RenderToTarget (ContentContext &context, RenderTarget render_target, const sk_sp< flutter::DisplayList > &display_list, Rect cull_rect, bool reset_host_buffer, bool is_onscreen=true)
 Render the provided display list to the render target.
 

Macro Definition Documentation

◆ AUTO_DEPTH_CHECK

#define AUTO_DEPTH_CHECK ( )

Definition at line 116 of file dl_dispatcher.cc.

◆ AUTO_DEPTH_WATCHER

#define AUTO_DEPTH_WATCHER (   d)

Definition at line 115 of file dl_dispatcher.cc.

◆ UNIMPLEMENTED

#define UNIMPLEMENTED    FML_DLOG(ERROR) << "Unimplemented detail in " << __FUNCTION__;

Definition at line 120 of file dl_dispatcher.cc.

123 {
125 switch (options) {
128 desc.label = "Nearest Sampler";
129 break;
132 desc.label = "Linear Sampler";
133 break;
134 default:
135 break;
136 }
137 return desc;
138}
139
140static 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|
148void DlDispatcherBase::setAntiAlias(bool aa) {
150
151 paint_.anti_alias = aa;
152}
153
154static Paint::Style ToStyle(flutter::DlDrawStyle style) {
155 switch (style) {
157 return Paint::Style::kFill;
159 return Paint::Style::kStroke;
162 break;
163 }
164 return Paint::Style::kFill;
165}
166
167// |flutter::DlOpReceiver|
168void DlDispatcherBase::setDrawStyle(flutter::DlDrawStyle style) {
170
171 paint_.style = ToStyle(style);
172}
173
174// |flutter::DlOpReceiver|
175void DlDispatcherBase::setColor(flutter::DlColor color) {
177
178 paint_.color = skia_conversions::ToColor(color);
179}
180
181// |flutter::DlOpReceiver|
182void DlDispatcherBase::setStrokeWidth(DlScalar width) {
184
185 paint_.stroke.width = width;
186}
187
188// |flutter::DlOpReceiver|
189void DlDispatcherBase::setStrokeMiter(DlScalar limit) {
191
192 paint_.stroke.miter_limit = limit;
193}
194
195// |flutter::DlOpReceiver|
196void DlDispatcherBase::setStrokeCap(flutter::DlStrokeCap cap) {
198
199 switch (cap) {
201 paint_.stroke.cap = Cap::kButt;
202 break;
204 paint_.stroke.cap = Cap::kRound;
205 break;
207 paint_.stroke.cap = Cap::kSquare;
208 break;
209 }
210}
211
212// |flutter::DlOpReceiver|
213void DlDispatcherBase::setStrokeJoin(flutter::DlStrokeJoin join) {
215
216 switch (join) {
218 paint_.stroke.join = Join::kMiter;
219 break;
221 paint_.stroke.join = Join::kRound;
222 break;
224 paint_.stroke.join = Join::kBevel;
225 break;
226 }
227}
228
229// |flutter::DlOpReceiver|
230void DlDispatcherBase::setColorSource(const flutter::DlColorSource* source) {
232
233 paint_.color_source = source;
234}
235
236// |flutter::DlOpReceiver|
237void DlDispatcherBase::setColorFilter(const flutter::DlColorFilter* filter) {
239
240 paint_.color_filter = filter;
241}
242
243// |flutter::DlOpReceiver|
244void DlDispatcherBase::setInvertColors(bool invert) {
246
247 paint_.invert_colors = invert;
248}
249
250// |flutter::DlOpReceiver|
251void DlDispatcherBase::setBlendMode(flutter::DlBlendMode dl_mode) {
253
254 paint_.blend_mode = dl_mode;
255}
256
257static FilterContents::BlurStyle ToBlurStyle(flutter::DlBlurStyle blur_style) {
258 switch (blur_style) {
260 return FilterContents::BlurStyle::kNormal;
262 return FilterContents::BlurStyle::kSolid;
264 return FilterContents::BlurStyle::kOuter;
266 return FilterContents::BlurStyle::kInner;
267 }
268}
269
270// |flutter::DlOpReceiver|
271void DlDispatcherBase::setMaskFilter(const flutter::DlMaskFilter* filter) {
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()) {
281 auto blur = filter->asBlur();
282
283 paint_.mask_blur_descriptor = {
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|
294void DlDispatcherBase::setImageFilter(const flutter::DlImageFilter* filter) {
296
297 paint_.image_filter = filter;
298}
299
300// |flutter::DlOpReceiver|
301void DlDispatcherBase::save(uint32_t total_content_depth) {
303
304 GetCanvas().Save(total_content_depth);
305}
306
307// |flutter::DlOpReceiver|
308void DlDispatcherBase::saveLayer(const DlRect& bounds,
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) {
315
316 auto paint = options.renders_with_attributes() ? paint_ : Paint{};
317 auto promise = options.content_is_clipped()
318 ? ContentBoundsPromise::kMayClipContents
319 : ContentBoundsPromise::kContainsContents;
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
327 GetCanvas().SaveLayer(
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|
337void DlDispatcherBase::restore() {
338 GetCanvas().Restore();
339}
340
341// |flutter::DlOpReceiver|
342void DlDispatcherBase::translate(DlScalar tx, DlScalar ty) {
344
345 GetCanvas().Translate({tx, ty, 0.0});
346}
347
348// |flutter::DlOpReceiver|
349void DlDispatcherBase::scale(DlScalar sx, DlScalar sy) {
351
352 GetCanvas().Scale({sx, sy, 1.0});
353}
354
355// |flutter::DlOpReceiver|
356void DlDispatcherBase::rotate(DlScalar degrees) {
358
359 GetCanvas().Rotate(Degrees{degrees});
360}
361
362// |flutter::DlOpReceiver|
363void DlDispatcherBase::skew(DlScalar sx, DlScalar sy) {
365
366 GetCanvas().Skew(sx, sy);
367}
368
369// clang-format off
370// |flutter::DlOpReceiver|
371void DlDispatcherBase::transform2DAffine(
372 DlScalar mxx, DlScalar mxy, DlScalar mxt,
373 DlScalar myx, DlScalar myy, DlScalar myt) {
375
376 transformFullPerspective(
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|
387void DlDispatcherBase::transformFullPerspective(
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) {
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 };
402 GetCanvas().Transform(transform);
403}
404// clang-format on
405
406// |flutter::DlOpReceiver|
407void DlDispatcherBase::transformReset() {
409
410 GetCanvas().ResetTransform();
411 GetCanvas().Transform(initial_matrix_);
412}
413
414static Entity::ClipOperation ToClipOperation(flutter::DlClipOp clip_op) {
415 switch (clip_op) {
417 return Entity::ClipOperation::kDifference;
419 return Entity::ClipOperation::kIntersect;
420 }
421}
422
423// |flutter::DlOpReceiver|
424void DlDispatcherBase::clipRect(const DlRect& rect,
425 flutter::DlClipOp clip_op,
426 bool is_aa) {
428
429 FillRectGeometry geom(rect);
430 GetCanvas().ClipGeometry(geom, ToClipOperation(clip_op), /*is_aa=*/is_aa);
431}
432
433// |flutter::DlOpReceiver|
434void DlDispatcherBase::clipOval(const DlRect& bounds,
435 flutter::DlClipOp clip_op,
436 bool is_aa) {
438
439 EllipseGeometry geom(bounds);
440 GetCanvas().ClipGeometry(geom, ToClipOperation(clip_op));
441}
442
443// |flutter::DlOpReceiver|
444void DlDispatcherBase::clipRoundRect(const DlRoundRect& rrect,
445 flutter::DlClipOp sk_op,
446 bool is_aa) {
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|
466void DlDispatcherBase::clipRoundSuperellipse(const DlRoundSuperellipse& rse,
467 flutter::DlClipOp sk_op,
468 bool is_aa) {
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|
485void DlDispatcherBase::clipPath(const DlPath& path,
486 flutter::DlClipOp sk_op,
487 bool is_aa) {
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|
512void DlDispatcherBase::drawColor(flutter::DlColor color,
513 flutter::DlBlendMode dl_mode) {
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|
523void DlDispatcherBase::drawPaint() {
525
526 GetCanvas().DrawPaint(paint_);
527}
528
529// |flutter::DlOpReceiver|
530void DlDispatcherBase::drawLine(const DlPoint& p0, const DlPoint& p1) {
532
533 GetCanvas().DrawLine(p0, p1, paint_);
534}
535
536// |flutter::DlOpReceiver|
537void DlDispatcherBase::drawDashedLine(const DlPoint& p0,
538 const DlPoint& p1,
539 DlScalar on_length,
540 DlScalar off_length) {
542
543 GetCanvas().DrawDashedLine(p0, p1, on_length, off_length, paint_);
544}
545
546// |flutter::DlOpReceiver|
547void DlDispatcherBase::drawRect(const DlRect& rect) {
549
550 GetCanvas().DrawRect(rect, paint_);
551}
552
553// |flutter::DlOpReceiver|
554void DlDispatcherBase::drawOval(const DlRect& bounds) {
556
557 GetCanvas().DrawOval(bounds, paint_);
558}
559
560// |flutter::DlOpReceiver|
561void DlDispatcherBase::drawCircle(const DlPoint& center, DlScalar radius) {
563
564 GetCanvas().DrawCircle(center, radius, paint_);
565}
566
567// |flutter::DlOpReceiver|
568void DlDispatcherBase::drawRoundRect(const DlRoundRect& rrect) {
570
571 GetCanvas().DrawRoundRect(rrect, paint_);
572}
573
574// |flutter::DlOpReceiver|
575void DlDispatcherBase::drawDiffRoundRect(const DlRoundRect& outer,
576 const DlRoundRect& inner) {
578
579 GetCanvas().DrawDiffRoundRect(outer, inner, paint_);
580}
581
582// |flutter::DlOpReceiver|
583void DlDispatcherBase::drawRoundSuperellipse(const DlRoundSuperellipse& rse) {
585
586 GetCanvas().DrawRoundSuperellipse(rse, paint_);
587}
588
589// |flutter::DlOpReceiver|
590void DlDispatcherBase::drawPath(const DlPath& path) {
592
593 GetCanvas().DrawPath(path, paint_);
594}
595
596void DlDispatcherBase::SimplifyOrDrawPath(Canvas& canvas,
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
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|
630void DlDispatcherBase::drawArc(const DlRect& oval_bounds,
631 DlScalar start_degrees,
632 DlScalar sweep_degrees,
633 bool use_center) {
635
636 GetCanvas().DrawArc(Arc(oval_bounds, Degrees(start_degrees),
637 Degrees(sweep_degrees), use_center),
638 paint_);
639}
640
641// |flutter::DlOpReceiver|
642void DlDispatcherBase::drawPoints(flutter::DlPointMode mode,
643 uint32_t count,
644 const DlPoint points[]) {
646
647 Paint paint = paint_;
648 paint.style = Paint::Style::kStroke;
649 switch (mode) {
651 // Cap::kButt is also treated as a square.
652 PointStyle point_style = paint.stroke.cap == Cap::kRound
653 ? PointStyle::kRound
654 : PointStyle::kSquare;
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;
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;
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
681std::shared_ptr<Texture> DlDispatcherBase::GetTexture(
682 const sk_sp<flutter::DlImage>& image) {
683 if (!image) {
684 return nullptr;
685 }
686 return image->asImpellerImage()->GetCachedTexture(GetContentContext());
687}
688
689void DlDispatcherBase::drawVertices(
690 const std::shared_ptr<flutter::DlVertices>& vertices,
691 flutter::DlBlendMode dl_mode) {}
692
693// |flutter::DlOpReceiver|
694void DlDispatcherBase::drawImage(const sk_sp<flutter::DlImage> image,
695 const DlPoint& point,
697 bool render_with_attributes) {
699
700 if (!image) {
701 return;
702 }
703
704 auto texture = GetTexture(image);
705 if (!texture) {
706 return;
707 }
708
709 const auto size = texture->GetSize();
710 const auto src = DlRect::MakeWH(size.width, size.height);
711 const auto dest = DlRect::MakeXYWH(point.x, point.y, size.width, size.height);
712
713 drawImageRect(image, // image
714 src, // source rect
715 dest, // destination rect
716 sampling, // sampling options
717 render_with_attributes, // render with attributes
719 );
720}
721
722// |flutter::DlOpReceiver|
723void DlDispatcherBase::drawImageRect(const sk_sp<flutter::DlImage> image,
724 const DlRect& src,
725 const DlRect& dst,
727 bool render_with_attributes,
731
732 GetCanvas().DrawImageRect(
733 GetTexture(image), // image
734 src, // source rect
735 dst, // destination rect
736 render_with_attributes ? paint_ : Paint(), // paint
737 skia_conversions::ToSamplerDescriptor(sampling) // sampling
738 );
739}
740
741// |flutter::DlOpReceiver|
742void DlDispatcherBase::drawImageNine(const sk_sp<flutter::DlImage> image,
743 const DlIRect& center,
744 const DlRect& dst,
746 bool render_with_attributes) {
748
749 NinePatchConverter converter = {};
750 converter.DrawNinePatch(GetTexture(image),
751 Rect::MakeLTRB(center.GetLeft(), center.GetTop(),
752 center.GetRight(), center.GetBottom()),
753 dst, ToSamplerDescriptor(filter), &GetCanvas(),
754 &paint_);
755}
756
757// |flutter::DlOpReceiver|
758void DlDispatcherBase::drawAtlas(const sk_sp<flutter::DlImage> atlas,
759 const RSTransform xform[],
760 const DlRect tex[],
761 const flutter::DlColor colors[],
762 int count,
765 const DlRect* cull_rect,
766 bool render_with_attributes) {
768
769 auto geometry =
770 DlAtlasGeometry(GetTexture(atlas), //
771 xform, //
772 tex, //
773 colors, //
774 static_cast<size_t>(count), //
775 mode, //
776 skia_conversions::ToSamplerDescriptor(sampling), //
777 ToOptRect(cull_rect) //
778 );
779 auto atlas_contents = std::make_shared<AtlasContents>();
780 atlas_contents->SetGeometry(&geometry);
781
782 GetCanvas().DrawAtlas(atlas_contents, paint_);
783}
784
785// |flutter::DlOpReceiver|
786void DlDispatcherBase::drawDisplayList(
787 const sk_sp<flutter::DisplayList> display_list,
788 DlScalar opacity) {
789 AUTO_DEPTH_WATCHER(display_list->total_depth());
790
791 // Save all values that must remain untouched after the operation.
792 Paint saved_paint = paint_;
793 Matrix saved_initial_matrix = initial_matrix_;
794
795 // Establish a new baseline for interpreting the new DL.
796 // Matrix and clip are left untouched, the current
797 // transform is saved as the new base matrix, and paint
798 // values are reset to defaults.
799 initial_matrix_ = GetCanvas().GetCurrentTransform();
800 paint_ = Paint();
801
802 // Handle passed opacity in the most brute-force way by using
803 // a SaveLayer. If the display_list is able to inherit the
804 // opacity, this could also be handled by modulating all of its
805 // attribute settings (for example, color), by the indicated
806 // opacity.
807 int restore_count = GetCanvas().GetSaveCount();
808 if (opacity < SK_Scalar1) {
809 Paint save_paint;
810 save_paint.color = Color(0, 0, 0, opacity);
811 GetCanvas().SaveLayer(save_paint, display_list->GetBounds(), nullptr,
812 ContentBoundsPromise::kContainsContents,
813 display_list->total_depth(),
814 display_list->can_apply_group_opacity());
815 } else {
816 // The display list may alter the clip, which must be restored to the
817 // current clip at the end of playback.
818 GetCanvas().Save(display_list->total_depth());
819 }
820
821 // TODO(131445): Remove this restriction if we can correctly cull with
822 // perspective transforms.
823 if (display_list->has_rtree() && !initial_matrix_.HasPerspective()) {
824 // The canvas remembers the screen-space culling bounds clipped by
825 // the surface and the history of clip calls. DisplayList can cull
826 // the ops based on a rectangle expressed in its "destination bounds"
827 // so we need the canvas to transform those into the current local
828 // coordinate space into which the DisplayList will be rendered.
829 auto global_culling_bounds = GetCanvas().GetLocalCoverageLimit();
830 if (global_culling_bounds.has_value()) {
831 Rect cull_rect = global_culling_bounds->TransformBounds(
832 GetCanvas().GetCurrentTransform().Invert());
833 display_list->Dispatch(*this, cull_rect);
834 } else {
835 // If the culling bounds are empty, this display list can be skipped
836 // entirely.
837 }
838 } else {
839 display_list->Dispatch(*this);
840 }
841
842 // Restore all saved state back to what it was before we interpreted
843 // the display_list
845 GetCanvas().RestoreToCount(restore_count);
846 initial_matrix_ = saved_initial_matrix;
847 paint_ = saved_paint;
848}
849
850// |flutter::DlOpReceiver|
851void DlDispatcherBase::drawText(const std::shared_ptr<flutter::DlText>& text,
852 DlScalar x,
853 DlScalar y) {
855
856 auto text_frame = text->GetTextFrame();
857
858 // When running with Impeller enabled Skia text blobs are converted to
859 // Impeller text frames in paragraph_skia.cc
860 FML_CHECK(text_frame != nullptr);
861 GetCanvas().DrawTextFrame(text_frame, //
862 impeller::Point{x, y}, //
863 paint_ //
864 );
865}
866
867// |flutter::DlOpReceiver|
868void DlDispatcherBase::drawShadow(const DlPath& path,
869 const flutter::DlColor color,
870 const DlScalar elevation,
871 bool transparent_occluder,
872 DlScalar dpr) {
874
875 Color spot_color = skia_conversions::ToColor(color);
876 spot_color.alpha *= 0.25;
877
878 // Compute the spot color -- ported from SkShadowUtils::ComputeTonalColors.
879 {
880 Scalar max =
881 std::max(std::max(spot_color.red, spot_color.green), spot_color.blue);
882 Scalar min =
883 std::min(std::min(spot_color.red, spot_color.green), spot_color.blue);
884 Scalar luminance = (min + max) * 0.5;
885
886 Scalar alpha_adjust =
887 (2.6f + (-2.66667f + 1.06667f * spot_color.alpha) * spot_color.alpha) *
888 spot_color.alpha;
889 Scalar color_alpha =
890 (3.544762f + (-4.891428f + 2.3466f * luminance) * luminance) *
891 luminance;
892 color_alpha = std::clamp(alpha_adjust * color_alpha, 0.0f, 1.0f);
893
894 Scalar greyscale_alpha =
895 std::clamp(spot_color.alpha * (1 - 0.4f * luminance), 0.0f, 1.0f);
896
897 Scalar color_scale = color_alpha * (1 - greyscale_alpha);
898 Scalar tonal_alpha = color_scale + greyscale_alpha;
899 Scalar unpremul_scale = tonal_alpha != 0 ? color_scale / tonal_alpha : 0;
900 spot_color = Color(unpremul_scale * spot_color.red,
901 unpremul_scale * spot_color.green,
902 unpremul_scale * spot_color.blue, tonal_alpha);
903 }
904
905 Vector3 light_position(0, -1, 1);
906 Scalar occluder_z = dpr * elevation;
907
908 constexpr Scalar kLightRadius = 800 / 600; // Light radius / light height
909
910 Paint paint;
911 paint.style = Paint::Style::kFill;
912 paint.color = spot_color;
913 paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
914 .style = FilterContents::BlurStyle::kNormal,
915 .sigma = Radius{kLightRadius * occluder_z /
916 GetCanvas().GetCurrentTransform().GetScale().y},
917 };
918
919 GetCanvas().Save(1u);
920 GetCanvas().PreConcat(
921 Matrix::MakeTranslation(Vector2(0, -occluder_z * light_position.y)));
922
923 SimplifyOrDrawPath(GetCanvas(), path, paint);
925
926 GetCanvas().Restore();
927}
928
929/// Subclasses
930
931static bool RequiresReadbackForBlends(
932 const ContentContext& renderer,
933 flutter::DlBlendMode max_root_blend_mode) {
934 return !renderer.GetDeviceCapabilities().SupportsFramebufferFetch() &&
935 max_root_blend_mode > Entity::kLastPipelineBlendMode;
936}
937
938CanvasDlDispatcher::CanvasDlDispatcher(ContentContext& renderer,
939 RenderTarget& render_target,
940 bool is_onscreen,
941 bool has_root_backdrop_filter,
942 flutter::DlBlendMode max_root_blend_mode,
943 IRect32 cull_rect)
944 : DlDispatcherBase(),
945 canvas_(renderer,
946 render_target,
947 is_onscreen,
948 has_root_backdrop_filter ||
949 RequiresReadbackForBlends(renderer, max_root_blend_mode),
950 cull_rect),
951 renderer_(renderer) {}
952
953Canvas& CanvasDlDispatcher::GetCanvas() {
954 return canvas_;
955}
956
957const ContentContext& CanvasDlDispatcher::GetContentContext() const {
958 return renderer_;
959}
960
961void CanvasDlDispatcher::drawVertices(
962 const std::shared_ptr<flutter::DlVertices>& vertices,
963 flutter::DlBlendMode dl_mode) {
965
966 GetCanvas().DrawVertices(
967 std::make_shared<DlVerticesGeometry>(vertices, renderer_), dl_mode,
968 paint_);
969}
970
971void CanvasDlDispatcher::SetBackdropData(
972 std::unordered_map<int64_t, BackdropData> backdrop,
973 size_t backdrop_count) {
974 GetCanvas().SetBackdropData(std::move(backdrop), backdrop_count);
975}
976
977//// Text Frame Dispatcher
978
979FirstPassDispatcher::FirstPassDispatcher(const ContentContext& renderer,
980 const Matrix& initial_matrix,
981 const Rect cull_rect)
982 : renderer_(renderer), matrix_(initial_matrix) {
983 cull_rect_state_.push_back(cull_rect);
984}
985
986FirstPassDispatcher::~FirstPassDispatcher() {
987 FML_DCHECK(cull_rect_state_.size() == 1);
988}
989
990void FirstPassDispatcher::save() {
991 stack_.emplace_back(matrix_);
992 cull_rect_state_.push_back(cull_rect_state_.back());
993}
994
995void FirstPassDispatcher::saveLayer(const DlRect& bounds,
996 const flutter::SaveLayerOptions options,
997 const flutter::DlImageFilter* backdrop,
998 std::optional<int64_t> backdrop_id) {
999 save();
1000
1001 backdrop_count_ += (backdrop == nullptr ? 0 : 1);
1002 if (backdrop != nullptr && backdrop_id.has_value()) {
1003 std::shared_ptr<flutter::DlImageFilter> shared_backdrop =
1004 backdrop->shared();
1005 std::unordered_map<int64_t, BackdropData>::iterator existing =
1006 backdrop_data_.find(backdrop_id.value());
1007 if (existing == backdrop_data_.end()) {
1008 backdrop_data_[backdrop_id.value()] =
1009 BackdropData{.backdrop_count = 1, .last_backdrop = shared_backdrop};
1010 } else {
1011 BackdropData& data = existing->second;
1012 data.backdrop_count++;
1013 if (data.all_filters_equal) {
1014 data.all_filters_equal = (*data.last_backdrop == *shared_backdrop);
1015 data.last_backdrop = shared_backdrop;
1016 }
1017 }
1018 }
1019
1020 // This dispatcher does not track enough state to accurately compute
1021 // cull rects with image filters.
1022 auto global_cull_rect = cull_rect_state_.back();
1023 if (has_image_filter_ || global_cull_rect.IsMaximum()) {
1024 cull_rect_state_.back() = Rect::MakeMaximum();
1025 } else {
1026 auto global_save_bounds = bounds.TransformBounds(matrix_);
1027 auto new_cull_rect = global_cull_rect.Intersection(global_save_bounds);
1028 if (new_cull_rect.has_value()) {
1029 cull_rect_state_.back() = new_cull_rect.value();
1030 } else {
1031 cull_rect_state_.back() = Rect::MakeLTRB(0, 0, 0, 0);
1032 }
1033 }
1034}
1035
1036void FirstPassDispatcher::restore() {
1037 matrix_ = stack_.back();
1038 stack_.pop_back();
1039 cull_rect_state_.pop_back();
1040}
1041
1042void FirstPassDispatcher::translate(DlScalar tx, DlScalar ty) {
1043 matrix_ = matrix_.Translate({tx, ty});
1044}
1045
1046void FirstPassDispatcher::scale(DlScalar sx, DlScalar sy) {
1047 matrix_ = matrix_.Scale({sx, sy, 1.0f});
1048}
1049
1050void FirstPassDispatcher::rotate(DlScalar degrees) {
1051 matrix_ = matrix_ * Matrix::MakeRotationZ(Degrees(degrees));
1052}
1053
1054void FirstPassDispatcher::skew(DlScalar sx, DlScalar sy) {
1055 matrix_ = matrix_ * Matrix::MakeSkew(sx, sy);
1056}
1057
1058// clang-format off
1059// 2x3 2D affine subset of a 4x4 transform in row major order
1060void FirstPassDispatcher::transform2DAffine(
1061 DlScalar mxx, DlScalar mxy, DlScalar mxt,
1062 DlScalar myx, DlScalar myy, DlScalar myt) {
1063 matrix_ = matrix_ * Matrix::MakeColumn(
1064 mxx, myx, 0.0f, 0.0f,
1065 mxy, myy, 0.0f, 0.0f,
1066 0.0f, 0.0f, 1.0f, 0.0f,
1067 mxt, myt, 0.0f, 1.0f
1068 );
1069}
1070// clang-format on
1071
1072// clang-format off
1073// full 4x4 transform in row major order
1074void FirstPassDispatcher::transformFullPerspective(
1075 DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt,
1076 DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt,
1077 DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt,
1078 DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) {
1079 matrix_ = matrix_ * Matrix::MakeColumn(
1080 mxx, myx, mzx, mwx,
1081 mxy, myy, mzy, mwy,
1082 mxz, myz, mzz, mwz,
1083 mxt, myt, mzt, mwt
1084 );
1085}
1086// clang-format on
1087
1088void FirstPassDispatcher::transformReset() {
1089 matrix_ = Matrix();
1090}
1091
1092void FirstPassDispatcher::drawText(const std::shared_ptr<flutter::DlText>& text,
1093 DlScalar x,
1094 DlScalar y) {
1095 GlyphProperties properties;
1096 auto text_frame = text->GetTextFrame();
1097 if (text_frame == nullptr) {
1098 return;
1099 }
1100
1101 properties.stroke = paint_.GetStroke();
1102
1103 if (text_frame->HasColor()) {
1104 // Alpha is always applied when rendering, remove it here so
1105 // we do not double-apply the alpha.
1106 properties.tone_or_color = paint_.color.WithAlpha(1.0);
1107 } else {
1108 properties.tone_or_color = GlyphProperties::ComputeTone(paint_.color);
1109 }
1110
1111 renderer_.GetLazyGlyphAtlas()->AddTextFrame(text_frame, //
1112 Point(x, y), //
1113 matrix_, //
1114 properties //
1115 );
1116}
1117
1118const Rect FirstPassDispatcher::GetCurrentLocalCullingBounds() const {
1119 auto cull_rect = cull_rect_state_.back();
1120 if (!cull_rect.IsEmpty() && !cull_rect.IsMaximum()) {
1121 Matrix inverse = matrix_.Invert();
1122 cull_rect = cull_rect.TransformBounds(inverse);
1123 }
1124 return cull_rect;
1125}
1126
1127void FirstPassDispatcher::drawDisplayList(
1128 const sk_sp<flutter::DisplayList> display_list,
1129 DlScalar opacity) {
1130 [[maybe_unused]] size_t stack_depth = stack_.size();
1131 save();
1132 Paint old_paint = paint_;
1133 paint_ = Paint{};
1134 bool old_has_image_filter = has_image_filter_;
1135 has_image_filter_ = false;
1136
1137 if (matrix_.HasPerspective()) {
1138 display_list->Dispatch(*this);
1139 } else {
1140 Rect local_cull_bounds = GetCurrentLocalCullingBounds();
1141 if (local_cull_bounds.IsMaximum()) {
1142 display_list->Dispatch(*this);
1143 } else if (!local_cull_bounds.IsEmpty()) {
1144 DlIRect cull_rect = DlIRect::RoundOut(local_cull_bounds);
1145 display_list->Dispatch(*this, cull_rect);
1146 }
1147 }
1148
1149 restore();
1150 paint_ = old_paint;
1151 has_image_filter_ = old_has_image_filter;
1152 FML_DCHECK(stack_depth == stack_.size());
1153}
1154
1155// |flutter::DlOpReceiver|
1156void FirstPassDispatcher::setDrawStyle(flutter::DlDrawStyle style) {
1157 paint_.style = ToStyle(style);
1158}
1159
1160// |flutter::DlOpReceiver|
1161void FirstPassDispatcher::setColor(flutter::DlColor color) {
1162 paint_.color = skia_conversions::ToColor(color);
1163}
1164
1165// |flutter::DlOpReceiver|
1166void FirstPassDispatcher::setStrokeWidth(DlScalar width) {
1167 paint_.stroke.width = width;
1168}
1169
1170// |flutter::DlOpReceiver|
1171void FirstPassDispatcher::setStrokeMiter(DlScalar limit) {
1172 paint_.stroke.miter_limit = limit;
1173}
1174
1175// |flutter::DlOpReceiver|
1176void FirstPassDispatcher::setStrokeCap(flutter::DlStrokeCap cap) {
1177 switch (cap) {
1179 paint_.stroke.cap = Cap::kButt;
1180 break;
1182 paint_.stroke.cap = Cap::kRound;
1183 break;
1185 paint_.stroke.cap = Cap::kSquare;
1186 break;
1187 }
1188}
1189
1190// |flutter::DlOpReceiver|
1191void FirstPassDispatcher::setStrokeJoin(flutter::DlStrokeJoin join) {
1192 switch (join) {
1194 paint_.stroke.join = Join::kMiter;
1195 break;
1197 paint_.stroke.join = Join::kRound;
1198 break;
1200 paint_.stroke.join = Join::kBevel;
1201 break;
1202 }
1203}
1204
1205// |flutter::DlOpReceiver|
1206void FirstPassDispatcher::setImageFilter(const flutter::DlImageFilter* filter) {
1207 if (filter == nullptr) {
1208 has_image_filter_ = false;
1209 } else {
1210 has_image_filter_ = true;
1211 }
1212}
1213
1214namespace {
1215bool PixelFormatSupportsMSAA(std::optional<PixelFormat> pixel_format) {
1216 return !pixel_format.has_value();
1217}
1218} // namespace
1219
1220std::pair<std::unordered_map<int64_t, BackdropData>, size_t>
1221FirstPassDispatcher::TakeBackdropData() {
1222 std::unordered_map<int64_t, BackdropData> temp;
1223 std::swap(temp, backdrop_data_);
1224 return std::make_pair(temp, backdrop_count_);
1225}
1226
1227std::shared_ptr<Texture> DisplayListToTexture(
1228 const sk_sp<flutter::DisplayList>& display_list,
1229 ISize size,
1230 AiksContext& context,
1231 bool reset_host_buffer,
1232 bool generate_mips,
1233 std::optional<PixelFormat> target_pixel_format) {
1234 int mip_count = 1;
1235 if (generate_mips) {
1236 mip_count = size.MipCount();
1237 }
1238 // Do not use the render target cache as the lifecycle of this texture
1239 // will outlive a particular frame.
1240 impeller::RenderTargetAllocator render_target_allocator =
1242 context.GetContext()->GetResourceAllocator());
1244 if (context.GetContext()->GetCapabilities()->SupportsOffscreenMSAA() &&
1245 PixelFormatSupportsMSAA(target_pixel_format)) {
1246 target = render_target_allocator.CreateOffscreenMSAA(
1247 *context.GetContext(), // context
1248 size, // size
1249 /*mip_count=*/mip_count,
1250 "Picture Snapshot MSAA", // label
1252 kDefaultColorAttachmentConfigMSAA, // color_attachment_config
1253 std::nullopt, // stencil_attachment_config
1254 nullptr, // existing_color_msaa_texture
1255 nullptr, // existing_color_resolve_texture
1256 nullptr, // existing_depth_stencil_texture
1257 target_pixel_format // target_format
1258 );
1259 } else {
1260 target = render_target_allocator.CreateOffscreen(
1261 *context.GetContext(), // context
1262 size, // size
1263 /*mip_count=*/mip_count,
1264 "Picture Snapshot", // label
1266 kDefaultColorAttachmentConfig, // color_attachment_config
1267 std::nullopt, // stencil_attachment_config
1268 nullptr, // existing_color_texture
1269 nullptr, // existing_depth_stencil_texture
1270 target_pixel_format // target_format
1271 );
1272 }
1273 if (!target.IsValid()) {
1274 return nullptr;
1275 }
1276
1277 DlIRect cull_rect = DlIRect::MakeWH(size.width, size.height);
1279 context.GetContentContext(), impeller::Matrix(), Rect::MakeSize(size));
1280 display_list->Dispatch(collector, cull_rect);
1281 impeller::CanvasDlDispatcher impeller_dispatcher(
1282 context.GetContentContext(), //
1283 target, //
1284 /*is_onscreen=*/false, //
1285 display_list->root_has_backdrop_filter(), //
1286 display_list->max_root_blend_mode(), //
1288 );
1289 const auto& [data, count] = collector.TakeBackdropData();
1290 impeller_dispatcher.SetBackdropData(data, count);
1291 context.GetContentContext().GetTextShadowCache().MarkFrameStart();
1292 fml::ScopedCleanupClosure cleanup([&] {
1293 if (reset_host_buffer) {
1294 context.GetContentContext().GetTransientsDataBuffer().Reset();
1295 context.GetContentContext().GetTransientsIndexesBuffer().Reset();
1296 }
1297 context.GetContentContext().GetTextShadowCache().MarkFrameEnd();
1298 context.GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames();
1299 context.GetContext()->DisposeThreadLocalCachedResources();
1300 });
1301
1302 display_list->Dispatch(impeller_dispatcher, cull_rect);
1303 impeller_dispatcher.FinishRecording();
1304
1305 return target.GetRenderTargetTexture();
1306}
1307
1308bool RenderToTarget(ContentContext& context,
1309 RenderTarget render_target,
1310 const sk_sp<flutter::DisplayList>& display_list,
1311 Rect cull_rect,
1312 bool reset_host_buffer,
1313 bool is_onscreen) {
1314 FirstPassDispatcher collector(context, impeller::Matrix(), cull_rect);
1315 display_list->Dispatch(collector, cull_rect);
1316
1317 impeller::CanvasDlDispatcher impeller_dispatcher(
1318 context, //
1319 render_target, //
1320 /*is_onscreen=*/is_onscreen, //
1321 display_list->root_has_backdrop_filter(), //
1322 display_list->max_root_blend_mode(), //
1323 IRect32::RoundOut(cull_rect) //
1324 );
1325 const auto& [data, count] = collector.TakeBackdropData();
1326 impeller_dispatcher.SetBackdropData(data, count);
1327 context.GetTextShadowCache().MarkFrameStart();
1328 fml::ScopedCleanupClosure cleanup([&] {
1329 if (reset_host_buffer) {
1330 context.ResetTransientsBuffers();
1331 }
1332 context.GetTextShadowCache().MarkFrameEnd();
1333 });
1334
1335 display_list->Dispatch(impeller_dispatcher, cull_rect);
1336 impeller_dispatcher.FinishRecording();
1337 context.GetLazyGlyphAtlas()->ResetTextFrames();
1338
1339 return true;
1340}
1341
1342} // namespace impeller
virtual T type() const =0
virtual std::shared_ptr< D > shared() const =0
DlBlurStyle style() const
virtual const DlBlurMaskFilter * asBlur() const
bool content_is_clipped() const
bool renders_with_attributes() const
bool bounds_from_caller() const
bool content_is_unbounded() const
bool can_distribute_opacity() const
Wraps a closure that is invoked in the destructor unless released by the caller.
Definition closure.h:32
a wrapper around the impeller [Allocator] instance that can be used to provide caching of allocated r...
virtual RenderTarget CreateOffscreenMSAA(const Context &context, ISize size, int mip_count, std::string_view label="Offscreen MSAA", RenderTarget::AttachmentConfigMSAA color_attachment_config=RenderTarget::kDefaultColorAttachmentConfigMSAA, std::optional< RenderTarget::AttachmentConfig > stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &existing_color_msaa_texture=nullptr, const std::shared_ptr< Texture > &existing_color_resolve_texture=nullptr, const std::shared_ptr< Texture > &existing_depth_stencil_texture=nullptr, std::optional< PixelFormat > target_pixel_format=std::nullopt)
virtual RenderTarget CreateOffscreen(const Context &context, ISize size, int mip_count, std::string_view label="Offscreen", RenderTarget::AttachmentConfig color_attachment_config=RenderTarget::kDefaultColorAttachmentConfig, std::optional< RenderTarget::AttachmentConfig > stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &existing_color_texture=nullptr, const std::shared_ptr< Texture > &existing_depth_stencil_texture=nullptr, std::optional< PixelFormat > target_pixel_format=std::nullopt)
#define AUTO_DEPTH_WATCHER(d)
#define UNIMPLEMENTED
#define AUTO_DEPTH_CHECK()
int32_t x
FlutterVulkanImage * image
uint32_t * target
#define FML_CHECK(condition)
Definition logging.h:104
#define FML_DCHECK(condition)
Definition logging.h:122
std::u16string text
FlTexture * texture
double y
DlStrokeJoin
Definition dl_paint.h:37
@ kMiter
extends to miter limit
@ kBevel
connects outside edges
impeller::RoundRect DlRoundRect
DlStrokeCap
Definition dl_paint.h:28
@ kRound
adds circle
@ kButt
no stroke extension
@ kSquare
adds square
impeller::Rect DlRect
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
DlPointMode
Definition dl_types.h:15
@ kLines
draw each separate pair of points as a line segment
@ kPolygon
draw each pair of overlapping points as a line segment
@ kPoints
draw each point separately
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switch_defs.h:52
DlDrawStyle
Definition dl_paint.h:19
@ kStrokeAndFill
both strokes and fills shapes
@ kStroke
strokes boundary of shapes
@ kFill
fills interior of shapes
impeller::IRect32 DlIRect
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switch_defs.h:36
@ kNormal
fuzzy inside and outside
@ kOuter
nothing inside, fuzzy outside
@ kInner
fuzzy inside, nothing outside
@ kSolid
solid inside, fuzzy outside
void Reset(SkPathBuilder *path)
Definition path_ops.cc:40
impeller::Point DlPoint
DlSrcRectConstraint
Definition dl_types.h:21
Point Vector2
Definition point.h:430
float Scalar
Definition scalar.h:19
static Paint::Style ToStyle(flutter::DlDrawStyle style)
std::shared_ptr< Texture > DisplayListToTexture(const sk_sp< flutter::DisplayList > &display_list, ISize size, AiksContext &context, bool reset_host_buffer, bool generate_mips, std::optional< PixelFormat > target_pixel_format)
Render the provided display list to a texture with the given size.
TRect< Scalar > Rect
Definition rect.h:822
static std::optional< const Rect > ToOptRect(const flutter::DlRect *rect)
PointStyle
Definition canvas.h:66
TPoint< Scalar > Point
Definition point.h:426
static Entity::ClipOperation ToClipOperation(flutter::DlClipOp clip_op)
static bool RequiresReadbackForBlends(const ContentContext &renderer, flutter::DlBlendMode max_root_blend_mode)
Subclasses.
static impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlFilterMode options)
BlendMode
Definition color.h:58
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.
static FilterContents::BlurStyle ToBlurStyle(flutter::DlBlurStyle blur_style)
Definition ref_ptr.h:261
int32_t width
A 4x4 matrix using column-major storage.
Definition matrix.h:37
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition rect.h:506
static constexpr TRect MakeSize(const TSize< U > &size)
Definition rect.h:150
const size_t start
const size_t end
std::vector< Point > points

◆ USE_DEPTH_WATCHER

#define USE_DEPTH_WATCHER   true

Definition at line 44 of file dl_dispatcher.cc.