binding.dart 14.2 KB
Newer Older
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'dart:async';
6
import 'dart:developer';
7
import 'dart:typed_data';
8

9
import 'package:flutter/foundation.dart';
10
import 'package:flutter/gestures.dart';
11
import 'package:flutter/scheduler.dart';
12
import 'package:flutter/semantics.dart';
Ian Hickson's avatar
Ian Hickson committed
13
import 'package:flutter/services.dart';
14 15

import 'box.dart';
16
import 'debug.dart';
17
import 'object.dart';
18
import 'view.dart';
19

Ian Hickson's avatar
Ian Hickson committed
20
export 'package:flutter/gestures.dart' show HitTestResult;
21

22 23 24
// Examples can assume:
// dynamic context;

Florian Loitsch's avatar
Florian Loitsch committed
25
/// The glue between the render tree and the Flutter engine.
26
mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
27
  @override
Ian Hickson's avatar
Ian Hickson committed
28 29
  void initInstances() {
    super.initInstances();
30
    _instance = this;
31
    _pipelineOwner = PipelineOwner(
32
      onNeedVisualUpdate: ensureVisualUpdate,
33 34
      onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
      onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
35
    );
36
    window
37
      ..onMetricsChanged = handleMetricsChanged
38
      ..onTextScaleFactorChanged = handleTextScaleFactorChanged
39
      ..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
40 41
      ..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
      ..onSemanticsAction = _handleSemanticsAction;
Ian Hickson's avatar
Ian Hickson committed
42
    initRenderView();
43
    _handleSemanticsEnabledChanged();
44
    assert(renderView != null);
45
    addPersistentFrameCallback(_handlePersistentFrameCallback);
46
    _mouseTracker = _createMouseTracker();
47 48
  }

49 50 51
  /// The current [RendererBinding], if one has been created.
  static RendererBinding get instance => _instance;
  static RendererBinding _instance;
52 53 54 55

  @override
  void initServiceExtensions() {
    super.initServiceExtensions();
56

57
    assert(() {
58
      // these service extensions only work in debug mode
59
      registerBoolServiceExtension(
60
        name: 'debugPaint',
61
        getter: () async => debugPaintSizeEnabled,
62 63
        setter: (bool value) {
          if (debugPaintSizeEnabled == value)
64
            return Future<void>.value();
65
          debugPaintSizeEnabled = value;
66
          return _forceRepaint();
67
        },
68
      );
69
      registerBoolServiceExtension(
70 71 72
        name: 'debugPaintBaselinesEnabled',
        getter: () async => debugPaintBaselinesEnabled,
        setter: (bool value) {
73
          if (debugPaintBaselinesEnabled == value)
74
            return Future<void>.value();
75 76
          debugPaintBaselinesEnabled = value;
          return _forceRepaint();
77
        },
78 79
      );
      registerBoolServiceExtension(
80 81 82 83 84 85 86
        name: 'repaintRainbow',
        getter: () async => debugRepaintRainbowEnabled,
        setter: (bool value) {
          final bool repaint = debugRepaintRainbowEnabled && !value;
          debugRepaintRainbowEnabled = value;
          if (repaint)
            return _forceRepaint();
87
          return Future<void>.value();
88 89
        },
      );
90 91 92 93 94 95 96 97 98
      registerBoolServiceExtension(
        name: 'debugCheckElevationsEnabled',
        getter: () async => debugCheckElevationsEnabled,
        setter: (bool value) {
          if (debugCheckElevationsEnabled == value) {
            return Future<void>.value();
          }
          debugCheckElevationsEnabled = value;
          return _forceRepaint();
99
        },
100
      );
101 102 103 104 105 106 107
      registerSignalServiceExtension(
        name: 'debugDumpLayerTree',
        callback: () {
          debugDumpLayerTree();
          return debugPrintDone;
        },
      );
108
      return true;
109
    }());
110

111
    if (!kReleaseMode) {
112 113 114 115 116 117 118 119
      // these service extensions work in debug or profile mode
      registerSignalServiceExtension(
        name: 'debugDumpRenderTree',
        callback: () {
          debugDumpRenderTree();
          return debugPrintDone;
        },
      );
120

121 122 123 124 125 126 127
      registerSignalServiceExtension(
        name: 'debugDumpSemanticsTreeInTraversalOrder',
        callback: () {
          debugDumpSemanticsTree(DebugSemanticsDumpOrder.traversalOrder);
          return debugPrintDone;
        },
      );
128

129 130 131 132 133 134 135 136
      registerSignalServiceExtension(
        name: 'debugDumpSemanticsTreeInInverseHitTestOrder',
        callback: () {
          debugDumpSemanticsTree(DebugSemanticsDumpOrder.inverseHitTest);
          return debugPrintDone;
        },
      );
    }
137
  }
