Allow displaying compositor statistics via a widget

Example:
  import 'package:sky/widgets.dart';
  void main() => runApp(new Center(child:
      new StatisticsOverlay.allEnabled()));
diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart
index 49d1e3d..1e22221 100644
--- a/packages/flutter/lib/src/rendering/layer.dart
+++ b/packages/flutter/lib/src/rendering/layer.dart
@@ -87,6 +87,29 @@
 
 }
 
+/// A layer that indicates to the compositor that it should display
+/// certain statistics within it
+class StatisticsLayer extends Layer {
+  StatisticsLayer({
+    Offset offset: Offset.zero,
+    this.paintBounds,
+    this.optionsMask
+  }) : super(offset: offset);
+
+  /// The rectangle in this layer's coodinate system that bounds the recording
+  Rect paintBounds;
+
+  /// A mask specifying the statistics to display
+  int optionsMask;
+
+  void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
+    assert(optionsMask != null);
+    builder.addStatistics(optionsMask, paintBounds.shift(layerOffset));
+  }
+
+}
+
+
 /// A composited layer that has a list of children
 class ContainerLayer extends Layer {
   ContainerLayer({ Offset offset: Offset.zero }) : super(offset: offset);
diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart
index 07cee15..0daaab2 100644
--- a/packages/flutter/lib/src/rendering/object.dart
+++ b/packages/flutter/lib/src/rendering/object.dart
@@ -130,6 +130,15 @@
     }
   }
 
+  void paintStatistics(int optionsMask, Offset offset, Size size) {
+    StatisticsLayer statsLayer = new StatisticsLayer(
+      offset: offset,
+      paintBounds: new Rect.fromLTWH(0.0, 0.0, size.width, size.height),
+      optionsMask : optionsMask
+    );
+    _containerLayer.append(statsLayer);
+  }
+
   // Below we have various variants of the paintChild() method, which
   // do additional work, such as clipping or transforming, at the same
   // time as painting the children.
diff --git a/packages/flutter/lib/src/rendering/statistics_box.dart b/packages/flutter/lib/src/rendering/statistics_box.dart
new file mode 100644
index 0000000..98780ea
--- /dev/null
+++ b/packages/flutter/lib/src/rendering/statistics_box.dart
@@ -0,0 +1,47 @@
+// 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.
+
+import 'package:sky/src/rendering/box.dart';
+import 'package:sky/src/rendering/object.dart';
+
+class StatisticsBox extends RenderBox {
+
+  StatisticsBox({int optionsMask: 0}) : _optionsMask = optionsMask;
+
+  int _optionsMask;
+  int get optionsMask => _optionsMask;
+  void set optionsMask (int mask) {
+    if (mask == _optionsMask) {
+      return;
+    }
+    _optionsMask = mask;
+    markNeedsPaint();
+  }
+
+  bool get sizedByParent => true;
+
+  double getMinIntrinsicWidth(BoxConstraints constraints) {
+    return constraints.minWidth;
+  }
+
+  double getMaxIntrinsicWidth(BoxConstraints constraints) {
+    return constraints.maxWidth;
+  }
+
+  double getMinIntrinsicHeight(BoxConstraints constraints) {
+    return constraints.minHeight;
+  }
+
+  double getMaxIntrinsicHeight(BoxConstraints constraints) {
+    return constraints.maxHeight;
+  }
+
+  void performResize() {
+    size = constraints.constrain(Size.infinite);
+  }
+
+  void paint(PaintingContext context, Offset offset) {
+    context.paintStatistics(optionsMask, offset, size);
+  }
+}
diff --git a/packages/flutter/lib/src/widgets/statistics_overlay.dart b/packages/flutter/lib/src/widgets/statistics_overlay.dart
new file mode 100644
index 0000000..e3d62fc
--- /dev/null
+++ b/packages/flutter/lib/src/widgets/statistics_overlay.dart
@@ -0,0 +1,60 @@
+// 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.
+
+import 'package:sky/src/widgets/framework.dart';
+import 'package:sky/src/rendering/statistics_box.dart';
+
+/// The options that control whether the statistics overlay displays certain
+/// aspects of the compositor
+enum StatisticsOption {
+  /// Display the frame time and FPS of the last frame rendered. This field is
+  /// updated every frame.
+  ///
+  /// This is the time spent by the rasterizer as it tries
+  /// to convert the layer tree obtained from the widgets into OpenGL commands
+  /// and tries to flush them onto the screen. When the total time taken by this
+  /// step exceeds the frame slice, a frame is lost.
+  displayRasterizerStatistics,
+  /// Display the rasterizer frame times as they change over a set period of
+  /// time in the form of a graph. The y axis of the graph denotes the total
+  /// time spent by the rasterizer as a fraction of the total frame slice. When
+  /// the bar turns red, a frame is lost.
+  visualizeRasterizerStatistics,
+  /// Display the frame time and FPS at which the interface can construct a
+  /// layer tree for the rasterizer (whose behavior is described above) to
+  /// consume.
+  ///
+  /// This involves all layout, animations, etc. When the total time taken by
+  /// this step exceeds the frame slice, a frame is lost.
+  displayEngineStatistics,
+  /// Display the engine frame times as they change over a set period of time
+  /// in the form of a graph. The y axis of the graph denotes the total time
+  /// spent by the eninge as a fraction of the total frame slice. When the bar
+  /// turns red, a frame is lost.
+  visualizeEngineStatistics,
+}
+
+class StatisticsOverlay extends LeafRenderObjectWidget {
+
+  /// Create a statistics overlay that only displays specific statistics. The
+  /// mask is created by shifting 1 by the index of the specific StatisticOption
+  /// to enable.
+  StatisticsOverlay({ this.optionsMask, Key key }) : super(key: key);
+
+  /// Create a statistics overaly that displays all available statistics
+  StatisticsOverlay.allEnabled({ Key key }) : super(key: key), optionsMask = (
+    1 << StatisticsOption.displayRasterizerStatistics.index |
+    1 << StatisticsOption.visualizeRasterizerStatistics.index |
+    1 << StatisticsOption.displayEngineStatistics.index |
+    1 << StatisticsOption.visualizeEngineStatistics.index
+  );
+
+  final int optionsMask;
+
+  StatisticsBox createRenderObject() => new StatisticsBox(optionsMask: optionsMask);
+
+  void updateRenderObject(StatisticsBox renderObject, RenderObjectWidget oldWidget) {
+    renderObject.optionsMask = optionsMask;
+  }
+}
diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart
index 3e7f257..28e2553 100644
--- a/packages/flutter/lib/widgets.dart
+++ b/packages/flutter/lib/widgets.dart
@@ -43,6 +43,7 @@
 export 'src/widgets/raised_button.dart';
 export 'src/widgets/scaffold.dart';
 export 'src/widgets/scrollable.dart';
+export 'src/widgets/statistics_overlay.dart';
 export 'src/widgets/snack_bar.dart';
 export 'src/widgets/switch.dart';
 export 'src/widgets/tabs.dart';