binding.dart 10.4 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:ui' as ui show window;
8

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

import 'box.dart';
15
import 'debug.dart';
16
import 'object.dart';
Hixie's avatar
Hixie committed
17
import 'semantics.dart';
18
import 'view.dart';
19

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

Florian Loitsch's avatar
Florian Loitsch committed
22
/// The glue between the render tree and the Flutter engine.
23
abstract class RendererBinding extends BindingBase implements SchedulerBinding, ServicesBinding, HitTestable {
24
  @override
Ian Hickson's avatar
Ian Hickson committed
25 26
  void initInstances() {
    super.initInstances();
27
    _instance = this;
28 29
    _pipelineOwner = new PipelineOwner(
      onNeedVisualUpdate: ensureVisualUpdate,
30 31
      onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
      onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
32
    );
33 34 35 36
    ui.window
      ..onMetricsChanged = handleMetricsChanged
      ..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
      ..onSemanticsAction = _handleSemanticsAction;
Ian Hickson's avatar
Ian Hickson committed
37
    initRenderView();
38
    _handleSemanticsEnabledChanged();
39
    assert(renderView != null);
40 41 42
    addPersistentFrameCallback(_handlePersistentFrameCallback);
  }

43 44 45
  /// The current [RendererBinding], if one has been created.
  static RendererBinding get instance => _instance;
  static RendererBinding _instance;
46 47 48 49

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

51
    assert(() {
52 53
      // this service extension only works in checked mode
      registerBoolServiceExtension(
54
        name: 'debugPaint',
55
        getter: () async => debugPaintSizeEnabled,
56 57
        setter: (bool value) {
          if (debugPaintSizeEnabled == value)
58
            return new Future<Null>.value();
59
          debugPaintSizeEnabled = value;
60
          return _forceRepaint();
61 62
        }
      );
63 64
      return true;
    });
65

66 67
    registerSignalServiceExtension(
      name: 'debugDumpRenderTree',
68
      callback: () { debugDumpRenderTree(); return debugPrintDone; }
69
    );
70

71 72 73 74
    assert(() {
      // this service extension only works in checked mode
      registerBoolServiceExtension(
        name: 'repaintRainbow',
75
        getter: () async => debugRepaintRainbowEnabled,
76
        setter: (bool value) {
77
          final bool repaint = debugRepaintRainbowEnabled && !value;
78
          debugRepaintRainbowEnabled = value;
79
          if (repaint)
80 81
            return _forceRepaint();
          return new Future<Null>.value();
82 83 84 85 86
        }
      );
      return true;
    });
  }
87

88 89 90 91 92 93
  /// Creates a [RenderView] object to be the root of the
  /// [RenderObject] rendering tree, and initializes it so that it
  /// will be rendered when the engine is next ready to display a
  /// frame.
  ///
  /// Called automatically when the binding is created.
Ian Hickson's avatar
Ian Hickson committed
94
  void initRenderView() {
95 96 97
    assert(renderView == null);
    renderView = new RenderView(configuration: createViewConfiguration());
    renderView.scheduleInitialFrame();
98 99
  }

100 101
  /// The render tree's owner, which maintains dirty state for layout,
  /// composite, paint, and accessibility semantics
102 103
  PipelineOwner get pipelineOwner => _pipelineOwner;
  PipelineOwner _pipelineOwner;
104

Florian Loitsch's avatar
Florian Loitsch committed
105
  /// The render tree that's attached to the output surface.
106
  RenderView get renderView => _pipelineOwner.rootNode;
107 108
  /// 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.
109
  set renderView(RenderView value) {
110
    assert(value != null);
111
    _pipelineOwner.rootNode = value;
112 113
  }

114
  /// Called when the system metrics change.
115 116
  ///
  /// See [ui.window.onMetricsChanged].
Ian Hickson's avatar
Ian Hickson committed
117
  void handleMetricsChanged() {
118
    assert(renderView != null);
119 120 121 122 123 124 125 126 127 128 129 130 131 132
    renderView.configuration = createViewConfiguration();
  }

  /// 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() {
133
    final double devicePixelRatio = ui.window.devicePixelRatio;
134
    return new ViewConfiguration(
135 136
      size: ui.window.physicalSize / devicePixelRatio,
      devicePixelRatio: devicePixelRatio
137
    );
138 139
  }

140 141 142
  SemanticsHandle _semanticsHandle;

  void _handleSemanticsEnabledChanged() {
143 144 145
    setSemanticsEnabled(ui.window.semanticsEnabled);
  }

146 147
  /// Whether the render tree associated with this binding should produce a tree
  /// of [SemanticsNode] objects.
148 149
  void setSemanticsEnabled(bool enabled) {
    if (enabled) {
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
      _semanticsHandle ??= _pipelineOwner.ensureSemantics();
    } else {
      _semanticsHandle?.dispose();
      _semanticsHandle = null;
    }
  }

  void _handleSemanticsAction(int id, SemanticsAction action) {
    _pipelineOwner.semanticsOwner?.performAction(id, action);
  }

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

  void _handleSemanticsOwnerDisposed() {
    renderView.clearSemantics();
Hixie's avatar
Hixie committed
167 168
  }

169 170 171 172
  void _handlePersistentFrameCallback(Duration timeStamp) {
    beginFrame();
  }

Ian Hickson's avatar
Ian Hickson committed
173
  /// Pump the rendering pipeline to generate a frame.