138

139 140
  /// Creates a [RenderView] object to be the root of the
  /// [RenderObject] rendering tree, and initializes it so that it
141
  /// will be rendered when the next frame is requested.
142 143
  ///
  /// Called automatically when the binding is created.
Ian Hickson's avatar
Ian Hickson committed
144
  void initRenderView() {
145
    assert(renderView == null);
146
    renderView = RenderView(configuration: createViewConfiguration(), window: window);
147
    renderView.prepareInitialFrame();
148 149
  }

150 151 152 153 154
  /// The object that manages state about currently connected mice, for hover
  /// notification.
  MouseTracker get mouseTracker => _mouseTracker;
  MouseTracker _mouseTracker;

155 156
  /// The render tree's owner, which maintains dirty state for layout,
  /// composite, paint, and accessibility semantics
157 158
  PipelineOwner get pipelineOwner => _pipelineOwner;
  PipelineOwner _pipelineOwner;
159

Florian Loitsch's avatar
Florian Loitsch committed
160
  /// The render tree that's attached to the output surface.
161
  RenderView get renderView => _pipelineOwner.rootNode;
162 163
  /// Sets the given [RenderView] object (which must not be null), and its tree, to
  /// be the new render tree to display. The previous tree, if any, is detached.
164
  set renderView(RenderView value) {
165
    assert(value != null);
166
    _pipelineOwner.rootNode = value;
167 168
  }

169
  /// Called when the system metrics change.
170
  ///
171
  /// See [Window.onMetricsChanged].
172
  @protected
Ian Hickson's avatar
Ian Hickson committed
173
  void handleMetricsChanged() {
174
    assert(renderView != null);
175
    renderView.configuration = createViewConfiguration();
176
    scheduleForcedFrame();
177 178
  }

179 180 181
  /// Called when the platform text scale factor changes.
  ///
  /// See [Window.onTextScaleFactorChanged].
182
  @protected
183 184
  void handleTextScaleFactorChanged() { }

185 186 187 188 189 190
  /// {@template on_platform_brightness_change}
  /// Called when the platform brightness changes.
  ///
  /// The current platform brightness can be queried either from a Flutter
  /// binding, or from a [MediaQuery] widget.
  ///
191 192
  /// {@tool sample}
  /// Querying [Window.platformBrightness].
193 194 195 196
  ///
  /// ```dart
  /// final Brightness brightness = WidgetsBinding.instance.window.platformBrightness;
  /// ```
197
  /// {@end-tool}
198
  ///
199 200
  /// {@tool sample}
  /// Querying [MediaQuery] directly.
201 202 203 204
  ///
  /// ```dart
  /// final Brightness brightness = MediaQuery.platformBrightnessOf(context);
  /// ```
205
  /// {@end-tool}
206
  ///
207 208
  /// {@tool sample}
  /// Querying [MediaQueryData].
209 210 211 212 213
  ///
  /// ```dart
  /// final MediaQueryData mediaQueryData = MediaQuery.of(context);
  /// final Brightness brightness = mediaQueryData.platformBrightness;
  /// ```
214
  /// {@end-tool}
215 216 217 218 219 220
  ///
  /// See [Window.onPlatformBrightnessChanged].
  /// {@endtemplate}
  @protected
  void handlePlatformBrightnessChanged() { }

221 222 223 224 225 226 227 228 229 230 231
  /// Returns a [ViewConfiguration] configured for the [RenderView] based on the
  /// current environment.
  ///
  /// This is called during construction and also in response to changes to the
  /// system metrics.
  ///
  /// Bindings can override this method to change what size or device pixel
  /// ratio the [RenderView] will use. For example, the testing framework uses
  /// this to force the display into 800x600 when a test is run on the device
  /// using `flutter run`.
  ViewConfiguration createViewConfiguration() {
232
    final double devicePixelRatio = window.devicePixelRatio;
233
    return ViewConfiguration(
234
      size: window.physicalSize / devicePixelRatio,
235
      devicePixelRatio: devicePixelRatio,
236
    );
237 238
  }

