Merge pull request #1244 from chinmaygarde/master
Fix Build: Remove incorrect include of deleted picture_rasterizer.h
diff --git a/sky/engine/core/painting/Rect.dart b/sky/engine/core/painting/Rect.dart
index 11646b2..6763038 100644
--- a/sky/engine/core/painting/Rect.dart
+++ b/sky/engine/core/painting/Rect.dart
@@ -63,8 +63,8 @@
return new Rect.fromLTRB(
math.max(left, other.left),
math.max(top, other.top),
- math.max(right, other.right),
- math.max(bottom, other.bottom));
+ math.min(right, other.right),
+ math.min(bottom, other.bottom));
}
/// The distance between the left and right edges of this rectangle
diff --git a/sky/packages/sky/lib/src/animation/animated_value.dart b/sky/packages/sky/lib/src/animation/animated_value.dart
index 8d4ed9f..68da613 100644
--- a/sky/packages/sky/lib/src/animation/animated_value.dart
+++ b/sky/packages/sky/lib/src/animation/animated_value.dart
@@ -30,9 +30,9 @@
/// can be made to take longer in one direction that the other.
class AnimationTiming {
AnimationTiming({
- this.interval,
+ this.interval: const Interval(0.0, 1.0),
this.reverseInterval,
- this.curve,
+ this.curve: linear,
this.reverseCurve
});
diff --git a/sky/packages/sky/lib/src/animation/curves.dart b/sky/packages/sky/lib/src/animation/curves.dart
index 791f45b..9fd00d3 100644
--- a/sky/packages/sky/lib/src/animation/curves.dart
+++ b/sky/packages/sky/lib/src/animation/curves.dart
@@ -27,14 +27,9 @@
double transform(double t) => t;
}
-/// A curve that is initially 0.0, then linear, then 1.0
+/// A curve that is 0.0 until start, then linear from 0.0 to 1.0 at end, then 1.0
class Interval implements Curve {
- Interval(this.start, this.end) {
- assert(start >= 0.0);
- assert(start <= 1.0);
- assert(end >= 0.0);
- assert(end <= 1.0);
- }
+ const Interval(this.start, this.end);
/// The smallest value for which this interval is 0.0
final double start;
@@ -43,6 +38,10 @@
final double end;
double transform(double t) {
+ assert(start >= 0.0);
+ assert(start <= 1.0);
+ assert(end >= 0.0);
+ assert(end <= 1.0);
return ((t - start) / (end - start)).clamp(0.0, 1.0);
}
}
diff --git a/sky/packages/sky/lib/src/services/shell.dart b/sky/packages/sky/lib/src/services/shell.dart
index 88b2140..3f3f411 100644
--- a/sky/packages/sky/lib/src/services/shell.dart
+++ b/sky/packages/sky/lib/src/services/shell.dart
@@ -18,15 +18,33 @@
return new ApplicationConnection(null, serviceProvider);
}
+// A replacement for requestService. Implementations should return true
+// if they handled the request, or false if the request should fall through
+// to the default requestService.
+typedef bool OverrideRequestService(String url, Object proxy);
+
+// Set this to intercept calls to requestService and supply an alternative
+// implementation of a service (for example, a mock for testing).
+OverrideRequestService overrideRequestService;
+
class _ShellImpl {
_ShellImpl._();
final ApplicationConnection _connection = _initConnection();
- void requestService(String url, Object proxy) {
+ void _requestService(String url, Object proxy) {
if (embedder.shell == null) _connection.requestService(proxy);
else embedder.connectToService(url, proxy);
}
+
+ void requestService(String url, Object proxy) {
+ if (overrideRequestService != null) {
+ if (overrideRequestService(url, proxy))
+ return;
+ }
+
+ _requestService(url, proxy);
+ }
}
final _ShellImpl shell = new _ShellImpl._();
diff --git a/sky/packages/sky/lib/src/widgets/dialog.dart b/sky/packages/sky/lib/src/widgets/dialog.dart
index 7d16f54..da5b194 100644
--- a/sky/packages/sky/lib/src/widgets/dialog.dart
+++ b/sky/packages/sky/lib/src/widgets/dialog.dart
@@ -139,21 +139,19 @@
final Completer completer;
final RouteBuilder builder;
- Widget build(Navigator navigator, RouteBase route) => builder(navigator, route);
- bool get isOpaque => false;
-
- void popState([dynamic result]) {
- completer.complete(result);
- }
-
Duration get transitionDuration => _kTransitionDuration;
- TransitionBase buildTransition({ Key key, Widget child, WatchableAnimationPerformance performance }) {
+ bool get isOpaque => false;
+ Widget build(Key key, Navigator navigator, RouteBase route, WatchableAnimationPerformance performance) {
return new FadeTransition(
performance: performance,
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: easeOut),
- child: child
+ child: builder(navigator, route)
);
}
+
+ void popState([dynamic result]) {
+ completer.complete(result);
+ }
}
Future showDialog(Navigator navigator, DialogBuilder builder) {
diff --git a/sky/packages/sky/lib/src/widgets/editable_text.dart b/sky/packages/sky/lib/src/widgets/editable_text.dart
index 82794c9..3280da4 100644
--- a/sky/packages/sky/lib/src/widgets/editable_text.dart
+++ b/sky/packages/sky/lib/src/widgets/editable_text.dart
@@ -205,7 +205,7 @@
if (!value.composing.isValid) {
// TODO(eseidel): This is the wrong height if empty!
- return new Text(value.text, style: style);
+ return new Row([new Text(value.text, style: style)]);
}
TextStyle composingStyle = style.merge(const TextStyle(decoration: underline));
diff --git a/sky/packages/sky/lib/src/widgets/navigator.dart b/sky/packages/sky/lib/src/widgets/navigator.dart
index d432b01..7eeac86 100644
--- a/sky/packages/sky/lib/src/widgets/navigator.dart
+++ b/sky/packages/sky/lib/src/widgets/navigator.dart
@@ -13,40 +13,44 @@
typedef void NotificationCallback();
abstract class RouteBase {
- Widget build(Navigator navigator, RouteBase route);
- bool get isOpaque;
- void popState([dynamic result]) { assert(result == null); }
-
AnimationPerformance _performance;
NotificationCallback onDismissed;
NotificationCallback onCompleted;
+ AnimationPerformance createPerformance() {
+ AnimationPerformance result = new AnimationPerformance(duration: transitionDuration);
+ result.addStatusListener((AnimationStatus status) {
+ switch (status) {
+ case AnimationStatus.dismissed:
+ if (onDismissed != null)
+ onDismissed();
+ break;
+ case AnimationStatus.completed:
+ if (onCompleted != null)
+ onCompleted();
+ break;
+ default:
+ ;
+ }
+ });
+ return result;
+ }
WatchableAnimationPerformance ensurePerformance({ Direction direction }) {
assert(direction != null);
- if (_performance == null) {
- _performance = new AnimationPerformance(duration: transitionDuration);
- _performance.addStatusListener((AnimationStatus status) {
- switch (status) {
- case AnimationStatus.dismissed:
- if (onDismissed != null)
- onDismissed();
- break;
- case AnimationStatus.completed:
- if (onCompleted != null)
- onCompleted();
- break;
- default:
- ;
- }
- });
- }
+ if (_performance == null)
+ _performance = createPerformance();
AnimationStatus desiredStatus = direction == Direction.forward ? AnimationStatus.forward : AnimationStatus.reverse;
if (_performance.status != desiredStatus)
_performance.play(direction);
return _performance.view;
}
+ bool get isActuallyOpaque => _performance != null && _performance.isCompleted && isOpaque;
+
+ bool get hasContent => true; // set to false if you have nothing useful to return from build()
Duration get transitionDuration;
- TransitionBase buildTransition({ Key key, Widget child, WatchableAnimationPerformance performance });
+ bool get isOpaque;
+ Widget build(Key key, Navigator navigator, RouteBase route, WatchableAnimationPerformance performance);
+ void popState([dynamic result]) { assert(result == null); }
String toString() => '$runtimeType()';
}
@@ -59,11 +63,11 @@
final String name;
final RouteBuilder builder;
- Widget build(Navigator navigator, RouteBase route) => builder(navigator, route);
bool get isOpaque => true;
Duration get transitionDuration => _kTransitionDuration;
- TransitionBase buildTransition({ Key key, Widget child, WatchableAnimationPerformance performance }) {
+
+ Widget build(Key key, Navigator navigator, RouteBase route, WatchableAnimationPerformance performance) {
// TODO(jackson): Hit testing should ignore transform
// TODO(jackson): Block input unless content is interactive
return new SlideTransition(
@@ -73,7 +77,7 @@
child: new FadeTransition(
performance: performance,
opacity: new AnimatedValue<double>(0.0, end: 1.0, curve: easeOut),
- child: child
+ child: builder(navigator, route)
)
);
}
@@ -88,7 +92,6 @@
RouteBase route;
StatefulComponent owner;
- Widget build(Navigator navigator, RouteBase route) => null;
bool get isOpaque => false;
void popState([dynamic result]) {
@@ -97,23 +100,9 @@
callback(this);
}
- // Custom state routes shouldn't be asked to construct a transition
- Duration get transitionDuration {
- assert(false);
- return const Duration();
- }
- TransitionBase buildTransition({ Key key, Widget child, WatchableAnimationPerformance performance }) {
- assert(false);
- return null;
- }
-}
-
-class HistoryEntry {
- HistoryEntry({ this.route });
- final RouteBase route;
- bool fullyOpaque = false;
- // TODO(jackson): Keep track of the requested transition
- String toString() => "HistoryEntry($route, hashCode=$hashCode)";
+ bool get hasContent => false;
+ Duration get transitionDuration => const Duration();
+ Widget build(Key key, Navigator navigator, RouteBase route, WatchableAnimationPerformance performance) => null;
}
class NavigationState {
@@ -123,14 +112,14 @@
if (route.name != null)
namedRoutes[route.name] = route;
}
- history.add(new HistoryEntry(route: routes[0]));
+ history.add(routes[0]);
}
- List<HistoryEntry> history = new List<HistoryEntry>();
+ List<RouteBase> history = new List<RouteBase>();
int historyIndex = 0;
Map<String, RouteBase> namedRoutes = new Map<String, RouteBase>();
- RouteBase get currentRoute => history[historyIndex].route;
+ RouteBase get currentRoute => history[historyIndex];
bool hasPrevious() => historyIndex > 0;
void pushNamed(String name) {
@@ -141,22 +130,20 @@
void push(RouteBase route) {
assert(!_debugCurrentlyHaveRoute(route));
- HistoryEntry historyEntry = new HistoryEntry(route: route);
- history.insert(historyIndex + 1, historyEntry);
+ history.insert(historyIndex + 1, route);
historyIndex++;
}
void pop([dynamic result]) {
if (historyIndex > 0) {
- HistoryEntry entry = history[historyIndex];
- entry.route.popState(result);
- entry.fullyOpaque = false;
+ RouteBase route = history[historyIndex];
+ route.popState(result);
historyIndex--;
}
}
bool _debugCurrentlyHaveRoute(RouteBase route) {
- return history.any((entry) => entry.route == route);
+ return history.any((candidate) => candidate == route);
}
}
@@ -201,39 +188,25 @@
Widget build() {
List<Widget> visibleRoutes = new List<Widget>();
- for (int i = 0; i < state.history.length; i++) {
- // Avoid building routes that are not visible
- if (i + 1 < state.history.length && state.history[i + 1].fullyOpaque)
+ for (int i = state.history.length-1; i >= 0; i -= 1) {
+ RouteBase route = state.history[i];
+ if (!route.hasContent)
continue;
- HistoryEntry historyEntry = state.history[i];
- Widget child = historyEntry.route.build(this, historyEntry.route);
- if (i == 0) {
- visibleRoutes.add(child);
- continue;
- }
- if (child == null)
- continue;
- WatchableAnimationPerformance performance = historyEntry.route.ensurePerformance(
+ WatchableAnimationPerformance performance = route.ensurePerformance(
direction: (i <= state.historyIndex) ? Direction.forward : Direction.reverse
);
- historyEntry.route.onDismissed = () {
+ route.onDismissed = () {
setState(() {
- assert(state.history.contains(historyEntry));
- state.history.remove(historyEntry);
+ assert(state.history.contains(route));
+ state.history.remove(route);
});
};
- historyEntry.route.onCompleted = () {
- setState(() {
- historyEntry.fullyOpaque = historyEntry.route.isOpaque;
- });
- };
- TransitionBase transition = historyEntry.route.buildTransition(
- key: new ObjectKey(historyEntry),
- child: child,
- performance: performance
- );
- visibleRoutes.add(transition);
+ Key key = new ObjectKey(route);
+ Widget widget = route.build(key, this, route, performance);
+ visibleRoutes.add(widget);
+ if (route.isActuallyOpaque)
+ break;
}
- return new Focus(child: new Stack(visibleRoutes));
+ return new Focus(child: new Stack(visibleRoutes.reversed.toList()));
}
}
diff --git a/sky/packages/sky/lib/src/widgets/popup_menu.dart b/sky/packages/sky/lib/src/widgets/popup_menu.dart
index 71186a7..4dac20a 100644
--- a/sky/packages/sky/lib/src/widgets/popup_menu.dart
+++ b/sky/packages/sky/lib/src/widgets/popup_menu.dart
@@ -15,7 +15,7 @@
import 'package:sky/src/widgets/transitions.dart';
const Duration _kMenuDuration = const Duration(milliseconds: 300);
-double _kMenuCloseIntervalEnd = 2.0 / 3.0;
+const double _kMenuCloseIntervalEnd = 2.0 / 3.0;
const double _kMenuWidthStep = 56.0;
const double _kMenuMargin = 16.0; // 24.0 on tablet
const double _kMenuMinWidth = 2.0 * _kMenuWidthStep;
diff --git a/sky/packages/sky/pubspec.yaml b/sky/packages/sky/pubspec.yaml
index bd043c8..fe20c39 100644
--- a/sky/packages/sky/pubspec.yaml
+++ b/sky/packages/sky/pubspec.yaml
@@ -1,5 +1,5 @@
name: sky
-version: 0.0.45
+version: 0.0.46
author: Chromium Authors <sky-dev@googlegroups.com>
description: A framework for writing Sky applications
homepage: https://github.com/domokit/sky_engine/tree/master/sky/packages/sky
@@ -9,8 +9,8 @@
mojo_services: 0.0.23
mojo: 0.0.23
newton: ^0.1.2
- sky_engine: ^0.0.22
- sky_services: ^0.0.22
+ sky_engine: ^0.0.23
+ sky_services: ^0.0.23
sky_tools: ^0.0.12
vector_math: ^1.4.3
intl: ^0.12.4+2
diff --git a/sky/packages/sky_engine/pubspec.yaml b/sky/packages/sky_engine/pubspec.yaml
index 0a200a5..964d6dd 100644
--- a/sky/packages/sky_engine/pubspec.yaml
+++ b/sky/packages/sky_engine/pubspec.yaml
@@ -1,5 +1,5 @@
name: sky_engine
-version: 0.0.22
+version: 0.0.23
author: Chromium Authors <sky-dev@googlegroups.com>
description: Dart SDK extensions for dart:sky
homepage: https://github.com/domokit/sky_engine
diff --git a/sky/packages/sky_services/pubspec.yaml b/sky/packages/sky_services/pubspec.yaml
index 6486be2..1903c99 100644
--- a/sky/packages/sky_services/pubspec.yaml
+++ b/sky/packages/sky_services/pubspec.yaml
@@ -1,5 +1,5 @@
name: sky_services
-version: 0.0.22
+version: 0.0.23
author: Chromium Authors <sky-dev@googlegroups.com>
description: Mojom interfaces associated with Sky
homepage: https://github.com/domokit/sky_engine/tree/master/sky/packages/sky_services
diff --git a/sky/unit/test/engine/rect_test_disabled.dart b/sky/unit/test/engine/rect_test_disabled.dart
new file mode 100644
index 0000000..14d7303
--- /dev/null
+++ b/sky/unit/test/engine/rect_test_disabled.dart
@@ -0,0 +1,33 @@
+import 'dart:sky';
+
+import 'package:test/test.dart';
+
+void main() {
+ test("rect accessors", () {
+ Rect r = new Rect.fromLTRB(1.0, 3.0, 5.0, 7.0);
+ expect(r.left, equals(1.0));
+ expect(r.top, equals(3.0));
+ expect(r.right, equals(5.0));
+ expect(r.bottom, equals(7.0));
+ });
+
+ test("rect created by width and height", () {
+ Rect r = new Rect.fromLTWH(1.0, 3.0, 5.0, 7.0);
+ expect(r.left, equals(1.0));
+ expect(r.top, equals(3.0));
+ expect(r.right, equals(6.0));
+ expect(r.bottom, equals(10.0));
+ });
+
+ test("rect intersection", () {
+ Rect r1 = new Rect.fromLTRB(0.0, 0.0, 100.0, 100.0);
+ Rect r2 = new Rect.fromLTRB(50.0, 50.0, 200.0, 200.0);
+ Rect r3 = r1.intersect(r2);
+ expect(r3.left, equals(50.0));
+ expect(r3.top, equals(50.0));
+ expect(r3.right, equals(100.0));
+ expect(r3.bottom, equals(100.0));
+ Rect r4 = r2.intersect(r1);
+ expect(r4, equals(r3));
+ });
+}
diff --git a/sky/unit/test/services/mock_services.dart b/sky/unit/test/services/mock_services.dart
new file mode 100644
index 0000000..264d597
--- /dev/null
+++ b/sky/unit/test/services/mock_services.dart
@@ -0,0 +1,31 @@
+import 'package:sky/src/services/shell.dart' as shell;
+
+// Tests can use ServiceMocker to register replacement implementations
+// of Mojo services.
+class _ServiceMocker {
+ _ServiceMocker() {
+ shell.overrideRequestService = _requestService;
+ }
+
+ // Map of interface names to mock implementations.
+ Map<String, Object> _interfaceMock = new Map<String, Object>();
+
+ bool _requestService(String url, Object proxy) {
+ Object mock = _interfaceMock[proxy.impl.name];
+ if (mock != null) {
+ // Replace the proxy's implementation of the service interface with the
+ // mock.
+ proxy.ptr = mock;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // Provide a mock implementation for a Mojo interface.
+ void registerMockService(String interfaceName, Object mock) {
+ _interfaceMock[interfaceName] = mock;
+ }
+}
+
+final _ServiceMocker serviceMocker = new _ServiceMocker();
diff --git a/sky/unit/test/widget/input_test.dart b/sky/unit/test/widget/input_test.dart
new file mode 100644
index 0000000..7628ccd
--- /dev/null
+++ b/sky/unit/test/widget/input_test.dart
@@ -0,0 +1,59 @@
+import 'package:mojo_services/keyboard/keyboard.mojom.dart';
+import 'package:sky/services.dart';
+import 'package:sky/widgets.dart';
+import 'package:test/test.dart';
+
+import 'widget_tester.dart';
+import '../services/mock_services.dart';
+
+class MockKeyboard implements KeyboardService {
+ KeyboardClient client;
+
+ void show(Object client, int type) {
+ this.client = client.impl;
+ }
+
+ void showByRequest() {}
+
+ void hide() {}
+}
+
+void main() {
+ test('Editable text has consistent width', () {
+ WidgetTester tester = new WidgetTester();
+
+ MockKeyboard mockKeyboard = new MockKeyboard();
+ serviceMocker.registerMockService(KeyboardServiceName, mockKeyboard);
+
+ GlobalKey inputKey = new GlobalKey();
+ String inputValue;
+
+ Widget builder() {
+ return new Center(
+ child: new Input(
+ key: inputKey,
+ placeholder: 'Placeholder',
+ onChanged: (value) { inputValue = value; }
+ )
+ );
+ }
+
+ tester.pumpFrame(builder);
+
+ Input input = tester.findWidget((Widget widget) => widget.key == inputKey);
+ Size emptyInputSize = input.renderObject.size;
+
+ // Simulate entry of text through the keyboard.
+ expect(mockKeyboard.client, isNotNull);
+ const String testValue = 'Test';
+ mockKeyboard.client.setComposingText(testValue, testValue.length);
+
+ // Check that the onChanged event handler fired.
+ expect(inputValue, equals(testValue));
+
+ tester.pumpFrame(builder);
+
+ // Check that the Input with text has the same size as the empty Input.
+ expect(input.renderObject.size, equals(emptyInputSize));
+ });
+}