• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 The Chromium 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:async';
6import 'dart:developer';
7import 'dart:typed_data';
8
9import 'package:flutter/foundation.dart';
10import 'package:flutter/gestures.dart';
11import 'package:flutter/scheduler.dart';
12import 'package:flutter/semantics.dart';
13import 'package:flutter/services.dart';
14
15import 'box.dart';
16import 'debug.dart';
17import 'object.dart';
18import 'view.dart';
19
20export 'package:flutter/gestures.dart' show HitTestResult;
21
22// Examples can assume:
23// dynamic context;
24
25/// The glue between the render tree and the Flutter engine.
26mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
27  @override
28  void initInstances() {
29    super.initInstances();
30    _instance = this;
31    _pipelineOwner = PipelineOwner(
32      onNeedVisualUpdate: ensureVisualUpdate,
33      onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
34      onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
35    );
36    window
37      ..onMetricsChanged = handleMetricsChanged
38      ..onTextScaleFactorChanged = handleTextScaleFactorChanged
39      ..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
40      ..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
41      ..onSemanticsAction = _handleSemanticsAction;
42    initRenderView();
43    _handleSemanticsEnabledChanged();
44    assert(renderView != null);
45    addPersistentFrameCallback(_handlePersistentFrameCallback);
46    _mouseTracker = _createMouseTracker();
47  }
48
49  /// The current [RendererBinding], if one has been created.
50  static RendererBinding get instance => _instance;
51  static RendererBinding _instance;
52
53  @override
54  void initServiceExtensions() {
55    super.initServiceExtensions();
56
57    assert(() {
58      // these service extensions only work in debug mode
59      registerBoolServiceExtension(
60        name: 'debugPaint',
61        getter: () async => debugPaintSizeEnabled,
62        setter: (bool value) {
63          if (debugPaintSizeEnabled == value)
64            return Future<void>.value();
65          debugPaintSizeEnabled = value;
66          return _forceRepaint();
67        },
68      );
69      registerBoolServiceExtension(
70        name: 'debugPaintBaselinesEnabled',
71        getter: () async => debugPaintBaselinesEnabled,
72        setter: (bool value) {
73          if (debugPaintBaselinesEnabled == value)
74            return Future<void>.value();
75          debugPaintBaselinesEnabled = value;
76          return _forceRepaint();
77        },
78      );
79      registerBoolServiceExtension(
80        name: 'repaintRainbow',
81        getter: () async => debugRepaintRainbowEnabled,
82        setter: (bool value) {
83          final bool repaint = debugRepaintRainbowEnabled && !value;
84          debugRepaintRainbowEnabled = value;
85          if (repaint)
86            return _forceRepaint();
87          return Future<void>.value();
88        },
89      );
90      registerBoolServiceExtension(
91        name: 'debugCheckElevationsEnabled',
92        getter: () async => debugCheckElevationsEnabled,
93        setter: (bool value) {
94          if (debugCheckElevationsEnabled == value) {
95            return Future<void>.value();
96          }
97          debugCheckElevationsEnabled = value;
98          return _forceRepaint();
99        }
100      );
101      registerSignalServiceExtension(
102        name: 'debugDumpLayerTree',
103        callback: () {
104          debugDumpLayerTree();
105          return debugPrintDone;
106        },
107      );
108      return true;
109    }());
110
111    if (!kReleaseMode) {
112      // these service extensions work in debug or profile mode
113      registerSignalServiceExtension(
114        name: 'debugDumpRenderTree',
115        callback: () {
116          debugDumpRenderTree();
117          return debugPrintDone;
118        },
119      );
120
121      registerSignalServiceExtension(
122        name: 'debugDumpSemanticsTreeInTraversalOrder',
123        callback: () {
124          debugDumpSemanticsTree(DebugSemanticsDumpOrder.traversalOrder);
125          return debugPrintDone;
126        },
127      );
128
129      registerSignalServiceExtension(
130        name: 'debugDumpSemanticsTreeInInverseHitTestOrder',
131        callback: () {
132          debugDumpSemanticsTree(DebugSemanticsDumpOrder.inverseHitTest);
133          return debugPrintDone;
134        },
135      );
136    }
137  }
138
139  /// Creates a [RenderView] object to be the root of the
140  /// [RenderObject] rendering tree, and initializes it so that it
141  /// will be rendered when the engine is next ready to display a
142  /// frame.
143  ///
144  /// Called automatically when the binding is created.
145  void initRenderView() {
146    assert(renderView == null);
147    renderView = RenderView(configuration: createViewConfiguration(), window: window);
148    renderView.scheduleInitialFrame();
149  }
150
151  /// The object that manages state about currently connected mice, for hover
152  /// notification.
153  MouseTracker get mouseTracker => _mouseTracker;
154  MouseTracker _mouseTracker;
155
156  /// The render tree's owner, which maintains dirty state for layout,
157  /// composite, paint, and accessibility semantics
158  PipelineOwner get pipelineOwner => _pipelineOwner;
159  PipelineOwner _pipelineOwner;
160
161  /// The render tree that's attached to the output surface.
162  RenderView get renderView => _pipelineOwner.rootNode;
163  /// Sets the given [RenderView] object (which must not be null), and its tree, to
164  /// be the new render tree to display. The previous tree, if any, is detached.
165  set renderView(RenderView value) {
166    assert(value != null);
167    _pipelineOwner.rootNode = value;
168  }
169
170  /// Called when the system metrics change.
171  ///
172  /// See [Window.onMetricsChanged].
173  @protected
174  void handleMetricsChanged() {
175    assert(renderView != null);
176    renderView.configuration = createViewConfiguration();
177    scheduleForcedFrame();
178  }
179
180  /// Called when the platform text scale factor changes.
181  ///
182  /// See [Window.onTextScaleFactorChanged].
183  @protected
184  void handleTextScaleFactorChanged() { }
185
186  /// {@template on_platform_brightness_change}
187  /// Called when the platform brightness changes.
188  ///
189  /// The current platform brightness can be queried either from a Flutter
190  /// binding, or from a [MediaQuery] widget.
191  ///
192  /// {@tool sample}
193  /// Querying [Window.platformBrightness].
194  ///
195  /// ```dart
196  /// final Brightness brightness = WidgetsBinding.instance.window.platformBrightness;
197  /// ```
198  /// {@end-tool}
199  ///
200  /// {@tool sample}
201  /// Querying [MediaQuery] directly.
202  ///
203  /// ```dart
204  /// final Brightness brightness = MediaQuery.platformBrightnessOf(context);
205  /// ```
206  /// {@end-tool}
207  ///
208  /// {@tool sample}
209  /// Querying [MediaQueryData].
210  ///
211  /// ```dart
212  /// final MediaQueryData mediaQueryData = MediaQuery.of(context);
213  /// final Brightness brightness = mediaQueryData.platformBrightness;
214  /// ```
215  /// {@end-tool}
216  ///
217  /// See [Window.onPlatformBrightnessChanged].
218  /// {@endtemplate}
219  @protected
220  void handlePlatformBrightnessChanged() { }
221
222  /// Returns a [ViewConfiguration] configured for the [RenderView] based on the
223  /// current environment.
224  ///
225  /// This is called during construction and also in response to changes to the
226  /// system metrics.
227  ///
228  /// Bindings can override this method to change what size or device pixel
229  /// ratio the [RenderView] will use. For example, the testing framework uses
230  /// this to force the display into 800x600 when a test is run on the device
231  /// using `flutter run`.
232  ViewConfiguration createViewConfiguration() {
233    final double devicePixelRatio = window.devicePixelRatio;
234    return ViewConfiguration(
235      size: window.physicalSize / devicePixelRatio,
236      devicePixelRatio: devicePixelRatio,
237    );
238  }
239
240  SemanticsHandle _semanticsHandle;
241
242  // Creates a [MouseTracker] which manages state about currently connected
243  // mice, for hover notification.
244  MouseTracker _createMouseTracker() {
245    return MouseTracker(pointerRouter, renderView.hitTestMouseTrackers);
246  }
247
248  void _handleSemanticsEnabledChanged() {
249    setSemanticsEnabled(window.semanticsEnabled);
250  }
251
252  /// Whether the render tree associated with this binding should produce a tree
253  /// of [SemanticsNode] objects.
254  void setSemanticsEnabled(bool enabled) {
255    if (enabled) {
256      _semanticsHandle ??= _pipelineOwner.ensureSemantics();
257    } else {
258      _semanticsHandle?.dispose();
259      _semanticsHandle = null;
260    }
261  }
262
263  void _handleSemanticsAction(int id, SemanticsAction action, ByteData args) {
264    _pipelineOwner.semanticsOwner?.performAction(
265      id,
266      action,
267      args != null ? const StandardMessageCodec().decodeMessage(args) : null,
268    );
269  }
270
271  void _handleSemanticsOwnerCreated() {
272    renderView.scheduleInitialSemantics();
273  }
274
275  void _handleSemanticsOwnerDisposed() {
276    renderView.clearSemantics();
277  }
278
279  void _handlePersistentFrameCallback(Duration timeStamp) {
280    drawFrame();
281  }
282
283  /// Pump the rendering pipeline to generate a frame.
284  ///
285  /// This method is called by [handleDrawFrame], which itself is called
286  /// automatically by the engine when it is time to lay out and paint a frame.
287  ///
288  /// Each frame consists of the following phases:
289  ///
290  /// 1. The animation phase: The [handleBeginFrame] method, which is registered
291  /// with [Window.onBeginFrame], invokes all the transient frame callbacks
292  /// registered with [scheduleFrameCallback], in registration order. This
293  /// includes all the [Ticker] instances that are driving [AnimationController]
294  /// objects, which means all of the active [Animation] objects tick at this
295  /// point.
296  ///
297  /// 2. Microtasks: After [handleBeginFrame] returns, any microtasks that got
298  /// scheduled by transient frame callbacks get to run. This typically includes
299  /// callbacks for futures from [Ticker]s and [AnimationController]s that
300  /// completed this frame.
301  ///
302  /// After [handleBeginFrame], [handleDrawFrame], which is registered with
303  /// [Window.onDrawFrame], is called, which invokes all the persistent frame
304  /// callbacks, of which the most notable is this method, [drawFrame], which
305  /// proceeds as follows:
306  ///
307  /// 3. The layout phase: All the dirty [RenderObject]s in the system are laid
308  /// out (see [RenderObject.performLayout]). See [RenderObject.markNeedsLayout]
309  /// for further details on marking an object dirty for layout.
310  ///
311  /// 4. The compositing bits phase: The compositing bits on any dirty
312  /// [RenderObject] objects are updated. See
313  /// [RenderObject.markNeedsCompositingBitsUpdate].
314  ///
315  /// 5. The paint phase: All the dirty [RenderObject]s in the system are
316  /// repainted (see [RenderObject.paint]). This generates the [Layer] tree. See
317  /// [RenderObject.markNeedsPaint] for further details on marking an object
318  /// dirty for paint.
319  ///
320  /// 6. The compositing phase: The layer tree is turned into a [Scene] and
321  /// sent to the GPU.
322  ///
323  /// 7. The semantics phase: All the dirty [RenderObject]s in the system have
324  /// their semantics updated (see [RenderObject.semanticsAnnotator]). This
325  /// generates the [SemanticsNode] tree. See
326  /// [RenderObject.markNeedsSemanticsUpdate] for further details on marking an
327  /// object dirty for semantics.
328  ///
329  /// For more details on steps 3-7, see [PipelineOwner].
330  ///
331  /// 8. The finalization phase: After [drawFrame] returns, [handleDrawFrame]
332  /// then invokes post-frame callbacks (registered with [addPostFrameCallback]).
333  ///
334  /// Some bindings (for example, the [WidgetsBinding]) add extra steps to this
335  /// list (for example, see [WidgetsBinding.drawFrame]).
336  //
337  // When editing the above, also update widgets/binding.dart's copy.
338  @protected
339  void drawFrame() {
340    assert(renderView != null);
341    pipelineOwner.flushLayout();
342    pipelineOwner.flushCompositingBits();
343    pipelineOwner.flushPaint();
344    renderView.compositeFrame(); // this sends the bits to the GPU
345    pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
346  }
347
348  @override
349  Future<void> performReassemble() async {
350    await super.performReassemble();
351    Timeline.startSync('Dirty Render Tree', arguments: timelineWhitelistArguments);
352    try {
353      renderView.reassemble();
354    } finally {
355      Timeline.finishSync();
356    }
357    scheduleWarmUpFrame();
358    await endOfFrame;
359  }
360
361  @override
362  void hitTest(HitTestResult result, Offset position) {
363    assert(renderView != null);
364    renderView.hitTest(result, position: position);
365    super.hitTest(result, position);
366  }
367
368  Future<void> _forceRepaint() {
369    RenderObjectVisitor visitor;
370    visitor = (RenderObject child) {
371      child.markNeedsPaint();
372      child.visitChildren(visitor);
373    };
374    instance?.renderView?.visitChildren(visitor);
375    return endOfFrame;
376  }
377}
378
379/// Prints a textual representation of the entire render tree.
380void debugDumpRenderTree() {
381  debugPrint(RendererBinding.instance?.renderView?.toStringDeep() ?? 'Render tree unavailable.');
382}
383
384/// Prints a textual representation of the entire layer tree.
385void debugDumpLayerTree() {
386  debugPrint(RendererBinding.instance?.renderView?.debugLayer?.toStringDeep() ?? 'Layer tree unavailable.');
387}
388
389/// Prints a textual representation of the entire semantics tree.
390/// This will only work if there is a semantics client attached.
391/// Otherwise, a notice that no semantics are available will be printed.
392///
393/// The order in which the children of a [SemanticsNode] will be printed is
394/// controlled by the [childOrder] parameter.
395void debugDumpSemanticsTree(DebugSemanticsDumpOrder childOrder) {
396  debugPrint(RendererBinding.instance?.renderView?.debugSemantics?.toStringDeep(childOrder: childOrder) ?? 'Semantics not collected.');
397}
398
399/// A concrete binding for applications that use the Rendering framework
400/// directly. This is the glue that binds the framework to the Flutter engine.
401///
402/// You would only use this binding if you are writing to the
403/// rendering layer directly. If you are writing to a higher-level
404/// library, such as the Flutter Widgets library, then you would use
405/// that layer's binding.
406///
407/// See also [BindingBase].
408class RenderingFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, SemanticsBinding, RendererBinding {
409  /// Creates a binding for the rendering layer.
410  ///
411  /// The `root` render box is attached directly to the [renderView] and is
412  /// given constraints that require it to fill the window.
413  RenderingFlutterBinding({ RenderBox root }) {
414    assert(renderView != null);
415    renderView.child = root;
416  }
417}
418