239 240
  SemanticsHandle _semanticsHandle;

241 242 243
  // Creates a [MouseTracker] which manages state about currently connected
  // mice, for hover notification.
  MouseTracker _createMouseTracker() {
244
    return MouseTracker(pointerRouter, renderView.hitTestMouseTrackers);
245 246
  }

247
  void _handleSemanticsEnabledChanged() {
248
    setSemanticsEnabled(window.semanticsEnabled);
249 250
  }

251 252
  /// Whether the render tree associated with this binding should produce a tree
  /// of [SemanticsNode] objects.
253 254
  void setSemanticsEnabled(bool enabled) {
    if (enabled) {
255 256 257 258 259 260 261
      _semanticsHandle ??= _pipelineOwner.ensureSemantics();
    } else {
      _semanticsHandle?.dispose();
      _semanticsHandle = null;
    }
  }

262 263 264 265 266 267
  void _handleSemanticsAction(int id, SemanticsAction action, ByteData args) {
    _pipelineOwner.semanticsOwner?.performAction(
      id,
      action,
      args != null ? const StandardMessageCodec().decodeMessage(args) : null,
    );
268 269 270 271 272 273 274 275
  }

  void _handleSemanticsOwnerCreated() {
    renderView.scheduleInitialSemantics();
  }

  void _handleSemanticsOwnerDisposed() {
    renderView.clearSemantics();
Hixie's avatar
Hixie committed
276 277
  }

278
  void _handlePersistentFrameCallback(Duration timeStamp) {
279
    drawFrame();
280 281
  }

Ian Hickson's avatar
Ian Hickson committed
282
  /// Pump the rendering pipeline to generate a frame.
283
  ///
284
  /// This method is called by [handleDrawFrame], which itself is called
285
  /// automatically by the engine when it is time to lay out and paint a frame.
286 287 288 289
  ///
  /// Each frame consists of the following phases:
  ///
  /// 1. The animation phase: The [handleBeginFrame] method, which is registered
290 291 292 293 294
  /// with [Window.onBeginFrame], invokes all the transient frame callbacks
  /// registered with [scheduleFrameCallback], in registration order. This
  /// includes all the [Ticker] instances that are driving [AnimationController]
  /// objects, which means all of the active [Animation] objects tick at this
  /// point.
295
  ///
296 297 298 299
  /// 2. Microtasks: After [handleBeginFrame] returns, any microtasks that got
  /// scheduled by transient frame callbacks get to run. This typically includes
  /// callbacks for futures from [Ticker]s and [AnimationController]s that
  /// completed this frame.
300
  ///
301
  /// After [handleBeginFrame], [handleDrawFrame], which is registered with
302
  /// [Window.onDrawFrame], is called, which invokes all the persistent frame
303 304 305 306
  /// callbacks, of which the most notable is this method, [drawFrame], which
  /// proceeds as follows:
  ///
  /// 3. The layout phase: All the dirty [RenderObject]s in the system are laid
307 308 309
  /// out (see [RenderObject.performLayout]). See [RenderObject.markNeedsLayout]
  /// for further details on marking an object dirty for layout.
  ///
310
  /// 4. The compositing bits phase: The compositing bits on any dirty
311 312 313
  /// [RenderObject] objects are updated. See
  /// [RenderObject.markNeedsCompositingBitsUpdate].
  ///
314
  /// 5. The paint phase: All the dirty [RenderObject]s in the system are
315 316 317 318
  /// repainted (see [RenderObject.paint]). This generates the [Layer] tree. See
  /// [RenderObject.markNeedsPaint] for further details on marking an object
  /// dirty for paint.
  ///
319
  /// 6. The compositing phase: The layer tree is turned into a [Scene] and
320 321
  /// sent to the GPU.
  ///
322
  /// 7. The semantics phase: All the dirty [RenderObject]s in the system have
323
  /// their semantics updated (see [RenderObject.semanticsAnnotator]). This
