binding.dart 12.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:typed_data';
8
import 'dart:ui' as ui show window;
9

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

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

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

Florian Loitsch's avatar
Florian Loitsch committed
23
/// The glue between the render tree and the Flutter engine.
24
abstract class RendererBinding extends BindingBase with ServicesBinding, SchedulerBinding, HitTestable {
25 26 27 28
  // This class is intended to be used as a mixin, and should not be
  // extended directly.
  factory RendererBinding._() => null;

29
  @override
Ian Hickson's avatar
Ian Hickson committed
30 31
  void initInstances() {
    super.initInstances();
32
    _instance = this;
33 34
    _pipelineOwner = new PipelineOwner(
      onNeedVisualUpdate: ensureVisualUpdate,
35 36
      onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
      onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
37
    );
38 39
    ui.window
      ..onMetricsChanged = handleMetricsChanged
40
      ..onTextScaleFactorChanged = handleTextScaleFactorChanged
41 42
      ..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
      ..onSemanticsAction = _handleSemanticsAction;
Ian Hickson's avatar
Ian Hickson committed
43
    initRenderView();
44
    _handleSemanticsEnabledChanged();
45
    assert(renderView != null);
46 47 48
    addPersistentFrameCallback(_handlePersistentFrameCallback);
  }

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 checked mode
59
      registerBoolServiceExtension(
60
        name: 'debugPaint',
61
        getter: () async => debugPaintSizeEnabled,
62 63
        setter: (bool value) {
          if (debugPaintSizeEnabled == value)
64
            return new Future<Null>.value();
65
          debugPaintSizeEnabled = value;
66
          return _forceRepaint();
67 68
        }
      );
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
      registerBoolServiceExtension(
          name: 'debugPaintBaselinesEnabled',
          getter: () async => debugPaintBaselinesEnabled,
          setter: (bool value) {
          if (debugPaintBaselinesEnabled == value)
            return new Future<Null>.value();
          debugPaintBaselinesEnabled = value;
          return _forceRepaint();
        }
      );
      registerBoolServiceExtension(
          name: 'repaintRainbow',
          getter: () async => debugRepaintRainbowEnabled,
          setter: (bool value) {
            final bool repaint = debugRepaintRainbowEnabled && !value;
            debugRepaintRainbowEnabled = value;
            if (repaint)
              return _forceRepaint();
            return new Future<Null>.value();
          }
      );
90
      return true;
91
    }());
92

93 94
    registerSignalServiceExtension(
      name: 'debugDumpRenderTree',
95
      callback: () { debugDumpRenderTree(); return debugPrintDone; }
96
    );
97

98 99 100 101 102 103
    registerSignalServiceExtension(
      name: 'debugDumpLayerTree',
      callback: () { debugDumpLayerTree(); return debugPrintDone; }
    );

    registerSignalServiceExtension(
104 105
      name: 'debugDumpSemanticsTreeInGeometricOrder',
      callback: () { debugDumpSemanticsTree(DebugSemanticsDumpOrder.geometricOrder); return debugPrintDone; }
106 107 108
    );

    registerSignalServiceExtension(
109 110
      name: 'debugDumpSemanticsTreeInInverseHitTestOrder',
      callback: () { debugDumpSemanticsTree(DebugSemanticsDumpOrder.inverseHitTest); return debugPrintDone; }
111
    );
112
  }
113

114 115 116 117 118 119
  /// 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
120
  void initRenderView() {
121 122 123
    assert(renderView == null);
    renderView = new RenderView(configuration: createViewConfiguration());
    renderView.scheduleInitialFrame();
124 125
  }

126 127
  /// The render tree's owner, which maintains dirty state for layout,
  /// composite, paint, and accessibility semantics
128 129
  PipelineOwner get pipelineOwner => _pipelineOwner;
  PipelineOwner _pipelineOwner;
130

