From c6f0b8447dbf178268e426bf8c04ac2736385392 Mon Sep 17 00:00:00 2001 From: Hixie Date: Wed, 17 Jun 2015 19:09:28 -0700 Subject: [PATCH] Fork some more files from the old framework, so that the transition will be easier to perform. Summary: framework/animation/* -> animation/* framework/debug/utils.dart -> debug/utils.dart framework/shell.dart -> mojo/shell.dart framework/embedder.dart -> mojo/embedder.dart framework/net/* -> mojo/net/* This should have no code changes except fixing and reordering imports. R=abarth@chromium.org Review URL: https://codereview.chromium.org/1189943004. --- sdk/BUILD.gn | 12 +- sdk/lib/animation/README.md | 2 + sdk/lib/animation/animated_value.dart | 84 ++++++++ sdk/lib/animation/curves.dart | 72 +++++++ sdk/lib/animation/fling_curve.dart | 55 +++++ sdk/lib/animation/generators.dart | 162 ++++++++++++++ sdk/lib/animation/mechanics.dart | 213 +++++++++++++++++++ sdk/lib/animation/scroll_behavior.dart | 115 ++++++++++ sdk/lib/{framework => }/debug/utils.dart | 0 sdk/lib/mojo/embedder.dart | 72 +++++++ sdk/lib/mojo/net/fetch.dart | 54 +++++ sdk/lib/mojo/net/image_cache.dart | 46 ++++ sdk/lib/mojo/shell.dart | 27 +++ sdk/lib/rendering/box.dart | 4 +- sdk/lib/widgets/animated_component.dart | 2 +- sdk/lib/widgets/drawer.dart | 4 +- sdk/lib/widgets/fixed_height_scrollable.dart | 2 +- sdk/lib/widgets/ink_well.dart | 4 +- sdk/lib/widgets/popup_menu.dart | 2 +- sdk/lib/widgets/scrollable.dart | 6 +- sdk/lib/widgets/toggleable.dart | 4 +- 21 files changed, 927 insertions(+), 15 deletions(-) create mode 100644 sdk/lib/animation/README.md create mode 100644 sdk/lib/animation/animated_value.dart create mode 100644 sdk/lib/animation/curves.dart create mode 100644 sdk/lib/animation/fling_curve.dart create mode 100644 sdk/lib/animation/generators.dart create mode 100644 sdk/lib/animation/mechanics.dart create mode 100644 sdk/lib/animation/scroll_behavior.dart rename sdk/lib/{framework => }/debug/utils.dart (100%) create mode 100644 sdk/lib/mojo/embedder.dart create mode 100644 sdk/lib/mojo/net/fetch.dart create mode 100644 sdk/lib/mojo/net/image_cache.dart create mode 100644 sdk/lib/mojo/shell.dart diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index d568f13dc..45e317c47 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -9,9 +9,16 @@ dart_pkg("sdk") { "CHANGELOG.md", "README.md", "bin/init.dart", + "lib/animation/animated_value.dart", + "lib/animation/curves.dart", + "lib/animation/fling_curve.dart", + "lib/animation/generators.dart", + "lib/animation/mechanics.dart", + "lib/animation/scroll_behavior.dart", "lib/app/scheduler.dart", "lib/assets/.gitignore", "lib/assets/material-design-icons.sha1", + "lib/debug/utils.dart", "lib/download_material_design_icons", "lib/editing2/editable_string.dart", "lib/editing2/editable_text.dart", @@ -49,7 +56,6 @@ dart_pkg("sdk") { "lib/framework/components/tool_bar.dart", "lib/framework/debug/shake-to-reload.sky", "lib/framework/debug/tracing.dart", - "lib/framework/debug/utils.dart", "lib/framework/editing/editable_string.dart", "lib/framework/editing/editable_text.dart", "lib/framework/editing/keyboard.dart", @@ -66,6 +72,10 @@ dart_pkg("sdk") { "lib/framework/theme/typography.dart", "lib/framework/theme/view_configuration.dart", "lib/internals.dart", + "lib/mojo/embedder.dart", + "lib/mojo/net/fetch.dart", + "lib/mojo/net/image_cache.dart", + "lib/mojo/shell.dart", "lib/painting/box_painter.dart", "lib/painting/shadows.dart", "lib/painting/text_style.dart", diff --git a/sdk/lib/animation/README.md b/sdk/lib/animation/README.md new file mode 100644 index 000000000..4fdbcecc1 --- /dev/null +++ b/sdk/lib/animation/README.md @@ -0,0 +1,2 @@ +This directory contains animation-related libraries that only depend +on core Dart libraries and ../sky/*. diff --git a/sdk/lib/animation/animated_value.dart b/sdk/lib/animation/animated_value.dart new file mode 100644 index 000000000..1511ed220 --- /dev/null +++ b/sdk/lib/animation/animated_value.dart @@ -0,0 +1,84 @@ +// 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 'dart:async'; + +import 'curves.dart'; +import 'generators.dart'; + +typedef void Callback (); + +class AnimatedValue { + StreamController _controller = new StreamController.broadcast(sync: true); + AnimationGenerator _animation; + Completer _completer; + double _value; + + AnimatedValue(double initial, { Callback onChange }) { + _value = initial; + _onChange = onChange; + } + Callback _onChange; + + // A stream of change in value from |initial|. The stream does not + // contain the initial value. Consumers should check the initial value via + // the |value| accessor. + // TODO(ianh): Rename this to valueStream once we've landed the fn2 fork + Stream get onValueChanged => _controller.stream; + + double get value => _value; + + void set value(double value) { + stop(); + _setValue(value); + } + + bool get isAnimating => _animation != null; + + void _setValue(double value) { + _value = value; + _controller.add(_value); + if (_onChange != null) + _onChange(); + } + + void _done() { + _animation = null; + if (_completer == null) + return; + Completer completer = _completer; + _completer = null; + completer.complete(_value); + } + + void stop() { + if (_animation != null) { + _animation.cancel(); // will call _done() if it isn't already finished + _done(); + } + } + + Future animateTo(double newValue, double duration, + { Curve curve: linear, double initialDelay: 0.0 }) { + stop(); + + _animation = new AnimationGenerator( + duration: duration, + begin: _value, + end: newValue, + curve: curve, + initialDelay: initialDelay) + ..onTick.listen(_setValue, onDone: _done); + + _completer = new Completer(); + return _completer.future; + } + + double get remainingTime { + if (_animation == null) + return 0.0; + return _animation.remainingTime; + } + +} diff --git a/sdk/lib/animation/curves.dart b/sdk/lib/animation/curves.dart new file mode 100644 index 000000000..8e285762e --- /dev/null +++ b/sdk/lib/animation/curves.dart @@ -0,0 +1,72 @@ +// 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. + +double _evaluateCubic(double a, double b, double m) { + // TODO(abarth): Would Math.pow be faster? + return 3 * a * (1 - m) * (1 - m) * m + 3 * b * (1 - m) * m * m + m * m * m; +} + +const double _kCubicErrorBound = 0.001; + +abstract class Curve { + double transform(double t); +} + +class Linear implements Curve { + const Linear(); + + double transform(double t) { + return t; + } +} + +class ParabolicFall implements Curve { + const ParabolicFall(); + + double transform(double t) { + return -t*t + 1; + } +} + +class ParabolicRise implements Curve { + const ParabolicRise(); + + double transform(double t) { + return -(t-1)*(t-1) + 1; + } +} + +class Cubic implements Curve { + final double a; + final double b; + final double c; + final double d; + + const Cubic(this.a, this.b, this.c, this.d); + + double transform(double t) { + double start = 0.0; + double end = 1.0; + while (true) { + double midpoint = (start + end) / 2; + double estimate = _evaluateCubic(a, c, midpoint); + + if ((t - estimate).abs() < _kCubicErrorBound) + return _evaluateCubic(b, d, midpoint); + + if (estimate < t) + start = midpoint; + else + end = midpoint; + } + } +} + +const Linear linear = const Linear(); +const Cubic ease = const Cubic(0.25, 0.1, 0.25, 1.0); +const Cubic easeIn = const Cubic(0.42, 0.0, 1.0, 1.0); +const Cubic easeOut = const Cubic(0.0, 0.0, 0.58, 1.0); +const Cubic easeInOut = const Cubic(0.42, 0.0, 0.58, 1.0); +const ParabolicRise parabolicRise = const ParabolicRise(); +const ParabolicFall parabolicFall = const ParabolicFall(); diff --git a/sdk/lib/animation/fling_curve.dart b/sdk/lib/animation/fling_curve.dart new file mode 100644 index 000000000..3a9f54f4a --- /dev/null +++ b/sdk/lib/animation/fling_curve.dart @@ -0,0 +1,55 @@ +// 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 "dart:math" as math; + +const double _kDefaultAlpha = -5707.62; +const double _kDefaultBeta = 172.0; +const double _kDefaultGamma = 3.7; + +double _positionAtTime(double t) { + return _kDefaultAlpha * math.exp(-_kDefaultGamma * t) + - _kDefaultBeta * t + - _kDefaultAlpha; +} + +double _velocityAtTime(double t) { + return -_kDefaultAlpha * _kDefaultGamma * math.exp(-_kDefaultGamma * t) + - _kDefaultBeta; +} + +double _timeAtVelocity(double v) { + return -math.log((v + _kDefaultBeta) / (-_kDefaultAlpha * _kDefaultGamma)) + / _kDefaultGamma; +} + +final double _kMaxVelocity = _velocityAtTime(0.0); +final double _kCurveDuration = _timeAtVelocity(0.0); + +class FlingCurve { + double _timeOffset; + double _positionOffset; + double _startTime; + double _previousPosition; + double _direction; + + FlingCurve(double velocity, double startTime) { + double startingVelocity = math.min(_kMaxVelocity, velocity.abs()); + _timeOffset = _timeAtVelocity(startingVelocity); + _positionOffset = _positionAtTime(_timeOffset); + _startTime = startTime / 1000.0; + _previousPosition = 0.0; + _direction = velocity.sign; + } + + double update(double timeStamp) { + double t = timeStamp / 1000.0 - _startTime + _timeOffset; + if (t >= _kCurveDuration) + return 0.0; + double position = _positionAtTime(t) - _positionOffset; + double positionDelta = position - _previousPosition; + _previousPosition = position; + return _direction * math.max(0.0, positionDelta); + } +} diff --git a/sdk/lib/animation/generators.dart b/sdk/lib/animation/generators.dart new file mode 100644 index 000000000..2110ed0b9 --- /dev/null +++ b/sdk/lib/animation/generators.dart @@ -0,0 +1,162 @@ +// 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 'dart:async'; +import 'dart:math' as math; + +import '../app/scheduler.dart' as scheduler; +import 'curves.dart'; +import 'mechanics.dart'; + +abstract class Generator { + Stream get onTick; // TODO(ianh): rename this to tickStream + void cancel(); +} + +class FrameGenerator extends Generator { + Function onDone; + StreamController _controller; + + Stream get onTick => _controller.stream; + + int _animationId = 0; + bool _cancelled = false; + + FrameGenerator({this.onDone}) { + _controller = new StreamController( + sync: true, + onListen: _scheduleTick, + onCancel: cancel); + } + + void cancel() { + if (_cancelled) { + return; + } + if (_animationId != 0) { + scheduler.cancelAnimationFrame(_animationId); + } + _animationId = 0; + _cancelled = true; + if (onDone != null) { + onDone(); + } + } + + void _scheduleTick() { + assert(_animationId == 0); + _animationId = scheduler.requestAnimationFrame(_tick); + } + + void _tick(double timeStamp) { + _animationId = 0; + _controller.add(timeStamp); + if (!_cancelled) { + _scheduleTick(); + } + } +} + +class AnimationGenerator extends Generator { + Stream get onTick => _stream; + final double initialDelay; + final double duration; + final double begin; + final double end; + final Curve curve; + + FrameGenerator _generator; + Stream _stream; + bool _done = false; + double _lastTime; + + AnimationGenerator({ + this.initialDelay: 0.0, + this.duration, + this.begin: 0.0, + this.end: 1.0, + this.curve: linear, + Function onDone + }) { + assert(curve != null); + assert(duration != null && duration > 0.0); + _generator = new FrameGenerator(onDone: onDone); + + double startTime = 0.0; + _stream = _generator.onTick.map((timeStamp) { + if (startTime == 0.0) + startTime = timeStamp; + + double t = (timeStamp - (startTime + initialDelay)) / duration; + _lastTime = math.max(0.0, math.min(t, 1.0)); + return _lastTime; + }) + .takeWhile(_checkForCompletion) + .where((t) => t >= 0.0) + .map(_transform); + } + + double get remainingTime { + if (_lastTime == null) + return duration; + return duration - _lastTime; + } + + void cancel() { + _generator.cancel(); + } + + double _transform(double t) { + if (_done) + return end; + return begin + (end - begin) * curve.transform(t); + } + + // This is required because Dart Streams don't have takeUntil (inclusive). + bool _checkForCompletion(double t) { + if (_done) + return false; + + _done = t >= 1; + return true; + } +} + +class Simulation extends Generator { + Stream get onTick => _stream; + final System system; + + FrameGenerator _generator; + Stream _stream; + double _previousTime = 0.0; + + Simulation(this.system, {Function terminationCondition, Function onDone}) { + _generator = new FrameGenerator(onDone: onDone); + _stream = _generator.onTick.map(_update); + + if (terminationCondition != null) { + bool done = false; + _stream = _stream.takeWhile((_) { + if (done) + return false; + done = terminationCondition(); + return true; + }); + } + } + + void cancel() { + _generator.cancel(); + } + + double _update(double timeStamp) { + double previousTime = _previousTime; + _previousTime = timeStamp; + if (previousTime == 0.0) + return timeStamp; + double deltaT = timeStamp - previousTime; + system.update(deltaT); + return timeStamp; + } +} diff --git a/sdk/lib/animation/mechanics.dart b/sdk/lib/animation/mechanics.dart new file mode 100644 index 000000000..6a6cc4cad --- /dev/null +++ b/sdk/lib/animation/mechanics.dart @@ -0,0 +1,213 @@ +// 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 'dart:math' as math; + +const double kGravity = -0.980; // m^s-2 + +abstract class System { + void update(double deltaT); +} + +class Particle extends System { + final double mass; + double velocity; + double position; + + Particle({this.mass: 1.0, this.velocity: 0.0, this.position: 0.0}); + + void applyImpulse(double impulse) { + velocity += impulse / mass; + } + + void update(double deltaT) { + position += velocity * deltaT; + } + + void setVelocityFromEnergy({double energy, double direction}) { + assert(direction == -1.0 || direction == 1.0); + assert(energy >= 0.0); + velocity = math.sqrt(2.0 * energy / mass) * direction; + } +} + +abstract class Box { + void confine(Particle p); +} + +class ClosedBox extends Box { + final double min; // m + final double max; // m + + ClosedBox({this.min, this.max}) { + assert(min == null || max == null || min <= max); + } + + void confine(Particle p) { + if (min != null) { + p.position = math.max(min, p.position); + if (p.position == min) + p.velocity = math.max(0.0, p.velocity); + } + if (max != null) { + p.position = math.min(max, p.position); + if (p.position == max) + p.velocity = math.min(0.0, p.velocity); + } + } +} + +class GeofenceBox extends Box { + final double min; // m + final double max; // m + + final Function onEscape; + + GeofenceBox({this.min, this.max, this.onEscape}) { + assert(min == null || max == null || min <= max); + assert(onEscape != null); + } + + void confine(Particle p) { + if (((min != null) && (p.position < min)) || + ((max != null) && (p.position > max))) + onEscape(); + } +} + +class ParticleInBox extends System { + final Particle particle; + final Box box; + + ParticleInBox({this.particle, this.box}) { + box.confine(particle); + } + + void update(double deltaT) { + particle.update(deltaT); + box.confine(particle); + } +} + +class ParticleInBoxWithFriction extends ParticleInBox { + final double friction; // unitless + final double _sign; + + final Function onStop; + + ParticleInBoxWithFriction({Particle particle, Box box, this.friction, this.onStop}) + : super(particle: particle, box: box), + _sign = particle.velocity.sign; + + void update(double deltaT) { + double force = -_sign * friction * particle.mass * -kGravity; + particle.applyImpulse(force * deltaT); + if (particle.velocity.sign != _sign) { + particle.velocity = 0.0; + } + super.update(deltaT); + if ((particle.velocity == 0.0) && (onStop != null)) + onStop(); + } +} + +class Spring { + final double k; + double displacement; + + Spring(this.k, {this.displacement: 0.0}); + + double get force => -k * displacement; +} + +class ParticleAndSpringInBox extends System { + final Particle particle; + final Spring spring; + final Box box; + + ParticleAndSpringInBox({this.particle, this.spring, this.box}) { + _applyInvariants(); + } + + void update(double deltaT) { + particle.applyImpulse(spring.force * deltaT); + particle.update(deltaT); + _applyInvariants(); + } + + void _applyInvariants() { + box.confine(particle); + spring.displacement = particle.position; + } +} + +class ParticleClimbingRamp extends System { + + // This is technically the same as ParticleInBoxWithFriction. The + // difference is in how the system is set up. Here, we configure the + // system so as to stop by a certain distance after having been + // given an initial impulse from rest, whereas + // ParticleInBoxWithFriction is set up to stop with a consistent + // decelerating force assuming an initial velocity. The angle theta + // (0 < theta < π/2) is used to configure how much energy the + // particle is to start with; lower angles result in a gentler kick + // while higher angles result in a faster conclusion. + + final Particle particle; + final Box box; + final double theta; + final double _sinTheta; + + ParticleClimbingRamp({ + this.particle, + this.box, + double theta, // in radians + double targetPosition}) : this.theta = theta, this._sinTheta = math.sin(theta) { + assert(theta > 0.0); + assert(theta < math.PI / 2.0); + double deltaPosition = targetPosition - particle.position; + double tanTheta = math.tan(theta); + // We need to give the particle exactly as much (kinetic) energy + // as it needs to get to the top of the slope and stop with + // energy=0. This is exactly the same amount of energy as the + // potential energy at the top of the slope, which is g*h*m. + // If the slope's horizontal component is delta P long, then + // the height is delta P times tan theta. + particle.setVelocityFromEnergy( + energy: (kGravity * (deltaPosition * tanTheta) * particle.mass).abs(), + direction: deltaPosition > 0.0 ? 1.0 : -1.0 + ); + box.confine(particle); + } + + void update(double deltaT) { + particle.update(deltaT); + // Note that we apply the impulse from gravity after updating the particle's + // position so that we overestimate the distance traveled by the particle. + // That ensures that we actually hit the edge of the box and don't wind up + // reversing course. + particle.applyImpulse(particle.mass * kGravity * _sinTheta * deltaT); + box.confine(particle); + } +} + +class Multisystem extends System { + final Particle particle; + + System _currentSystem; + + Multisystem({ this.particle, System system }) { + assert(system != null); + _currentSystem = system; + } + + void update(double deltaT) { + _currentSystem.update(deltaT); + } + + void transitionToSystem(System system) { + assert(system != null); + _currentSystem = system; + } +} diff --git a/sdk/lib/animation/scroll_behavior.dart b/sdk/lib/animation/scroll_behavior.dart new file mode 100644 index 000000000..f94e5378a --- /dev/null +++ b/sdk/lib/animation/scroll_behavior.dart @@ -0,0 +1,115 @@ +// 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 'dart:math' as math; + +import 'mechanics.dart'; +import 'generators.dart'; + +const double _kScrollFriction = 0.005; +const double _kOverscrollFriction = 0.075; +const double _kBounceSlopeAngle = math.PI / 512.0; // radians + +abstract class ScrollBehavior { + Simulation release(Particle particle) => null; + + // Returns the new scroll offset. + double applyCurve(double scrollOffset, double scrollDelta); +} + +class BoundedScrollBehavior extends ScrollBehavior { + double minOffset; + double maxOffset; + + BoundedScrollBehavior({this.minOffset: 0.0, this.maxOffset}); + + double applyCurve(double scrollOffset, double scrollDelta) { + double newScrollOffset = scrollOffset + scrollDelta; + if (minOffset != null) + newScrollOffset = math.max(minOffset, newScrollOffset); + if (maxOffset != null) + newScrollOffset = math.min(maxOffset, newScrollOffset); + return newScrollOffset; + } +} + +class OverscrollBehavior extends ScrollBehavior { + + double _contentsHeight; + double get contentsHeight => _contentsHeight; + void set contentsHeight (double value) { + if (_contentsHeight != value) { + _contentsHeight = value; + // TODO(ianh) now what? what if we have a simulation ongoing? + } + } + + double _containerHeight; + double get containerHeight => _containerHeight; + void set containerHeight (double value) { + if (_containerHeight != value) { + _containerHeight = value; + // TODO(ianh) now what? what if we have a simulation ongoing? + } + } + + OverscrollBehavior({double contentsHeight: 0.0, double containerHeight: 0.0}) + : _contentsHeight = contentsHeight, + _containerHeight = containerHeight; + + double get maxScroll => math.max(0.0, _contentsHeight - _containerHeight); + + Simulation release(Particle particle) { + System system; + if ((particle.position >= 0.0) && (particle.position < maxScroll)) { + if (particle.velocity == 0.0) + return null; + System slowdownSystem = new ParticleInBoxWithFriction( + particle: particle, + friction: _kScrollFriction, + box: new GeofenceBox(min: 0.0, max: maxScroll, onEscape: () { + (system as Multisystem).transitionToSystem(new ParticleInBoxWithFriction( + particle: particle, + friction: _kOverscrollFriction, + box: new ClosedBox(), + onStop: () => (system as Multisystem).transitionToSystem(getBounceBackSystem(particle)) + )); + })); + system = new Multisystem(particle: particle, system: slowdownSystem); + } else { + system = getBounceBackSystem(particle); + } + return new Simulation(system, terminationCondition: () => particle.position == 0.0); + } + + System getBounceBackSystem(Particle particle) { + if (particle.position < 0.0) + return new ParticleClimbingRamp( + particle: particle, + box: new ClosedBox(max: 0.0), + theta: _kBounceSlopeAngle, + targetPosition: 0.0); + return new ParticleClimbingRamp( + particle: particle, + box: new ClosedBox(min: maxScroll), + theta: _kBounceSlopeAngle, + targetPosition: maxScroll); + } + + double applyCurve(double scrollOffset, double scrollDelta) { + double newScrollOffset = scrollOffset + scrollDelta; + // If we're overscrolling, we want move the scroll offset 2x + // slower than we would otherwise. Therefore, we "rewind" the + // newScrollOffset by half the amount that we moved it above. + // Notice that we clap the "old" value to 0.0 so that we only + // reduce the portion of scrollDelta that's applied beyond 0.0. We + // do similar things for overscroll in the other direction. + if (newScrollOffset < 0.0) { + newScrollOffset -= (newScrollOffset - math.min(0.0, scrollOffset)) / 2.0; + } else if (newScrollOffset > maxScroll) { + newScrollOffset -= (newScrollOffset - math.max(maxScroll, scrollOffset)) / 2.0; + } + return newScrollOffset; + } +} diff --git a/sdk/lib/framework/debug/utils.dart b/sdk/lib/debug/utils.dart similarity index 100% rename from sdk/lib/framework/debug/utils.dart rename to sdk/lib/debug/utils.dart diff --git a/sdk/lib/mojo/embedder.dart b/sdk/lib/mojo/embedder.dart new file mode 100644 index 000000000..1bcf13ba2 --- /dev/null +++ b/sdk/lib/mojo/embedder.dart @@ -0,0 +1,72 @@ +// 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 "dart:sky.internals" as internals; + +import "package:mojo/application.dart"; +import "package:mojo/bindings.dart" as bindings; +import "package:mojo/core.dart" as core; +import "package:mojom/mojo/service_provider.mojom.dart"; +import "package:mojom/mojo/service_registry.mojom.dart"; +import "package:mojom/mojo/shell.mojom.dart"; + +final _EmbedderImpl embedder = new _EmbedderImpl(); + +class _EmbedderImpl { + ApplicationConnection _connection; + ServiceRegistryProxy _serviceRegistry; + ShellProxy _shell; + bool _internalsHasNoShell = false; + + ShellProxy get shell { + if (_internalsHasNoShell || _shell != null) return _shell; + + try { + _shell = new ShellProxy.fromHandle( + new core.MojoHandle(internals.takeShellProxyHandle())); + } catch (e) { + _internalsHasNoShell = true; + } + return _shell; + } + + ApplicationConnection get connection { + if (_connection == null) { + var stubHandle = + new core.MojoHandle(internals.takeServicesProvidedToEmbedder()); + var proxyHandle = + new core.MojoHandle(internals.takeServicesProvidedByEmbedder()); + _connection = new ApplicationConnection(stubHandle.isValid + ? new ServiceProviderStub.fromHandle(stubHandle) + : null, proxyHandle.isValid + ? new ServiceProviderProxy.fromHandle(proxyHandle) + : null); + } + return _connection; + } + + ApplicationConnection connectToApplication(String url) { + var proxy = new ServiceProviderProxy.unbound(); + var stub = new ServiceProviderStub.unbound(); + shell.ptr.connectToApplication(url, proxy, stub); + return new ApplicationConnection(stub, proxy); + } + + void connectToService(String url, bindings.ProxyBase proxy) { + var appSp = new ServiceProviderProxy.unbound(); + shell.ptr.connectToApplication(url, appSp, null); + var pipe = new core.MojoMessagePipe(); + proxy.impl.bind(pipe.endpoints[0]); + appSp.ptr.connectToService(proxy.name, pipe.endpoints[1]); + appSp.close(); + } + + ServiceRegistryProxy get serviceRegistry { + if (_serviceRegistry == null) { + _serviceRegistry = new ServiceRegistryProxy.fromHandle( + new core.MojoHandle(internals.takeServiceRegistry())); + } + return _serviceRegistry; + } +} diff --git a/sdk/lib/mojo/net/fetch.dart b/sdk/lib/mojo/net/fetch.dart new file mode 100644 index 000000000..834112c01 --- /dev/null +++ b/sdk/lib/mojo/net/fetch.dart @@ -0,0 +1,54 @@ +// 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 'dart:async'; +import 'dart:typed_data'; + +import 'package:mojo/core.dart' as core; +import 'package:mojom/mojo/network_service.mojom.dart'; +import 'package:mojom/mojo/url_loader.mojom.dart'; +import 'package:mojom/mojo/url_request.mojom.dart'; +import 'package:mojom/mojo/url_response.mojom.dart'; + +import '../shell.dart' as shell; + +class Response { + ByteData body; + + Response(this.body); + + String bodyAsString() { + return new String.fromCharCodes(new Uint8List.view(body.buffer)); + } +} + +Future fetch(UrlRequest request) async { + NetworkServiceProxy net = new NetworkServiceProxy.unbound(); + shell.requestService("mojo:authenticated_network_service", net); + + UrlLoaderProxy loader = new UrlLoaderProxy.unbound(); + net.ptr.createUrlLoader(loader); + + UrlResponse response = (await loader.ptr.start(request)).response; + + loader.close(); + net.close(); + return response; +} + +Future fetchUrl(String relativeUrl) async { + String url = Uri.base.resolve(relativeUrl).toString(); + UrlRequest request = new UrlRequest() + ..url = url + ..autoFollowRedirects = true; + return fetch(request); +} + +Future fetchBody(String relativeUrl) async { + UrlResponse response = await fetchUrl(relativeUrl); + if (response.body == null) return new Response(null); + + ByteData data = await core.DataPipeDrainer.drainHandle(response.body); + return new Response(data); +} diff --git a/sdk/lib/mojo/net/image_cache.dart b/sdk/lib/mojo/net/image_cache.dart new file mode 100644 index 000000000..fca61fd70 --- /dev/null +++ b/sdk/lib/mojo/net/image_cache.dart @@ -0,0 +1,46 @@ +// 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 'dart:sky'; +import 'dart:collection'; + +import 'package:mojom/mojo/url_response.mojom.dart'; + +import 'fetch.dart'; + +final HashMap> _pendingRequests = + new HashMap>(); + +final HashMap _completedRequests = + new HashMap(); + +void _loadComplete(url, image) { + _completedRequests[url] = image; + _pendingRequests[url].forEach((c) => c(image)); + _pendingRequests.remove(url); +} + +void load(String url, ImageDecoderCallback callback) { + Image result = _completedRequests[url]; + if (result != null) { + callback(_completedRequests[url]); + return; + } + + bool newRequest = false; + _pendingRequests.putIfAbsent(url, () { + newRequest = true; + return new List(); + }).add(callback); + if (newRequest) { + fetchUrl(url).then((UrlResponse response) { + if (response.statusCode >= 400) { + _loadComplete(url, null); + return; + } + new ImageDecoder(response.body.handle.h, + (image) => _loadComplete(url, image)); + }); + } +} diff --git a/sdk/lib/mojo/shell.dart b/sdk/lib/mojo/shell.dart new file mode 100644 index 000000000..8961f727f --- /dev/null +++ b/sdk/lib/mojo/shell.dart @@ -0,0 +1,27 @@ +// 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 "dart:sky.internals" as internals; + +import "package:mojo/application.dart"; +import "package:mojom/mojo/service_provider.mojom.dart"; +import 'package:mojo/core.dart' as core; + +import "embedder.dart"; + +ApplicationConnection _initConnection() { + int rawHandle = internals.takeServicesProvidedByEmbedder(); + core.MojoHandle proxyHandle = new core.MojoHandle(rawHandle); + ServiceProviderProxy serviceProvider = null; + if (proxyHandle.isValid) serviceProvider = + new ServiceProviderProxy.fromHandle(proxyHandle); + return new ApplicationConnection(null, serviceProvider); +} + +final ApplicationConnection _connection = _initConnection(); + +void requestService(String url, Object proxy) { + if (embedder.shell == null) _connection.requestService(proxy); + else embedder.connectToService(url, proxy); +} diff --git a/sdk/lib/rendering/box.dart b/sdk/lib/rendering/box.dart index 0679b9b87..fd999ad8b 100644 --- a/sdk/lib/rendering/box.dart +++ b/sdk/lib/rendering/box.dart @@ -7,8 +7,8 @@ import 'dart:sky' as sky; import 'package:vector_math/vector_math.dart'; -import '../framework/debug/utils.dart'; -import '../framework/net/image_cache.dart' as image_cache; +import '../debug/utils.dart'; +import '../mojo/net/image_cache.dart' as image_cache; import '../painting/box_painter.dart'; import 'object.dart'; diff --git a/sdk/lib/widgets/animated_component.dart b/sdk/lib/widgets/animated_component.dart index a7d4e3088..23573bb95 100644 --- a/sdk/lib/widgets/animated_component.dart +++ b/sdk/lib/widgets/animated_component.dart @@ -4,7 +4,7 @@ import 'dart:async'; -import '../framework/animation/animated_value.dart'; +import '../animation/animated_value.dart'; import 'basic.dart'; typedef void SetterFunction(double value); diff --git a/sdk/lib/widgets/drawer.dart b/sdk/lib/widgets/drawer.dart index 11a161ce5..afe3a4484 100644 --- a/sdk/lib/widgets/drawer.dart +++ b/sdk/lib/widgets/drawer.dart @@ -7,8 +7,8 @@ import 'dart:sky' as sky; import 'package:vector_math/vector_math.dart'; -import '../framework/animation/animated_value.dart'; -import '../framework/animation/curves.dart'; +import '../animation/animated_value.dart'; +import '../animation/curves.dart'; import '../theme2/colors.dart'; import '../theme2/shadows.dart'; import 'animated_component.dart'; diff --git a/sdk/lib/widgets/fixed_height_scrollable.dart b/sdk/lib/widgets/fixed_height_scrollable.dart index 3ae0d0474..18a410954 100644 --- a/sdk/lib/widgets/fixed_height_scrollable.dart +++ b/sdk/lib/widgets/fixed_height_scrollable.dart @@ -6,7 +6,7 @@ import 'dart:math' as math; import 'package:vector_math/vector_math.dart'; -import '../framework/animation/scroll_behavior.dart'; +import '../animation/scroll_behavior.dart'; import 'basic.dart'; import 'scrollable.dart'; diff --git a/sdk/lib/widgets/ink_well.dart b/sdk/lib/widgets/ink_well.dart index 85ef2259e..95a78daeb 100644 --- a/sdk/lib/widgets/ink_well.dart +++ b/sdk/lib/widgets/ink_well.dart @@ -5,8 +5,8 @@ import 'dart:math' as math; import 'dart:sky' as sky; -import '../framework/animation/animated_value.dart'; -import '../framework/animation/curves.dart'; +import '../animation/animated_value.dart'; +import '../animation/curves.dart'; import '../rendering/box.dart'; import '../rendering/object.dart'; import 'basic.dart'; diff --git a/sdk/lib/widgets/popup_menu.dart b/sdk/lib/widgets/popup_menu.dart index 88d08f54c..d9ab4f28c 100644 --- a/sdk/lib/widgets/popup_menu.dart +++ b/sdk/lib/widgets/popup_menu.dart @@ -6,7 +6,7 @@ import 'dart:async'; import 'dart:math' as math; import 'dart:sky' as sky; -import '../framework/animation/animated_value.dart'; +import '../animation/animated_value.dart'; import '../painting/box_painter.dart'; import '../theme2/colors.dart'; import '../theme2/shadows.dart'; diff --git a/sdk/lib/widgets/scrollable.dart b/sdk/lib/widgets/scrollable.dart index 68fd45144..076201a4c 100644 --- a/sdk/lib/widgets/scrollable.dart +++ b/sdk/lib/widgets/scrollable.dart @@ -5,9 +5,9 @@ import 'dart:math' as math; import 'dart:sky' as sky; -import '../framework/animation/generators.dart'; -import '../framework/animation/mechanics.dart'; -import '../framework/animation/scroll_behavior.dart'; +import '../animation/generators.dart'; +import '../animation/mechanics.dart'; +import '../animation/scroll_behavior.dart'; import '../theme2/edges.dart'; import '../theme2/view_configuration.dart' as config; import 'basic.dart'; diff --git a/sdk/lib/widgets/toggleable.dart b/sdk/lib/widgets/toggleable.dart index 2ff09472e..9f36b8b1d 100644 --- a/sdk/lib/widgets/toggleable.dart +++ b/sdk/lib/widgets/toggleable.dart @@ -4,10 +4,10 @@ import 'dart:sky' as sky; +import '../animation/animated_value.dart'; +import '../animation/curves.dart'; import 'animated_component.dart'; import 'basic.dart'; -import '../framework/animation/animated_value.dart'; -import '../framework/animation/curves.dart'; typedef void ValueChanged(value); -- GitLab