324 325 326 327
  /// generates the [SemanticsNode] tree. See
  /// [RenderObject.markNeedsSemanticsUpdate] for further details on marking an
  /// object dirty for semantics.
  ///
328
  /// For more details on steps 3-7, see [PipelineOwner].
329
  ///
330 331
  /// 8. The finalization phase: After [drawFrame] returns, [handleDrawFrame]
  /// then invokes post-frame callbacks (registered with [addPostFrameCallback]).
332 333
  ///
  /// Some bindings (for example, the [WidgetsBinding]) add extra steps to this
334
  /// list (for example, see [WidgetsBinding.drawFrame]).
335 336
  //
  // When editing the above, also update widgets/binding.dart's copy.
Ian Hickson's avatar
Ian Hickson committed
337
  @protected
338
  void drawFrame() {
339
    assert(renderView != null);
340 341 342
    pipelineOwner.flushLayout();
    pipelineOwner.flushCompositingBits();
    pipelineOwner.flushPaint();
Hixie's avatar
Hixie committed
343
    renderView.compositeFrame(); // this sends the bits to the GPU
344
    pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
345 346
  }

347
  @override
348
  Future<void> performReassemble() async {
349
    await super.performReassemble();
350
    Timeline.startSync('Dirty Render Tree', arguments: timelineWhitelistArguments);
351 352 353 354 355
    try {
      renderView.reassemble();
    } finally {
      Timeline.finishSync();
    }
356
    scheduleWarmUpFrame();
357
    await endOfFrame;
358 359
  }

360
  @override
361
  void hitTest(HitTestResult result, Offset position) {
362 363
    assert(renderView != null);
    renderView.hitTest(result, position: position);
364
    super.hitTest(result, position);
365
  }
366

367
  Future<void> _forceRepaint() {
368 369 370 371 372 373
    RenderObjectVisitor visitor;
    visitor = (RenderObject child) {
      child.markNeedsPaint();
      child.visitChildren(visitor);
    };
    instance?.renderView?.visitChildren(visitor);
374
    return endOfFrame;
375
  }
376
}
377

Florian Loitsch's avatar
Florian Loitsch committed
378
/// Prints a textual representation of the entire render tree.
379
void debugDumpRenderTree() {
380
  debugPrint(RendererBinding.instance?.renderView?.toStringDeep() ?? 'Render tree unavailable.');
381
}
382

Florian Loitsch's avatar
Florian Loitsch committed
383
/// Prints a textual representation of the entire layer tree.
384
void debugDumpLayerTree() {
385
  debugPrint(RendererBinding.instance?.renderView?.debugLayer?.toStringDeep() ?? 'Layer tree unavailable.');
Ian Hickson's avatar
Ian Hickson committed
386 387
}

Hixie's avatar
Hixie committed
388 389
/// Prints a textual representation of the entire semantics tree.
/// This will only work if there is a semantics client attached.
390 391 392 393 394
/// Otherwise, a notice that no semantics are available will be printed.
///
/// The order in which the children of a [SemanticsNode] will be printed is
/// controlled by the [childOrder] parameter.
void debugDumpSemanticsTree(DebugSemanticsDumpOrder childOrder) {
395
  debugPrint(RendererBinding.instance?.renderView?.debugSemantics?.toStringDeep(childOrder: childOrder) ?? 'Semantics not collected.');
Hixie's avatar
Hixie committed
396 397
}

Ian Hickson's avatar
Ian Hickson committed
398 399
/// A concrete binding for applications that use the Rendering framework
/// directly. This is the glue that binds the framework to the Flutter engine.
400 401 402 403 404 405 406
///
/// You would only use this binding if you are writing to the
/// rendering layer directly. If you are writing to a higher-level
/// library, such as the Flutter Widgets library, then you would use
/// that layer's binding.
///
/// See also [BindingBase].
407
class RenderingFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, SemanticsBinding, PaintingBinding, RendererBinding {
408 409 410 411
  /// Creates a binding for the rendering layer.
  ///
  /// The `root` render box is attached directly to the [renderView] and is
  /// given constraints that require it to fill the window.
Ian Hickson's avatar
Ian Hickson committed
412
  RenderingFlutterBinding({ RenderBox root }) {
413
    assert(renderView != null);
Ian Hickson's avatar
Ian Hickson committed
414 415
    renderView.child = root;
  }
416
}