binding.dart 9.93 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';
Ian Hickson's avatar
Ian Hickson committed
11
import 'package:meta/meta.dart';
12 13

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

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

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

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

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

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

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

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

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

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

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

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

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
  SemanticsHandle _semanticsHandle;

  void _handleSemanticsEnabledChanged() {
    if (ui.window.semanticsEnabled) {
      _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
159 160
  }

161 162 163 164
  void _handlePersistentFrameCallback(Duration timeStamp) {
    beginFrame();
  }

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

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

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

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

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

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

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

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