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