From ce6b330a808ba0a848d9a73a0c609a5a915ab9f1 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Mon, 14 Dec 2015 10:22:20 -0800 Subject: [PATCH 1/3] expose flutter debug functionality using VM service extensions --- .../flutter/lib/src/rendering/binding.dart | 1 + packages/flutter/lib/src/rendering/debug.dart | 72 ++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index c41b6bbd75..de3326f7cf 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart @@ -25,6 +25,7 @@ abstract class Renderer extends Scheduler ui.window.onMetricsChanged = handleMetricsChanged; initRenderView(); addPersistentFrameCallback(_handlePersistentFrameCallback); + initServiceExtensions(); } static Renderer _instance; diff --git a/packages/flutter/lib/src/rendering/debug.dart b/packages/flutter/lib/src/rendering/debug.dart index 5aade81413..0cac38c068 100644 --- a/packages/flutter/lib/src/rendering/debug.dart +++ b/packages/flutter/lib/src/rendering/debug.dart @@ -2,11 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' as ui; import 'dart:async'; import 'dart:collection'; +import 'dart:convert' show JSON; +import 'dart:developer'; +import 'dart:ui' as ui; import 'package:flutter/painting.dart'; +import 'package:flutter/scheduler.dart'; import 'package:vector_math/vector_math_64.dart'; /// Causes each RenderBox to paint a box around its bounds. @@ -54,6 +57,73 @@ List debugDescribeTransform(Matrix4 transform) { return matrix; } +bool _extensionsInitialized = false; + +void initServiceExtensions() { + if (_extensionsInitialized) + return; + + registerExtension('flutter', _flutter); + // TODO: Expose debugDumpApp(). + // TODO: Expose StatisticsOverlay. + registerExtension('flutter.debugPaint', _debugPaint); + registerExtension('flutter.timeDilation', _timeDilation); + + _extensionsInitialized = true; + + // Emit an info level log message; this tells the debugger that the Flutter + // service extensions are registered. + log('Flutter initialized', name: 'flutter', level: 800); +} + +/// Just respond to the request. Clients can use the existence of this call to +/// know that the debug client is a Flutter app. +Future _flutter(String method, Map parameters) { + String result = JSON.encode({ 'type': '_extensionType', 'method': method }); + return new Future.value(new ServiceExtensionResponse.result(result)); +} + +/// Toggle the [debugPaintSizeEnabled] setting. +Future _debugPaint(String method, Map parameters) { + if (parameters.containsKey('enabled')) { + // TODO: This is a work around for a VM bug: sdk/25208 - all params are + // coerced to strings. + // bool enabled = parameters['enabled'] == true; + debugPaintSizeEnabled = parameters['enabled'].toString() == 'true'; + // TODO: How to cause a redraw? + } + + String result = JSON.encode({ + 'type': '_extensionType', + 'method': method, + 'enabled': debugPaintSizeEnabled + }); + return new Future.value(new ServiceExtensionResponse.result(result)); +} + +/// Manipulate the scheduler's [timeDilation] field. +Future _timeDilation(String method, Map parameters) { + if (parameters.containsKey('timeDilation')) { + // TODO: Workaround for https://github.com/dart-lang/sdk/issues/25208. + dynamic param = parameters['timeDilation']; + if (param is String) { + param = double.parse(param); + } else if (param is num) { + param = param.toDouble(); + } + timeDilation = param; + } else { + timeDilation = 1.0; + } + + String result = JSON.encode({ + 'type': '_extensionType', + 'method': method, + 'timeDilation': '${timeDilation}' + }); + return new Future.value(new ServiceExtensionResponse.result(result)); +} + /// Prints a message to the console, which you can access using the "flutter" /// tool's "logs" command ("flutter logs"). /// From 211aeabb87a79b10076aa925ffb61460dee8d689 Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Mon, 14 Dec 2015 12:51:39 -0800 Subject: [PATCH 2/3] review comments --- packages/flutter/lib/src/rendering/debug.dart | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/packages/flutter/lib/src/rendering/debug.dart b/packages/flutter/lib/src/rendering/debug.dart index 0cac38c068..71138f2483 100644 --- a/packages/flutter/lib/src/rendering/debug.dart +++ b/packages/flutter/lib/src/rendering/debug.dart @@ -9,6 +9,7 @@ import 'dart:developer'; import 'dart:ui' as ui; import 'package:flutter/painting.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:vector_math/vector_math_64.dart'; @@ -63,34 +64,43 @@ void initServiceExtensions() { if (_extensionsInitialized) return; - registerExtension('flutter', _flutter); - // TODO: Expose debugDumpApp(). - // TODO: Expose StatisticsOverlay. - registerExtension('flutter.debugPaint', _debugPaint); - registerExtension('flutter.timeDilation', _timeDilation); - _extensionsInitialized = true; - // Emit an info level log message; this tells the debugger that the Flutter - // service extensions are registered. - log('Flutter initialized', name: 'flutter', level: 800); + assert(() { + registerExtension('flutter', _flutter); + // TODO: Expose debugDumpApp(). + // TODO: Expose StatisticsOverlay. + registerExtension('flutter.debugPaint', _debugPaint); + registerExtension('flutter.timeDilation', _timeDilation); + + // Emit an info level log message; this tells the debugger that the Flutter + // service extensions are registered. + log('Flutter initialized', name: 'flutter', level: 800); + + return true; + }); } /// Just respond to the request. Clients can use the existence of this call to /// know that the debug client is a Flutter app. -Future _flutter(String method, Map parameters) { +Future _flutter(String method, Map parameters) { String result = JSON.encode({ 'type': '_extensionType', 'method': method }); - return new Future.value(new ServiceExtensionResponse.result(result)); + return new Future.value(new ServiceExtensionResponse.result(result)); } /// Toggle the [debugPaintSizeEnabled] setting. -Future _debugPaint(String method, Map parameters) { +Future _debugPaint(String method, Map parameters) { if (parameters.containsKey('enabled')) { - // TODO: This is a work around for a VM bug: sdk/25208 - all params are - // coerced to strings. - // bool enabled = parameters['enabled'] == true; + // TODO: This is a work around for a VM bug: sdk/25208 - all params are coerced to strings. debugPaintSizeEnabled = parameters['enabled'].toString() == 'true'; - // TODO: How to cause a redraw? + + // Redraw everything - mark the world as dirty. + RenderObjectVisitor visitor; + visitor = (RenderObject child) { + child.markNeedsPaint(); + child.visitChildren(visitor); + }; + Renderer.instance.renderView.visitChildren(visitor); } String result = JSON.encode({ @@ -98,11 +108,11 @@ Future _debugPaint(String method, Map parameters) { 'method': method, 'enabled': debugPaintSizeEnabled }); - return new Future.value(new ServiceExtensionResponse.result(result)); + return new Future.value(new ServiceExtensionResponse.result(result)); } /// Manipulate the scheduler's [timeDilation] field. -Future _timeDilation(String method, Map parameters) { +Future _timeDilation(String method, Map parameters) { if (parameters.containsKey('timeDilation')) { // TODO: Workaround for https://github.com/dart-lang/sdk/issues/25208. dynamic param = parameters['timeDilation']; @@ -119,9 +129,9 @@ Future _timeDilation(String method, Map parameters) { String result = JSON.encode({ 'type': '_extensionType', 'method': method, - 'timeDilation': '${timeDilation}' + 'timeDilation': '$timeDilation' }); - return new Future.value(new ServiceExtensionResponse.result(result)); + return new Future.value(new ServiceExtensionResponse.result(result)); } /// Prints a message to the console, which you can access using the "flutter" From cde14ab649ad999f65ed280fd05f422ea928ed3b Mon Sep 17 00:00:00 2001 From: Devon Carew Date: Mon, 14 Dec 2015 19:04:34 -0800 Subject: [PATCH 3/3] more checked mode guards; more types; fewer todos --- .../flutter/lib/src/rendering/binding.dart | 5 +- packages/flutter/lib/src/rendering/debug.dart | 59 ++++++++++--------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index de3326f7cf..e43f817d68 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart @@ -24,8 +24,11 @@ abstract class Renderer extends Scheduler _instance = this; ui.window.onMetricsChanged = handleMetricsChanged; initRenderView(); + assert(() { + initServiceExtensions(); + return true; + }); addPersistentFrameCallback(_handlePersistentFrameCallback); - initServiceExtensions(); } static Renderer _instance; diff --git a/packages/flutter/lib/src/rendering/debug.dart b/packages/flutter/lib/src/rendering/debug.dart index 71138f2483..7e3338f2f8 100644 --- a/packages/flutter/lib/src/rendering/debug.dart +++ b/packages/flutter/lib/src/rendering/debug.dart @@ -5,7 +5,7 @@ import 'dart:async'; import 'dart:collection'; import 'dart:convert' show JSON; -import 'dart:developer'; +import 'dart:developer' as developer; import 'dart:ui' as ui; import 'package:flutter/painting.dart'; @@ -67,15 +67,13 @@ void initServiceExtensions() { _extensionsInitialized = true; assert(() { - registerExtension('flutter', _flutter); - // TODO: Expose debugDumpApp(). - // TODO: Expose StatisticsOverlay. - registerExtension('flutter.debugPaint', _debugPaint); - registerExtension('flutter.timeDilation', _timeDilation); + developer.registerExtension('flutter', _flutter); + developer.registerExtension('flutter.debugPaint', _debugPaint); + developer.registerExtension('flutter.timeDilation', _timeDilation); // Emit an info level log message; this tells the debugger that the Flutter // service extensions are registered. - log('Flutter initialized', name: 'flutter', level: 800); + developer.log('Flutter initialized', name: 'flutter', level: 800); return true; }); @@ -83,15 +81,20 @@ void initServiceExtensions() { /// Just respond to the request. Clients can use the existence of this call to /// know that the debug client is a Flutter app. -Future _flutter(String method, Map parameters) { - String result = JSON.encode({ 'type': '_extensionType', 'method': method }); - return new Future.value(new ServiceExtensionResponse.result(result)); +Future _flutter(String method, Map parameters) { + return new Future.value( + new developer.ServiceExtensionResponse.result(JSON.encode({ + 'type': '_extensionType', + 'method': method + })) + ); } /// Toggle the [debugPaintSizeEnabled] setting. -Future _debugPaint(String method, Map parameters) { +Future _debugPaint(String method, Map parameters) { if (parameters.containsKey('enabled')) { - // TODO: This is a work around for a VM bug: sdk/25208 - all params are coerced to strings. + // TODO(devoncarew): This is a work around for a VM bug: sdk/25208 - all + // params are coerced to strings. debugPaintSizeEnabled = parameters['enabled'].toString() == 'true'; // Redraw everything - mark the world as dirty. @@ -100,21 +103,22 @@ Future _debugPaint(String method, Map child.markNeedsPaint(); child.visitChildren(visitor); }; - Renderer.instance.renderView.visitChildren(visitor); + Renderer.instance?.renderView?.visitChildren(visitor); } - String result = JSON.encode({ - 'type': '_extensionType', - 'method': method, - 'enabled': debugPaintSizeEnabled - }); - return new Future.value(new ServiceExtensionResponse.result(result)); + return new Future.value( + new developer.ServiceExtensionResponse.result(JSON.encode({ + 'type': '_extensionType', + 'method': method, + 'enabled': debugPaintSizeEnabled + })) + ); } /// Manipulate the scheduler's [timeDilation] field. -Future _timeDilation(String method, Map parameters) { +Future _timeDilation(String method, Map parameters) { if (parameters.containsKey('timeDilation')) { - // TODO: Workaround for https://github.com/dart-lang/sdk/issues/25208. + // TODO(devoncarew): Workaround for https://github.com/dart-lang/sdk/issues/25208. dynamic param = parameters['timeDilation']; if (param is String) { param = double.parse(param); @@ -126,12 +130,13 @@ Future _timeDilation(String method, Map.value(new ServiceExtensionResponse.result(result)); + return new Future.value( + new developer.ServiceExtensionResponse.result(JSON.encode({ + 'type': '_extensionType', + 'method': method, + 'timeDilation': '$timeDilation' + })) + ); } /// Prints a message to the console, which you can access using the "flutter"