1// Copyright 2014 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
5/// @docImport 'dart:ui';
6///
7/// @docImport 'package:flutter/widgets.dart';
8///
9/// @docImport 'layer.dart';
10library;
11
12import 'dart:async';
13import 'dart:ui' as ui show PictureRecorder, SceneBuilder, SemanticsUpdate;
14
15import 'package:flutter/foundation.dart';
16import 'package:flutter/gestures.dart';
17import 'package:flutter/scheduler.dart';
18import 'package:flutter/semantics.dart';
19import 'package:flutter/services.dart';
20
21import 'debug.dart';
22import 'mouse_tracker.dart';
23import 'object.dart';
24import 'service_extensions.dart';
25import 'view.dart';
26
27export 'package:flutter/gestures.dart' show HitTestResult;
28
29// Examples can assume:
30// late BuildContext context;
31
32/// The glue between the render trees and the Flutter engine.
33///
34/// The [RendererBinding] manages multiple independent render trees. Each render
35/// tree is rooted in a [RenderView] that must be added to the binding via
36/// [addRenderView] to be considered during frame production, hit testing, etc.
37/// Furthermore, the render tree must be managed by a [PipelineOwner] that is
38/// part of the pipeline owner tree rooted at [rootPipelineOwner].
39///
40/// Adding [PipelineOwner]s and [RenderView]s to this binding in the way
41/// described above is left as a responsibility for a higher level abstraction.
42/// The widgets library, for example, introduces the [View] widget, which
43/// registers its [RenderView] and [PipelineOwner] with this binding.
44mixin RendererBinding
45 on
46 BindingBase,
47 ServicesBinding,
48 SchedulerBinding,
49 GestureBinding,
50 SemanticsBinding,
51 HitTestable {
52 @override
53 void initInstances() {
54 super.initInstances();
55 _instance = this;
56 _rootPipelineOwner = createRootPipelineOwner();
57 platformDispatcher
58 ..onMetricsChanged = handleMetricsChanged
59 ..onTextScaleFactorChanged = handleTextScaleFactorChanged
60 ..onPlatformBrightnessChanged = handlePlatformBrightnessChanged;
61 addPersistentFrameCallback(_handlePersistentFrameCallback);
62 initMouseTracker();
63 if (kIsWeb) {
64 addPostFrameCallback(_handleWebFirstFrame, debugLabel: 'RendererBinding.webFirstFrame');
65 }
66 rootPipelineOwner.attach(_manifold);
67 }
68
69 /// The current [RendererBinding], if one has been created.
70 ///
71 /// Provides access to the features exposed by this mixin. The binding must
72 /// be initialized before using this getter; this is typically done by calling
73 /// [runApp] or [WidgetsFlutterBinding.ensureInitialized].
74 static RendererBinding get instance => BindingBase.checkInstance(_instance);
75 static RendererBinding? _instance;
76
77 @override
78 void initServiceExtensions() {
79 super.initServiceExtensions();
80
81 assert(() {
82 // these service extensions only work in debug mode
83 registerBoolServiceExtension(
84 name: RenderingServiceExtensions.invertOversizedImages.name,
85 getter: () async => debugInvertOversizedImages,
86 setter: (bool value) async {
87 if (debugInvertOversizedImages != value) {
88 debugInvertOversizedImages = value;
89 // We don't want to block the vm service response on the frame
90 // actually rendering, just schedule it and return;
91 unawaited(_forceRepaint());
92 }
93 },
94 );
95 registerBoolServiceExtension(
96 name: RenderingServiceExtensions.debugPaint.name,
97 getter: () async => debugPaintSizeEnabled,
98 setter: (bool value) async {
99 if (debugPaintSizeEnabled == value) {
100 return;
101 }
102 debugPaintSizeEnabled = value;
103 // We don't want to block the vm service response on the frame
104 // actually rendering, just schedule it and return;
105 unawaited(_forceRepaint());
106 },
107 );
108 registerBoolServiceExtension(
109 name: RenderingServiceExtensions.debugPaintBaselinesEnabled.name,
110 getter: () async => debugPaintBaselinesEnabled,
111 setter: (bool value) async {
112 if (debugPaintBaselinesEnabled == value) {
113 return;
114 }
115 debugPaintBaselinesEnabled = value;
116 // We don't want to block the vm service response on the frame
117 // actually rendering, just schedule it and return;
118 unawaited(_forceRepaint());
119 },
120 );
121 registerBoolServiceExtension(
122 name: RenderingServiceExtensions.repaintRainbow.name,
123 getter: () async => debugRepaintRainbowEnabled,
124 setter: (bool value) async {
125 final bool repaint = debugRepaintRainbowEnabled && !value;
126 debugRepaintRainbowEnabled = value;
127 if (repaint) {
128 // We don't want to block the vm service response on the frame
129 // actually rendering, just schedule it and return;
130 unawaited(_forceRepaint());
131 }
132 },
133 );
134 registerServiceExtension(
135 name: RenderingServiceExtensions.debugDumpLayerTree.name,
136 callback: (Map<String, String> parameters) async {
137 return <String, Object>{'data': _debugCollectLayerTrees()};
138 },
139 );
140 registerBoolServiceExtension(
141 name: RenderingServiceExtensions.debugDisableClipLayers.name,
142 getter: () async => debugDisableClipLayers,
143 setter: (bool value) async {
144 if (debugDisableClipLayers == value) {
145 return;
146 }
147 debugDisableClipLayers = value;
148 // We don't want to block the vm service response on the frame
149 // actually rendering, just schedule it and return;
150 unawaited(_forceRepaint());
151 },
152 );
153 registerBoolServiceExtension(
154 name: RenderingServiceExtensions.debugDisablePhysicalShapeLayers.name,
155 getter: () async => debugDisablePhysicalShapeLayers,
156 setter: (bool value) async {
157 if (debugDisablePhysicalShapeLayers == value) {
158 return;
159 }
160 debugDisablePhysicalShapeLayers = value;
161 // We don't want to block the vm service response on the frame
162 // actually rendering, just schedule it and return;
163 unawaited(_forceRepaint());
164 },
165 );
166 registerBoolServiceExtension(
167 name: RenderingServiceExtensions.debugDisableOpacityLayers.name,
168 getter: () async => debugDisableOpacityLayers,
169 setter: (bool value) async {
170 if (debugDisableOpacityLayers == value) {
171 return;
172 }
173 debugDisableOpacityLayers = value;
174 // We don't want to block the vm service response on the frame
175 // actually rendering, just schedule it and return;
176 unawaited(_forceRepaint());
177 },
178 );
179 return true;
180 }());
181
182 if (!kReleaseMode) {
183 // these service extensions work in debug or profile mode
184 registerServiceExtension(
185 name: RenderingServiceExtensions.debugDumpRenderTree.name,
186 callback: (Map<String, String> parameters) async {
187 return <String, Object>{'data': _debugCollectRenderTrees()};
188 },
189 );
190 registerServiceExtension(
191 name: RenderingServiceExtensions.debugDumpSemanticsTreeInTraversalOrder.name,
192 callback: (Map<String, String> parameters) async {
193 return <String, Object>{
194 'data': _debugCollectSemanticsTrees(DebugSemanticsDumpOrder.traversalOrder),
195 };
196 },
197 );
198 registerServiceExtension(
199 name: RenderingServiceExtensions.debugDumpSemanticsTreeInInverseHitTestOrder.name,
200 callback: (Map<String, String> parameters) async {
201 return <String, Object>{
202 'data': _debugCollectSemanticsTrees(DebugSemanticsDumpOrder.inverseHitTest),
203 };
204 },
205 );
206 registerBoolServiceExtension(
207 name: RenderingServiceExtensions.profileRenderObjectPaints.name,
208 getter: () async => debugProfilePaintsEnabled,
209 setter: (bool value) async {
210 if (debugProfilePaintsEnabled != value) {
211 debugProfilePaintsEnabled = value;
212 }
213 },
214 );
215 registerBoolServiceExtension(
216 name: RenderingServiceExtensions.profileRenderObjectLayouts.name,
217 getter: () async => debugProfileLayoutsEnabled,
218 setter: (bool value) async {
219 if (debugProfileLayoutsEnabled != value) {
220 debugProfileLayoutsEnabled = value;
221 }
222 },
223 );
224 }
225 }
226
227 late final PipelineManifold _manifold = _BindingPipelineManifold(this);
228
229 /// The object that manages state about currently connected mice, for hover
230 /// notification.
231 MouseTracker get mouseTracker => _mouseTracker!;
232 MouseTracker? _mouseTracker;
233
234 /// Deprecated. Will be removed in a future version of Flutter.
235 ///
236 /// This is typically the owner of the render tree bootstrapped by [runApp]
237 /// and rooted in [renderView]. It maintains dirty state for layout,
238 /// composite, paint, and accessibility semantics for that tree.
239 ///
240 /// However, by default, the [pipelineOwner] does not participate in frame
241 /// production because it is not automatically attached to the
242 /// [rootPipelineOwner] or any of its descendants. It is also not
243 /// automatically associated with the [renderView]. This is left as a
244 /// responsibility for a higher level abstraction. The [WidgetsBinding], for
245 /// example, wires this up in [WidgetsBinding.wrapWithDefaultView], which is
246 /// called indirectly from [runApp].
247 ///
248 /// Apps, that don't use the [WidgetsBinding] or don't call [runApp] (or
249 /// [WidgetsBinding.wrapWithDefaultView]) must manually add this pipeline owner
250 /// to the pipeline owner tree rooted at [rootPipelineOwner] and assign a
251 /// [RenderView] to it if the they want to use this deprecated property.
252 ///
253 /// Instead of accessing this deprecated property, consider interacting with
254 /// the root of the [PipelineOwner] tree (exposed in [rootPipelineOwner]) or
255 /// instead of accessing the [SemanticsOwner] of any [PipelineOwner] consider
256 /// interacting with the [SemanticsBinding] (exposed via
257 /// [SemanticsBinding.instance]) directly.
258 @Deprecated(
259 'Interact with the pipelineOwner tree rooted at RendererBinding.rootPipelineOwner instead. '
260 'Or instead of accessing the SemanticsOwner of any PipelineOwner interact with the SemanticsBinding directly. '
261 'This feature was deprecated after v3.10.0-12.0.pre.',
262 )
263 late final PipelineOwner pipelineOwner = PipelineOwner(
264 onSemanticsOwnerCreated: () {
265 (pipelineOwner.rootNode as RenderView?)?.scheduleInitialSemantics();
266 },
267 onSemanticsUpdate: (ui.SemanticsUpdate update) {
268 (pipelineOwner.rootNode as RenderView?)?.updateSemantics(update);
269 },
270 onSemanticsOwnerDisposed: () {
271 (pipelineOwner.rootNode as RenderView?)?.clearSemantics();
272 },
273 );
274
275 /// Deprecated. Will be removed in a future version of Flutter.
276 ///
277 /// This is typically the root of the render tree bootstrapped by [runApp].
278 ///
279 /// However, by default this render view is not associated with any
280 /// [PipelineOwner] and therefore isn't considered during frame production.
281 /// It is also not registered with this binding via [addRenderView].
282 /// Wiring this up is left as a responsibility for a higher level. The
283 /// [WidgetsBinding], for example, sets this up in
284 /// [WidgetsBinding.wrapWithDefaultView], which is called indirectly from
285 /// [runApp].
286 ///
287 /// Apps that don't use the [WidgetsBinding] or don't call [runApp] (or
288 /// [WidgetsBinding.wrapWithDefaultView]) must manually assign a
289 /// [PipelineOwner] to this [RenderView], make sure the pipeline owner is part
290 /// of the pipeline owner tree rooted at [rootPipelineOwner], and call
291 /// [addRenderView] if they want to use this deprecated property.
292 ///
293 /// Instead of interacting with this deprecated property, consider using
294 /// [renderViews] instead, which contains all [RenderView]s managed by the
295 /// binding.
296 @Deprecated(
297 'Consider using RendererBinding.renderViews instead as the binding may manage multiple RenderViews. '
298 'This feature was deprecated after v3.10.0-12.0.pre.',
299 )
300 // TODO(goderbauer): When this deprecated property is removed also delete the _ReusableRenderView class.
301 late final RenderView renderView = _ReusableRenderView(view: platformDispatcher.implicitView!);
302
303 /// Creates the [PipelineOwner] that serves as the root of the pipeline owner
304 /// tree ([rootPipelineOwner]).
305 ///
306 /// {@template flutter.rendering.createRootPipelineOwner}
307 /// By default, the root pipeline owner is not setup to manage a render tree
308 /// and its [PipelineOwner.rootNode] must not be assigned. If necessary,
309 /// [createRootPipelineOwner] may be overridden to create a root pipeline
310 /// owner configured to manage its own render tree.
311 ///
312 /// In typical use, child pipeline owners are added to the root pipeline owner
313 /// (via [PipelineOwner.adoptChild]). Those children typically do each manage
314 /// their own [RenderView] and produce distinct render trees which render
315 /// their content into the [FlutterView] associated with that [RenderView].
316 /// {@endtemplate}
317 PipelineOwner createRootPipelineOwner() {
318 return _DefaultRootPipelineOwner();
319 }
320
321 /// The [PipelineOwner] that is the root of the PipelineOwner tree.
322 ///
323 /// {@macro flutter.rendering.createRootPipelineOwner}
324 PipelineOwner get rootPipelineOwner => _rootPipelineOwner;
325 late PipelineOwner _rootPipelineOwner;
326
327 /// The [RenderView]s managed by this binding.
328 ///
329 /// A [RenderView] is added by [addRenderView] and removed by [removeRenderView].
330 Iterable<RenderView> get renderViews => _viewIdToRenderView.values;
331 final Map<Object, RenderView> _viewIdToRenderView = <Object, RenderView>{};
332
333 /// Adds a [RenderView] to this binding.
334 ///
335 /// The binding will interact with the [RenderView] in the following ways:
336 ///
337 /// * setting and updating [RenderView.configuration],
338 /// * calling [RenderView.compositeFrame] when it is time to produce a new
339 /// frame, and
340 /// * forwarding relevant pointer events to the [RenderView] for hit testing.
341 ///
342 /// To remove a [RenderView] from the binding, call [removeRenderView].
343 void addRenderView(RenderView view) {
344 final Object viewId = view.flutterView.viewId;
345 assert(!_viewIdToRenderView.containsValue(view));
346 assert(!_viewIdToRenderView.containsKey(viewId));
347 _viewIdToRenderView[viewId] = view;
348 view.configuration = createViewConfigurationFor(view);
349 }
350
351 /// Removes a [RenderView] previously added with [addRenderView] from the
352 /// binding.
353 void removeRenderView(RenderView view) {
354 final Object viewId = view.flutterView.viewId;
355 assert(_viewIdToRenderView[viewId] == view);
356 _viewIdToRenderView.remove(viewId);
357 }
358
359 /// Returns a [ViewConfiguration] configured for the provided [RenderView]
360 /// based on the current environment.
361 ///
362 /// This is called during [addRenderView] and also in response to changes to
363 /// the system metrics to update all [renderViews] added to the binding.
364 ///
365 /// Bindings can override this method to change what size or device pixel
366 /// ratio the [RenderView] will use. For example, the testing framework uses
367 /// this to force the display into 800x600 when a test is run on the device
368 /// using `flutter run`.
369 @protected
370 ViewConfiguration createViewConfigurationFor(RenderView renderView) {
371 return ViewConfiguration.fromView(renderView.flutterView);
372 }
373
374 /// Create a [SceneBuilder].
375 ///
376 /// This hook enables test bindings to instrument the rendering layer.
377 ///
378 /// This is used by the [RenderView] to create the [SceneBuilder] that is
379 /// passed to the [Layer] system to render the scene.
380 ui.SceneBuilder createSceneBuilder() => ui.SceneBuilder();
381
382 /// Create a [PictureRecorder].
383 ///
384 /// This hook enables test bindings to instrument the rendering layer.
385 ///
386 /// This is used by the [PaintingContext] to create the [PictureRecorder]s
387 /// used when painting [RenderObject]s into [Picture]s passed to
388 /// [PictureLayer]s.
389 ui.PictureRecorder createPictureRecorder() => ui.PictureRecorder();
390
391 /// Create a [Canvas] from a [PictureRecorder].
392 ///
393 /// This hook enables test bindings to instrument the rendering layer.
394 ///
395 /// This is used by the [PaintingContext] after creating a [PictureRecorder]
396 /// using [createPictureRecorder].
397 Canvas createCanvas(ui.PictureRecorder recorder) => Canvas(recorder);
398
399 /// Called when the system metrics change.
400 ///
401 /// See [dart:ui.PlatformDispatcher.onMetricsChanged].
402 @protected
403 @visibleForTesting
404 void handleMetricsChanged() {
405 bool forceFrame = false;
406 for (final RenderView view in renderViews) {
407 forceFrame = forceFrame || view.child != null;
408 view.configuration = createViewConfigurationFor(view);
409 }
410 if (forceFrame) {
411 scheduleForcedFrame();
412 }
413 }
414
415 /// Called when the platform text scale factor changes.
416 ///
417 /// See [dart:ui.PlatformDispatcher.onTextScaleFactorChanged].
418 @protected
419 void handleTextScaleFactorChanged() {}
420
421 /// Called when the platform brightness changes.
422 ///
423 /// The current platform brightness can be queried from a Flutter binding or
424 /// from a [MediaQuery] widget. The latter is preferred from widgets because
425 /// it causes the widget to be automatically rebuilt when the brightness
426 /// changes.
427 ///
428 /// {@tool snippet}
429 /// Querying [MediaQuery.platformBrightnessOf] directly. Preferred.
430 ///
431 /// ```dart
432 /// final Brightness brightness = MediaQuery.platformBrightnessOf(context);
433 /// ```
434 /// {@end-tool}
435 ///
436 /// {@tool snippet}
437 /// Querying [PlatformDispatcher.platformBrightness].
438 ///
439 /// ```dart
440 /// final Brightness brightness = WidgetsBinding.instance.platformDispatcher.platformBrightness;
441 /// ```
442 /// {@end-tool}
443 ///
444 /// See [dart:ui.PlatformDispatcher.onPlatformBrightnessChanged].
445 @protected
446 void handlePlatformBrightnessChanged() {}
447
448 /// Creates a [MouseTracker] which manages state about currently connected
449 /// mice, for hover notification.
450 ///
451 /// Used by testing framework to reinitialize the mouse tracker between tests.
452 @visibleForTesting
453 void initMouseTracker([MouseTracker? tracker]) {
454 _mouseTracker?.dispose();
455 _mouseTracker =
456 tracker ??
457 MouseTracker((Offset position, int viewId) {
458 final HitTestResult result = HitTestResult();
459 hitTestInView(result, position, viewId);
460 return result;
461 });
462 }
463
464 @override // from GestureBinding
465 void dispatchEvent(PointerEvent event, HitTestResult? hitTestResult) {
466 _mouseTracker!.updateWithEvent(
467 event,
468 // When the button is pressed, normal hit test uses a cached
469 // result, but MouseTracker requires that the hit test is re-executed to
470 // update the hovering events.
471 event is PointerMoveEvent ? null : hitTestResult,
472 );
473 super.dispatchEvent(event, hitTestResult);
474 }
475
476 @override
477 void performSemanticsAction(SemanticsActionEvent action) {
478 // Due to the asynchronicity in some screen readers (they may not have
479 // processed the latest semantics update yet) this code is more forgiving
480 // and actions for views/nodes that no longer exist are gracefully ignored.
481 _viewIdToRenderView[action.viewId]?.owner?.semanticsOwner?.performAction(
482 action.nodeId,
483 action.type,
484 action.arguments,
485 );
486 }
487
488 void _handleWebFirstFrame(Duration _) {
489 assert(kIsWeb);
490 const MethodChannel methodChannel = MethodChannel('flutter/service_worker');
491 methodChannel.invokeMethod<void>('first-frame');
492 }
493
494 void _handlePersistentFrameCallback(Duration timeStamp) {
495 drawFrame();
496 _scheduleMouseTrackerUpdate();
497 }
498
499 bool _debugMouseTrackerUpdateScheduled = false;
500 void _scheduleMouseTrackerUpdate() {
501 assert(!_debugMouseTrackerUpdateScheduled);
502 assert(() {
503 _debugMouseTrackerUpdateScheduled = true;
504 return true;
505 }());
506 SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
507 assert(_debugMouseTrackerUpdateScheduled);
508 assert(() {
509 _debugMouseTrackerUpdateScheduled = false;
510 return true;
511 }());
512 _mouseTracker!.updateAllDevices();
513 }, debugLabel: 'RendererBinding.mouseTrackerUpdate');
514 }
515
516 int _firstFrameDeferredCount = 0;
517 bool _firstFrameSent = false;
518
519 /// Whether frames produced by [drawFrame] are sent to the engine.
520 ///
521 /// If false the framework will do all the work to produce a frame,
522 /// but the frame is never sent to the engine to actually appear on screen.
523 ///
524 /// See also:
525 ///
526 /// * [deferFirstFrame], which defers when the first frame is sent to the
527 /// engine.
528 bool get sendFramesToEngine => _firstFrameSent || _firstFrameDeferredCount == 0;
529
530 /// Tell the framework to not send the first frames to the engine until there
531 /// is a corresponding call to [allowFirstFrame].
532 ///
533 /// Call this to perform asynchronous initialization work before the first
534 /// frame is rendered (which takes down the splash screen). The framework
535 /// will still do all the work to produce frames, but those frames are never
536 /// sent to the engine and will not appear on screen.
537 ///
538 /// Calling this has no effect after the first frame has been sent to the
539 /// engine.
540 void deferFirstFrame() {
541 assert(_firstFrameDeferredCount >= 0);
542 _firstFrameDeferredCount += 1;
543 }
544
545 /// Called after [deferFirstFrame] to tell the framework that it is ok to
546 /// send the first frame to the engine now.
547 ///
548 /// For best performance, this method should only be called while the
549 /// [schedulerPhase] is [SchedulerPhase.idle].
550 ///
551 /// This method may only be called once for each corresponding call
552 /// to [deferFirstFrame].
553 void allowFirstFrame() {
554 assert(_firstFrameDeferredCount > 0);
555 _firstFrameDeferredCount -= 1;
556 // Always schedule a warm up frame even if the deferral count is not down to
557 // zero yet since the removal of a deferral may uncover new deferrals that
558 // are lower in the widget tree.
559 if (!_firstFrameSent) {
560 scheduleWarmUpFrame();
561 }
562 }
563
564 /// Call this to pretend that no frames have been sent to the engine yet.
565 ///
566 /// This is useful for tests that want to call [deferFirstFrame] and
567 /// [allowFirstFrame] since those methods only have an effect if no frames
568 /// have been sent to the engine yet.
569 void resetFirstFrameSent() {
570 _firstFrameSent = false;
571 }
572
573 /// Pump the rendering pipeline to generate a frame.
574 ///
575 /// This method is called by [handleDrawFrame], which itself is called
576 /// automatically by the engine when it is time to lay out and paint a frame.
577 ///
578 /// Each frame consists of the following phases:
579 ///
580 /// 1. The animation phase: The [handleBeginFrame] method, which is registered
581 /// with [PlatformDispatcher.onBeginFrame], invokes all the transient frame
582 /// callbacks registered with [scheduleFrameCallback], in registration order.
583 /// This includes all the [Ticker] instances that are driving
584 /// [AnimationController] objects, which means all of the active [Animation]
585 /// objects tick at this point.
586 ///
587 /// 2. Microtasks: After [handleBeginFrame] returns, any microtasks that got
588 /// scheduled by transient frame callbacks get to run. This typically includes
589 /// callbacks for futures from [Ticker]s and [AnimationController]s that
590 /// completed this frame.
591 ///
592 /// After [handleBeginFrame], [handleDrawFrame], which is registered with
593 /// [dart:ui.PlatformDispatcher.onDrawFrame], is called, which invokes all the
594 /// persistent frame callbacks, of which the most notable is this method,
595 /// [drawFrame], which proceeds as follows:
596 ///
597 /// 3. The layout phase: All the dirty [RenderObject]s in the system are laid
598 /// out (see [RenderObject.performLayout]). See [RenderObject.markNeedsLayout]
599 /// for further details on marking an object dirty for layout.
600 ///
601 /// 4. The compositing bits phase: The compositing bits on any dirty
602 /// [RenderObject] objects are updated. See
603 /// [RenderObject.markNeedsCompositingBitsUpdate].
604 ///
605 /// 5. The paint phase: All the dirty [RenderObject]s in the system are
606 /// repainted (see [RenderObject.paint]). This generates the [Layer] tree. See
607 /// [RenderObject.markNeedsPaint] for further details on marking an object
608 /// dirty for paint.
609 ///
610 /// 6. The compositing phase: The layer tree is turned into a [Scene] and
611 /// sent to the GPU.
612 ///
613 /// 7. The semantics phase: All the dirty [RenderObject]s in the system have
614 /// their semantics updated. This generates the [SemanticsNode] tree. See
615 /// [RenderObject.markNeedsSemanticsUpdate] for further details on marking an
616 /// object dirty for semantics.
617 ///
618 /// For more details on steps 3-7, see [PipelineOwner].
619 ///
620 /// 8. The finalization phase: After [drawFrame] returns, [handleDrawFrame]
621 /// then invokes post-frame callbacks (registered with [addPostFrameCallback]).
622 ///
623 /// Some bindings (for example, the [WidgetsBinding]) add extra steps to this
624 /// list (for example, see [WidgetsBinding.drawFrame]).
625 //
626 // When editing the above, also update widgets/binding.dart's copy.
627 @protected
628 void drawFrame() {
629 rootPipelineOwner.flushLayout();
630 rootPipelineOwner.flushCompositingBits();
631 rootPipelineOwner.flushPaint();
632 if (sendFramesToEngine) {
633 for (final RenderView renderView in renderViews) {
634 renderView.compositeFrame(); // this sends the bits to the GPU
635 }
636 rootPipelineOwner.flushSemantics(); // this sends the semantics to the OS.
637 _firstFrameSent = true;
638 }
639 }
640
641 @override
642 Future<void> performReassemble() async {
643 await super.performReassemble();
644 if (!kReleaseMode) {
645 FlutterTimeline.startSync('Preparing Hot Reload (layout)');
646 }
647 try {
648 for (final RenderView renderView in renderViews) {
649 renderView.reassemble();
650 }
651 } finally {
652 if (!kReleaseMode) {
653 FlutterTimeline.finishSync();
654 }
655 }
656 scheduleWarmUpFrame();
657 await endOfFrame;
658 }
659
660 @override
661 void hitTestInView(HitTestResult result, Offset position, int viewId) {
662 _viewIdToRenderView[viewId]?.hitTest(result, position: position);
663 super.hitTestInView(result, position, viewId);
664 }
665
666 Future<void> _forceRepaint() {
667 late RenderObjectVisitor visitor;
668 visitor = (RenderObject child) {
669 child.markNeedsPaint();
670 child.visitChildren(visitor);
671 };
672 for (final RenderView renderView in renderViews) {
673 renderView.visitChildren(visitor);
674 }
675 return endOfFrame;
676 }
677}
678
679String _debugCollectRenderTrees() {
680 if (RendererBinding.instance.renderViews.isEmpty) {
681 return 'No render tree root was added to the binding.';
682 }
683 return <String>[
684 for (final RenderView renderView in RendererBinding.instance.renderViews)
685 renderView.toStringDeep(),
686 ].join('\n\n');
687}
688
689/// Prints a textual representation of the render trees.
690///
691/// {@template flutter.rendering.debugDumpRenderTree}
692/// It prints the trees associated with every [RenderView] in
693/// [RendererBinding.renderViews], separated by two blank lines.
694/// {@endtemplate}
695void debugDumpRenderTree() {
696 debugPrint(_debugCollectRenderTrees());
697}
698
699String _debugCollectLayerTrees() {
700 if (RendererBinding.instance.renderViews.isEmpty) {
701 return 'No render tree root was added to the binding.';
702 }
703 return <String>[
704 for (final RenderView renderView in RendererBinding.instance.renderViews)
705 renderView.debugLayer?.toStringDeep() ?? 'Layer tree unavailable for $renderView.',
706 ].join('\n\n');
707}
708
709/// Prints a textual representation of the layer trees.
710///
711/// {@macro flutter.rendering.debugDumpRenderTree}
712void debugDumpLayerTree() {
713 debugPrint(_debugCollectLayerTrees());
714}
715
716String _debugCollectSemanticsTrees(DebugSemanticsDumpOrder childOrder) {
717 if (RendererBinding.instance.renderViews.isEmpty) {
718 return 'No render tree root was added to the binding.';
719 }
720 const String explanation =
721 'For performance reasons, the framework only generates semantics when asked to do so by the platform.\n'
722 'Usually, platforms only ask for semantics when assistive technologies (like screen readers) are running.\n'
723 'To generate semantics, try turning on an assistive technology (like VoiceOver or TalkBack) on your device.';
724 final List<String> trees = <String>[];
725 bool printedExplanation = false;
726 for (final RenderView renderView in RendererBinding.instance.renderViews) {
727 final String? tree = renderView.debugSemantics?.toStringDeep(childOrder: childOrder);
728 if (tree != null) {
729 trees.add(tree);
730 } else {
731 String message = 'Semantics not generated for $renderView.';
732 if (!printedExplanation) {
733 printedExplanation = true;
734 message = '$message\n$explanation';
735 }
736 trees.add(message);
737 }
738 }
739 return trees.join('\n\n');
740}
741
742/// Prints a textual representation of the semantics trees.
743///
744/// {@macro flutter.rendering.debugDumpRenderTree}
745///
746/// Semantics trees are only constructed when semantics are enabled (see
747/// [SemanticsBinding.semanticsEnabled]). If a semantics tree is not available,
748/// a notice about the missing semantics tree is printed instead.
749///
750/// The order in which the children of a [SemanticsNode] will be printed is
751/// controlled by the [childOrder] parameter.
752void debugDumpSemanticsTree([
753 DebugSemanticsDumpOrder childOrder = DebugSemanticsDumpOrder.traversalOrder,
754]) {
755 debugPrint(_debugCollectSemanticsTrees(childOrder));
756}
757
758/// Prints a textual representation of the [PipelineOwner] tree rooted at
759/// [RendererBinding.rootPipelineOwner].
760void debugDumpPipelineOwnerTree() {
761 debugPrint(RendererBinding.instance.rootPipelineOwner.toStringDeep());
762}
763
764/// A concrete binding for applications that use the Rendering framework
765/// directly. This is the glue that binds the framework to the Flutter engine.
766///
767/// When using the rendering framework directly, this binding, or one that
768/// implements the same interfaces, must be used. The following
769/// mixins are used to implement this binding:
770///
771/// * [GestureBinding], which implements the basics of hit testing.
772/// * [SchedulerBinding], which introduces the concepts of frames.
773/// * [ServicesBinding], which provides access to the plugin subsystem.
774/// * [SemanticsBinding], which supports accessibility.
775/// * [PaintingBinding], which enables decoding images.
776/// * [RendererBinding], which handles the render tree.
777///
778/// You would only use this binding if you are writing to the
779/// rendering layer directly. If you are writing to a higher-level
780/// library, such as the Flutter Widgets library, then you would use
781/// that layer's binding (see [WidgetsFlutterBinding]).
782///
783/// The [RenderingFlutterBinding] can manage multiple render trees. Each render
784/// tree is rooted in a [RenderView] that must be added to the binding via
785/// [addRenderView] to be consider during frame production, hit testing, etc.
786/// Furthermore, the render tree must be managed by a [PipelineOwner] that is
787/// part of the pipeline owner tree rooted at [rootPipelineOwner].
788///
789/// Adding [PipelineOwner]s and [RenderView]s to this binding in the way
790/// described above is left as a responsibility for a higher level abstraction.
791/// The binding does not own any [RenderView]s directly.
792class RenderingFlutterBinding extends BindingBase
793 with
794 GestureBinding,
795 SchedulerBinding,
796 ServicesBinding,
797 SemanticsBinding,
798 PaintingBinding,
799 RendererBinding {
800 /// Returns an instance of the binding that implements
801 /// [RendererBinding]. If no binding has yet been initialized, the
802 /// [RenderingFlutterBinding] class is used to create and initialize
803 /// one.
804 ///
805 /// You need to call this method before using the rendering framework
806 /// if you are using it directly. If you are using the widgets framework,
807 /// see [WidgetsFlutterBinding.ensureInitialized].
808 static RendererBinding ensureInitialized() {
809 if (RendererBinding._instance == null) {
810 RenderingFlutterBinding();
811 }
812 return RendererBinding.instance;
813 }
814}
815
816/// A [PipelineManifold] implementation that is backed by the [RendererBinding].
817class _BindingPipelineManifold extends ChangeNotifier implements PipelineManifold {
818 _BindingPipelineManifold(this._binding) {
819 if (kFlutterMemoryAllocationsEnabled) {
820 ChangeNotifier.maybeDispatchObjectCreation(this);
821 }
822 _binding.addSemanticsEnabledListener(notifyListeners);
823 }
824
825 final RendererBinding _binding;
826
827 @override
828 void requestVisualUpdate() {
829 _binding.ensureVisualUpdate();
830 }
831
832 @override
833 bool get semanticsEnabled => _binding.semanticsEnabled;
834
835 @override
836 void dispose() {
837 _binding.removeSemanticsEnabledListener(notifyListeners);
838 super.dispose();
839 }
840}
841
842// A [PipelineOwner] that cannot have a root node.
843final class _DefaultRootPipelineOwner extends PipelineOwner {
844 _DefaultRootPipelineOwner() : super(onSemanticsUpdate: _onSemanticsUpdate);
845
846 @override
847 set rootNode(RenderObject? _) {
848 assert(() {
849 throw FlutterError.fromParts(<DiagnosticsNode>[
850 ErrorSummary('Cannot set a rootNode on the default root pipeline owner.'),
851 ErrorDescription(
852 'By default, the RendererBinding.rootPipelineOwner is not configured '
853 'to manage a root node because this pipeline owner does not define a '
854 'proper onSemanticsUpdate callback to handle semantics for that node.',
855 ),
856 ErrorHint(
857 'Typically, the root pipeline owner does not manage a root node. '
858 'Instead, properly configured child pipeline owners (which do manage '
859 'root nodes) are added to it. Alternatively, if you do want to set a '
860 'root node for the root pipeline owner, override '
861 'RendererBinding.createRootPipelineOwner to create a '
862 'pipeline owner that is configured to properly handle semantics for '
863 'the provided root node.',
864 ),
865 ]);
866 }());
867 }
868
869 static void _onSemanticsUpdate(ui.SemanticsUpdate _) {
870 // Neve called because we don't have a root node.
871 assert(false);
872 }
873}
874
875// Prior to multi view support, the [RendererBinding] would own a long-lived
876// [RenderView], that was never disposed (see [RendererBinding.renderView]).
877// With multi view support, the [RendererBinding] no longer owns a [RenderView]
878// and instead higher level abstractions (like the [View] widget) can add/remove
879// multiple [RenderView]s to the binding as needed. When the [View] widget is no
880// longer needed, it expects to dispose its [RenderView].
881//
882// This special version of a [RenderView] now exists as a bridge between those
883// worlds to continue supporting the [RendererBinding.renderView] property
884// through its deprecation period. Per the property's contract, it is supposed
885// to be long-lived, but it is also managed by a [View] widget (introduced by
886// [WidgetsBinding.wrapWithDefaultView]), that expects to dispose its render
887// object at the end of the widget's life time. This special version now
888// implements logic to reset the [RenderView] when it is "disposed" so it can be
889// reused by another [View] widget.
890//
891// Once the deprecated [RendererBinding.renderView] property is removed, this
892// class is no longer necessary.
893class _ReusableRenderView extends RenderView {
894 _ReusableRenderView({required super.view});
895
896 bool _initialFramePrepared = false;
897
898 @override
899 void prepareInitialFrame() {
900 if (_initialFramePrepared) {
901 return;
902 }
903 super.prepareInitialFrame();
904 _initialFramePrepared = true;
905 }
906
907 @override
908 void scheduleInitialSemantics() {
909 clearSemantics();
910 super.scheduleInitialSemantics();
911 }
912
913 @override
914 // ignore: must_call_super
915 void dispose() {
916 child = null;
917 }
918}
919