174
  ///
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
  /// This method is called by [handleBeginFrame], which itself is called
  /// automatically by the engine when when it is time to lay out and paint a
  /// frame.
  ///
  /// Each frame consists of the following phases:
  ///
  /// 1. The animation phase: The [handleBeginFrame] method, which is registered
  /// with [ui.window.onBeginFrame], invokes all the transient frame callbacks
  /// registered with [scheduleFrameCallback] and [addFrameCallback], 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.
  ///
  /// [handleBeginFrame] then invokes all the persistent frame callbacks, of which
  /// the most notable is this method, [beginFrame], which proceeds as follows:
  ///
  /// 2. The layout phase: All the dirty [RenderObject]s in the system are laid
  /// out (see [RenderObject.performLayout]). See [RenderObject.markNeedsLayout]
  /// for further details on marking an object dirty for layout.
  ///
  /// 3. The compositing bits phase: The compositing bits on any dirty
  /// [RenderObject] objects are updated. See
  /// [RenderObject.markNeedsCompositingBitsUpdate].
  ///
  /// 4. The paint phase: All the dirty [RenderObject]s in the system are
  /// repainted (see [RenderObject.paint]). This generates the [Layer] tree. See
  /// [RenderObject.markNeedsPaint] for further details on marking an object
  /// dirty for paint.
  ///
  /// 5. The compositing phase: The layer tree is turned into a [ui.Scene] and
  /// sent to the GPU.
  ///
  /// 6. The semantics phase: All the dirty [RenderObject]s in the system have
208
  /// their semantics updated (see [RenderObject.SemanticsAnnotator]). This
209 210 211 212 213 214 215 216 217 218
  /// generates the [SemanticsNode] tree. See
  /// [RenderObject.markNeedsSemanticsUpdate] for further details on marking an
  /// object dirty for semantics.
  ///
  /// For more details on steps 2-6, see [PipelineOwner].
  ///
  /// 7. The finalization phase: After [beginFrame] returns, [handleBeginFrame]
  /// then invokes post-frame callbacks (registered with [addPostFrameCallback].
  ///
  /// Some bindings (for example, the [WidgetsBinding]) add extra steps to this
219
  /// list (for example, see [WidgetsBinding.beginFrame]).
220 221
  //
  // When editing the above, also update widgets/binding.dart's copy.
Ian Hickson's avatar
Ian Hickson committed
222
  @protected
223
  void beginFrame() {
224
    assert(renderView != null);
225 226 227
    pipelineOwner.flushLayout();
    pipelineOwner.flushCompositingBits();
    pipelineOwner.flushPaint();
Hixie's avatar
Hixie committed
228
    renderView.compositeFrame(); // this sends the bits to the GPU
229
    pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
230 231
  }

232
  @override
233 234
  Future<Null> reassembleApplication() async {
    await super.reassembleApplication();
235 236 237 238 239 240
    Timeline.startSync('Dirty Render Tree');
    try {
      renderView.reassemble();
    } finally {
      Timeline.finishSync();
    }
Ian Hickson's avatar
Ian Hickson committed
241
    handleBeginFrame(null);
242
    await endOfFrame;
243 244
  }

245
  @override
Ian Hickson's avatar
Ian Hickson committed
246
  void hitTest(HitTestResult result, Point position) {
247 248
    assert(renderView != null);
    renderView.hitTest(result, position: position);
249
    // This super call is safe since it will be bound to a mixed-in declaration.
Adam Barth's avatar
Adam Barth committed
250
    super.hitTest(result, position); // ignore: abstract_super_member_reference
251
  }
252

253
  Future<Null> _forceRepaint() {
254 255 256 257 258 259
    RenderObjectVisitor visitor;
    visitor = (RenderObject child) {
      child.markNeedsPaint();
      child.visitChildren(visitor);
    };
    instance?.renderView?.visitChildren(visitor);
260
    return endOfFrame;
261
  }
262
}
263

Florian Loitsch's avatar
Florian Loitsch committed
264
/// Prints a textual representation of the entire render tree.
265
void debugDumpRenderTree() {
266
  debugPrint(RendererBinding.instance?.renderView?.toStringDeep());
267
}
268

Florian Loitsch's avatar
Florian Loitsch committed
269
/// Prints a textual representation of the entire layer tree.
270
void debugDumpLayerTree() {
271
  debugPrint(RendererBinding.instance?.renderView?.debugLayer?.toStringDeep());
Ian Hickson's avatar
Ian Hickson committed
272 273
}

Hixie's avatar
Hixie committed
274 275 276 277
/// Prints a textual representation of the entire semantics tree.
/// This will only work if there is a semantics client attached.
/// Otherwise, the tree is empty and this will print "null".
void debugDumpSemanticsTree() {
278
  debugPrint(RendererBinding.instance?.renderView?.debugSemantics?.toStringDeep() ?? 'Semantics not collected.');
Hixie's avatar
Hixie committed
279 280
}

Ian Hickson's avatar
Ian Hickson committed
281 282
/// A concrete binding for applications that use the Rendering framework
/// directly. This is the glue that binds the framework to the Flutter engine.
283 284 285 286 287 288 289
///
/// 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].
290
class RenderingFlutterBinding extends BindingBase with SchedulerBinding, GestureBinding, ServicesBinding, RendererBinding {
291 292 293 294
  /// 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
295
  RenderingFlutterBinding({ RenderBox root }) {
296
    assert(renderView != null);
Ian Hickson's avatar
Ian Hickson committed
297 298
    renderView.child = root;
  }
299
}