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

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

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

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

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

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

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

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

64 65 66 67
    registerSignalServiceExtension(
      name: 'debugDumpRenderTree',
      callback: debugDumpRenderTree
    );
68

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

85 86 87 88 89 90
  /// 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
91
  void initRenderView() {
92 93 94
    assert(renderView == null);
    renderView = new RenderView(configuration: createViewConfiguration());
    renderView.scheduleInitialFrame();
95 96
  }

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

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

111
  /// Called when the system metrics change.
112 113
  ///
  /// See [ui.window.onMetricsChanged].
Ian Hickson's avatar
Ian Hickson committed
114
  void handleMetricsChanged() {
115
    assert(renderView != null);
116 117 118 119 120 121 122 123 124 125 126 127 128 129
    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() {
130
    final double devicePixelRatio = ui.window.devicePixelRatio;
131
    return new ViewConfiguration(
132 133
      size: ui.window.physicalSize / devicePixelRatio,
      devicePixelRatio: devicePixelRatio
134
    );
135 136
  }

137 138 139
  SemanticsHandle _semanticsHandle;

  void _handleSemanticsEnabledChanged() {
140 141 142 143 144
    setSemanticsEnabled(ui.window.semanticsEnabled);
  }

  void setSemanticsEnabled(bool enabled) {
    if (enabled) {
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
      _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
162 163
  }

164 165 166 167
  void _handlePersistentFrameCallback(Duration timeStamp) {
    beginFrame();
  }

Ian Hickson's avatar
Ian Hickson committed
168
  /// Pump the rendering pipeline to generate a frame.
169
  ///
170 171 172 173 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
  /// 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
203
  /// their semantics updated (see [RenderObject.SemanticsAnnotator]). This
204 205 206 207 208 209 210 211 212 213
  /// 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
214
  /// list (for example, see [WidgetsBinding.beginFrame]).
215 216
  //
  // When editing the above, also update widgets/binding.dart's copy.
Ian Hickson's avatar
Ian Hickson committed
217
  @protected
218
  void beginFrame() {
219
    assert(renderView != null);
220 221 222
    pipelineOwner.flushLayout();
    pipelineOwner.flushCompositingBits();
    pipelineOwner.flushPaint();
Hixie's avatar
Hixie committed
223
    renderView.compositeFrame(); // this sends the bits to the GPU
224
    pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
225 226
  }

227 228 229
  @override
  void reassembleApplication() {
    super.reassembleApplication();
230
    renderView.reassemble();
Ian Hickson's avatar
Ian Hickson committed
231
    handleBeginFrame(null);
232 233
  }

234
  @override
Ian Hickson's avatar
Ian Hickson committed
235
  void hitTest(HitTestResult result, Point position) {
236 237
    assert(renderView != null);
    renderView.hitTest(result, position: position);
238
    // This super call is safe since it will be bound to a mixed-in declaration.
Adam Barth's avatar
Adam Barth committed
239
    super.hitTest(result, position); // ignore: abstract_super_member_reference
240
  }
241 242 243 244 245 246 247 248 249

  void _forceRepaint() {
    RenderObjectVisitor visitor;
    visitor = (RenderObject child) {
      child.markNeedsPaint();
      child.visitChildren(visitor);
    };
    instance?.renderView?.visitChildren(visitor);
  }
250
}
251

Florian Loitsch's avatar
Florian Loitsch committed
252
/// Prints a textual representation of the entire render tree.
253
void debugDumpRenderTree() {
254
  debugPrint(RendererBinding.instance?.renderView?.toStringDeep());
255
}
256

Florian Loitsch's avatar
Florian Loitsch committed
257
/// Prints a textual representation of the entire layer tree.
258
void debugDumpLayerTree() {
259
  debugPrint(RendererBinding.instance?.renderView?.layer?.toStringDeep());
Ian Hickson's avatar
Ian Hickson committed
260 261
}

Hixie's avatar
Hixie committed
262 263 264 265
/// 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() {
266
  debugPrint(RendererBinding.instance?.renderView?.debugSemantics?.toStringDeep() ?? 'Semantics not collected.');
Hixie's avatar
Hixie committed
267 268
}

Ian Hickson's avatar
Ian Hickson committed
269 270
/// A concrete binding for applications that use the Rendering framework
/// directly. This is the glue that binds the framework to the Flutter engine.
271 272 273 274 275 276 277
///
/// 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].
278
class RenderingFlutterBinding extends BindingBase with SchedulerBinding, GestureBinding, ServicesBinding, RendererBinding {
279 280 281 282
  /// 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
283
  RenderingFlutterBinding({ RenderBox root }) {
284
    assert(renderView != null);
Ian Hickson's avatar
Ian Hickson committed
285 286
    renderView.child = root;
  }
287
}