Florian Loitsch's avatar
Florian Loitsch committed
131
  /// The render tree that's attached to the output surface.
132
  RenderView get renderView => _pipelineOwner.rootNode;
133 134
  /// 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.
135
  set renderView(RenderView value) {
136
    assert(value != null);
137
    _pipelineOwner.rootNode = value;
138 139
  }

140
  /// Called when the system metrics change.
141
  ///
142
  /// See [Window.onMetricsChanged].
143
  @protected
Ian Hickson's avatar
Ian Hickson committed
144
  void handleMetricsChanged() {
145
    assert(renderView != null);
146
    renderView.configuration = createViewConfiguration();
147
    scheduleForcedFrame();
148 149
  }

150 151 152
  /// Called when the platform text scale factor changes.
  ///
  /// See [Window.onTextScaleFactorChanged].
153
  @protected
154 155
  void handleTextScaleFactorChanged() { }

156 157 158 159 160 161 162 163 164 165 166
  /// 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() {
167
    final double devicePixelRatio = ui.window.devicePixelRatio;
168
    return new ViewConfiguration(
169
      size: ui.window.physicalSize / devicePixelRatio,
170
      devicePixelRatio: devicePixelRatio,
171
    );
172 173
  }

174 175 176
  SemanticsHandle _semanticsHandle;

  void _handleSemanticsEnabledChanged() {
177 178 179
    setSemanticsEnabled(ui.window.semanticsEnabled);
  }

180 181
  /// Whether the render tree associated with this binding should produce a tree
  /// of [SemanticsNode] objects.
182 183
  void setSemanticsEnabled(bool enabled) {
    if (enabled) {
184 185 186 187 188 189 190
      _semanticsHandle ??= _pipelineOwner.ensureSemantics();
    } else {
      _semanticsHandle?.dispose();
      _semanticsHandle = null;
    }
  }

191 192 193 194 195 196
  void _handleSemanticsAction(int id, SemanticsAction action, ByteData args) {
    _pipelineOwner.semanticsOwner?.performAction(
      id,
      action,
      args != null ? const StandardMessageCodec().decodeMessage(args) : null,
    );
197 198 199 200 201 202 203 204
  }

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

  void _handleSemanticsOwnerDisposed() {
    renderView.clearSemantics();
Hixie's avatar
Hixie committed
205 206
  }

207
  void _handlePersistentFrameCallback(Duration timeStamp) {
208
    drawFrame();
209 210
  }

Ian Hickson's avatar
Ian Hickson committed
211
  /// Pump the rendering pipeline to generate a frame.
212
  ///
213
  /// This method is called by [handleDrawFrame], which itself is called
214 215 216 217 218 219
  /// 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
220 221 222 223 224
  /// 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.
225
  ///
226 227 228 229
  /// 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.
230
  ///
231
  /// After [handleBeginFrame], [handleDrawFrame], which is registered with
232
  /// [Window.onDrawFrame], is called, which invokes all the persistent frame
233 234 235 236
  /// 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
237 238 239
  /// out (see [RenderObject.performLayout]). See [RenderObject.markNeedsLayout]
  /// for further details on marking an object dirty for layout.
  ///
240
  /// 4. The compositing bits phase: The compositing bits on any dirty
241 242 243
  /// [RenderObject] objects are updated. See
  /// [RenderObject.markNeedsCompositingBitsUpdate].
  ///
244
  /// 5. The paint phase: All the dirty [RenderObject]s in the system are
245 246 247 248
  /// repainted (see [RenderObject.paint]). This generates the [Layer] tree. See
  /// [RenderObject.markNeedsPaint] for further details on marking an object
  /// dirty for paint.
  ///
249
  /// 6. The compositing phase: The layer tree is turned into a [Scene] and
250 251
  /// sent to the GPU.
  ///
252
  /// 7. The semantics phase: All the dirty [RenderObject]s in the system have
253
  /// their semantics updated (see [RenderObject.semanticsAnnotator]). This
254 255 256 257
  /// generates the [SemanticsNode] tree. See
  /// [RenderObject.markNeedsSemanticsUpdate] for further details on marking an
  /// object dirty for semantics.
  ///
258
  /// For more details on steps 3-7, see [PipelineOwner].
259
  ///
260 261
  /// 8. The finalization phase: After [drawFrame] returns, [handleDrawFrame]
  /// then invokes post-frame callbacks (registered with [addPostFrameCallback]).
262 263
  ///
  /// Some bindings (for example, the [WidgetsBinding]) add extra steps to this
264
  /// list (for example, see [WidgetsBinding.drawFrame]).
265 266
  //
  // When editing the above, also update widgets/binding.dart's copy.
Ian Hickson's avatar
Ian Hickson committed
267
  @protected
268
  void drawFrame() {
269
    assert(renderView != null);
270 271 272
    pipelineOwner.flushLayout();
    pipelineOwner.flushCompositingBits();
    pipelineOwner.flushPaint();
Hixie's avatar
Hixie committed
273
    renderView.compositeFrame(); // this sends the bits to the GPU
274
    pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
275 276
  }

277
  @override
278 279
  Future<Null> performReassemble() async {
    await super.performReassemble();
280
    Timeline.startSync('Dirty Render Tree', arguments: timelineWhitelistArguments);
281 282 283 284 285
    try {
      renderView.reassemble();
    } finally {
      Timeline.finishSync();
    }
286
    scheduleWarmUpFrame();
287
    await endOfFrame;
288 289
  }

290
  @override
291
  void hitTest(HitTestResult result, Offset position) {
292 293
    assert(renderView != null);
    renderView.hitTest(result, position: position);
294
    // This super call is safe since it will be bound to a mixed-in declaration.
Adam Barth's avatar
Adam Barth committed
295
    super.hitTest(result, position); // ignore: abstract_super_member_reference
296
  }
297

298
  Future<Null> _forceRepaint() {
299 300 301 302 303 304
    RenderObjectVisitor visitor;
    visitor = (RenderObject child) {
      child.markNeedsPaint();
      child.visitChildren(visitor);
    };
    instance?.renderView?.visitChildren(visitor);
305
    return endOfFrame;
306
  }
307
}
308

Florian Loitsch's avatar
Florian Loitsch committed
309
/// Prints a textual representation of the entire render tree.
310
void debugDumpRenderTree() {
311
  debugPrint(RendererBinding.instance?.renderView?.toStringDeep() ?? 'Render tree unavailable.');
312
}
313

Florian Loitsch's avatar
Florian Loitsch committed
314
/// Prints a textual representation of the entire layer tree.
315
void debugDumpLayerTree() {
316
  debugPrint(RendererBinding.instance?.renderView?.debugLayer?.toStringDeep() ?? 'Layer tree unavailable.');
Ian Hickson's avatar
Ian Hickson committed
317 318
}

Hixie's avatar
Hixie committed
319 320
/// Prints a textual representation of the entire semantics tree.
/// This will only work if there is a semantics client attached.
321 322 323 324 325
/// 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) {
326
  debugPrint(RendererBinding.instance?.renderView?.debugSemantics?.toStringDeep(childOrder: childOrder) ?? 'Semantics not collected.');
Hixie's avatar
Hixie committed
327 328
}

Ian Hickson's avatar
Ian Hickson committed
329 330
/// A concrete binding for applications that use the Rendering framework
/// directly. This is the glue that binds the framework to the Flutter engine.
331 332 333 334 335 336 337
///
/// 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].
338
class RenderingFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, RendererBinding {
339 340 341 342
  /// 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
343
  RenderingFlutterBinding({ RenderBox root }) {
344
    assert(renderView != null);
Ian Hickson's avatar
Ian Hickson committed
345 346
    renderView.child = root;
  }
347
}