Add Alignment, which will replace FractionalOffset (#12342)

Unlike FractionalOffset, Alignment uses the center as the zero of the
coordinate system, which makes the RTL math work out much cleaner.

Also, make FractionalOffset into a subclass of Alignment so that clients
can continue to use FractionalOffset.
diff --git a/packages/flutter/lib/painting.dart b/packages/flutter/lib/painting.dart
index c74b7dc..d01cb4a 100644
--- a/packages/flutter/lib/painting.dart
+++ b/packages/flutter/lib/painting.dart
@@ -17,6 +17,7 @@
 ///    painting boxes.
 library painting;
 
+export 'src/painting/alignment.dart';
 export 'src/painting/basic_types.dart';
 export 'src/painting/border_radius.dart';
 export 'src/painting/borders.dart';
diff --git a/packages/flutter/lib/src/cupertino/nav_bar.dart b/packages/flutter/lib/src/cupertino/nav_bar.dart
index 6077955..8c77ca8 100644
--- a/packages/flutter/lib/src/cupertino/nav_bar.dart
+++ b/packages/flutter/lib/src/cupertino/nav_bar.dart
@@ -416,7 +416,7 @@
               child: new OverflowBox(
                 minHeight: 0.0,
                 maxHeight: double.INFINITY,
-                alignment: FractionalOffsetDirectional.bottomStart,
+                alignment: AlignmentDirectional.bottomStart,
                 child: new Padding(
                   padding: const EdgeInsetsDirectional.only(
                     start: _kNavBarEdgePadding,
diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart
index 28fcfb3..6ad1101 100644
--- a/packages/flutter/lib/src/cupertino/route.dart
+++ b/packages/flutter/lib/src/cupertino/route.dart
@@ -11,21 +11,21 @@
 const double _kMinFlingVelocity = 1.0; // Screen widths per second.
 
 // Fractional offset from offscreen to the right to fully on screen.
-final FractionalOffsetTween _kRightMiddleTween = new FractionalOffsetTween(
-  begin: FractionalOffset.topRight,
-  end: FractionalOffset.topLeft,
+final AlignmentTween _kRightMiddleTween = new AlignmentTween(
+  begin: Alignment.centerRight * 2.0,
+  end: Alignment.center,
 );
 
 // Fractional offset from fully on screen to 1/3 offscreen to the left.
-final FractionalOffsetTween _kMiddleLeftTween = new FractionalOffsetTween(
-  begin: FractionalOffset.topLeft,
-  end: const FractionalOffset(-1.0/3.0, 0.0),
+final AlignmentTween _kMiddleLeftTween = new AlignmentTween(
+  begin: Alignment.center,
+  end: const Alignment(-2.0/3.0, 0.0),
 );
 
 // Fractional offset from offscreen below to fully on screen.
-final FractionalOffsetTween _kBottomUpTween = new FractionalOffsetTween(
-  begin: FractionalOffset.bottomLeft,
-  end: FractionalOffset.topLeft,
+final AlignmentTween _kBottomUpTween = new AlignmentTween(
+  begin: Alignment.bottomCenter * 2.0,
+  end: Alignment.center,
 );
 
 // Custom decoration from no shadow to page shadow mimicking iOS page
@@ -35,8 +35,8 @@
   end: const _CupertinoEdgeShadowDecoration(
     edgeGradient: const LinearGradient(
       // Spans 5% of the page.
-      begin: const FractionalOffset(0.95, 0.0),
-      end: FractionalOffset.topRight,
+      begin: const Alignment(0.90, 0.0),
+      end: Alignment.centerRight,
       // Eyeballed gradient used to mimic a drop shadow on the left side only.
       colors: const <Color>[
         const Color(0x00000000),
@@ -318,9 +318,9 @@
       super(key: key);
 
   // When this page is coming in to cover another page.
-  final Animation<FractionalOffset> _primaryPositionAnimation;
+  final Animation<Alignment> _primaryPositionAnimation;
   // When this page is becoming covered by another page.
-  final Animation<FractionalOffset> _secondaryPositionAnimation;
+  final Animation<Alignment> _secondaryPositionAnimation;
   final Animation<Decoration> _primaryShadowAnimation;
 
   /// The widget below this widget in the tree.
@@ -361,7 +361,7 @@
        ),
        super(key: key);
 
-  final Animation<FractionalOffset> _positionAnimation;
+  final Animation<Alignment> _positionAnimation;
 
   /// The widget below this widget in the tree.
   final Widget child;
@@ -562,7 +562,7 @@
       const _CupertinoEdgeShadowDecoration();
 
   /// A gradient to draw to the left of the box being decorated.
-  /// FractionalOffsets are relative to the original box translated one box
+  /// Alignments are relative to the original box translated one box
   /// width to the left.
   final LinearGradient edgeGradient;
 
diff --git a/packages/flutter/lib/src/cupertino/tab_scaffold.dart b/packages/flutter/lib/src/cupertino/tab_scaffold.dart
index 53d9603..63e1fb2 100644
--- a/packages/flutter/lib/src/cupertino/tab_scaffold.dart
+++ b/packages/flutter/lib/src/cupertino/tab_scaffold.dart
@@ -145,7 +145,7 @@
 
     if (widget.tabBar != null) {
       stacked.add(new Align(
-        alignment: FractionalOffset.bottomCenter,
+        alignment: Alignment.bottomCenter,
         // Override the tab bar's currentIndex to the current tab and hook in
         // our own listener to update the _currentPage on top of a possibly user
         // provided callback.
diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart
index c683f50..1b88ffa 100644
--- a/packages/flutter/lib/src/material/app_bar.dart
+++ b/packages/flutter/lib/src/material/app_bar.dart
@@ -448,7 +448,7 @@
     }
 
     appBar = new Align(
-      alignment: FractionalOffset.topCenter,
+      alignment: Alignment.topCenter,
       child: appBar,
     );
 
diff --git a/packages/flutter/lib/src/material/bottom_navigation_bar.dart b/packages/flutter/lib/src/material/bottom_navigation_bar.dart
index a1ce6f0..e645a8b 100644
--- a/packages/flutter/lib/src/material/bottom_navigation_bar.dart
+++ b/packages/flutter/lib/src/material/bottom_navigation_bar.dart
@@ -215,14 +215,14 @@
     return (leftWeights + _flex(_animations[index]) / 2.0) / allWeights;
   }
 
-  FractionalOffset _circleOffset(int index) {
+  Alignment _circleOffset(int index) {
     final double iconSize = widget.iconSize;
     final Tween<double> yOffsetTween = new Tween<double>(
       begin: (18.0 + iconSize / 2.0) / kBottomNavigationBarHeight, // 18dp + icon center
       end: (6.0 + iconSize / 2.0) / kBottomNavigationBarHeight     // 6dp + icon center
     );
 
-    return new FractionalOffset(
+    return new Alignment(
       _xOffset(index),
       yOffsetTween.evaluate(_animations[index])
     );
@@ -283,10 +283,10 @@
                     widget.onTap(i);
                 },
                 child: new Stack(
-                  alignment: FractionalOffset.center,
+                  alignment: Alignment.center,
                   children: <Widget>[
                     new Align(
-                      alignment: FractionalOffset.topCenter,
+                      alignment: Alignment.topCenter,
                       child: new Container(
                         margin: new EdgeInsets.only(
                           top: new Tween<double>(
@@ -304,7 +304,7 @@
                       ),
                     ),
                     new Align(
-                      alignment: FractionalOffset.bottomCenter,
+                      alignment: Alignment.bottomCenter,
                       child: new Container(
                         margin: const EdgeInsets.only(bottom: 10.0),
                         child: DefaultTextStyle.merge(
@@ -319,7 +319,7 @@
                                 end: 1.0,
                               ).evaluate(_animations[i]),
                             )),
-                            alignment: FractionalOffset.bottomCenter,
+                            alignment: Alignment.bottomCenter,
                             child: widget.items[i].title,
                           ),
                         ),
@@ -352,10 +352,10 @@
                     widget.onTap(i);
                 },
                 child: new Stack(
-                  alignment: FractionalOffset.center,
+                  alignment: Alignment.center,
                   children: <Widget>[
                     new Align(
-                      alignment: FractionalOffset.topCenter,
+                      alignment: Alignment.topCenter,
                       child: new Container(
                         margin: new EdgeInsets.only(
                           top: new Tween<double>(
@@ -373,7 +373,7 @@
                       ),
                     ),
                     new Align(
-                      alignment: FractionalOffset.bottomCenter,
+                      alignment: Alignment.bottomCenter,
                       child: new Container(
                         margin: const EdgeInsets.only(bottom: 10.0),
                         child: new FadeTransition(
@@ -465,7 +465,7 @@
   AnimationController controller;
   CurvedAnimation animation;
 
-  FractionalOffset get offset {
+  Alignment get offset {
     return state._circleOffset(index);
   }
 
@@ -487,11 +487,13 @@
   // bounding rectangle's corners touches the egde of the circle. Drawing a
   // circle beyond this radius is futile since there is no perceivable
   // difference within the cropped rectangle.
-  double _maxRadius(FractionalOffset offset, Size size) {
-    final double dx = offset.dx;
-    final double dy = offset.dy;
-    final double x = (dx > 0.5 ? dx : 1.0 - dx) * size.width;
-    final double y = (dy > 0.5 ? dy : 1.0 - dy) * size.height;
+  double _maxRadius(Alignment alignment, Size size) {
+    final double dx = alignment.x;
+    final double dy = alignment.y;
+    final double halfWidth = size.width / 2.0;
+    final double halfHeight = size.height / 2.0;
+    final double x = halfWidth + dx.abs() * halfWidth;
+    final double y = halfHeight + dy.abs() * halfHeight;
     return math.sqrt(x * x + y * y);
   }
 
@@ -517,20 +519,22 @@
     for (_Circle circle in circles) {
       final Tween<double> radiusTween = new Tween<double>(
         begin: 0.0,
-        end: _maxRadius(circle.offset, size)
+        end: _maxRadius(circle.offset, size),
       );
       final Paint paint = new Paint()..color = circle.color;
       final Rect rect = new Rect.fromLTWH(0.0, 0.0, size.width, size.height);
       canvas.clipRect(rect);
       final double navWidth = math.min(bottomNavMaxWidth, size.width);
+      final double halfNavWidth = navWidth / 2.0;
+      final double halfHeight = size.height / 2.0;
       final Offset center = new Offset(
-        (size.width - navWidth) / 2.0 + circle.offset.dx * navWidth,
-        circle.offset.dy * size.height
+        (size.width - navWidth) / 2.0 + halfNavWidth + circle.offset.x * halfNavWidth,
+        halfHeight + circle.offset.y * halfHeight,
       );
       canvas.drawCircle(
         center,
         radiusTween.lerp(circle.animation.value),
-        paint
+        paint,
       );
     }
   }
diff --git a/packages/flutter/lib/src/material/data_table.dart b/packages/flutter/lib/src/material/data_table.dart
index 05ca6da..8d0f892 100644
--- a/packages/flutter/lib/src/material/data_table.dart
+++ b/packages/flutter/lib/src/material/data_table.dart
@@ -408,7 +408,7 @@
     label = new Container(
       padding: padding,
       height: _kHeadingRowHeight,
-      alignment: numeric ? FractionalOffset.centerRight : FractionalOffsetDirectional.centerStart,
+      alignment: numeric ? Alignment.centerRight : AlignmentDirectional.centerStart,
       child: new AnimatedDefaultTextStyle(
         style: new TextStyle(
           // TODO(ianh): font family should be Roboto; see https://github.com/flutter/flutter/issues/3116
@@ -460,7 +460,7 @@
     label = new Container(
       padding: padding,
       height: _kDataRowHeight,
-      alignment: numeric ? FractionalOffset.centerRight : FractionalOffsetDirectional.centerStart,
+      alignment: numeric ? Alignment.centerRight : AlignmentDirectional.centerStart,
       child: new DefaultTextStyle(
         style: new TextStyle(
           // TODO(ianh): font family should be Roboto; see https://github.com/flutter/flutter/issues/3116
@@ -774,7 +774,7 @@
       child: new Transform(
         transform: new Matrix4.rotationZ(_orientationOffset + _orientationAnimation.value)
                              ..setTranslationRaw(0.0, _kArrowIconBaselineOffset, 0.0),
-        alignment: FractionalOffset.center,
+        alignment: Alignment.center,
         child: new Icon(
           Icons.arrow_downward,
           size: _kArrowIconSize,
diff --git a/packages/flutter/lib/src/material/drawer.dart b/packages/flutter/lib/src/material/drawer.dart
index 5bd287a..2d50015 100644
--- a/packages/flutter/lib/src/material/drawer.dart
+++ b/packages/flutter/lib/src/material/drawer.dart
@@ -267,7 +267,7 @@
   Widget _buildDrawer(BuildContext context) {
     if (_controller.status == AnimationStatus.dismissed) {
       return new Align(
-        alignment: FractionalOffsetDirectional.centerStart,
+        alignment: AlignmentDirectional.centerStart,
         child: new GestureDetector(
           key: _gestureDetectorKey,
           onHorizontalDragUpdate: _move,
@@ -299,9 +299,9 @@
                 ),
               ),
               new Align(
-                alignment: FractionalOffsetDirectional.centerStart,
+                alignment: AlignmentDirectional.centerStart,
                 child: new Align(
-                  alignment: FractionalOffsetDirectional.centerEnd,
+                  alignment: AlignmentDirectional.centerEnd,
                   widthFactor: _controller.value,
                   child: new RepaintBoundary(
                     child: new FocusScope(
diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart
index 90fba67..c0cc91d 100644
--- a/packages/flutter/lib/src/material/dropdown.dart
+++ b/packages/flutter/lib/src/material/dropdown.dart
@@ -361,7 +361,7 @@
   Widget build(BuildContext context) {
     return new Container(
       height: _kMenuItemHeight,
-      alignment: FractionalOffset.centerLeft,
+      alignment: Alignment.centerLeft,
       child: child,
     );
   }
@@ -589,7 +589,7 @@
             // the hint or nothing at all.
             new IndexedStack(
               index: _selectedIndex ?? hintIndex,
-              alignment: FractionalOffset.centerLeft,
+              alignment: Alignment.centerLeft,
               children: items,
             ),
             new Icon(Icons.arrow_drop_down,
diff --git a/packages/flutter/lib/src/material/flexible_space_bar.dart b/packages/flutter/lib/src/material/flexible_space_bar.dart
index 1b0c358..aa67b48 100644
--- a/packages/flutter/lib/src/material/flexible_space_bar.dart
+++ b/packages/flutter/lib/src/material/flexible_space_bar.dart
@@ -92,16 +92,16 @@
     return null;
   }
 
-  FractionalOffset _getTitleAlignment(bool effectiveCenterTitle) {
+  Alignment _getTitleAlignment(bool effectiveCenterTitle) {
     if (effectiveCenterTitle)
-      return FractionalOffset.bottomCenter;
+      return Alignment.bottomCenter;
     final TextDirection textDirection = Directionality.of(context);
     assert(textDirection != null);
     switch (textDirection) {
       case TextDirection.rtl:
-        return FractionalOffset.bottomRight;
+        return Alignment.bottomRight;
       case TextDirection.ltr:
-        return FractionalOffset.bottomLeft;
+        return Alignment.bottomLeft;
     }
     return null;
   }
@@ -152,7 +152,7 @@
         final double scaleValue = new Tween<double>(begin: 1.5, end: 1.0).lerp(t);
         final Matrix4 scaleTransform = new Matrix4.identity()
           ..scale(scaleValue, scaleValue, 1.0);
-        final FractionalOffset titleAlignment = _getTitleAlignment(effectiveCenterTitle);
+        final Alignment titleAlignment = _getTitleAlignment(effectiveCenterTitle);
         children.add(new Container(
           padding: new EdgeInsetsDirectional.only(
             start: effectiveCenterTitle ? 0.0 : 72.0,
diff --git a/packages/flutter/lib/src/material/icon_button.dart b/packages/flutter/lib/src/material/icon_button.dart
index 7696171..0be7e96 100644
--- a/packages/flutter/lib/src/material/icon_button.dart
+++ b/packages/flutter/lib/src/material/icon_button.dart
@@ -73,7 +73,7 @@
     Key key,
     this.iconSize: 24.0,
     this.padding: const EdgeInsets.all(8.0),
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     @required this.icon,
     this.color,
     this.highlightColor,
@@ -107,8 +107,8 @@
 
   /// Defines how the icon is positioned within the IconButton.
   ///
-  /// This property must not be null. It defaults to [FractionalOffset.center].
-  final FractionalOffsetGeometry alignment;
+  /// This property must not be null. It defaults to [Alignment.center].
+  final AlignmentGeometry alignment;
 
   /// The icon to display inside the button.
   ///
diff --git a/packages/flutter/lib/src/material/list_tile.dart b/packages/flutter/lib/src/material/list_tile.dart
index 0389559..218ca95 100644
--- a/packages/flutter/lib/src/material/list_tile.dart
+++ b/packages/flutter/lib/src/material/list_tile.dart
@@ -397,7 +397,7 @@
         child: new Container(
           margin: const EdgeInsetsDirectional.only(end: 16.0),
           width: 40.0,
-          alignment: FractionalOffsetDirectional.centerStart,
+          alignment: AlignmentDirectional.centerStart,
           child: leading,
         ),
       ));
@@ -432,7 +432,7 @@
         data: iconThemeData,
         child: new Container(
           margin: const EdgeInsetsDirectional.only(start: 16.0),
-          alignment: FractionalOffsetDirectional.centerEnd,
+          alignment: AlignmentDirectional.centerEnd,
           child: trailing,
         ),
       ));
diff --git a/packages/flutter/lib/src/material/page.dart b/packages/flutter/lib/src/material/page.dart
index cc16859..e086207 100644
--- a/packages/flutter/lib/src/material/page.dart
+++ b/packages/flutter/lib/src/material/page.dart
@@ -9,9 +9,9 @@
 import 'theme.dart';
 
 // Fractional offset from 1/4 screen below the top to fully on screen.
-final FractionalOffsetTween _kBottomUpTween = new FractionalOffsetTween(
-  begin: FractionalOffset.bottomLeft,
-  end: FractionalOffset.topLeft
+final AlignmentTween _kBottomUpTween = new AlignmentTween(
+  begin: Alignment.bottomCenter * 0.5,
+  end: Alignment.center
 );
 
 // Used for Android and Fuchsia.
@@ -26,7 +26,7 @@
        )),
        super(key: key);
 
-  final Animation<FractionalOffset> _positionAnimation;
+  final Animation<Alignment> _positionAnimation;
   final Widget child;
 
   @override
diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart
index df4d446..4e526a4 100644
--- a/packages/flutter/lib/src/material/popup_menu.dart
+++ b/packages/flutter/lib/src/material/popup_menu.dart
@@ -447,7 +447,7 @@
             type: MaterialType.card,
             elevation: route.elevation,
             child: new Align(
-              alignment: FractionalOffset.topRight,
+              alignment: Alignment.topRight,
               widthFactor: width.evaluate(route.animation),
               heightFactor: height.evaluate(route.animation),
               child: child,
diff --git a/packages/flutter/lib/src/material/refresh_indicator.dart b/packages/flutter/lib/src/material/refresh_indicator.dart
index 89b6870..3d763d7 100644
--- a/packages/flutter/lib/src/material/refresh_indicator.dart
+++ b/packages/flutter/lib/src/material/refresh_indicator.dart
@@ -384,15 +384,15 @@
           left: 0.0,
           right: 0.0,
           child: new SizeTransition(
-            axisAlignment: _isIndicatorAtTop ? 1.0 : 0.0,
+            axisAlignment: _isIndicatorAtTop ? 1.0 : -1.0,
             sizeFactor: _positionFactor, // this is what brings it down
             child: new Container(
               padding: _isIndicatorAtTop
                 ? new EdgeInsets.only(top: widget.displacement)
                 : new EdgeInsets.only(bottom: widget.displacement),
               alignment: _isIndicatorAtTop
-                ? FractionalOffset.topCenter
-                : FractionalOffset.bottomCenter,
+                ? Alignment.topCenter
+                : Alignment.bottomCenter,
               child: new ScaleTransition(
                 scale: _scaleFactor,
                 child: new AnimatedBuilder(
diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart
index f4a8c5e..ecb0f1e 100644
--- a/packages/flutter/lib/src/material/scaffold.dart
+++ b/packages/flutter/lib/src/material/scaffold.dart
@@ -898,7 +898,7 @@
         bottomSheets.add(_currentBottomSheet._widget);
       final Widget stack = new Stack(
         children: bottomSheets,
-        alignment: FractionalOffset.bottomCenter,
+        alignment: Alignment.bottomCenter,
       );
       _addIfNonNull(
         children,
@@ -1053,7 +1053,7 @@
       animation: widget.animationController,
       builder: (BuildContext context, Widget child) {
         return new Align(
-          alignment: FractionalOffsetDirectional.topStart,
+          alignment: AlignmentDirectional.topStart,
           heightFactor: widget.animationController.value,
           child: child
         );
diff --git a/packages/flutter/lib/src/material/snack_bar.dart b/packages/flutter/lib/src/material/snack_bar.dart
index 291606d..c0a98bf 100644
--- a/packages/flutter/lib/src/material/snack_bar.dart
+++ b/packages/flutter/lib/src/material/snack_bar.dart
@@ -82,7 +82,7 @@
   const SnackBarAction({
     Key key,
     @required this.label,
-    @required this.onPressed
+    @required this.onPressed,
   }) : assert(label != null),
        assert(onPressed != null),
        super(key: key);
@@ -117,7 +117,7 @@
   Widget build(BuildContext context) {
     return new FlatButton(
       onPressed: _haveTriggeredAction ? null : _handlePressed,
-      child: new Text(widget.label)
+      child: new Text(widget.label),
     );
   }
 }
@@ -192,7 +192,7 @@
     final ThemeData darkTheme = new ThemeData(
       brightness: Brightness.dark,
       accentColor: theme.accentColor,
-      accentColorBrightness: theme.accentColorBrightness
+      accentColorBrightness: theme.accentColorBrightness,
     );
     final List<Widget> children = <Widget>[
       const SizedBox(width: _kSnackBarPadding),
@@ -202,15 +202,15 @@
           child: new DefaultTextStyle(
             style: darkTheme.textTheme.subhead,
             child: content,
-          )
-        )
-      )
+          ),
+        ),
+      ),
     ];
     if (action != null) {
       children.add(new ButtonTheme.bar(
         padding: const EdgeInsets.symmetric(horizontal: _kSnackBarPadding),
         textTheme: ButtonTextTheme.accent,
-        child: action
+        child: action,
       ));
     } else {
       children.add(const SizedBox(width: _kSnackBarPadding));
@@ -222,9 +222,9 @@
         animation: heightAnimation,
         builder: (BuildContext context, Widget child) {
           return new Align(
-            alignment: FractionalOffsetDirectional.topStart,
+            alignment: AlignmentDirectional.topStart,
             heightFactor: heightAnimation.value,
-            child: child
+            child: child,
           );
         },
         child: new Semantics(
@@ -245,14 +245,14 @@
                   opacity: fadeAnimation,
                   child: new Row(
                     children: children,
-                    crossAxisAlignment: CrossAxisAlignment.center
-                  )
-                )
-              )
-            )
-          )
-        )
-      )
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                  ),
+                ),
+              ),
+            ),
+          ),
+        ),
+      ),
     );
   }
 
@@ -278,7 +278,7 @@
       backgroundColor: backgroundColor,
       action: action,
       duration: duration,
-      animation: newAnimation
+      animation: newAnimation,
     );
   }
 }
diff --git a/packages/flutter/lib/src/material/stepper.dart b/packages/flutter/lib/src/material/stepper.dart
index 3974c14..2a7d143 100644
--- a/packages/flutter/lib/src/material/stepper.dart
+++ b/packages/flutter/lib/src/material/stepper.dart
@@ -297,7 +297,7 @@
               color: _isDark() ? _kErrorDark : _kErrorLight,
             ),
             child: new Align(
-              alignment: const FractionalOffset(0.5, 0.9), // 0.9 looks better than the geometrical 0.66.
+              alignment: const Alignment(0.0, 0.8), // 0.8 looks better than the geometrical 0.33.
               child: _buildCircleChild(index, oldState && widget.steps[index].state != StepState.error),
             ),
           ),
diff --git a/packages/flutter/lib/src/material/user_accounts_drawer_header.dart b/packages/flutter/lib/src/material/user_accounts_drawer_header.dart
index dff1aa7..e526941 100644
--- a/packages/flutter/lib/src/material/user_accounts_drawer_header.dart
+++ b/packages/flutter/lib/src/material/user_accounts_drawer_header.dart
@@ -70,7 +70,7 @@
   Widget addDropdownIcon(Widget line) {
     final Widget icon = new Expanded(
       child: new Align(
-        alignment: FractionalOffsetDirectional.centerEnd,
+        alignment: AlignmentDirectional.centerEnd,
         child: new Icon(
           isOpen ? Icons.arrow_drop_up : Icons.arrow_drop_down,
           color: Colors.white
diff --git a/packages/flutter/lib/src/painting/alignment.dart b/packages/flutter/lib/src/painting/alignment.dart
new file mode 100644
index 0000000..de50645
--- /dev/null
+++ b/packages/flutter/lib/src/painting/alignment.dart
@@ -0,0 +1,618 @@
+// Copyright 2017 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:ui' as ui show lerpDouble;
+
+import 'package:flutter/foundation.dart';
+
+import 'basic_types.dart';
+
+/// Base class for [Alignment] that allows for text-direction aware
+/// resolution.
+///
+/// A property or argument of this type accepts classes created either with [new
+/// Alignment] and its variants, or [new AlignmentDirectional].
+///
+/// To convert a [AlignmentGeometry] object of indeterminate type into a
+/// [Alignment] object, call the [resolve] method.
+@immutable
+abstract class AlignmentGeometry {
+  /// Abstract const constructor. This constructor enables subclasses to provide
+  /// const constructors so that they can be used in const expressions.
+  const AlignmentGeometry();
+
+  double get _x;
+
+  double get _start;
+
+  double get _y;
+
+  /// Returns the sum of two [AlignmentGeometry] objects.
+  ///
+  /// If you know you are adding two [Alignment] or two [AlignmentDirectional]
+  /// objects, consider using the `+` operator instead, which always returns an
+  /// object of the same type as the operands, and is typed accordingly.
+  ///
+  /// If [add] is applied to two objects of the same type ([Alignment] or
+  /// [AlignmentDirectional]), an object of that type will be returned (though
+  /// this is not reflected in the type system). Otherwise, an object
+  /// representing a combination of both is returned. That object can be turned
+  /// into a concrete [Alignment] using [resolve].
+  AlignmentGeometry add(AlignmentGeometry other) {
+    return new _MixedAlignment(
+      _x + other._x,
+      _start + other._start,
+      _y + other._y,
+    );
+  }
+
+  /// Returns the negation of the given [AlignmentGeometry] object.
+  ///
+  /// This is the same as multiplying the object by -1.0.
+  ///
+  /// This operator returns an object of the same type as the operand.
+  AlignmentGeometry operator -();
+
+  /// Scales the [AlignmentGeometry] object in each dimension by the given factor.
+  ///
+  /// This operator returns an object of the same type as the operand.
+  AlignmentGeometry operator *(double other);
+
+  /// Divides the [AlignmentGeometry] object in each dimension by the given factor.
+  ///
+  /// This operator returns an object of the same type as the operand.
+  AlignmentGeometry operator /(double other);
+
+  /// Integer divides the [AlignmentGeometry] object in each dimension by the given factor.
+  ///
+  /// This operator returns an object of the same type as the operand.
+  AlignmentGeometry operator ~/(double other);
+
+  /// Computes the remainder in each dimension by the given factor.
+  ///
+  /// This operator returns an object of the same type as the operand.
+  AlignmentGeometry operator %(double other);
+
+  /// Linearly interpolate between two [AlignmentGeometry] objects.
+  ///
+  /// If either is null, this function interpolates from [Alignment.center], and
+  /// the result is an object of the same type as the non-null argument.
+  ///
+  /// If [lerp] is applied to two objects of the same type ([Alignment] or
+  /// [AlignmentDirectional]), an object of that type will be returned (though
+  /// this is not reflected in the type system). Otherwise, an object
+  /// representing a combination of both is returned. That object can be turned
+  /// into a concrete [Alignment] using [resolve].
+  static AlignmentGeometry lerp(AlignmentGeometry a, AlignmentGeometry b, double t) {
+    if (a == null && b == null)
+      return null;
+    if (a == null)
+      return b * t;
+    if (b == null)
+      return a * (1.0 - t);
+    if (a is Alignment && b is Alignment)
+      return Alignment.lerp(a, b, t);
+    if (a is AlignmentDirectional && b is AlignmentDirectional)
+      return AlignmentDirectional.lerp(a, b, t);
+    return new _MixedAlignment(
+      ui.lerpDouble(a._x, b._x, t),
+      ui.lerpDouble(a._start, b._start, t),
+      ui.lerpDouble(a._y, b._y, t),
+    );
+  }
+
+  /// Convert this instance into a [Alignment], which uses literal
+  /// coordinates (the `x` coordinate being explicitly a distance from the
+  /// left).
+  ///
+  /// See also:
+  ///
+  ///  * [Alignment], for which this is a no-op (returns itself).
+  ///  * [AlignmentDirectional], which flips the horizontal direction
+  ///    based on the `direction` argument.
+  Alignment resolve(TextDirection direction);
+
+  @override
+  String toString() {
+    if (_start == 0.0)
+      return Alignment._stringify(_x, _y);
+    if (_x == 0.0)
+      return AlignmentDirectional._stringify(_start, _y);
+    return Alignment._stringify(_x, _y) + ' + ' + AlignmentDirectional._stringify(_start, 0.0);
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    if (other is! AlignmentGeometry)
+      return false;
+    final AlignmentGeometry typedOther = other;
+    return _x == typedOther._x &&
+           _start == typedOther._start &&
+           _y == typedOther._y;
+  }
+
+  @override
+  int get hashCode => hashValues(_x, _start, _y);
+}
+
+/// A point within a rectangle.
+///
+/// `Alignment(0.0, 0.0)` represents the center of the rectangle. The distance
+/// from -1.0 to +1.0 is the distance from one side of the rectangle to the
+/// other side of the rectangle. Therefore, 2.0 units horizontally (or
+/// vertically) is equivalent to the width (or height) of the rectangle.
+///
+/// `Alignment(-1.0, -1.0)` represents the top left of the rectangle.
+///
+/// `Alignment(1.0, 1.0)` represents the bottom right of the rectangle.
+///
+/// `Alignment(0.0, 3.0)` represents a point that is horizontally centered with
+/// respect to the rectangel and vertically below the bottom of the rectangle by
+/// the height of the rectangle.
+///
+/// [Alignment] use visual coordinates, which means increasing [x] moves the
+/// point from left to right. To support layouts with a right-to-left
+/// [TextDirection], consider using [AlignmentDirectional], in which the
+/// direction the point moves when increasing the horizontal value depends on
+/// the [TextDirection].
+///
+/// A variety of widgets use [Alignment] in their configuration, most
+/// notably:
+///
+///  * [Align] positions a child according to a [Alignment].
+///
+/// See also:
+///
+///  * [AlignmentDirectional], which has a horizontal coordinate orientation
+///    that depends on the [TextDirection].
+///  * [AlignmentGeometry], which is an abstract type that is agnostic as to
+///    whether the horizontal direction depends on the [TextDirection].
+class Alignment extends AlignmentGeometry {
+  /// Creates an alignment.
+  ///
+  /// The [x] and [y] arguments must not be null.
+  const Alignment(this.x, this.y)
+    : assert(x != null),
+      assert(y != null);
+
+  /// The distance fraction in the horizontal direction.
+  ///
+  /// A value of -1.0 corresponds to the leftmost edge. A value of 1.0
+  /// corresponds to the rightmost edge. Values are not limited to that range;
+  /// values less than -1.0 represent positions to the left of the left edge,
+  /// and values greater than 1.0 represent positions to the right of the right
+  /// edge.
+  final double x;
+
+  /// The distance fraction in the vertical direction.
+  ///
+  /// A value of -1.0 corresponds to the topmost edge. A value of 1.0
+  /// corresponds to the bottommost edge. Values are not limited to that range;
+  /// values less than -1.0 represent positions above the top, and values
+  /// greater than 1.0 represent positions below the bottom.
+  final double y;
+
+  @override
+  double get _x => x;
+
+  @override
+  double get _start => 0.0;
+
+  @override
+  double get _y => y;
+
+  /// The top left corner.
+  static const Alignment topLeft = const Alignment(-1.0, -1.0);
+
+  /// The center point along the top edge.
+  static const Alignment topCenter = const Alignment(0.0, -1.0);
+
+  /// The top right corner.
+  static const Alignment topRight = const Alignment(1.0, -1.0);
+
+  /// The center point along the left edge.
+  static const Alignment centerLeft = const Alignment(-1.0, 0.0);
+
+  /// The center point, both horizontally and vertically.
+  static const Alignment center = const Alignment(0.0, 0.0);
+
+  /// The center point along the right edge.
+  static const Alignment centerRight = const Alignment(1.0, 0.0);
+
+  /// The bottom left corner.
+  static const Alignment bottomLeft = const Alignment(-1.0, 1.0);
+
+  /// The center point along the bottom edge.
+  static const Alignment bottomCenter = const Alignment(0.0, 1.0);
+
+  /// The bottom right corner.
+  static const Alignment bottomRight = const Alignment(1.0, 1.0);
+
+  @override
+  AlignmentGeometry add(AlignmentGeometry other) {
+    if (other is Alignment)
+      return this + other;
+    return super.add(other);
+  }
+
+  /// Returns the difference between two [Alignment]s.
+  Alignment operator -(Alignment other) {
+    return new Alignment(x - other.x, y - other.y);
+  }
+
+  /// Returns the sum of two [Alignment]s.
+  Alignment operator +(Alignment other) {
+    return new Alignment(x + other.x, y + other.y);
+  }
+
+  /// Returns the negation of the given [Alignment].
+  @override
+  Alignment operator -() {
+    return new Alignment(-x, -y);
+  }
+
+  /// Scales the [Alignment] in each dimension by the given factor.
+  @override
+  Alignment operator *(double other) {
+    return new Alignment(x * other, y * other);
+  }
+
+  /// Divides the [Alignment] in each dimension by the given factor.
+  @override
+  Alignment operator /(double other) {
+    return new Alignment(x / other, y / other);
+  }
+
+  /// Integer divides the [Alignment] in each dimension by the given factor.
+  @override
+  Alignment operator ~/(double other) {
+    return new Alignment((x ~/ other).toDouble(), (y ~/ other).toDouble());
+  }
+
+  /// Computes the remainder in each dimension by the given factor.
+  @override
+  Alignment operator %(double other) {
+    return new Alignment(x % other, y % other);
+  }
+
+  /// Returns the offset that is this fraction in the direction of the given offset.
+  Offset alongOffset(Offset other) {
+    final double centerX = other.dx / 2.0;
+    final double centerY = other.dy / 2.0;
+    return new Offset(centerX + x * centerX, centerY + y * centerY);
+  }
+
+  /// Returns the offset that is this fraction within the given size.
+  Offset alongSize(Size other) {
+    final double centerX = other.width / 2.0;
+    final double centerY = other.height / 2.0;
+    return new Offset(centerX + x * centerX, centerY + y * centerY);
+  }
+
+  /// Returns the point that is this fraction within the given rect.
+  Offset withinRect(Rect rect) {
+    final double halfWidth = rect.width / 2.0;
+    final double halfHeight = rect.height / 2.0;
+    return new Offset(
+      rect.left + halfWidth + x * halfWidth,
+      rect.top + halfHeight + y * halfHeight,
+    );
+  }
+
+  /// Returns a rect of the given size, aligned within given rect as specified
+  /// by this alignment.
+  ///
+  /// For example, a 100×100 size inscribed on a 200×200 rect using
+  /// [Alignment.topLeft] would be the 100×100 rect at the top left of
+  /// the 200×200 rect.
+  Rect inscribe(Size size, Rect rect) {
+    final double halfWidthDelta = (rect.width - size.width) / 2.0;
+    final double halfHeightDelta = (rect.height - size.height) / 2.0;
+    return new Rect.fromLTWH(
+      rect.left + halfWidthDelta + x * halfWidthDelta,
+      rect.top + halfHeightDelta + y * halfHeightDelta,
+      size.width,
+      size.height,
+    );
+  }
+
+  /// Linearly interpolate between two [Alignment]s.
+  ///
+  /// If either is null, this function interpolates from [Alignment.center].
+  static Alignment lerp(Alignment a, Alignment b, double t) {
+    if (a == null && b == null)
+      return null;
+    if (a == null)
+      return new Alignment(ui.lerpDouble(0.0, b.x, t), ui.lerpDouble(0.0, b.y, t));
+    if (b == null)
+      return new Alignment(ui.lerpDouble(a.x, 0.0, t), ui.lerpDouble(a.y, 0.0, t));
+    return new Alignment(ui.lerpDouble(a.x, b.x, t), ui.lerpDouble(a.y, b.y, t));
+  }
+
+  @override
+  Alignment resolve(TextDirection direction) => this;
+
+  static String _stringify(double x, double y) {
+    if (x == -1.0 && y == -1.0)
+      return 'Alignment.topLeft';
+    if (x == 0.0 && y == -1.0)
+      return 'Alignment.topCenter';
+    if (x == 1.0 && y == -1.0)
+      return 'Alignment.topRight';
+    if (x == -1.0 && y == 0.0)
+      return 'Alignment.centerLeft';
+    if (x == 0.0 && y == 0.0)
+      return 'Alignment.center';
+    if (x == 1.0 && y == 0.0)
+      return 'Alignment.centerRight';
+    if (x == -1.0 && y == 1.0)
+      return 'Alignment.bottomLeft';
+    if (x == 0.0 && y == 1.0)
+      return 'Alignment.bottomCenter';
+    if (x == 1.0 && y == 1.0)
+      return 'Alignment.bottomRight';
+    return 'Alignment(${x.toStringAsFixed(1)}, '
+                     '${y.toStringAsFixed(1)})';
+  }
+
+  @override
+  String toString() => _stringify(x, y);
+}
+
+/// An offset that's expressed as a fraction of a [Size], but whose horizontal
+/// component is dependent on the writing direction.
+///
+/// This can be used to indicate an offset from the left in [TextDirection.ltr]
+/// text and an offset from the right in [TextDirection.rtl] text without having
+/// to be aware of the current text direction.
+///
+/// See also:
+///
+///  * [Alignment], a variant that is defined in physical terms (i.e.
+///    whose horizontal component does not depend on the text direction).
+class AlignmentDirectional extends AlignmentGeometry {
+  /// Creates a directional alignment.
+  ///
+  /// The [start] and [y] arguments must not be null.
+  const AlignmentDirectional(this.start, this.y)
+    : assert(start != null),
+      assert(y != null);
+
+  /// The distance fraction in the horizontal direction.
+  ///
+  /// A value of -1.0 corresponds to the edge on the "start" side, which is the
+  /// left side in [TextDirection.ltr] contexts and the right side in
+  /// [TextDirection.rtl] contexts. A value of 1.0 corresponds to the opposite
+  /// edge, the "end" side. Values are not limited to that range; values less
+  /// than -1.0 represent positions beyond the start edge, and values greater than
+  /// 1.0 represent positions beyond the end edge.
+  ///
+  /// This value is normalized into a [Alignment.x] value by the [resolve]
+  /// method.
+  final double start;
+
+  /// The distance fraction in the vertical direction.
+  ///
+  /// A value of -1.0 corresponds to the topmost edge. A value of 1.0
+  /// corresponds to the bottommost edge. Values are not limited to that range;
+  /// values less than -1.0 represent positions above the top, and values
+  /// greater than 1.0 represent positions below the bottom.
+  ///
+  /// This value is passed through to [Alignment.y] unmodified by the
+  /// [resolve] method.
+  final double y;
+
+  @override
+  double get _x => 0.0;
+
+  @override
+  double get _start => start;
+
+  @override
+  double get _y => y;
+
+  /// The top corner on the "start" side.
+  static const AlignmentDirectional topStart = const AlignmentDirectional(-1.0, -1.0);
+
+  /// The center point along the top edge.
+  ///
+  /// Consider using [Alignment.topCenter] instead, as it does not need
+  /// to be [resolve]d to be used.
+  static const AlignmentDirectional topCenter = const AlignmentDirectional(0.0, -1.0);
+
+  /// The top corner on the "end" side.
+  static const AlignmentDirectional topEnd = const AlignmentDirectional(1.0, -1.0);
+
+  /// The center point along the "start" edge.
+  static const AlignmentDirectional centerStart = const AlignmentDirectional(-1.0, 0.0);
+
+  /// The center point, both horizontally and vertically.
+  ///
+  /// Consider using [Alignment.center] instead, as it does not need to
+  /// be [resolve]d to be used.
+  static const AlignmentDirectional center = const AlignmentDirectional(0.0, 0.0);
+
+  /// The center point along the "end" edge.
+  static const AlignmentDirectional centerEnd = const AlignmentDirectional(1.0, 0.0);
+
+  /// The bottom corner on the "start" side.
+  static const AlignmentDirectional bottomStart = const AlignmentDirectional(-1.0, 1.0);
+
+  /// The center point along the bottom edge.
+  ///
+  /// Consider using [Alignment.bottomCenter] instead, as it does not
+  /// need to be [resolve]d to be used.
+  static const AlignmentDirectional bottomCenter = const AlignmentDirectional(0.0, 1.0);
+
+  /// The bottom corner on the "end" side.
+  static const AlignmentDirectional bottomEnd = const AlignmentDirectional(1.0, 1.0);
+
+  @override
+  AlignmentGeometry add(AlignmentGeometry other) {
+    if (other is AlignmentDirectional)
+      return this + other;
+    return super.add(other);
+  }
+
+  /// Returns the difference between two [AlignmentDirectional]s.
+  AlignmentDirectional operator -(AlignmentDirectional other) {
+    return new AlignmentDirectional(start - other.start, y - other.y);
+  }
+
+  /// Returns the sum of two [AlignmentDirectional]s.
+  AlignmentDirectional operator +(AlignmentDirectional other) {
+    return new AlignmentDirectional(start + other.start, y + other.y);
+  }
+
+  /// Returns the negation of the given [AlignmentDirectional].
+  @override
+  AlignmentDirectional operator -() {
+    return new AlignmentDirectional(-start, -y);
+  }
+
+  /// Scales the [AlignmentDirectional] in each dimension by the given factor.
+  @override
+  AlignmentDirectional operator *(double other) {
+    return new AlignmentDirectional(start * other, y * other);
+  }
+
+  /// Divides the [AlignmentDirectional] in each dimension by the given factor.
+  @override
+  AlignmentDirectional operator /(double other) {
+    return new AlignmentDirectional(start / other, y / other);
+  }
+
+  /// Integer divides the [AlignmentDirectional] in each dimension by the given factor.
+  @override
+  AlignmentDirectional operator ~/(double other) {
+    return new AlignmentDirectional((start ~/ other).toDouble(), (y ~/ other).toDouble());
+  }
+
+  /// Computes the remainder in each dimension by the given factor.
+  @override
+  AlignmentDirectional operator %(double other) {
+    return new AlignmentDirectional(start % other, y % other);
+  }
+
+  /// Linearly interpolate between two [AlignmentDirectional]s.
+  ///
+  /// If either is null, this function interpolates from [AlignmentDirectional.center].
+  static AlignmentDirectional lerp(AlignmentDirectional a, AlignmentDirectional b, double t) {
+    if (a == null && b == null)
+      return null;
+    if (a == null)
+      return new AlignmentDirectional(ui.lerpDouble(0.0, b.start, t), ui.lerpDouble(0.0, b.y, t));
+    if (b == null)
+      return new AlignmentDirectional(ui.lerpDouble(a.start, 0.0, t), ui.lerpDouble(a.y, 0.0, t));
+    return new AlignmentDirectional(ui.lerpDouble(a.start, b.start, t), ui.lerpDouble(a.y, b.y, t));
+  }
+
+  @override
+  Alignment resolve(TextDirection direction) {
+    assert(direction != null);
+    switch (direction) {
+      case TextDirection.rtl:
+        return new Alignment(-start, y);
+      case TextDirection.ltr:
+        return new Alignment(start, y);
+    }
+    return null;
+  }
+
+  static String _stringify(double start, double y) {
+    if (start == -1.0 && y == -1.0)
+      return 'AlignmentDirectional.topStart';
+    if (start == 0.0 && y == -1.0)
+      return 'AlignmentDirectional.topCenter';
+    if (start == 1.0 && y == -1.0)
+      return 'AlignmentDirectional.topEnd';
+    if (start == -1.0 && y == 0.0)
+      return 'AlignmentDirectional.centerStart';
+    if (start == 0.0 && y == 0.0)
+      return 'AlignmentDirectional.center';
+    if (start == 1.0 && y == 0.0)
+      return 'AlignmentDirectional.centerEnd';
+    if (start == -1.0 && y == 1.0)
+      return 'AlignmentDirectional.bottomStart';
+    if (start == 0.0 && y == 1.0)
+      return 'AlignmentDirectional.bottomCenter';
+    if (start == 1.0 && y == 1.0)
+      return 'AlignmentDirectional.bottomEnd';
+    return 'AlignmentDirectional(${start.toStringAsFixed(1)}, '
+                     '${y.toStringAsFixed(1)})';
+  }
+
+  @override
+  String toString() => _stringify(start, y);
+}
+
+class _MixedAlignment extends AlignmentGeometry {
+  const _MixedAlignment(this._x, this._start, this._y);
+
+  @override
+  final double _x;
+
+  @override
+  final double _start;
+
+  @override
+  final double _y;
+
+  @override
+  _MixedAlignment operator -() {
+    return new _MixedAlignment(
+      -_x,
+      -_start,
+      -_y,
+    );
+  }
+
+  @override
+  _MixedAlignment operator *(double other) {
+    return new _MixedAlignment(
+      _x * other,
+      _start * other,
+      _y * other,
+    );
+  }
+
+  @override
+  _MixedAlignment operator /(double other) {
+    return new _MixedAlignment(
+      _x / other,
+      _start / other,
+      _y / other,
+    );
+  }
+
+  @override
+  _MixedAlignment operator ~/(double other) {
+    return new _MixedAlignment(
+      (_x ~/ other).toDouble(),
+      (_start ~/ other).toDouble(),
+      (_y ~/ other).toDouble(),
+    );
+  }
+
+  @override
+  _MixedAlignment operator %(double other) {
+    return new _MixedAlignment(
+      _x % other,
+      _start % other,
+      _y % other,
+    );
+  }
+
+  @override
+  Alignment resolve(TextDirection direction) {
+    assert(direction != null);
+    switch (direction) {
+      case TextDirection.rtl:
+        return new Alignment(_x - _start, _y);
+      case TextDirection.ltr:
+        return new Alignment(_x + _start, _y);
+    }
+    return null;
+  }
+}
diff --git a/packages/flutter/lib/src/painting/box_fit.dart b/packages/flutter/lib/src/painting/box_fit.dart
index d2bb9ba..6550e06 100644
--- a/packages/flutter/lib/src/painting/box_fit.dart
+++ b/packages/flutter/lib/src/painting/box_fit.dart
@@ -98,9 +98,9 @@
 /// This method does not express an opinion regarding the alignment of the
 /// source and destination sizes within the input and output rectangles.
 /// Typically they are centered (this is what [BoxDecoration] does, for
-/// instance, and is how [BoxFit] is defined). The [FractionalOffset] class
-/// provides a convenience function, [FractionalOffset.inscribe], for resolving
-/// the sizes to rects, as shown in the example below.
+/// instance, and is how [BoxFit] is defined). The [Alignment] class provides a
+/// convenience function, [Alignment.inscribe], for resolving the sizes to
+/// rects, as shown in the example below.
 ///
 /// ## Sample code
 ///
@@ -112,8 +112,8 @@
 /// void paintImage(ui.Image image, Rect outputRect, Canvas canvas, Paint paint, BoxFit fit) {
 ///   final Size imageSize = new Size(image.width.toDouble(), image.height.toDouble());
 ///   final FittedSizes sizes = applyBoxFit(fit, imageSize, outputRect.size);
-///   final Rect inputSubrect = FractionalOffset.center.inscribe(sizes.source, Offset.zero & imageSize);
-///   final Rect outputSubrect = FractionalOffset.center.inscribe(sizes.destination, outputRect);
+///   final Rect inputSubrect = Alignment.center.inscribe(sizes.source, Offset.zero & imageSize);
+///   final Rect outputSubrect = Alignment.center.inscribe(sizes.destination, outputRect);
 ///   canvas.drawImageRect(image, inputSubrect, outputSubrect, paint);
 /// }
 /// ```
diff --git a/packages/flutter/lib/src/painting/flutter_logo.dart b/packages/flutter/lib/src/painting/flutter_logo.dart
index da88bc2..f63d13c 100644
--- a/packages/flutter/lib/src/painting/flutter_logo.dart
+++ b/packages/flutter/lib/src/painting/flutter_logo.dart
@@ -9,11 +9,11 @@
 import 'package:flutter/services.dart';
 import 'package:flutter/foundation.dart';
 
+import 'alignment.dart';
 import 'basic_types.dart';
 import 'box_fit.dart';
 import 'decoration.dart';
 import 'edge_insets.dart';
-import 'fractional_offset.dart';
 import 'text_painter.dart';
 import 'text_span.dart';
 import 'text_style.dart';
@@ -397,7 +397,7 @@
     }
     final FittedSizes fittedSize = applyBoxFit(BoxFit.contain, logoSize, canvasSize);
     assert(fittedSize.source == logoSize);
-    final Rect rect = FractionalOffset.center.inscribe(fittedSize.destination, offset & canvasSize);
+    final Rect rect = Alignment.center.inscribe(fittedSize.destination, offset & canvasSize);
     final double centerSquareHeight = canvasSize.shortestSide;
     final Rect centerSquare = new Rect.fromLTWH(
       offset.dx + (canvasSize.width - centerSquareHeight) / 2.0,
diff --git a/packages/flutter/lib/src/painting/fractional_offset.dart b/packages/flutter/lib/src/painting/fractional_offset.dart
index fa33335..516ac8e 100644
--- a/packages/flutter/lib/src/painting/fractional_offset.dart
+++ b/packages/flutter/lib/src/painting/fractional_offset.dart
@@ -6,171 +6,9 @@
 
 import 'package:flutter/foundation.dart';
 
+import 'alignment.dart';
 import 'basic_types.dart';
 
-/// Base class for [FractionalOffset] that allows for text-direction aware
-/// resolution.
-///
-/// A property or argument of this type accepts classes created either with [new
-/// FractionalOffset] and its variants, or [new FractionalOffsetDirectional].
-///
-/// To convert a [FractionalOffsetGeometry] object of indeterminate type into a
-/// [FractionalOffset] object, call the [resolve] method.
-abstract class FractionalOffsetGeometry {
-  /// Abstract const constructor. This constructor enables subclasses to provide
-  /// const constructors so that they can be used in const expressions.
-  const FractionalOffsetGeometry();
-
-  /// The [FractionalOffset.dx] to which this object will [resolve] in [TextDirection.ltr].
-  double get _dxForRTL;
-
-  /// The [FractionalOffset.dx] to which this object will [resolve] in [TextDirection.ltr].
-  double get _dxForLTR;
-
-  double get _dy;
-
-  /// Returns the difference between two [FractionalOffsetGeometry] objects.
-  ///
-  /// If you know you are applying this to two [FractionalOffset]s or two
-  /// [FractionalOffsetDirectional] objects, consider using the binary infix `-`
-  /// operator instead, which always returns an object of the same type as the
-  /// operands, and is typed accordingly.
-  ///
-  /// If [subtract] is applied to two objects of the same type ([FractionalOffset] or
-  /// [FractionalOffsetDirectional]), an object of that type will be returned (though
-  /// this is not reflected in the type system). Otherwise, an object
-  /// representing a combination of both is returned. That object can be turned
-  /// into a concrete [FractionalOffset] using [resolve].
-  ///
-  /// This method returns the same result as [add] applied to the result of
-  /// negating the argument (using the prefix unary `-` operator or multiplying
-  /// the argument by -1.0 using the `*` operator).
-  FractionalOffsetGeometry subtract(FractionalOffsetGeometry other) {
-    return new _SchrodingersFractionalOffset(
-      _dxForRTL - other._dxForRTL,
-      _dxForLTR - other._dxForLTR,
-      _dy - other._dy,
-    );
-  }
-
-  /// Returns the sum of two [FractionalOffsetGeometry] objects.
-  ///
-  /// If you know you are adding two [FractionalOffset] or two [FractionalOffsetDirectional]
-  /// objects, consider using the `+` operator instead, which always returns an
-  /// object of the same type as the operands, and is typed accordingly.
-  ///
-  /// If [add] is applied to two objects of the same type ([FractionalOffset] or
-  /// [FractionalOffsetDirectional]), an object of that type will be returned (though
-  /// this is not reflected in the type system). Otherwise, an object
-  /// representing a combination of both is returned. That object can be turned
-  /// into a concrete [FractionalOffset] using [resolve].
-  FractionalOffsetGeometry add(FractionalOffsetGeometry other) {
-    return new _SchrodingersFractionalOffset(
-      _dxForRTL + other._dxForRTL,
-      _dxForLTR + other._dxForLTR,
-      _dy + other._dy,
-    );
-  }
-
-  /// Returns the negation of the given [FractionalOffsetGeometry] object.
-  ///
-  /// This is the same as multiplying the object by -1.0.
-  ///
-  /// This operator returns an object of the same type as the operand.
-  FractionalOffsetGeometry operator -();
-
-  /// Scales the [FractionalOffsetGeometry] object in each dimension by the given factor.
-  ///
-  /// This operator returns an object of the same type as the operand.
-  FractionalOffsetGeometry operator *(double other);
-
-  /// Divides the [FractionalOffsetGeometry] object in each dimension by the given factor.
-  ///
-  /// This operator returns an object of the same type as the operand.
-  FractionalOffsetGeometry operator /(double other);
-
-  /// Integer divides the [FractionalOffsetGeometry] object in each dimension by the given factor.
-  ///
-  /// This operator returns an object of the same type as the operand.
-  FractionalOffsetGeometry operator ~/(double other);
-
-  /// Computes the remainder in each dimension by the given factor.
-  ///
-  /// This operator returns an object of the same type as the operand.
-  FractionalOffsetGeometry operator %(double other);
-
-  /// Linearly interpolate between two [FractionalOffsetGeometry] objects.
-  ///
-  /// If either is null, this function interpolates from [FractionalOffset.center], and
-  /// the result is an object of the same type as the non-null argument.
-  ///
-  /// If [lerp] is applied to two objects of the same type ([FractionalOffset] or
-  /// [FractionalOffsetDirectional]), an object of that type will be returned (though
-  /// this is not reflected in the type system). Otherwise, an object
-  /// representing a combination of both is returned. That object can be turned
-  /// into a concrete [FractionalOffset] using [resolve].
-  static FractionalOffsetGeometry lerp(FractionalOffsetGeometry a, FractionalOffsetGeometry b, double t) {
-    if (a == null && b == null)
-      return null;
-    if ((a == null || a is FractionalOffset) && (b == null || b is FractionalOffset))
-      return FractionalOffset.lerp(a, b, t);
-    if ((a == null || a is FractionalOffsetDirectional) && (b == null || b is FractionalOffsetDirectional))
-      return FractionalOffsetDirectional.lerp(a, b, t);
-    if (a == null) {
-      return new _SchrodingersFractionalOffset(
-        ui.lerpDouble(0.5, b._dxForRTL, t),
-        ui.lerpDouble(0.5, b._dxForLTR, t),
-        ui.lerpDouble(0.5, b._dy, t),
-      );
-    }
-    if (b == null) {
-      return new _SchrodingersFractionalOffset(
-        ui.lerpDouble(a._dxForRTL, 0.5, t),
-        ui.lerpDouble(a._dxForLTR, 0.5, t),
-        ui.lerpDouble(a._dy, 0.5, t),
-      );
-    }
-    return new _SchrodingersFractionalOffset(
-      ui.lerpDouble(a._dxForRTL, b._dxForRTL, t),
-      ui.lerpDouble(a._dxForLTR, b._dxForLTR, t),
-      ui.lerpDouble(a._dy, b._dy, t),
-    );
-  }
-
-  /// Convert this instance into a [FractionalOffset], which uses literal
-  /// coordinates (the `x` coordinate being explicitly a distance from the
-  /// left).
-  ///
-  /// See also:
-  ///
-  ///  * [FractionalOffset], for which this is a no-op (returns itself).
-  ///  * [FractionalOffsetDirectional], which flips the horizontal direction
-  ///    based on the `direction` argument.
-  FractionalOffset resolve(TextDirection direction) {
-    assert(direction != null);
-    switch (direction) {
-      case TextDirection.rtl:
-        return new FractionalOffset(_dxForRTL, _dy);
-      case TextDirection.ltr:
-        return new FractionalOffset(_dxForLTR, _dy);
-    }
-    return null;
-  }
-
-  @override
-  bool operator ==(dynamic other) {
-    if (other is! FractionalOffsetGeometry)
-      return false;
-    final FractionalOffsetGeometry typedOther = other;
-    return _dxForRTL == typedOther._dxForRTL &&
-           _dxForLTR == typedOther._dxForLTR &&
-           _dy == typedOther._dy;
-  }
-
-  @override
-  int get hashCode => hashValues(_dxForRTL, _dxForLTR, _dy);
-}
-
 /// An offset that's expressed as a fraction of a [Size].
 ///
 /// `FractionalOffset(1.0, 0.0)` represents the top right of the [Size].
@@ -181,41 +19,34 @@
 /// below the bottom of the rectangle by the height of the [Size].
 ///
 /// The [FractionalOffset] class specifies offsets in terms of a distance from
-/// the top left, regardless of the [TextDirection]. To support both
-/// left-to-right and right-to-left layouts, consider using
-/// [FractionalOffsetDirectional], which is expressed in terms of an offset from
-/// the leading edge, which is then resolved in terms of a [TextDirection]
-/// (typically obtained from the ambient [Directionality]).
-///
-/// A variety of widgets use [FractionalOffset] in their configuration, most
-/// notably:
-///
-///  * [Align] positions a child according to a [FractionalOffset].
-///  * [FractionalTranslation] moves a child according to a [FractionalOffset].
+/// the top left, regardless of the [TextDirection].
 ///
 /// See also:
 ///
-///  * [FractionalOffsetDirectional], which (for properties and arguments that
-///    accept the type [FractionalOffsetGeometry]) allows the horizontal
-///    coordinate to be specified in a [TextDirection]-aware manner.
+///  * [Alignment], which uses a coordinate system based on the center of the
+///    rectangle instead of the top left corner of the rectangle.
 @immutable
-class FractionalOffset extends FractionalOffsetGeometry {
+class FractionalOffset extends Alignment {
   /// Creates a fractional offset.
   ///
   /// The [dx] and [dy] arguments must not be null.
-  const FractionalOffset(this.dx, this.dy)
+  const FractionalOffset(double dx, double dy)
     : assert(dx != null),
-      assert(dy != null);
+      assert(dy != null),
+      super(dx * 2.0 - 1.0, dy * 2.0 - 1.0);
 
   /// Creates a fractional offset from a specific offset and size.
   ///
   /// The returned [FractionalOffset] describes the position of the
   /// [Offset] in the [Size], as a fraction of the [Size].
-  FractionalOffset.fromOffsetAndSize(Offset offset, Size size) :
-    assert(size != null),
-    assert(offset != null),
-    dx = offset.dx / size.width,
-    dy = offset.dy / size.height;
+  factory FractionalOffset.fromOffsetAndSize(Offset offset, Size size) {
+    assert(size != null);
+    assert(offset != null);
+    return new FractionalOffset(
+      offset.dx / size.width,
+      offset.dy / size.height,
+    );
+  }
 
   /// Creates a fractional offset from a specific offset and rectangle.
   ///
@@ -240,13 +71,7 @@
   /// negative values represent positions to the left of the left edge, and
   /// values greater than 1.0 represent positions to the right of the right
   /// edge.
-  final double dx;
-
-  @override
-  double get _dxForRTL => dx;
-
-  @override
-  double get _dxForLTR => dx;
+  double get dx => (x + 1.0) / 2.0;
 
   /// The distance fraction in the vertical direction.
   ///
@@ -254,10 +79,7 @@
   /// to the bottommost edge. Values are not limited to that range; negative
   /// values represent positions above the top, and values greater than 1.0
   /// represent positions below the bottom.
-  final double dy;
-
-  @override
-  double get _dy => dy;
+  double get dy => (y + 1.0) / 2.0;
 
   /// The top left corner.
   static const FractionalOffset topLeft = const FractionalOffset(0.0, 0.0);
@@ -286,89 +108,6 @@
   /// The bottom right corner.
   static const FractionalOffset bottomRight = const FractionalOffset(1.0, 1.0);
 
-  @override
-  FractionalOffsetGeometry subtract(FractionalOffsetGeometry other) {
-    if (other is FractionalOffset)
-      return this - other;
-    return super.subtract(other);
-  }
-
-  @override
-  FractionalOffsetGeometry add(FractionalOffsetGeometry other) {
-    if (other is FractionalOffset)
-      return this + other;
-    return super.add(other);
-  }
-
-  /// Returns the difference between two [FractionalOffset]s.
-  FractionalOffset operator -(FractionalOffset other) {
-    return new FractionalOffset(dx - other.dx, dy - other.dy);
-  }
-
-  /// Returns the sum of two [FractionalOffset]s.
-  FractionalOffset operator +(FractionalOffset other) {
-    return new FractionalOffset(dx + other.dx, dy + other.dy);
-  }
-
-  /// Returns the negation of the given [FractionalOffset].
-  @override
-  FractionalOffset operator -() {
-    return new FractionalOffset(-dx, -dy);
-  }
-
-  /// Scales the [FractionalOffset] in each dimension by the given factor.
-  @override
-  FractionalOffset operator *(double other) {
-    return new FractionalOffset(dx * other, dy * other);
-  }
-
-  /// Divides the [FractionalOffset] in each dimension by the given factor.
-  @override
-  FractionalOffset operator /(double other) {
-    return new FractionalOffset(dx / other, dy / other);
-  }
-
-  /// Integer divides the [FractionalOffset] in each dimension by the given factor.
-  @override
-  FractionalOffset operator ~/(double other) {
-    return new FractionalOffset((dx ~/ other).toDouble(), (dy ~/ other).toDouble());
-  }
-
-  /// Computes the remainder in each dimension by the given factor.
-  @override
-  FractionalOffset operator %(double other) {
-    return new FractionalOffset(dx % other, dy % other);
-  }
-
-  /// Returns the offset that is this fraction in the direction of the given offset.
-  Offset alongOffset(Offset other) {
-    return new Offset(dx * other.dx, dy * other.dy);
-  }
-
-  /// Returns the offset that is this fraction within the given size.
-  Offset alongSize(Size other) {
-    return new Offset(dx * other.width, dy * other.height);
-  }
-
-  /// Returns the point that is this fraction within the given rect.
-  Offset withinRect(Rect rect) {
-    return new Offset(rect.left + dx * rect.width, rect.top + dy * rect.height);
-  }
-
-  /// Returns a rect of the given size, centered at this fraction of the given rect.
-  ///
-  /// For example, a 100×100 size inscribed on a 200×200 rect using
-  /// [FractionalOffset.topLeft] would be the 100×100 rect at the top left of
-  /// the 200×200 rect.
-  Rect inscribe(Size size, Rect rect) {
-    return new Rect.fromLTWH(
-      rect.left + (rect.width - size.width) * dx,
-      rect.top + (rect.height - size.height) * dy,
-      size.width,
-      size.height,
-    );
-  }
-
   /// Linearly interpolate between two [FractionalOffset]s.
   ///
   /// If either is null, this function interpolates from [FractionalOffset.center].
@@ -381,276 +120,4 @@
       return new FractionalOffset(ui.lerpDouble(a.dx, 0.5, t), ui.lerpDouble(a.dy, 0.5, t));
     return new FractionalOffset(ui.lerpDouble(a.dx, b.dx, t), ui.lerpDouble(a.dy, b.dy, t));
   }
-
-  @override
-  FractionalOffset resolve(TextDirection direction) => this;
-
-  static String _stringify(double dx, double dy) {
-    if (dx == 0.0 && dy == 0.0)
-      return 'FractionalOffset.topLeft';
-    if (dx == 0.5 && dy == 0.0)
-      return 'FractionalOffset.topCenter';
-    if (dx == 1.0 && dy == 0.0)
-      return 'FractionalOffset.topRight';
-    if (dx == 0.0 && dy == 0.5)
-      return 'FractionalOffset.centerLeft';
-    if (dx == 0.5 && dy == 0.5)
-      return 'FractionalOffset.center';
-    if (dx == 1.0 && dy == 0.5)
-      return 'FractionalOffset.centerRight';
-    if (dx == 0.0 && dy == 1.0)
-      return 'FractionalOffset.bottomLeft';
-    if (dx == 0.5 && dy == 1.0)
-      return 'FractionalOffset.bottomCenter';
-    if (dx == 1.0 && dy == 1.0)
-      return 'FractionalOffset.bottomRight';
-    return 'FractionalOffset(${dx.toStringAsFixed(1)}, '
-                            '${dy.toStringAsFixed(1)})';
-  }
-
-  @override
-  String toString() => _stringify(dx, dy);
-}
-
-/// An offset that's expressed as a fraction of a [Size], but whose horizontal
-/// component is dependent on the writing direction.
-///
-/// This can be used to indicate an offset from the left in [TextDirection.ltr]
-/// text and an offset from the right in [TextDirection.rtl] text without having
-/// to be aware of the current text direction.
-///
-/// See also:
-///
-///  * [FractionalOffset], a variant that is defined in physical terms (i.e.
-///    whose horizontal component does not depend on the text direction).
-class FractionalOffsetDirectional extends FractionalOffsetGeometry {
-  /// Creates a directional fractional offset.
-  ///
-  /// The [start] and [dy] arguments must not be null.
-  const FractionalOffsetDirectional(this.start, this.dy)
-    : assert(start != null),
-      assert(dy != null);
-
-  /// The distance fraction in the horizontal direction.
-  ///
-  /// A value of 0.0 corresponds to the edge on the "start" side, which is the
-  /// left side in [TextDirection.ltr] contexts and the right side in
-  /// [TextDirection.rtl] contexts. A value of 1.0 corresponds to the opposite
-  /// edge, the "end" side. Values are not limited to that range; negative
-  /// values represent positions beyond the start edge, and values greater than
-  /// 1.0 represent positions beyond the end edge.
-  ///
-  /// This value is normalized into a [FractionalOffset.dx] value by the
-  /// [resolve] method.
-  final double start;
-
-  @override
-  double get _dxForRTL => 1.0 - start;
-
-  @override
-  double get _dxForLTR => start;
-
-  /// The distance fraction in the vertical direction.
-  ///
-  /// A value of 0.0 corresponds to the topmost edge. A value of 1.0 corresponds
-  /// to the bottommost edge. Values are not limited to that range; negative
-  /// values represent positions above the top, and values greater than 1.0
-  /// represent positions below the bottom.
-  ///
-  /// This value is passed through to [FractionalOffset.dy] unmodified by the
-  /// [resolve] method.
-  final double dy;
-
-  @override
-  double get _dy => dy;
-
-  /// The top corner on the "start" side.
-  static const FractionalOffsetDirectional topStart = const FractionalOffsetDirectional(0.0, 0.0);
-
-  /// The center point along the top edge.
-  ///
-  /// Consider using [FractionalOffset.topCenter] instead, as it does not need
-  /// to be [resolve]d to be used.
-  static const FractionalOffsetDirectional topCenter = const FractionalOffsetDirectional(0.5, 0.0);
-
-  /// The top corner on the "end" side.
-  static const FractionalOffsetDirectional topEnd = const FractionalOffsetDirectional(1.0, 0.0);
-
-  /// The center point along the "start" edge.
-  static const FractionalOffsetDirectional centerStart = const FractionalOffsetDirectional(0.0, 0.5);
-
-  /// The center point, both horizontally and vertically.
-  ///
-  /// Consider using [FractionalOffset.center] instead, as it does not need to
-  /// be [resolve]d to be used.
-  static const FractionalOffsetDirectional center = const FractionalOffsetDirectional(0.5, 0.5);
-
-  /// The center point along the "end" edge.
-  static const FractionalOffsetDirectional centerEnd = const FractionalOffsetDirectional(1.0, 0.5);
-
-  /// The bottom corner on the "start" side.
-  static const FractionalOffsetDirectional bottomStart = const FractionalOffsetDirectional(0.0, 1.0);
-
-  /// The center point along the bottom edge.
-  ///
-  /// Consider using [FractionalOffset.bottomCenter] instead, as it does not
-  /// need to be [resolve]d to be used.
-  static const FractionalOffsetDirectional bottomCenter = const FractionalOffsetDirectional(0.5, 1.0);
-
-  /// The bottom corner on the "end" side.
-  static const FractionalOffsetDirectional bottomEnd = const FractionalOffsetDirectional(1.0, 1.0);
-
-  @override
-  FractionalOffsetGeometry subtract(FractionalOffsetGeometry other) {
-    if (other is FractionalOffsetDirectional)
-      return this - other;
-    return super.subtract(other);
-  }
-
-  @override
-  FractionalOffsetGeometry add(FractionalOffsetGeometry other) {
-    if (other is FractionalOffsetDirectional)
-      return this + other;
-    return super.add(other);
-  }
-
-  /// Returns the difference between two [FractionalOffsetDirectional]s.
-  FractionalOffsetDirectional operator -(FractionalOffsetDirectional other) {
-    return new FractionalOffsetDirectional(start - other.start, dy - other.dy);
-  }
-
-  /// Returns the sum of two [FractionalOffsetDirectional]s.
-  FractionalOffsetDirectional operator +(FractionalOffsetDirectional other) {
-    return new FractionalOffsetDirectional(start + other.start, dy + other.dy);
-  }
-
-  /// Returns the negation of the given [FractionalOffsetDirectional].
-  @override
-  FractionalOffsetDirectional operator -() {
-    return new FractionalOffsetDirectional(-start, -dy);
-  }
-
-  /// Scales the [FractionalOffsetDirectional] in each dimension by the given factor.
-  @override
-  FractionalOffsetDirectional operator *(double other) {
-    return new FractionalOffsetDirectional(start * other, dy * other);
-  }
-
-  /// Divides the [FractionalOffsetDirectional] in each dimension by the given factor.
-  @override
-  FractionalOffsetDirectional operator /(double other) {
-    return new FractionalOffsetDirectional(start / other, dy / other);
-  }
-
-  /// Integer divides the [FractionalOffsetDirectional] in each dimension by the given factor.
-  @override
-  FractionalOffsetDirectional operator ~/(double other) {
-    return new FractionalOffsetDirectional((start ~/ other).toDouble(), (dy ~/ other).toDouble());
-  }
-
-  /// Computes the remainder in each dimension by the given factor.
-  @override
-  FractionalOffsetDirectional operator %(double other) {
-    return new FractionalOffsetDirectional(start % other, dy % other);
-  }
-
-  /// Linearly interpolate between two [FractionalOffsetDirectional]s.
-  ///
-  /// If either is null, this function interpolates from [FractionalOffset.center].
-  static FractionalOffsetDirectional lerp(FractionalOffsetDirectional a, FractionalOffsetDirectional b, double t) {
-    if (a == null && b == null)
-      return null;
-    if (a == null)
-      return new FractionalOffsetDirectional(ui.lerpDouble(0.5, b.start, t), ui.lerpDouble(0.5, b.dy, t));
-    if (b == null)
-      return new FractionalOffsetDirectional(ui.lerpDouble(a.start, 0.5, t), ui.lerpDouble(a.dy, 0.5, t));
-    return new FractionalOffsetDirectional(ui.lerpDouble(a.start, b.start, t), ui.lerpDouble(a.dy, b.dy, t));
-  }
-
-  @override
-  String toString() {
-    assert(start != 0.5);
-    if (start == 0.0 && dy == 0.0)
-      return 'FractionalOffsetDirectional.topStart';
-    if (start == 1.0 && dy == 0.0)
-      return 'FractionalOffsetDirectional.topEnd';
-    if (start == 0.0 && dy == 0.5)
-      return 'FractionalOffsetDirectional.centerStart';
-    if (start == 1.0 && dy == 0.5)
-      return 'FractionalOffsetDirectional.centerEnd';
-    if (start == 0.0 && dy == 1.0)
-      return 'FractionalOffsetDirectional.bottomStart';
-    if (start == 1.0 && dy == 1.0)
-      return 'FractionalOffsetDirectional.bottomEnd';
-    return 'FractionalOffsetDirectional(${start.toStringAsFixed(1)}, '
-                                       '${dy.toStringAsFixed(1)})';
-  }
-}
-
-class _SchrodingersFractionalOffset extends FractionalOffsetGeometry {
-  const _SchrodingersFractionalOffset(this._dxForRTL, this._dxForLTR, this._dy);
-
-  @override
-  final double _dxForRTL;
-
-  @override
-  final double _dxForLTR;
-
-  @override
-  final double _dy;
-
-  @override
-  _SchrodingersFractionalOffset operator -() {
-    return new _SchrodingersFractionalOffset(
-      -_dxForRTL,
-      -_dxForLTR,
-      -_dy,
-    );
-  }
-
-  @override
-  _SchrodingersFractionalOffset operator *(double other) {
-    return new _SchrodingersFractionalOffset(
-      _dxForRTL * other,
-      _dxForLTR * other,
-      _dy * other,
-    );
-  }
-
-  @override
-  _SchrodingersFractionalOffset operator /(double other) {
-    return new _SchrodingersFractionalOffset(
-      _dxForRTL / other,
-      _dxForLTR / other,
-      _dy / other,
-    );
-  }
-
-  @override
-  _SchrodingersFractionalOffset operator ~/(double other) {
-    return new _SchrodingersFractionalOffset(
-      (_dxForRTL ~/ other).toDouble(),
-      (_dxForLTR ~/ other).toDouble(),
-      (_dy ~/ other).toDouble(),
-    );
-  }
-
-  @override
-  _SchrodingersFractionalOffset operator %(double other) {
-    return new _SchrodingersFractionalOffset(
-      _dxForRTL % other,
-      _dxForLTR % other,
-      _dy % other,
-    );
-  }
-
-  @override
-  String toString() {
-    if (_dxForRTL == _dxForLTR)
-      return FractionalOffset._stringify(_dxForRTL, _dy);
-
-    return '${FractionalOffset._stringify(_dxForRTL, _dy)} in RTL'
-           ' or '
-           '${FractionalOffset._stringify(_dxForLTR, _dy)} in LTR';
-  }
 }
diff --git a/packages/flutter/lib/src/painting/gradient.dart b/packages/flutter/lib/src/painting/gradient.dart
index b84f058..510677c 100644
--- a/packages/flutter/lib/src/painting/gradient.dart
+++ b/packages/flutter/lib/src/painting/gradient.dart
@@ -6,8 +6,8 @@
 
 import 'package:flutter/foundation.dart';
 
+import 'alignment.dart';
 import 'basic_types.dart';
-import 'fractional_offset.dart';
 
 /// A 2D gradient.
 ///
@@ -27,7 +27,7 @@
   /// Creates a [Shader] for this gradient to fill the given rect.
   ///
   /// If the gradient's configuration is text-direction-dependent, for example
-  /// it uses [FractionalOffsetDirectional] objects instead of [FractionalOffset]
+  /// it uses [AlignmentDirectional] objects instead of [Alignment]
   /// objects, then the `textDirection` argument must not be null.
   Shader createShader(Rect rect, { TextDirection textDirection });
 }
@@ -64,8 +64,8 @@
 /// new Container(
 ///   decoration: new BoxDecoration(
 ///     gradient: new LinearGradient(
-///       begin: FractionalOffset.topLeft,
-///       end: new FractionalOffset(0.1, 0.0), // 10% of the width, so there are ten blinds.
+///       begin: Alignment.topLeft,
+///       end: new Alignment(0.8, 0.0), // 10% of the width, so there are ten blinds.
 ///       colors: [const Color(0xFFFFFFEE), const Color(0xFF999999)], // whitish to gray
 ///       tileMode: TileMode.repeated, // repeats the gradient over the canvas
 ///     ),
@@ -85,8 +85,8 @@
   /// The [colors] argument must not be null. If [stops] is non-null, it must
   /// have the same length as [colors].
   const LinearGradient({
-    this.begin: FractionalOffset.centerLeft,
-    this.end: FractionalOffset.centerRight,
+    this.begin: Alignment.centerLeft,
+    this.end: Alignment.centerRight,
     @required this.colors,
     this.stops,
     this.tileMode: TileMode.clamp,
@@ -97,35 +97,33 @@
 
   /// The offset at which stop 0.0 of the gradient is placed.
   ///
-  /// If this is a [FractionalOffset], then it is expressed as a vector from
-  /// coordinate (0.0,0.0), in a coordinate space that maps the top left of the
-  /// paint box at (0.0,0.0) and the bottom right at (1.0,1.0).
+  /// If this is a [Alignment], then it is expressed as a vector from
+  /// coordinate (0.0, 0.0), in a coordinate space that maps the center of the
+  /// paint box at (0.0, 0.0) and the bottom right at (1.0, 1.0).
   ///
-  /// For example, a begin offset of (0.0,0.5) is half way down the
+  /// For example, a begin offset of (-1.0, 0.0) is half way down the
   /// left side of the box.
   ///
-  /// It can also be a [FractionalOffsetDirectional], in which case it is
-  /// expressed as a vector from the top start corner, where the start is the
+  /// It can also be a [AlignmentDirectional], where the start is the
   /// left in left-to-right contexts and the right in right-to-left contexts. If
   /// a text-direction-dependent value is provided here, then the [createShader]
   /// method will need to be given a [TextDirection].
-  final FractionalOffsetGeometry begin;
+  final AlignmentGeometry begin;
 
   /// The offset at which stop 1.0 of the gradient is placed.
   ///
-  /// If this is a [FractionalOffset], then it is expressed as a vector from
-  /// coordinate (0.0,0.0), in a coordinate space that maps the top left of the
-  /// paint box at (0.0,0.0) and the bottom right at (1.0,1.0).
+  /// If this is a [Alignment], then it is expressed as a vector from
+  /// coordinate (0.0, 0.0), in a coordinate space that maps the center of the
+  /// paint box at (0.0, 0.0) and the bottom right at (1.0, 1.0).
   ///
-  /// For example, a begin offset of (1.0,0.5) is half way down the
+  /// For example, a begin offset of (1.0, 0.0) is half way down the
   /// right side of the box.
   ///
-  /// It can also be a [FractionalOffsetDirectional], in which case it is
-  /// expressed as a vector from the top start corner, where the start is the
-  /// left in left-to-right contexts and the right in right-to-left contexts. If
-  /// a text-direction-dependent value is provided here, then the [createShader]
+  /// It can also be a [AlignmentDirectional], where the start is the left in
+  /// left-to-right contexts and the right in right-to-left contexts. If a
+  /// text-direction-dependent value is provided here, then the [createShader]
   /// method will need to be given a [TextDirection].
-  final FractionalOffsetGeometry end;
+  final AlignmentGeometry end;
 
   /// The colors the gradient should obtain at each of the stops.
   ///
@@ -215,8 +213,8 @@
       interpolatedStops = a.stops ?? b.stops;
     }
     return new LinearGradient(
-      begin: FractionalOffsetGeometry.lerp(a.begin, b.begin, t),
-      end: FractionalOffsetGeometry.lerp(a.end, b.end, t),
+      begin: AlignmentGeometry.lerp(a.begin, b.begin, t),
+      end: AlignmentGeometry.lerp(a.end, b.end, t),
       colors: interpolatedColors,
       stops: interpolatedStops,
       tileMode: t < 0.5 ? a.tileMode : b.tileMode,
@@ -295,7 +293,7 @@
 /// ```dart
 /// void paintSky(Canvas canvas, Rect rect) {
 ///   var gradient = new RadialGradient(
-///     center: const FractionalOffset(0.7, 0.2), // near the top right
+///     center: const Alignment(0.7, -0.6), // near the top right
 ///     radius: 0.2,
 ///     colors: [
 ///       const Color(0xFFFFFF00), // yellow sun
@@ -324,7 +322,7 @@
   /// The [colors] argument must not be null. If [stops] is non-null, it must
   /// have the same length as [colors].
   const RadialGradient({
-    this.center: FractionalOffset.center,
+    this.center: Alignment.center,
     this.radius: 0.5,
     @required this.colors,
     this.stops,
@@ -334,22 +332,21 @@
        assert(colors != null),
        assert(tileMode != null);
 
-  /// The center of the gradient, as an offset into the unit square
-  /// describing the gradient which will be mapped onto the paint box.
+  /// The center of the gradient, as an offset into the (-1.0, -1.0) x (1.0, 1.0)
+  /// square describing the gradient which will be mapped onto the paint box.
   ///
-  /// For example, an offset of (0.5,0.5) will place the radial
+  /// For example, an alignment of (0.0, 0.0) will place the radial
   /// gradient in the center of the box.
   ///
-  /// If this is a [FractionalOffset], then it is expressed as a vector from
-  /// coordinate (0.0,0.0), in a coordinate space that maps the top left of the
-  /// paint box at (0.0,0.0) and the bottom right at (1.0,1.0).
+  /// If this is a [Alignment], then it is expressed as a vector from
+  /// coordinate (0.0, 0.0), in a coordinate space that maps the center of the
+  /// paint box at (0.0, 0.0) and the bottom right at (1.0, 1.0).
   ///
-  /// It can also be a [FractionalOffsetDirectional], in which case it is
-  /// expressed as a vector from the top start corner, where the start is the
-  /// left in left-to-right contexts and the right in right-to-left contexts. If
-  /// a text-direction-dependent value is provided here, then the [createShader]
+  /// It can also be a [AlignmentDirectional], where the start is the left in
+  /// left-to-right contexts and the right in right-to-left contexts. If a
+  /// text-direction-dependent value is provided here, then the [createShader]
   /// method will need to be given a [TextDirection].
-  final FractionalOffsetGeometry center;
+  final AlignmentGeometry center;
 
   /// The radius of the gradient, as a fraction of the shortest side
   /// of the paint box.
diff --git a/packages/flutter/lib/src/painting/images.dart b/packages/flutter/lib/src/painting/images.dart
index 446daeb..344d005 100644
--- a/packages/flutter/lib/src/painting/images.dart
+++ b/packages/flutter/lib/src/painting/images.dart
@@ -7,10 +7,10 @@
 import 'package:flutter/foundation.dart';
 import 'package:flutter/services.dart';
 
+import 'alignment.dart';
 import 'basic_types.dart';
 import 'borders.dart';
 import 'box_fit.dart';
-import 'fractional_offset.dart';
 
 /// How to paint any portions of a box not covered by an image.
 enum ImageRepeat {
@@ -41,7 +41,7 @@
     @required this.image,
     this.colorFilter,
     this.fit,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.centerSlice,
     this.repeat: ImageRepeat.noRepeat,
     this.matchTextDirection: false,
@@ -70,22 +70,22 @@
   /// How to align the image within its bounds.
   ///
   /// The alignment aligns the given position in the image to the given position
-  /// in the layout bounds. For example, a [FractionalOffset] alignment of (0.0,
-  /// 0.0) aligns the image to the top-left corner of its layout bounds, while a
-  /// [FractionalOffset] alignment of (1.0, 1.0) aligns the bottom right of the
+  /// in the layout bounds. For example, a [Alignment] alignment of (-1.0,
+  /// -1.0) aligns the image to the top-left corner of its layout bounds, while a
+  /// [Alignment] alignment of (1.0, 1.0) aligns the bottom right of the
   /// image with the bottom right corner of its layout bounds. Similarly, an
-  /// alignment of (0.5, 1.0) aligns the bottom middle of the image with the
+  /// alignment of (0.0, 1.0) aligns the bottom middle of the image with the
   /// middle of the bottom edge of its layout bounds.
   ///
   /// To display a subpart of an image, consider using a [CustomPainter] and
   /// [Canvas.drawImageRect].
   ///
   /// If the [alignment] is [TextDirection]-dependent (i.e. if it is a
-  /// [FractionalOffsetDirectional]), then a [TextDirection] must be available
+  /// [AlignmentDirectional]), then a [TextDirection] must be available
   /// when the image is painted.
   ///
-  /// Defaults to [FractionalOffset.center].
-  final FractionalOffsetGeometry alignment;
+  /// Defaults to [Alignment.center].
+  final AlignmentGeometry alignment;
 
   /// The center slice for a nine-patch image.
   ///
@@ -180,9 +180,9 @@
 ///
 ///  * `alignment`: How the destination rectangle defined by applying `fit` is
 ///    aligned within `rect`. For example, if `fit` is [BoxFit.contain] and
-///    `alignment` is [FractionalOffset.bottomRight], the image will be as large
+///    `alignment` is [Alignment.bottomRight], the image will be as large
 ///    as possible within `rect` and placed with its bottom right corner at the
-///    bottom right corner of `rect`. Defaults to [FractionalOffset.center].
+///    bottom right corner of `rect`. Defaults to [Alignment.center].
 ///
 ///  * `centerSlice`: The image is drawn in nine portions described by splitting
 ///    the image by drawing two horizontal lines and two vertical lines, where
@@ -219,7 +219,7 @@
   @required ui.Image image,
   ColorFilter colorFilter,
   BoxFit fit,
-  FractionalOffset alignment: FractionalOffset.center,
+  Alignment alignment: Alignment.center,
   Rect centerSlice,
   ImageRepeat repeat: ImageRepeat.noRepeat,
   bool flipHorizontally: false,
@@ -268,8 +268,10 @@
     // to nearest-neighbor.
     paint.filterQuality = FilterQuality.low;
   }
-  final double dx = (outputSize.width - destinationSize.width) * (flipHorizontally ? 1.0 - alignment.dx : alignment.dx);
-  final double dy = (outputSize.height - destinationSize.height) * alignment.dy;
+  final double halfWidthDelta = (outputSize.width - destinationSize.width) / 2.0;
+  final double halfHeightDelta = (outputSize.height - destinationSize.height) / 2.0;
+  final double dx = halfWidthDelta + (flipHorizontally ? -alignment.x : alignment.x) * halfWidthDelta;
+  final double dy = halfHeightDelta + alignment.y * halfHeightDelta;
   final Offset destinationPosition = rect.topLeft.translate(dx, dy);
   final Rect destinationRect = destinationPosition & destinationSize;
   final bool needSave = repeat != ImageRepeat.noRepeat || flipHorizontally;
diff --git a/packages/flutter/lib/src/rendering/animated_size.dart b/packages/flutter/lib/src/rendering/animated_size.dart
index 2443e15..dd39ac1 100644
--- a/packages/flutter/lib/src/rendering/animated_size.dart
+++ b/packages/flutter/lib/src/rendering/animated_size.dart
@@ -72,7 +72,7 @@
     @required TickerProvider vsync,
     @required Duration duration,
     Curve curve: Curves.linear,
-    FractionalOffsetGeometry alignment: FractionalOffset.center,
+    AlignmentGeometry alignment: Alignment.center,
     TextDirection textDirection,
     RenderBox child,
   }) : assert(vsync != null),
diff --git a/packages/flutter/lib/src/rendering/image.dart b/packages/flutter/lib/src/rendering/image.dart
index 8739f74..9da3939 100644
--- a/packages/flutter/lib/src/rendering/image.dart
+++ b/packages/flutter/lib/src/rendering/image.dart
@@ -32,7 +32,7 @@
     Color color,
     BlendMode colorBlendMode,
     BoxFit fit,
-    FractionalOffsetGeometry alignment: FractionalOffset.center,
+    AlignmentGeometry alignment: Alignment.center,
     ImageRepeat repeat: ImageRepeat.noRepeat,
     Rect centerSlice,
     bool matchTextDirection: false,
@@ -56,7 +56,7 @@
     _updateColorFilter();
   }
 
-  FractionalOffset _resolvedAlignment;
+  Alignment _resolvedAlignment;
   bool _flipHorizontally;
 
   void _resolve() {
@@ -178,9 +178,9 @@
   ///
   /// If this is set to a text-direction-dependent value, [textDirection] must
   /// not be null.
-  FractionalOffsetGeometry get alignment => _alignment;
-  FractionalOffsetGeometry _alignment;
-  set alignment(FractionalOffsetGeometry value) {
+  AlignmentGeometry get alignment => _alignment;
+  AlignmentGeometry _alignment;
+  set alignment(AlignmentGeometry value) {
     assert(value != null);
     if (value == _alignment)
       return;
@@ -343,7 +343,7 @@
     description.add(new DiagnosticsProperty<Color>('color', color, defaultValue: null));
     description.add(new EnumProperty<BlendMode>('colorBlendMode', colorBlendMode, defaultValue: null));
     description.add(new EnumProperty<BoxFit>('fit', fit, defaultValue: null));
-    description.add(new DiagnosticsProperty<FractionalOffset>('alignment', alignment, defaultValue: null));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null));
     description.add(new EnumProperty<ImageRepeat>('repeat', repeat, defaultValue: ImageRepeat.noRepeat));
     description.add(new DiagnosticsProperty<Rect>('centerSlice', centerSlice, defaultValue: null));
     description.add(new FlagProperty('matchTextDirection', value: matchTextDirection, ifTrue: 'match text direction'));
diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart
index 56b95a5..ce7dd95 100644
--- a/packages/flutter/lib/src/rendering/proxy_box.dart
+++ b/packages/flutter/lib/src/rendering/proxy_box.dart
@@ -1599,11 +1599,10 @@
   RenderTransform({
     @required Matrix4 transform,
     Offset origin,
-    FractionalOffset alignment,
+    Alignment alignment,
     this.transformHitTests: true,
     RenderBox child
   }) : assert(transform != null),
-       assert(alignment == null || (alignment.dx != null && alignment.dy != null)),
        super(child) {
     this.transform = transform;
     this.alignment = alignment;
@@ -1628,10 +1627,10 @@
   ///
   /// This is equivalent to setting an origin based on the size of the box.
   /// If it is specified at the same time as an offset, both are applied.
-  FractionalOffset get alignment => _alignment;
-  FractionalOffset _alignment;
-  set alignment(FractionalOffset value) {
-    assert(value == null || (value.dx != null && value.dy != null));
+  Alignment get alignment => _alignment;
+  Alignment _alignment;
+  set alignment(Alignment value) {
+    assert(value == null || (value.x != null && value.y != null));
     if (_alignment == value)
       return;
     _alignment = value;
@@ -1751,7 +1750,7 @@
     super.debugFillProperties(description);
     description.add(new TransformProperty('transform matrix', _transform));
     description.add(new DiagnosticsProperty<Offset>('origin', origin));
-    description.add(new DiagnosticsProperty<FractionalOffset>('alignment', alignment));
+    description.add(new DiagnosticsProperty<Alignment>('alignment', alignment));
     description.add(new DiagnosticsProperty<bool>('transformHitTests', transformHitTests));
   }
 }
@@ -1764,9 +1763,9 @@
   RenderFittedBox({
     RenderBox child,
     BoxFit fit: BoxFit.contain,
-    FractionalOffset alignment: FractionalOffset.center
+    Alignment alignment: Alignment.center
   }) : assert(fit != null),
-       assert(alignment != null && alignment.dx != null && alignment.dy != null),
+       assert(alignment != null),
        _fit = fit,
        _alignment = alignment,
        super(child);
@@ -1788,10 +1787,10 @@
   /// An alignment of (0.0, 0.0) aligns the child to the top-left corner of its
   /// parent's bounds.  An alignment of (1.0, 0.5) aligns the child to the middle
   /// of the right edge of its parent's bounds.
-  FractionalOffset get alignment => _alignment;
-  FractionalOffset _alignment;
-  set alignment(FractionalOffset value) {
-    assert(value != null && value.dx != null && value.dy != null);
+  Alignment get alignment => _alignment;
+  Alignment _alignment;
+  set alignment(Alignment value) {
+    assert(value != null && value.x != null && value.y != null);
     if (_alignment == value)
       return;
     _alignment = value;
@@ -1891,13 +1890,13 @@
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
     description.add(new EnumProperty<BoxFit>('fit', fit));
-    description.add(new DiagnosticsProperty<FractionalOffset>('alignment', alignment));
+    description.add(new DiagnosticsProperty<Alignment>('alignment', alignment));
   }
 }
 
 /// Applies a translation transformation before painting its child.
 ///
-/// The translation is expressed as a [FractionalOffset] relative to the
+/// The translation is expressed as a [Alignment] relative to the
 /// RenderFractionalTranslation box's size. Hit tests will only be detected
 /// inside the bounds of the RenderFractionalTranslation, even if the contents
 /// are offset such that they overflow.
@@ -1906,18 +1905,18 @@
   ///
   /// The [translation] argument must not be null.
   RenderFractionalTranslation({
-    FractionalOffset translation,
+    Alignment translation,
     this.transformHitTests: true,
     RenderBox child
-  }) : assert(translation == null || (translation.dx != null && translation.dy != null)),
+  }) : assert(translation == null || (translation.x != null && translation.y != null)),
        _translation = translation,
        super(child);
 
-  /// The translation to apply to the child, as a multiple of the size.
-  FractionalOffset get translation => _translation;
-  FractionalOffset _translation;
-  set translation(FractionalOffset value) {
-    assert(value == null || (value.dx != null && value.dy != null));
+  /// The translation to apply to the child, relative to the child's center.
+  Alignment get translation => _translation;
+  Alignment _translation;
+  set translation(Alignment value) {
+    assert(value == null || (value.x != null && value.y != null));
     if (_translation == value)
       return;
     _translation = value;
@@ -1935,27 +1934,41 @@
   @override
   bool hitTest(HitTestResult result, { Offset position }) {
     assert(!debugNeedsLayout);
-    if (transformHitTests)
-      position = new Offset(position.dx - translation.dx * size.width, position.dy - translation.dy * size.height);
+    if (transformHitTests) {
+      final double halfWidth = size.width / 2.0;
+      final double halfHeight = size.height / 2.0;
+      position = new Offset(
+        position.dx - translation.x * halfWidth,
+        position.dy - translation.y * halfHeight,
+      );
+    }
     return super.hitTest(result, position: position);
   }
 
   @override
   void paint(PaintingContext context, Offset offset) {
     assert(!debugNeedsLayout);
-    if (child != null)
-      super.paint(context, offset + translation.alongSize(size));
+    if (child != null) {
+      final double halfWidth = size.width / 2.0;
+      final double halfHeight = size.height / 2.0;
+      super.paint(context, new Offset(
+        offset.dx + translation.x * halfWidth,
+        offset.dy + translation.y * halfHeight,
+      ));
+    }
   }
 
   @override
   void applyPaintTransform(RenderBox child, Matrix4 transform) {
-    transform.translate(translation.dx * size.width, translation.dy * size.height);
+    final double halfWidth = size.width / 2.0;
+    final double halfHeight = size.height / 2.0;
+    transform.translate(translation.x * halfWidth, translation.y * halfHeight);
   }
 
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
-    description.add(new DiagnosticsProperty<FractionalOffset>('translation', translation));
+    description.add(new DiagnosticsProperty<Alignment>('translation', translation));
     description.add(new DiagnosticsProperty<bool>('transformHitTests', transformHitTests));
   }
 }
@@ -1997,7 +2010,7 @@
 ///   void paint(Canvas canvas, Size size) {
 ///     var rect = Offset.zero & size;
 ///     var gradient = new RadialGradient(
-///       center: const FractionalOffset(0.7, 0.2),
+///       center: const Alignment(0.7, -0.6),
 ///       radius: 0.2,
 ///       colors: [const Color(0xFFFFFF00), const Color(0xFF0099FF)],
 ///       stops: [0.4, 1.0],
diff --git a/packages/flutter/lib/src/rendering/shifted_box.dart b/packages/flutter/lib/src/rendering/shifted_box.dart
index 2f85669..a959bc7 100644
--- a/packages/flutter/lib/src/rendering/shifted_box.dart
+++ b/packages/flutter/lib/src/rendering/shifted_box.dart
@@ -222,13 +222,13 @@
 }
 
 /// Abstract class for one-child-layout render boxes that use a
-/// [FractionalOffsetGeometry] to align their children.
+/// [AlignmentGeometry] to align their children.
 abstract class RenderAligningShiftedBox extends RenderShiftedBox {
   /// Initializes member variables for subclasses.
   ///
   /// The [alignment] argument must not be null.
   RenderAligningShiftedBox({
-    FractionalOffsetGeometry alignment: FractionalOffset.center,
+    AlignmentGeometry alignment: Alignment.center,
     TextDirection textDirection,
     RenderBox child,
   }) : assert(alignment != null),
@@ -236,7 +236,7 @@
        _textDirection = textDirection,
        super(child);
 
-  FractionalOffset _resolvedAlignment;
+  Alignment _resolvedAlignment;
 
   void _resolve() {
     if (_resolvedAlignment != null)
@@ -252,21 +252,21 @@
   /// How to align the child.
   ///
   /// The x and y values of the alignment control the horizontal and vertical
-  /// alignment, respectively.  An x value of 0.0 means that the left edge of
+  /// alignment, respectively. An x value of -1.0 means that the left edge of
   /// the child is aligned with the left edge of the parent whereas an x value
   /// of 1.0 means that the right edge of the child is aligned with the right
   /// edge of the parent. Other values interpolate (and extrapolate) linearly.
-  /// For example, a value of 0.5 means that the center of the child is aligned
+  /// For example, a value of 0.0 means that the center of the child is aligned
   /// with the center of the parent.
   ///
-  /// If this is set to a [FractionalOffsetDirectional] object, then
+  /// If this is set to a [AlignmentDirectional] object, then
   /// [textDirection] must not be null.
-  FractionalOffsetGeometry get alignment => _alignment;
-  FractionalOffsetGeometry _alignment;
+  AlignmentGeometry get alignment => _alignment;
+  AlignmentGeometry _alignment;
   /// Sets the alignment to a new value, and triggers a layout update.
   ///
   /// The new alignment must not be null or have any null properties.
-  set alignment(FractionalOffsetGeometry value) {
+  set alignment(AlignmentGeometry value) {
     assert(value != null);
     if (_alignment == value)
       return;
@@ -309,16 +309,16 @@
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', alignment));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
     description.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
   }
 }
 
-/// Positions its child using a [FractionalOffset].
+/// Positions its child using a [AlignmentGeometry].
 ///
 /// For example, to align a box at the bottom right, you would pass this box a
 /// tight constraint that is bigger than the child's natural size,
-/// with an alignment of [FractionalOffset.bottomRight].
+/// with an alignment of [Alignment.bottomRight].
 ///
 /// By default, sizes to be as big as possible in both axes. If either axis is
 /// unconstrained, then in that direction it will be sized to fit the child's
@@ -330,7 +330,7 @@
     RenderBox child,
     double widthFactor,
     double heightFactor,
-    FractionalOffsetGeometry alignment: FractionalOffset.center,
+    AlignmentGeometry alignment: Alignment.center,
     TextDirection textDirection,
   }) : assert(widthFactor == null || widthFactor >= 0.0),
        assert(heightFactor == null || heightFactor >= 0.0),
@@ -475,7 +475,7 @@
     double maxWidth,
     double minHeight,
     double maxHeight,
-    FractionalOffsetGeometry alignment: FractionalOffset.center,
+    AlignmentGeometry alignment: Alignment.center,
     TextDirection textDirection,
   }) : _minWidth = minWidth,
        _maxWidth = maxWidth,
@@ -571,7 +571,7 @@
   RenderSizedOverflowBox({
     RenderBox child,
     @required Size requestedSize,
-    FractionalOffset alignment: FractionalOffset.center,
+    Alignment alignment: Alignment.center,
     TextDirection textDirection,
   }) : assert(requestedSize != null),
        _requestedSize = requestedSize,
@@ -643,7 +643,7 @@
     RenderBox child,
     double widthFactor,
     double heightFactor,
-    FractionalOffset alignment: FractionalOffset.center,
+    Alignment alignment: Alignment.center,
     TextDirection textDirection,
   }) : _widthFactor = widthFactor,
        _heightFactor = heightFactor,
diff --git a/packages/flutter/lib/src/rendering/stack.dart b/packages/flutter/lib/src/rendering/stack.dart
index c48b53a..62abe6d 100644
--- a/packages/flutter/lib/src/rendering/stack.dart
+++ b/packages/flutter/lib/src/rendering/stack.dart
@@ -297,7 +297,7 @@
   /// top left corners.
   RenderStack({
     List<RenderBox> children,
-    FractionalOffsetGeometry alignment: FractionalOffsetDirectional.topStart,
+    AlignmentGeometry alignment: AlignmentDirectional.topStart,
     TextDirection textDirection,
     StackFit fit: StackFit.loose,
     Overflow overflow: Overflow.clip,
@@ -319,7 +319,7 @@
       child.parentData = new StackParentData();
   }
 
-  FractionalOffset _resolvedAlignment;
+  Alignment _resolvedAlignment;
 
   void _resolve() {
     if (_resolvedAlignment != null)
@@ -336,14 +336,14 @@
   ///
   /// The non-positioned children are placed relative to each other such that
   /// the points determined by [alignment] are co-located. For example, if the
-  /// [alignment] is [FractionalOffset.topLeft], then the top left corner of
+  /// [alignment] is [Alignment.topLeft], then the top left corner of
   /// each non-positioned child will be located at the same global coordinate.
   ///
-  /// If this is set to a [FractionalOffsetDirectional] object, then
-  /// [textDirection] must not be null.
-  FractionalOffsetGeometry get alignment => _alignment;
-  FractionalOffsetGeometry _alignment;
-  set alignment(FractionalOffsetGeometry value) {
+  /// If this is set to a [AlignmentDirectional] object, then [textDirection]
+  /// must not be null.
+  AlignmentGeometry get alignment => _alignment;
+  AlignmentGeometry _alignment;
+  set alignment(AlignmentGeometry value) {
     assert(value != null);
     if (_alignment == value)
       return;
@@ -559,7 +559,7 @@
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', alignment));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
     description.add(new EnumProperty<TextDirection>('textDirection', textDirection));
     description.add(new EnumProperty<StackFit>('fit', fit));
     description.add(new EnumProperty<Overflow>('overflow', overflow));
@@ -577,7 +577,7 @@
   /// If the [index] parameter is null, nothing is displayed.
   RenderIndexedStack({
     List<RenderBox> children,
-    FractionalOffsetGeometry alignment: FractionalOffsetDirectional.topStart,
+    AlignmentGeometry alignment: AlignmentDirectional.topStart,
     TextDirection textDirection,
     int index: 0,
   }) : _index = index, super(
diff --git a/packages/flutter/lib/src/rendering/tweens.dart b/packages/flutter/lib/src/rendering/tweens.dart
index 7bc031a..70387f9 100644
--- a/packages/flutter/lib/src/rendering/tweens.dart
+++ b/packages/flutter/lib/src/rendering/tweens.dart
@@ -7,15 +7,14 @@
 
 /// An interpolation between two fractional offsets.
 ///
-/// This class specializes the interpolation of Tween<FractionalOffset> to be
-/// appropriate for rectangles.
+/// This class specializes the interpolation of [Tween<FractionalOffset>] to be
+/// appropriate for fractional offsets.
 ///
 /// See [Tween] for a discussion on how to use interpolation objects.
 ///
 /// See also:
 ///
-///  * [FractionalOffsetGeometryTween], which interpolates between two
-///    [FractionalOffsetGeometry] objects.
+///  * [AlignmentTween], which interpolates between to [Alignment] objects.
 class FractionalOffsetTween extends Tween<FractionalOffset> {
   /// Creates a fractional offset tween.
   ///
@@ -29,28 +28,51 @@
   FractionalOffset lerp(double t) => FractionalOffset.lerp(begin, end, t);
 }
 
-/// An interpolation between two [FractionalOffsetGeometry].
+/// An interpolation between two alignments.
 ///
-/// This class specializes the interpolation of [Tween<FractionalOffsetGeometry>]
-/// to be appropriate for rectangles.
+/// This class specializes the interpolation of [Tween<Alignment>] to be
+/// appropriate for alignments.
 ///
 /// See [Tween] for a discussion on how to use interpolation objects.
 ///
 /// See also:
 ///
-///  * [FractionalOffsetTween], which interpolates between two
-///    [FractionalOffset] objects.
-class FractionalOffsetGeometryTween extends Tween<FractionalOffsetGeometry> {
+///  * [AlignmentGeometryTween], which interpolates between two
+///    [AlignmentGeometry] objects.
+class AlignmentTween extends Tween<Alignment> {
+  /// Creates a fractional offset tween.
+  ///
+  /// The [begin] and [end] properties may be null; the null value
+  /// is treated as meaning the center.
+  AlignmentTween({ Alignment begin, Alignment end })
+    : super(begin: begin, end: end);
+
+  /// Returns the value this variable has at the given animation clock value.
+  @override
+  Alignment lerp(double t) => Alignment.lerp(begin, end, t);
+}
+
+/// An interpolation between two [AlignmentGeometry].
+///
+/// This class specializes the interpolation of [Tween<AlignmentGeometry>]
+/// to be appropriate for alignments.
+///
+/// See [Tween] for a discussion on how to use interpolation objects.
+///
+/// See also:
+///
+///  * [AlignmentTween], which interpolates between two [Alignment] objects.
+class AlignmentGeometryTween extends Tween<AlignmentGeometry> {
   /// Creates a fractional offset geometry tween.
   ///
   /// The [begin] and [end] properties may be null; the null value
   /// is treated as meaning the center.
-  FractionalOffsetGeometryTween({
-    FractionalOffsetGeometry begin,
-    FractionalOffsetGeometry end,
+  AlignmentGeometryTween({
+    AlignmentGeometry begin,
+    AlignmentGeometry end,
   }) : super(begin: begin, end: end);
 
   /// Returns the value this variable has at the given animation clock value.
   @override
-  FractionalOffsetGeometry lerp(double t) => FractionalOffsetGeometry.lerp(begin, end, t);
+  AlignmentGeometry lerp(double t) => AlignmentGeometry.lerp(begin, end, t);
 }
diff --git a/packages/flutter/lib/src/widgets/animated_cross_fade.dart b/packages/flutter/lib/src/widgets/animated_cross_fade.dart
index 7b6b308..7ddc211 100644
--- a/packages/flutter/lib/src/widgets/animated_cross_fade.dart
+++ b/packages/flutter/lib/src/widgets/animated_cross_fade.dart
@@ -115,7 +115,7 @@
     this.firstCurve: Curves.linear,
     this.secondCurve: Curves.linear,
     this.sizeCurve: Curves.linear,
-    this.alignment: FractionalOffset.topCenter,
+    this.alignment: Alignment.topCenter,
     @required this.crossFadeState,
     @required this.duration,
     this.layoutBuilder: defaultLayoutBuilder,
@@ -165,8 +165,8 @@
 
   /// How the children should be aligned while the size is animating.
   ///
-  /// Defaults to [FractionalOffset.topCenter].
-  final FractionalOffsetGeometry alignment;
+  /// Defaults to [Alignment.topCenter].
+  final AlignmentGeometry alignment;
 
   /// A builder that positions the [firstChild] and [secondChild] widgets.
   ///
@@ -218,7 +218,7 @@
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
     description.add(new EnumProperty<CrossFadeState>('crossFadeState', crossFadeState));
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', alignment, defaultValue: FractionalOffset.topCenter));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: Alignment.topCenter));
   }
 }
 
@@ -356,6 +356,6 @@
     super.debugFillProperties(description);
     description.add(new EnumProperty<CrossFadeState>('crossFadeState', widget.crossFadeState));
     description.add(new DiagnosticsProperty<AnimationController>('controller', _controller, showName: false));
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', widget.alignment, defaultValue: FractionalOffset.topCenter));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', widget.alignment, defaultValue: Alignment.topCenter));
   }
 }
diff --git a/packages/flutter/lib/src/widgets/animated_size.dart b/packages/flutter/lib/src/widgets/animated_size.dart
index 930060e..bf5817e 100644
--- a/packages/flutter/lib/src/widgets/animated_size.dart
+++ b/packages/flutter/lib/src/widgets/animated_size.dart
@@ -18,7 +18,7 @@
   const AnimatedSize({
     Key key,
     Widget child,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.curve: Curves.linear,
     @required this.duration,
     @required this.vsync,
@@ -28,13 +28,13 @@
   /// the same size as the child.
   ///
   /// The x and y values of the alignment control the horizontal and vertical
-  /// alignment, respectively. An x value of 0.0 means that the left edge of
+  /// alignment, respectively. An x value of -1.0 means that the left edge of
   /// the child is aligned with the left edge of the parent whereas an x value
   /// of 1.0 means that the right edge of the child is aligned with the right
   /// edge of the parent. Other values interpolate (and extrapolate) linearly.
-  /// For example, a value of 0.5 means that the center of the child is aligned
+  /// For example, a value of 0.0 means that the center of the child is aligned
   /// with the center of the parent.
-  final FractionalOffsetGeometry alignment;
+  final AlignmentGeometry alignment;
 
   /// The animation curve when transitioning this widget's size to match the
   /// child's size.
diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart
index 7cff47b..5beb4e6 100644
--- a/packages/flutter/lib/src/widgets/basic.dart
+++ b/packages/flutter/lib/src/widgets/basic.dart
@@ -19,6 +19,8 @@
   ValueNotifier;
 export 'package:flutter/painting.dart';
 export 'package:flutter/rendering.dart' show
+  AlignmentTween,
+  AlignmentGeometryTween,
   Axis,
   BoxConstraints,
   CrossAxisAlignment,
@@ -29,7 +31,6 @@
   FlowDelegate,
   FlowPaintingContext,
   FractionalOffsetTween,
-  FractionalOffsetGeometryTween,
   HitTestBehavior,
   LayerLink,
   MainAxisAlignment,
@@ -190,7 +191,7 @@
 /// new ShaderMask(
 ///   shaderCallback: (Rect bounds) {
 ///     return new RadialGradient(
-///       center: FractionalOffset.topLeft,
+///       center: Alignment.topLeft,
 ///       radius: 1.0,
 ///       colors: <Color>[Colors.yellow, Colors.deepOrange.shade900],
 ///       tileMode: TileMode.mirror,
@@ -435,7 +436,7 @@
 /// ```dart
 /// new ClipRect(
 ///   child: new Align(
-///     alignment: FractionalOffset.topCenter,
+///     alignment: Alignment.topCenter,
 ///     heightFactor: 0.5,
 ///     child: new Image.network(userAvatarUrl),
 ///   ),
@@ -712,7 +713,7 @@
 /// new Container(
 ///   color: Colors.black,
 ///   child: new Transform(
-///     alignment: FractionalOffset.topRight,
+///     alignment: Alignment.topRight,
 ///     transform: new Matrix4.skewY(0.3)..rotateZ(-math.PI / 12.0),
 ///     child: new Container(
 ///       padding: const EdgeInsets.all(8.0),
@@ -767,7 +768,7 @@
     Key key,
     @required double angle,
     this.origin,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.transformHitTests: true,
     Widget child,
   }) : transform = new Matrix4.rotationZ(angle),
@@ -787,7 +788,7 @@
   ///
   /// This is equivalent to setting an origin based on the size of the box.
   /// If it is specified at the same time as an offset, both are applied.
-  final FractionalOffset alignment;
+  final Alignment alignment;
 
   /// Whether to apply the translation when performing hit tests.
   final bool transformHitTests;
@@ -959,7 +960,7 @@
   const FittedBox({
     Key key,
     this.fit: BoxFit.contain,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     Widget child
   }) : assert(fit != null),
        assert(alignment != null),
@@ -970,10 +971,10 @@
 
   /// How to align the child within its parent's bounds.
   ///
-  /// An alignment of (0.0, 0.0) aligns the child to the top-left corner of its
-  /// parent's bounds.  An alignment of (1.0, 0.5) aligns the child to the middle
+  /// An alignment of (-1.0, -1.0) aligns the child to the top-left corner of its
+  /// parent's bounds.  An alignment of (1.0, 0.0) aligns the child to the middle
   /// of the right edge of its parent's bounds.
-  final FractionalOffset alignment;
+  final Alignment alignment;
 
   @override
   RenderFittedBox createRenderObject(BuildContext context) => new RenderFittedBox(fit: fit, alignment: alignment);
@@ -1000,8 +1001,8 @@
   }) : assert(translation != null),
        super(key: key, child: child);
 
-  /// The offset by which to translate the child, as a multiple of its size.
-  final FractionalOffset translation;
+  /// The translation to apply to the child, relative to the child's center.
+  final Alignment translation;
 
   /// Whether to apply the translation when performing hit tests.
   final bool transformHitTests;
@@ -1146,7 +1147,7 @@
 ///
 /// For example, to align a box at the bottom right, you would pass this box a
 /// tight constraint that is bigger than the child's natural size,
-/// with an alignment of [FractionalOffset.bottomRight].
+/// with an alignment of [Alignment.bottomRight].
 ///
 /// This widget will be as big as possible if its dimensions are constrained and
 /// [widthFactor] and [heightFactor] are null. If a dimension is unconstrained
@@ -1161,16 +1162,16 @@
 ///  * [CustomSingleChildLayout], which uses a delegate to control the layout of
 ///    a single child.
 ///  * [Center], which is the same as [Align] but with the [alignment] always
-///    set to [FractionalOffset.center].
+///    set to [Alignment.center].
 ///  * [FractionallySizedBox], which sizes its child based on a fraction of its own
-///    size and positions the child according to a [FractionalOffset] value.
+///    size and positions the child according to a [Alignment] value.
 class Align extends SingleChildRenderObjectWidget {
   /// Creates an alignment widget.
   ///
-  /// The alignment defaults to [FractionalOffset.center].
+  /// The alignment defaults to [Alignment.center].
   const Align({
     Key key,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.widthFactor,
     this.heightFactor,
     Widget child
@@ -1182,13 +1183,13 @@
   /// How to align the child.
   ///
   /// The x and y values of the alignment control the horizontal and vertical
-  /// alignment, respectively.  An x value of 0.0 means that the left edge of
+  /// alignment, respectively. An x value of -1.0 means that the left edge of
   /// the child is aligned with the left edge of the parent whereas an x value
   /// of 1.0 means that the right edge of the child is aligned with the right
   /// edge of the parent. Other values interpolate (and extrapolate) linearly.
-  /// For example, a value of 0.5 means that the center of the child is aligned
+  /// For example, a value of 0.0 means that the center of the child is aligned
   /// with the center of the parent.
-  final FractionalOffsetGeometry alignment;
+  final AlignmentGeometry alignment;
 
   /// If non-null, sets its width to the child's width multipled by this factor.
   ///
@@ -1222,7 +1223,7 @@
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', alignment));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
     description.add(new DoubleProperty('widthFactor', widthFactor, defaultValue: null));
     description.add(new DoubleProperty('heightFactor', heightFactor, defaultValue: null));
   }
@@ -1259,9 +1260,9 @@
 ///
 ///  * [SingleChildLayoutDelegate], which controls the layout of the child.
 ///  * [Align], which sizes itself based on its child's size and positions
-///    the child according to a [FractionalOffset] value.
+///    the child according to a [Alignment] value.
 ///  * [FractionallySizedBox], which sizes its child based on a fraction of its own
-///    size and positions the child according to a [FractionalOffset] value.
+///    size and positions the child according to a [Alignment] value.
 ///  * [CustomMultiChildLayout], which uses a delegate to position multiple
 ///    children.
 class CustomSingleChildLayout extends SingleChildRenderObjectWidget {
@@ -1536,7 +1537,7 @@
 /// See also:
 ///
 /// * [Align] (which sizes itself based on its child's size and positions
-///   the child according to a [FractionalOffset] value)
+///   the child according to a [Alignment] value)
 /// * [OverflowBox]
 class FractionallySizedBox extends SingleChildRenderObjectWidget {
   /// Creates a widget that sizes its child to a fraction of the total available space.
@@ -1545,7 +1546,7 @@
   /// non-negative.
   const FractionallySizedBox({
     Key key,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.widthFactor,
     this.heightFactor,
     Widget child,
@@ -1575,13 +1576,13 @@
   /// How to align the child.
   ///
   /// The x and y values of the alignment control the horizontal and vertical
-  /// alignment, respectively.  An x value of 0.0 means that the left edge of
+  /// alignment, respectively. An x value of -1.0 means that the left edge of
   /// the child is aligned with the left edge of the parent whereas an x value
   /// of 1.0 means that the right edge of the child is aligned with the right
   /// edge of the parent. Other values interpolate (and extrapolate) linearly.
-  /// For example, a value of 0.5 means that the center of the child is aligned
+  /// For example, a value of 0.0 means that the center of the child is aligned
   /// with the center of the parent.
-  final FractionalOffsetGeometry alignment;
+  final AlignmentGeometry alignment;
 
   @override
   RenderFractionallySizedOverflowBox createRenderObject(BuildContext context) {
@@ -1605,7 +1606,7 @@
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', alignment));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
     description.add(new DoubleProperty('widthFactor', widthFactor, defaultValue: null));
     description.add(new DoubleProperty('heightFactor', heightFactor, defaultValue: null));
   }
@@ -1686,7 +1687,7 @@
   /// Creates a widget that lets its child overflow itself.
   const OverflowBox({
     Key key,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.minWidth,
     this.maxWidth,
     this.minHeight,
@@ -1697,13 +1698,13 @@
   /// How to align the child.
   ///
   /// The x and y values of the alignment control the horizontal and vertical
-  /// alignment, respectively.  An x value of 0.0 means that the left edge of
+  /// alignment, respectively. An x value of -1.0 means that the left edge of
   /// the child is aligned with the left edge of the parent whereas an x value
   /// of 1.0 means that the right edge of the child is aligned with the right
   /// edge of the parent. Other values interpolate (and extrapolate) linearly.
-  /// For example, a value of 0.5 means that the center of the child is aligned
+  /// For example, a value of 0.0 means that the center of the child is aligned
   /// with the center of the parent.
-  final FractionalOffsetGeometry alignment;
+  final AlignmentGeometry alignment;
 
   /// The minimum width constraint to give the child. Set this to null (the
   /// default) to use the constraint from the parent instead.
@@ -1747,7 +1748,7 @@
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', alignment));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
     description.add(new DoubleProperty('minWidth', minWidth, defaultValue: null));
     description.add(new DoubleProperty('maxWidth', maxWidth, defaultValue: null));
     description.add(new DoubleProperty('minHeight', minHeight, defaultValue: null));
@@ -1764,7 +1765,7 @@
   const SizedOverflowBox({
     Key key,
     @required this.size,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     Widget child,
   }) : assert(size != null),
        assert(alignment != null),
@@ -1773,13 +1774,13 @@
   /// How to align the child.
   ///
   /// The x and y values of the alignment control the horizontal and vertical
-  /// alignment, respectively.  An x value of 0.0 means that the left edge of
+  /// alignment, respectively. An x value of -1.0 means that the left edge of
   /// the child is aligned with the left edge of the parent whereas an x value
   /// of 1.0 means that the right edge of the child is aligned with the right
   /// edge of the parent. Other values interpolate (and extrapolate) linearly.
-  /// For example, a value of 0.5 means that the center of the child is aligned
+  /// For example, a value of 0.0 means that the center of the child is aligned
   /// with the center of the parent.
-  final FractionalOffsetGeometry alignment;
+  final AlignmentGeometry alignment;
 
   /// The size this widget should attempt to be.
   final Size size;
@@ -1804,7 +1805,7 @@
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', alignment));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
     description.add(new DiagnosticsProperty<Size>('size', size, defaultValue: null));
   }
 }
@@ -2179,7 +2180,7 @@
 /// See also:
 ///
 ///  * [Align], which sizes itself based on its child's size and positions
-///    the child according to a [FractionalOffset] value.
+///    the child according to a [Alignment] value.
 ///  * [CustomSingleChildLayout], which uses a delegate to control the layout of
 ///    a single child.
 ///  * [CustomMultiChildLayout], which uses a delegate to position multiple
@@ -2193,7 +2194,7 @@
   /// top left corners.
   Stack({
     Key key,
-    this.alignment: FractionalOffsetDirectional.topStart,
+    this.alignment: AlignmentDirectional.topStart,
     this.textDirection,
     this.fit: StackFit.loose,
     this.overflow: Overflow.clip,
@@ -2204,9 +2205,9 @@
   ///
   /// The non-positioned children are placed relative to each other such that
   /// the points determined by [alignment] are co-located. For example, if the
-  /// [alignment] is [FractionalOffset.topLeft], then the top left corner of
+  /// [alignment] is [Alignment.topLeft], then the top left corner of
   /// each non-positioned child will be located at the same global coordinate.
-  final FractionalOffsetGeometry alignment;
+  final AlignmentGeometry alignment;
 
   /// The text direction with which to resolve [alignment].
   ///
@@ -2248,7 +2249,7 @@
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', alignment));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
     description.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
     description.add(new EnumProperty<StackFit>('fit', fit));
     description.add(new EnumProperty<Overflow>('overflow', overflow));
@@ -2269,7 +2270,7 @@
   /// The [index] argument must not be null.
   IndexedStack({
     Key key,
-    FractionalOffsetGeometry alignment: FractionalOffsetDirectional.topStart,
+    AlignmentGeometry alignment: AlignmentDirectional.topStart,
     TextDirection textDirection,
     StackFit sizing: StackFit.loose,
     this.index: 0,
@@ -3837,7 +3838,7 @@
     this.color,
     this.colorBlendMode,
     this.fit,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.repeat: ImageRepeat.noRepeat,
     this.centerSlice,
     this.matchTextDirection: false,
@@ -3889,22 +3890,22 @@
   /// How to align the image within its bounds.
   ///
   /// The alignment aligns the given position in the image to the given position
-  /// in the layout bounds. For example, a [FractionalOffset] alignment of (0.0,
-  /// 0.0) aligns the image to the top-left corner of its layout bounds, while a
-  /// [FractionalOffset] alignment of (1.0, 1.0) aligns the bottom right of the
+  /// in the layout bounds. For example, a [Alignment] alignment of (-1.0,
+  /// -1.0) aligns the image to the top-left corner of its layout bounds, while a
+  /// [Alignment] alignment of (1.0, 1.0) aligns the bottom right of the
   /// image with the bottom right corner of its layout bounds. Similarly, an
-  /// alignment of (0.5, 1.0) aligns the bottom middle of the image with the
+  /// alignment of (0.0, 1.0) aligns the bottom middle of the image with the
   /// middle of the bottom edge of its layout bounds.
   ///
   /// To display a subpart of an image, consider using a [CustomPainter] and
   /// [Canvas.drawImageRect].
   ///
   /// If the [alignment] is [TextDirection]-dependent (i.e. if it is a
-  /// [FractionalOffsetDirectional]), then an ambient [Directionality] widget
+  /// [AlignmentDirectional]), then an ambient [Directionality] widget
   /// must be in scope.
   ///
-  /// Defaults to [FractionalOffset.center].
-  final FractionalOffsetGeometry alignment;
+  /// Defaults to [Alignment.center].
+  final AlignmentGeometry alignment;
 
   /// How to paint any portions of the layout bounds not covered by the image.
   final ImageRepeat repeat;
@@ -3937,7 +3938,7 @@
 
   @override
   RenderImage createRenderObject(BuildContext context) {
-    assert((!matchTextDirection && alignment is FractionalOffset) || debugCheckHasDirectionality(context));
+    assert((!matchTextDirection && alignment is Alignment) || debugCheckHasDirectionality(context));
     return new RenderImage(
       image: image,
       width: width,
@@ -3950,7 +3951,7 @@
       repeat: repeat,
       centerSlice: centerSlice,
       matchTextDirection: matchTextDirection,
-      textDirection: matchTextDirection || alignment is! FractionalOffset ? Directionality.of(context) : null,
+      textDirection: matchTextDirection || alignment is! Alignment ? Directionality.of(context) : null,
     );
   }
 
@@ -3968,7 +3969,7 @@
       ..repeat = repeat
       ..centerSlice = centerSlice
       ..matchTextDirection = matchTextDirection
-      ..textDirection = matchTextDirection || alignment is! FractionalOffset ? Directionality.of(context) : null;
+      ..textDirection = matchTextDirection || alignment is! Alignment ? Directionality.of(context) : null;
   }
 
   @override
@@ -3981,7 +3982,7 @@
     description.add(new DiagnosticsProperty<Color>('color', color, defaultValue: null));
     description.add(new EnumProperty<BlendMode>('colorBlendMode', colorBlendMode, defaultValue: null));
     description.add(new EnumProperty<BoxFit>('fit', fit, defaultValue: null));
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', alignment, defaultValue: null));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null));
     description.add(new EnumProperty<ImageRepeat>('repeat', repeat, defaultValue: ImageRepeat.noRepeat));
     description.add(new DiagnosticsProperty<Rect>('centerSlice', centerSlice, defaultValue: null));
     description.add(new FlagProperty('matchTextDirection', value: matchTextDirection, ifTrue: 'match text direction'));
diff --git a/packages/flutter/lib/src/widgets/container.dart b/packages/flutter/lib/src/widgets/container.dart
index b61503c..7f7ac6d 100644
--- a/packages/flutter/lib/src/widgets/container.dart
+++ b/packages/flutter/lib/src/widgets/container.dart
@@ -25,7 +25,7 @@
 /// new DecoratedBox(
 ///   decoration: new BoxDecoration(
 ///     gradient: new RadialGradient(
-///       center: const FractionalOffset(0.25, 0.3),
+///       center: const Alignment(-0.5, -0.6),
 ///       radius: 0.15,
 ///       colors: <Color>[
 ///         const Color(0xFFEEEEEE),
@@ -207,7 +207,7 @@
 ///   ),
 ///   padding: const EdgeInsets.all(8.0),
 ///   color: Colors.teal.shade700,
-///   alignment: FractionalOffset.center,
+///   alignment: Alignment.center,
 ///   child: new Text('Hello World', style: Theme.of(context).textTheme.display1.copyWith(color: Colors.white)),
 ///   foregroundDecoration: new BoxDecoration(
 ///     image: new DecorationImage(
@@ -278,7 +278,7 @@
   /// constraints are unbounded, then the child will be shrink-wrapped instead.
   ///
   /// Ignored if [child] is null.
-  final FractionalOffsetGeometry alignment;
+  final AlignmentGeometry alignment;
 
   /// Empty space to inscribe inside the [decoration]. The [child], if any, is
   /// placed inside this padding.
@@ -362,7 +362,7 @@
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', alignment, showName: false, defaultValue: null));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, showName: false, defaultValue: null));
     description.add(new DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
     description.add(new DiagnosticsProperty<Decoration>('bg', decoration, defaultValue: null));
     description.add(new DiagnosticsProperty<Decoration>('fg', foregroundDecoration, defaultValue: null));
diff --git a/packages/flutter/lib/src/widgets/debug.dart b/packages/flutter/lib/src/widgets/debug.dart
index d0d64e9..5a8d4a2 100644
--- a/packages/flutter/lib/src/widgets/debug.dart
+++ b/packages/flutter/lib/src/widgets/debug.dart
@@ -232,7 +232,7 @@
         'determines the ambient reading direction and is used, for example, to '
         'determine how to lay out text, how to interpret "start" and "end" '
         'values, and to resolve EdgeInsetsDirectional, '
-        'FractionalOffsetDirectional, and other *Directional objects.'
+        'AlignmentDirectional, and other *Directional objects.'
       );
     }
     return true;
diff --git a/packages/flutter/lib/src/widgets/dismissible.dart b/packages/flutter/lib/src/widgets/dismissible.dart
index fecd84a..e83245f 100644
--- a/packages/flutter/lib/src/widgets/dismissible.dart
+++ b/packages/flutter/lib/src/widgets/dismissible.dart
@@ -135,19 +135,21 @@
        super(reclip: moveAnimation);
 
   final Axis axis;
-  final Animation<FractionalOffset> moveAnimation;
+  final Animation<Alignment> moveAnimation;
 
   @override
   Rect getClip(Size size) {
     assert(axis != null);
     switch (axis) {
       case Axis.horizontal:
-        final double offset = moveAnimation.value.dx * size.width;
+        final double halfWidth = size.width / 2.0;
+        final double offset = halfWidth + moveAnimation.value.x * halfWidth;
         if (offset < 0)
           return new Rect.fromLTRB(size.width + offset, 0.0, size.width, size.height);
         return new Rect.fromLTRB(0.0, 0.0, offset, size.height);
       case Axis.vertical:
-        final double offset = moveAnimation.value.dy * size.height;
+        final double halfHeight = size.height / 2.0;
+        final double offset = halfHeight + moveAnimation.value.y * halfHeight;
         if (offset < 0)
           return new Rect.fromLTRB(0.0, size.height + offset, size.width, size.height);
         return new Rect.fromLTRB(0.0, 0.0, size.width, offset);
@@ -175,7 +177,7 @@
   }
 
   AnimationController _moveController;
-  Animation<FractionalOffset> _moveAnimation;
+  Animation<Alignment> _moveAnimation;
 
   AnimationController _resizeController;
   Animation<double> _resizeAnimation;
@@ -268,11 +270,10 @@
   }
 
   void _updateMoveAnimation() {
-    _moveAnimation = new FractionalOffsetTween(
-      begin: FractionalOffset.topLeft,
-      end: _directionIsXAxis ?
-             new FractionalOffset(_dragExtent.sign, 0.0) :
-             new FractionalOffset(0.0, _dragExtent.sign)
+    final double end = _dragExtent.sign * 2.0;
+    _moveAnimation = new AlignmentTween(
+      begin: Alignment.center,
+      end: _directionIsXAxis ? new Alignment(end, 0.0) : new Alignment(0.0, end),
     ).animate(_moveController);
   }
 
diff --git a/packages/flutter/lib/src/widgets/fade_in_image.dart b/packages/flutter/lib/src/widgets/fade_in_image.dart
index 552b5aa..08bf803 100644
--- a/packages/flutter/lib/src/widgets/fade_in_image.dart
+++ b/packages/flutter/lib/src/widgets/fade_in_image.dart
@@ -73,7 +73,7 @@
     this.width,
     this.height,
     this.fit,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.repeat: ImageRepeat.noRepeat,
     this.matchTextDirection: false,
   }) : assert(placeholder != null),
@@ -121,7 +121,7 @@
     this.width,
     this.height,
     this.fit,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.repeat: ImageRepeat.noRepeat,
     this.matchTextDirection: false,
   }) : assert(placeholder != null),
@@ -177,7 +177,7 @@
     this.width,
     this.height,
     this.fit,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.repeat: ImageRepeat.noRepeat,
     this.matchTextDirection: false,
   }) : assert(placeholder != null),
@@ -239,19 +239,19 @@
   /// How to align the image within its bounds.
   ///
   /// The alignment aligns the given position in the image to the given position
-  /// in the layout bounds. For example, a [FractionalOffset] alignment of (0.0,
-  /// 0.0) aligns the image to the top-left corner of its layout bounds, while a
-  /// [FractionalOffset] alignment of (1.0, 1.0) aligns the bottom right of the
+  /// in the layout bounds. For example, a [Alignment] alignment of (-1.0,
+  /// -1.0) aligns the image to the top-left corner of its layout bounds, while a
+  /// [Alignment] alignment of (1.0, 1.0) aligns the bottom right of the
   /// image with the bottom right corner of its layout bounds. Similarly, an
-  /// alignment of (0.5, 1.0) aligns the bottom middle of the image with the
+  /// alignment of (0.0, 1.0) aligns the bottom middle of the image with the
   /// middle of the bottom edge of its layout bounds.
   ///
   /// If the [alignment] is [TextDirection]-dependent (i.e. if it is a
-  /// [FractionalOffsetDirectional]), then an ambient [Directionality] widget
+  /// [AlignmentDirectional]), then an ambient [Directionality] widget
   /// must be in scope.
   ///
-  /// Defaults to [FractionalOffset.center].
-  final FractionalOffsetGeometry alignment;
+  /// Defaults to [Alignment.center].
+  final AlignmentGeometry alignment;
 
   /// How to paint any portions of the layout bounds not covered by the image.
   final ImageRepeat repeat;
diff --git a/packages/flutter/lib/src/widgets/image.dart b/packages/flutter/lib/src/widgets/image.dart
index 2ff5375..7246e7a 100644
--- a/packages/flutter/lib/src/widgets/image.dart
+++ b/packages/flutter/lib/src/widgets/image.dart
@@ -113,7 +113,7 @@
     this.color,
     this.colorBlendMode,
     this.fit,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.repeat: ImageRepeat.noRepeat,
     this.centerSlice,
     this.matchTextDirection: false,
@@ -136,7 +136,7 @@
     this.color,
     this.colorBlendMode,
     this.fit,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.repeat: ImageRepeat.noRepeat,
     this.centerSlice,
     this.matchTextDirection: false,
@@ -162,7 +162,7 @@
     this.color,
     this.colorBlendMode,
     this.fit,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.repeat: ImageRepeat.noRepeat,
     this.centerSlice,
     this.matchTextDirection: false,
@@ -293,7 +293,7 @@
     this.color,
     this.colorBlendMode,
     this.fit,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.repeat: ImageRepeat.noRepeat,
     this.centerSlice,
     this.matchTextDirection: false,
@@ -318,7 +318,7 @@
     this.color,
     this.colorBlendMode,
     this.fit,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.repeat: ImageRepeat.noRepeat,
     this.centerSlice,
     this.matchTextDirection: false,
@@ -367,22 +367,22 @@
   /// How to align the image within its bounds.
   ///
   /// The alignment aligns the given position in the image to the given position
-  /// in the layout bounds. For example, a [FractionalOffset] alignment of (0.0,
-  /// 0.0) aligns the image to the top-left corner of its layout bounds, while a
-  /// [FractionalOffset] alignment of (1.0, 1.0) aligns the bottom right of the
+  /// in the layout bounds. For example, a [Alignment] alignment of (-1.0,
+  /// -1.0) aligns the image to the top-left corner of its layout bounds, while a
+  /// [Alignment] alignment of (1.0, 1.0) aligns the bottom right of the
   /// image with the bottom right corner of its layout bounds. Similarly, an
-  /// alignment of (0.5, 1.0) aligns the bottom middle of the image with the
+  /// alignment of (0.0, 1.0) aligns the bottom middle of the image with the
   /// middle of the bottom edge of its layout bounds.
   ///
   /// To display a subpart of an image, consider using a [CustomPainter] and
   /// [Canvas.drawImageRect].
   ///
   /// If the [alignment] is [TextDirection]-dependent (i.e. if it is a
-  /// [FractionalOffsetDirectional]), then an ambient [Directionality] widget
+  /// [AlignmentDirectional]), then an ambient [Directionality] widget
   /// must be in scope.
   ///
-  /// Defaults to [FractionalOffset.center].
-  final FractionalOffsetGeometry alignment;
+  /// Defaults to [Alignment.center].
+  final AlignmentGeometry alignment;
 
   /// How to paint any portions of the layout bounds not covered by the image.
   final ImageRepeat repeat;
@@ -433,7 +433,7 @@
     description.add(new DiagnosticsProperty<Color>('color', color, defaultValue: null));
     description.add(new EnumProperty<BlendMode>('colorBlendMode', colorBlendMode, defaultValue: null));
     description.add(new EnumProperty<BoxFit>('fit', fit, defaultValue: null));
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', alignment, defaultValue: null));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null));
     description.add(new EnumProperty<ImageRepeat>('repeat', repeat, defaultValue: ImageRepeat.noRepeat));
     description.add(new DiagnosticsProperty<Rect>('centerSlice', centerSlice, defaultValue: null));
     description.add(new FlagProperty('matchTextDirection', value: matchTextDirection, ifTrue: 'match text direction'));
diff --git a/packages/flutter/lib/src/widgets/image_icon.dart b/packages/flutter/lib/src/widgets/image_icon.dart
index 3618220..4b67bd4 100644
--- a/packages/flutter/lib/src/widgets/image_icon.dart
+++ b/packages/flutter/lib/src/widgets/image_icon.dart
@@ -75,7 +75,7 @@
       height: iconSize,
       color: iconColor,
       fit: BoxFit.scaleDown,
-      alignment: FractionalOffset.center
+      alignment: Alignment.center,
     );
   }
 
diff --git a/packages/flutter/lib/src/widgets/implicit_animations.dart b/packages/flutter/lib/src/widgets/implicit_animations.dart
index 6434f3a..8e49efc 100644
--- a/packages/flutter/lib/src/widgets/implicit_animations.dart
+++ b/packages/flutter/lib/src/widgets/implicit_animations.dart
@@ -391,7 +391,7 @@
   /// constraints are unbounded, then the child will be shrink-wrapped instead.
   ///
   /// Ignored if [child] is null.
-  final FractionalOffsetGeometry alignment;
+  final AlignmentGeometry alignment;
 
   /// Empty space to inscribe inside the [decoration]. The [child], if any, is
   /// placed inside this padding.
@@ -427,7 +427,7 @@
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometry>('alignment', alignment, showName: false, defaultValue: null));
+    description.add(new DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, showName: false, defaultValue: null));
     description.add(new DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
     description.add(new DiagnosticsProperty<Decoration>('bg', decoration, defaultValue: null));
     description.add(new DiagnosticsProperty<Decoration>('fg', foregroundDecoration, defaultValue: null));
@@ -438,7 +438,7 @@
 }
 
 class _AnimatedContainerState extends AnimatedWidgetBaseState<AnimatedContainer> {
-  FractionalOffsetGeometryTween _alignment;
+  AlignmentGeometryTween _alignment;
   EdgeInsetsGeometryTween _padding;
   DecorationTween _decoration;
   DecorationTween _foregroundDecoration;
@@ -448,7 +448,7 @@
 
   @override
   void forEachTween(TweenVisitor<dynamic> visitor) {
-    _alignment = visitor(_alignment, widget.alignment, (dynamic value) => new FractionalOffsetGeometryTween(begin: value));
+    _alignment = visitor(_alignment, widget.alignment, (dynamic value) => new AlignmentGeometryTween(begin: value));
     _padding = visitor(_padding, widget.padding, (dynamic value) => new EdgeInsetsGeometryTween(begin: value));
     _decoration = visitor(_decoration, widget.decoration, (dynamic value) => new DecorationTween(begin: value));
     _foregroundDecoration = visitor(_foregroundDecoration, widget.foregroundDecoration, (dynamic value) => new DecorationTween(begin: value));
@@ -474,7 +474,7 @@
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder description) {
     super.debugFillProperties(description);
-    description.add(new DiagnosticsProperty<FractionalOffsetGeometryTween>('alignment', _alignment, showName: false, defaultValue: null));
+    description.add(new DiagnosticsProperty<AlignmentGeometryTween>('alignment', _alignment, showName: false, defaultValue: null));
     description.add(new DiagnosticsProperty<EdgeInsetsGeometryTween>('padding', _padding, defaultValue: null));
     description.add(new DiagnosticsProperty<DecorationTween>('bg', _decoration, defaultValue: null));
     description.add(new DiagnosticsProperty<DecorationTween>('fg', _foregroundDecoration, defaultValue: null));
diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart
index c0b1a4e..14e0307 100644
--- a/packages/flutter/lib/src/widgets/routes.dart
+++ b/packages/flutter/lib/src/widgets/routes.dart
@@ -632,9 +632,9 @@
   ///       Widget child,
   ///    ) {
   ///     return new SlideTransition(
-  ///       position: new FractionalOffsetTween(
-  ///         begin: FractionalOffset.bottomLeft,
-  ///         end: FractionalOffset.topLeft
+  ///       position: new AlignmentTween(
+  ///         begin: Alignment.bottomCenter,
+  ///         end: Alignment.topCenter,
   ///       ).animate(animation),
   ///       child: child, // child is the value returned by pageBuilder
   ///     );
@@ -669,14 +669,14 @@
   ///       Widget child,
   ///   ) {
   ///     return new SlideTransition(
-  ///       position: new FractionalOffsetTween(
-  ///         begin: FractionalOffset.bottomLeft,
-  ///         end: FractionalOffset.topLeft,
+  ///       position: new AlignmentTween(
+  ///         begin: Alignment.bottomCenter,
+  ///         end: Alignment.topCenter,
   ///       ).animate(animation),
   ///       child: new SlideTransition(
-  ///         position: new FractionalOffsetTween(
-  ///           begin: FractionalOffset.topLeft,
-  ///           end: FractionalOffset.bottomLeft,
+  ///         position: new AlignmentTween(
+  ///           begin: Alignment.topCenter,
+  ///           end: Alignment.bottomCenter,
   ///         ).animate(secondaryAnimation),
   ///         child: child,
   ///       ),
diff --git a/packages/flutter/lib/src/widgets/scroll_view.dart b/packages/flutter/lib/src/widgets/scroll_view.dart
index e39aaec..a827e61 100644
--- a/packages/flutter/lib/src/widgets/scroll_view.dart
+++ b/packages/flutter/lib/src/widgets/scroll_view.dart
@@ -279,7 +279,7 @@
 ///       delegate: new SliverChildBuilderDelegate(
 ///         (BuildContext context, int index) {
 ///           return new Container(
-///             alignment: FractionalOffset.center,
+///             alignment: Alignment.center,
 ///             color: Colors.teal[100 * (index % 9)],
 ///             child: new Text('grid item $index'),
 ///           );
@@ -292,7 +292,7 @@
 ///       delegate: new SliverChildBuilderDelegate(
 ///         (BuildContext context, int index) {
 ///           return new Container(
-///             alignment: FractionalOffset.center,
+///             alignment: Alignment.center,
 ///             color: Colors.lightBlue[100 * (index % 9)],
 ///             child: new Text('list item $index'),
 ///           );
diff --git a/packages/flutter/lib/src/widgets/semantics_debugger.dart b/packages/flutter/lib/src/widgets/semantics_debugger.dart
index 779aeb9..1a6fe2d 100644
--- a/packages/flutter/lib/src/widgets/semantics_debugger.dart
+++ b/packages/flutter/lib/src/widgets/semantics_debugger.dart
@@ -279,7 +279,7 @@
     ..textAlign = TextAlign.center
     ..layout(maxWidth: rect.width);
 
-  textPainter.paint(canvas, FractionalOffset.center.inscribe(textPainter.size, rect).topLeft);
+  textPainter.paint(canvas, Alignment.center.inscribe(textPainter.size, rect).topLeft);
   canvas.restore();
 }
 
diff --git a/packages/flutter/lib/src/widgets/sliver.dart b/packages/flutter/lib/src/widgets/sliver.dart
index f67dda5..3989656 100644
--- a/packages/flutter/lib/src/widgets/sliver.dart
+++ b/packages/flutter/lib/src/widgets/sliver.dart
@@ -422,7 +422,7 @@
 ///   delegate: new SliverChildBuilderDelegate(
 ///     (BuildContext context, int index) {
 ///       return new Container(
-///         alignment: FractionalOffset.center,
+///         alignment: Alignment.center,
 ///         color: Colors.lightBlue[100 * (index % 9)],
 ///         child: new Text('list item $index'),
 ///       );
@@ -489,7 +489,7 @@
 ///   delegate: new SliverChildBuilderDelegate(
 ///     (BuildContext context, int index) {
 ///       return new Container(
-///         alignment: FractionalOffset.center,
+///         alignment: Alignment.center,
 ///         color: Colors.teal[100 * (index % 9)],
 ///         child: new Text('grid item $index'),
 ///       );
diff --git a/packages/flutter/lib/src/widgets/transitions.dart b/packages/flutter/lib/src/widgets/transitions.dart
index 3d5a0e7..f982b49 100644
--- a/packages/flutter/lib/src/widgets/transitions.dart
+++ b/packages/flutter/lib/src/widgets/transitions.dart
@@ -103,7 +103,7 @@
   /// The [position] argument must not be null.
   const SlideTransition({
     Key key,
-    @required Animation<FractionalOffsetGeometry> position,
+    @required Animation<Alignment> position,
     this.transformHitTests: true,
     this.child,
   }) : super(key: key, listenable: position);
@@ -112,7 +112,7 @@
   ///
   /// If the current value of the position animation is (dx, dy), the child will
   /// be translated horizontally by width * dx and vertically by height * dy.
-  Animation<FractionalOffsetGeometry> get position => listenable;
+  Animation<Alignment> get position => listenable;
 
   /// Whether hit testing should be affected by the slide animation.
   ///
@@ -140,11 +140,11 @@
   /// Creates a scale transition.
   ///
   /// The [scale] argument must not be null. The [alignment] argument defaults
-  /// to [FractionalOffset.center].
+  /// to [Alignment.center].
   const ScaleTransition({
     Key key,
     @required Animation<double> scale,
-    this.alignment: FractionalOffset.center,
+    this.alignment: Alignment.center,
     this.child,
   }) : super(key: key, listenable: scale);
 
@@ -158,8 +158,8 @@
   /// takes place, relative to the size of the box.
   ///
   /// For example, to set the origin of the scale to bottom middle, you can use
-  /// an alignment of (0.5, 1.0).
-  final FractionalOffset alignment;
+  /// an alignment of (0.0, 1.0).
+  final Alignment alignment;
 
   /// The widget below this widget in the tree.
   final Widget child;
@@ -203,7 +203,7 @@
     final Matrix4 transform = new Matrix4.rotationZ(turnsValue * math.PI * 2.0);
     return new Transform(
       transform: transform,
-      alignment: FractionalOffset.center,
+      alignment: Alignment.center,
       child: child,
     );
   }
@@ -217,13 +217,13 @@
   /// Creates a size transition.
   ///
   /// The [sizeFactor] argument must not be null. The [axis] argument defaults
-  /// to [Axis.vertical]. The [axisAlignment] defaults to 0.5, which centers the
+  /// to [Axis.vertical]. The [axisAlignment] defaults to 0.0, which centers the
   /// child along the main axis during the transition.
   const SizeTransition({
     Key key,
     this.axis: Axis.vertical,
     @required Animation<double> sizeFactor,
-    this.axisAlignment: 0.5,
+    this.axisAlignment: 0.0,
     this.child,
   }) : assert(axis != null),
        super(key: key, listenable: sizeFactor);
@@ -244,11 +244,11 @@
 
   @override
   Widget build(BuildContext context) {
-    FractionalOffsetDirectional alignment;
+    AlignmentDirectional alignment;
     if (axis == Axis.vertical)
-      alignment = new FractionalOffsetDirectional(0.0, axisAlignment);
+      alignment = new AlignmentDirectional(-1.0, axisAlignment);
     else
-      alignment = new FractionalOffsetDirectional(axisAlignment, 0.0);
+      alignment = new AlignmentDirectional(axisAlignment, -1.0);
     return new ClipRect(
       child: new Align(
         alignment: alignment,
diff --git a/packages/flutter/test/cupertino/page_test.dart b/packages/flutter/test/cupertino/page_test.dart
index e5035b6..1204325 100644
--- a/packages/flutter/test/cupertino/page_test.dart
+++ b/packages/flutter/test/cupertino/page_test.dart
@@ -33,13 +33,13 @@
     Offset widget2TopLeft = tester.getTopLeft(find.text('Page 2'));
 
     // Page 1 is moving to the left.
-    expect(widget1TransientTopLeft.dx < widget1InitialTopLeft.dx, true);
+    expect(widget1TransientTopLeft.dx, lessThan(widget1InitialTopLeft.dx));
     // Page 1 isn't moving vertically.
-    expect(widget1TransientTopLeft.dy == widget1InitialTopLeft.dy, true);
+    expect(widget1TransientTopLeft.dy, equals(widget1InitialTopLeft.dy));
     // iOS transition is horizontal only.
-    expect(widget1InitialTopLeft.dy == widget2TopLeft.dy, true);
+    expect(widget1InitialTopLeft.dy, equals(widget2TopLeft.dy));
     // Page 2 is coming in from the right.
-    expect(widget2TopLeft.dx > widget1InitialTopLeft.dx, true);
+    expect(widget2TopLeft.dx, greaterThan(widget1InitialTopLeft.dx));
 
     await tester.pumpAndSettle();
 
@@ -55,13 +55,13 @@
     widget2TopLeft = tester.getTopLeft(find.text('Page 2'));
 
     // Page 1 is coming back from the left.
-    expect(widget1TransientTopLeft.dx < widget1InitialTopLeft.dx, true);
+    expect(widget1TransientTopLeft.dx, lessThan(widget1InitialTopLeft.dx));
     // Page 1 isn't moving vertically.
-    expect(widget1TransientTopLeft.dy == widget1InitialTopLeft.dy, true);
+    expect(widget1TransientTopLeft.dy, equals(widget1InitialTopLeft.dy));
     // iOS transition is horizontal only.
-    expect(widget1InitialTopLeft.dy == widget2TopLeft.dy, true);
+    expect(widget1InitialTopLeft.dy, equals(widget2TopLeft.dy));
     // Page 2 is leaving towards the right.
-    expect(widget2TopLeft.dx > widget1InitialTopLeft.dx, true);
+    expect(widget2TopLeft.dx, greaterThan(widget1InitialTopLeft.dx));
 
     await tester.pumpAndSettle();
 
@@ -71,7 +71,7 @@
     widget1TransientTopLeft = tester.getTopLeft(find.text('Page 1'));
 
     // Page 1 is back where it started.
-    expect(widget1InitialTopLeft == widget1TransientTopLeft, true);
+    expect(widget1InitialTopLeft, equals(widget1TransientTopLeft));
   });
 
   testWidgets('test iOS fullscreen dialog transition', (WidgetTester tester) async {
@@ -105,11 +105,11 @@
     Offset widget2TopLeft = tester.getTopLeft(find.text('Page 2'));
 
     // Page 1 doesn't move.
-    expect(widget1TransientTopLeft == widget1InitialTopLeft, true);
+    expect(widget1TransientTopLeft, equals(widget1InitialTopLeft));
     // Fullscreen dialogs transitions vertically only.
-    expect(widget1InitialTopLeft.dx == widget2TopLeft.dx, true);
+    expect(widget1InitialTopLeft.dx, equals(widget2TopLeft.dx));
     // Page 2 is coming in from the bottom.
-    expect(widget2TopLeft.dy > widget1InitialTopLeft.dy, true);
+    expect(widget2TopLeft.dy, greaterThan(widget1InitialTopLeft.dy));
 
     await tester.pumpAndSettle();
 
@@ -125,11 +125,11 @@
     widget2TopLeft = tester.getTopLeft(find.text('Page 2'));
 
     // Page 1 doesn't move.
-    expect(widget1TransientTopLeft == widget1InitialTopLeft, true);
+    expect(widget1TransientTopLeft, equals(widget1InitialTopLeft));
     // Fullscreen dialogs transitions vertically only.
-    expect(widget1InitialTopLeft.dx == widget2TopLeft.dx, true);
+    expect(widget1InitialTopLeft.dx, equals(widget2TopLeft.dx));
     // Page 2 is leaving towards the bottom.
-    expect(widget2TopLeft.dy > widget1InitialTopLeft.dy, true);
+    expect(widget2TopLeft.dy, greaterThan(widget1InitialTopLeft.dy));
 
     await tester.pumpAndSettle();
 
@@ -139,7 +139,7 @@
     widget1TransientTopLeft = tester.getTopLeft(find.text('Page 1'));
 
     // Page 1 is back where it started.
-    expect(widget1InitialTopLeft == widget1TransientTopLeft, true);
+    expect(widget1InitialTopLeft, equals(widget1TransientTopLeft));
   });
 
   testWidgets('test only edge swipes work', (WidgetTester tester) async {
diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart
index cd38e34..396553a 100644
--- a/packages/flutter/test/material/app_bar_test.dart
+++ b/packages/flutter/test/material/app_bar_test.dart
@@ -999,8 +999,8 @@
             flexibleSpace: new DecoratedBox(
               decoration: new BoxDecoration(
                 gradient: new LinearGradient(
-                  begin: const FractionalOffset(0.50, 0.0),
-                  end: const FractionalOffset(0.48, 1.0),
+                  begin: const Alignment(0.0, -1.0),
+                  end: const Alignment(-0.04, 1.0),
                   colors: <Color>[Colors.blue.shade500, Colors.blue.shade800],
                 ),
               ),
@@ -1029,8 +1029,8 @@
             flexibleSpace: new DecoratedBox(
               decoration: new BoxDecoration(
                 gradient: new LinearGradient(
-                  begin: const FractionalOffset(0.50, 0.0),
-                  end: const FractionalOffset(0.48, 1.0),
+                  begin: const Alignment(0.0, -1.0),
+                  end: const Alignment(-0.04, 1.0),
                   colors: <Color>[Colors.blue.shade500, Colors.blue.shade800],
                 ),
               ),
diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart
index f19958c..e83ff93 100644
--- a/packages/flutter/test/material/dialog_test.dart
+++ b/packages/flutter/test/material/dialog_test.dart
@@ -160,7 +160,7 @@
       child: new Container(
         width: 100.0,
         height: 100.0,
-        alignment: FractionalOffset.center,
+        alignment: Alignment.center,
         child: const Text('Dialog1'),
       ),
     );
@@ -180,7 +180,7 @@
       child: new Container(
         width: 100.0,
         height: 100.0,
-        alignment: FractionalOffset.center,
+        alignment: Alignment.center,
         child: const Text('Dialog2'),
       ),
     );
diff --git a/packages/flutter/test/material/dropdown_test.dart b/packages/flutter/test/material/dropdown_test.dart
index 863d90f..e7ca17e 100644
--- a/packages/flutter/test/material/dropdown_test.dart
+++ b/packages/flutter/test/material/dropdown_test.dart
@@ -24,7 +24,7 @@
     bool isDense: false,
     Widget hint,
     List<String> items: menuItems,
-    FractionalOffset alignment: FractionalOffset.center,
+    Alignment alignment: Alignment.center,
   }) {
   return new MaterialApp(
     home: new Material(
@@ -219,7 +219,7 @@
       new MaterialApp(
         home: new Material(
           child: new Align(
-            alignment: FractionalOffset.topCenter,
+            alignment: Alignment.topCenter,
             child: button,
           ),
         ),
@@ -443,19 +443,19 @@
     // so that it fits within the frame.
 
     await popUpAndDown(
-      buildFrame(alignment: FractionalOffset.topLeft, value: menuItems.last)
+      buildFrame(alignment: Alignment.topLeft, value: menuItems.last)
     );
     expect(menuRect.topLeft, Offset.zero);
     expect(menuRect.topRight, new Offset(menuRect.width, 0.0));
 
     await popUpAndDown(
-      buildFrame(alignment: FractionalOffset.topCenter, value: menuItems.last)
+      buildFrame(alignment: Alignment.topCenter, value: menuItems.last)
     );
     expect(menuRect.topLeft, new Offset(buttonRect.left, 0.0));
     expect(menuRect.topRight, new Offset(buttonRect.right, 0.0));
 
     await popUpAndDown(
-      buildFrame(alignment: FractionalOffset.topRight, value: menuItems.last)
+      buildFrame(alignment: Alignment.topRight, value: menuItems.last)
     );
     expect(menuRect.topLeft, new Offset(800.0 - menuRect.width, 0.0));
     expect(menuRect.topRight, const Offset(800.0, 0.0));
@@ -465,19 +465,19 @@
     // is selected) and shifted horizontally so that it fits within the frame.
 
     await popUpAndDown(
-      buildFrame(alignment: FractionalOffset.centerLeft, value: menuItems.first)
+      buildFrame(alignment: Alignment.centerLeft, value: menuItems.first)
     );
     expect(menuRect.topLeft, new Offset(0.0, buttonRect.top));
     expect(menuRect.topRight, new Offset(menuRect.width, buttonRect.top));
 
     await popUpAndDown(
-      buildFrame(alignment: FractionalOffset.center, value: menuItems.first)
+      buildFrame(alignment: Alignment.center, value: menuItems.first)
     );
     expect(menuRect.topLeft, buttonRect.topLeft);
     expect(menuRect.topRight, buttonRect.topRight);
 
     await popUpAndDown(
-      buildFrame(alignment: FractionalOffset.centerRight, value: menuItems.first)
+      buildFrame(alignment: Alignment.centerRight, value: menuItems.first)
     );
     expect(menuRect.topLeft, new Offset(800.0 - menuRect.width, buttonRect.top));
     expect(menuRect.topRight, new Offset(800.0, buttonRect.top));
@@ -487,19 +487,19 @@
     // so that it fits within the frame.
 
     await popUpAndDown(
-      buildFrame(alignment: FractionalOffset.bottomLeft, value: menuItems.first)
+      buildFrame(alignment: Alignment.bottomLeft, value: menuItems.first)
     );
     expect(menuRect.bottomLeft, const Offset(0.0, 600.0));
     expect(menuRect.bottomRight, new Offset(menuRect.width, 600.0));
 
     await popUpAndDown(
-      buildFrame(alignment: FractionalOffset.bottomCenter, value: menuItems.first)
+      buildFrame(alignment: Alignment.bottomCenter, value: menuItems.first)
     );
     expect(menuRect.bottomLeft, new Offset(buttonRect.left, 600.0));
     expect(menuRect.bottomRight, new Offset(buttonRect.right, 600.0));
 
     await popUpAndDown(
-      buildFrame(alignment: FractionalOffset.bottomRight, value: menuItems.first)
+      buildFrame(alignment: Alignment.bottomRight, value: menuItems.first)
     );
     expect(menuRect.bottomLeft, new Offset(800.0 - menuRect.width, 600.0));
     expect(menuRect.bottomRight, const Offset(800.0, 600.0));
diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart
index a7453c6..cf679a6 100644
--- a/packages/flutter/test/material/tabs_test.dart
+++ b/packages/flutter/test/material/tabs_test.dart
@@ -444,7 +444,7 @@
     await tester.pumpWidget(
       new MaterialApp(
         home: new Align(
-          alignment: FractionalOffset.topLeft,
+          alignment: Alignment.topLeft,
           child: new SizedBox(
             width: 300.0,
             height: 200.0,
diff --git a/packages/flutter/test/painting/alignment_test.dart b/packages/flutter/test/painting/alignment_test.dart
new file mode 100644
index 0000000..d262540
--- /dev/null
+++ b/packages/flutter/test/painting/alignment_test.dart
@@ -0,0 +1,223 @@
+// Copyright 2017 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 'package:flutter/painting.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void approxExpect(Alignment a, Alignment b) {
+  expect(a.x, moreOrLessEquals(b.x));
+  expect(a.y, moreOrLessEquals(b.y));
+}
+
+void main() {
+  test('Alignment control test', () {
+    const Alignment offset = const Alignment(0.5, 0.25);
+
+    expect(offset, hasOneLineDescription);
+    expect(offset.hashCode, equals(const Alignment(0.5, 0.25).hashCode));
+
+    expect(offset / 2.0, const Alignment(0.25, 0.125));
+    expect(offset ~/ 2.0, const Alignment(0.0, 0.0));
+    expect(offset % 5.0, const Alignment(0.5, 0.25));
+  });
+
+  test('Alignment.lerp()', () {
+    final Alignment a = Alignment.topLeft;
+    final Alignment b = Alignment.topCenter;
+    expect(Alignment.lerp(a, b, 0.25), equals(const Alignment(-0.75, -1.0)));
+
+    expect(Alignment.lerp(null, null, 0.25), isNull);
+    expect(Alignment.lerp(null, b, 0.25), equals(const Alignment(0.0, -0.25)));
+    expect(Alignment.lerp(a, null, 0.25), equals(const Alignment(-0.75, -0.75)));
+  });
+
+  test('AlignmentGeometry invariants', () {
+    final AlignmentDirectional topStart = AlignmentDirectional.topStart;
+    final AlignmentDirectional topEnd = AlignmentDirectional.topEnd;
+    final Alignment center = Alignment.center;
+    final Alignment topLeft = Alignment.topLeft;
+    final Alignment topRight = Alignment.topRight;
+    final List<double> numbers = <double>[0.0, 1.0, -1.0, 2.0, 0.25, 0.5, 100.0, -999.75];
+
+    expect((topEnd * 0.0).add(topRight * 0.0), center);
+    expect(topEnd.add(topRight) * 0.0, (topEnd * 0.0).add(topRight * 0.0));
+    expect(topStart.add(topLeft), topLeft.add(topStart));
+    expect((topStart.add(topLeft)).resolve(TextDirection.ltr), (topStart.resolve(TextDirection.ltr)) + topLeft);
+    expect((topStart.add(topLeft)).resolve(TextDirection.rtl), (topStart.resolve(TextDirection.rtl)) + topLeft);
+    expect((topStart.add(topLeft)).resolve(TextDirection.ltr), (topStart.resolve(TextDirection.ltr)).add(topLeft));
+    expect((topStart.add(topLeft)).resolve(TextDirection.rtl), (topStart.resolve(TextDirection.rtl)).add(topLeft));
+    expect(topStart.resolve(TextDirection.ltr), topLeft);
+    expect(topStart.resolve(TextDirection.rtl), topRight);
+    expect(topEnd * 0.0, center);
+    expect(topLeft * 0.0, center);
+    expect(topStart * 1.0, topStart);
+    expect(topEnd * 1.0, topEnd);
+    expect(topLeft * 1.0, topLeft);
+    expect(topRight * 1.0, topRight);
+    for (double n in numbers) {
+      expect((topStart * n).add(topStart), topStart * (n + 1.0));
+      expect((topEnd * n).add(topEnd), topEnd * (n + 1.0));
+      for (double m in numbers)
+        expect((topStart * n).add(topStart * m), topStart * (n + m));
+    }
+    expect(topStart + topStart + topStart, topStart * 3.0); // without using "add"
+    for (TextDirection x in TextDirection.values) {
+      expect((topEnd * 0.0).add(topRight * 0.0).resolve(x), center.add(center).resolve(x));
+      expect((topEnd * 0.0).add(topLeft).resolve(x), center.add(topLeft).resolve(x));
+      expect(((topEnd * 0.0).resolve(x)).add(topLeft.resolve(x)), (center.resolve(x)).add(topLeft.resolve(x)));
+      expect(((topEnd * 0.0).resolve(x)).add(topLeft), (center.resolve(x)).add(topLeft));
+      expect((topEnd * 0.0).resolve(x), center.resolve(x));
+    }
+    expect(topStart, isNot(topLeft));
+    expect(topEnd, isNot(topLeft));
+    expect(topStart, isNot(topRight));
+    expect(topEnd, isNot(topRight));
+    expect(topStart.add(topLeft), isNot(topLeft));
+    expect(topStart.add(topLeft), isNot(topStart));
+  });
+
+  test('AlignmentGeometry.resolve()', () {
+    expect(const AlignmentDirectional(0.25, 0.3).resolve(TextDirection.ltr), const Alignment(0.25, 0.3));
+    expect(const AlignmentDirectional(0.25, 0.3).resolve(TextDirection.rtl), const Alignment(-0.25, 0.3));
+    expect(const AlignmentDirectional(-0.25, 0.3).resolve(TextDirection.ltr), const Alignment(-0.25, 0.3));
+    expect(const AlignmentDirectional(-0.25, 0.3).resolve(TextDirection.rtl), const Alignment(0.25, 0.3));
+    expect(const AlignmentDirectional(1.25, 0.3).resolve(TextDirection.ltr), const Alignment(1.25, 0.3));
+    expect(const AlignmentDirectional(1.25, 0.3).resolve(TextDirection.rtl), const Alignment(-1.25, 0.3));
+    expect(const AlignmentDirectional(0.5, -0.3).resolve(TextDirection.ltr), const Alignment(0.5, -0.3));
+    expect(const AlignmentDirectional(0.5, -0.3).resolve(TextDirection.rtl), const Alignment(-0.5, -0.3));
+    expect(const AlignmentDirectional(0.0, 0.0).resolve(TextDirection.ltr), const Alignment(0.0, 0.0));
+    expect(const AlignmentDirectional(0.0, 0.0).resolve(TextDirection.rtl), const Alignment(0.0, 0.0));
+    expect(const AlignmentDirectional(1.0, 1.0).resolve(TextDirection.ltr), const Alignment(1.0, 1.0));
+    expect(const AlignmentDirectional(1.0, 1.0).resolve(TextDirection.rtl), const Alignment(-1.0, 1.0));
+    final double $1 = 1.0; // we want these instances to be separate instances so that we're not just checking with a single object
+    expect(new AlignmentDirectional($1, 2.0), new AlignmentDirectional($1, 2.0));
+    expect(const AlignmentDirectional(1.0, 2.0), isNot(const AlignmentDirectional(2.0, 1.0)));
+    expect(const AlignmentDirectional(-1.0, 0.0).resolve(TextDirection.ltr),
+           const AlignmentDirectional(1.0, 0.0).resolve(TextDirection.rtl));
+    expect(const AlignmentDirectional(-1.0, 0.0).resolve(TextDirection.ltr),
+     isNot(const AlignmentDirectional(1.0, 0.0).resolve(TextDirection.ltr)));
+    expect(const AlignmentDirectional(1.0, 0.0).resolve(TextDirection.ltr),
+     isNot(const AlignmentDirectional(1.0, 0.0).resolve(TextDirection.rtl)));
+  });
+
+  test('AlignmentGeometry.lerp ad hoc tests', () {
+    final AlignmentGeometry mixed1 = const Alignment(10.0, 20.0).add(const AlignmentDirectional(30.0, 50.0));
+    final AlignmentGeometry mixed2 = const Alignment(70.0, 110.0).add(const AlignmentDirectional(130.0, 170.0));
+    final AlignmentGeometry mixed3 = const Alignment(25.0, 42.5).add(const AlignmentDirectional(55.0, 80.0));
+
+    for (TextDirection direction in TextDirection.values) {
+      expect(AlignmentGeometry.lerp(mixed1, mixed2, 0.0).resolve(direction), mixed1.resolve(direction));
+      expect(AlignmentGeometry.lerp(mixed1, mixed2, 1.0).resolve(direction), mixed2.resolve(direction));
+      expect(AlignmentGeometry.lerp(mixed1, mixed2, 0.25).resolve(direction), mixed3.resolve(direction));
+    }
+  });
+
+  test('lerp commutes with resolve', () {
+    final List<AlignmentGeometry> offsets = <AlignmentGeometry>[
+      Alignment.topLeft,
+      Alignment.topCenter,
+      Alignment.topRight,
+      AlignmentDirectional.topStart,
+      AlignmentDirectional.topCenter,
+      AlignmentDirectional.topEnd,
+      Alignment.centerLeft,
+      Alignment.center,
+      Alignment.centerRight,
+      AlignmentDirectional.centerStart,
+      AlignmentDirectional.center,
+      AlignmentDirectional.centerEnd,
+      Alignment.bottomLeft,
+      Alignment.bottomCenter,
+      Alignment.bottomRight,
+      AlignmentDirectional.bottomStart,
+      AlignmentDirectional.bottomCenter,
+      AlignmentDirectional.bottomEnd,
+      const Alignment(-1.0, 0.65),
+      const AlignmentDirectional(-1.0, 0.45),
+      const AlignmentDirectional(0.125, 0.625),
+      const Alignment(0.25, 0.875),
+      const Alignment(0.0625, 0.5625).add(const AlignmentDirectional(0.1875, 0.6875)),
+      const AlignmentDirectional(2.0, 3.0),
+      const Alignment(2.0, 3.0),
+      const Alignment(2.0, 3.0).add(const AlignmentDirectional(5.0, 3.0)),
+      const Alignment(10.0, 20.0).add(const AlignmentDirectional(30.0, 50.0)),
+      const Alignment(70.0, 110.0).add(const AlignmentDirectional(130.0, 170.0)),
+      const Alignment(25.0, 42.5).add(const AlignmentDirectional(55.0, 80.0)),
+      null,
+    ];
+
+    final List<double> times = <double>[ 0.25, 0.5, 0.75 ];
+
+    for (TextDirection direction in TextDirection.values) {
+      final Alignment defaultValue = AlignmentDirectional.center.resolve(direction);
+      for (AlignmentGeometry a in offsets) {
+        final Alignment resolvedA = a?.resolve(direction) ?? defaultValue;
+        for (AlignmentGeometry b in offsets) {
+          final Alignment resolvedB = b?.resolve(direction) ?? defaultValue;
+          approxExpect(Alignment.lerp(resolvedA, resolvedB, 0.0), resolvedA);
+          approxExpect(Alignment.lerp(resolvedA, resolvedB, 1.0), resolvedB);
+          approxExpect((AlignmentGeometry.lerp(a, b, 0.0) ?? defaultValue).resolve(direction), resolvedA);
+          approxExpect((AlignmentGeometry.lerp(a, b, 1.0) ?? defaultValue).resolve(direction), resolvedB);
+          for (double t in times) {
+            assert(t > 0.0);
+            assert(t < 1.0);
+            final Alignment value = (AlignmentGeometry.lerp(a, b, t) ?? defaultValue).resolve(direction);
+            approxExpect(value, Alignment.lerp(resolvedA, resolvedB, t));
+            final double minDX = math.min(resolvedA.x, resolvedB.x);
+            final double maxDX = math.max(resolvedA.x, resolvedB.x);
+            final double minDY = math.min(resolvedA.y, resolvedB.y);
+            final double maxDY = math.max(resolvedA.y, resolvedB.y);
+            expect(value.x, inInclusiveRange(minDX, maxDX));
+            expect(value.y, inInclusiveRange(minDY, maxDY));
+          }
+        }
+      }
+    }
+  });
+
+  test('AlignmentGeometry add/subtract', () {
+    final AlignmentGeometry directional = const AlignmentDirectional(1.0, 2.0);
+    final AlignmentGeometry normal = const Alignment(3.0, 5.0);
+    expect(directional.add(normal).resolve(TextDirection.ltr), const Alignment(4.0, 7.0));
+    expect(directional.add(normal).resolve(TextDirection.rtl), const Alignment(2.0, 7.0));
+    expect(normal.add(normal), normal * 2.0);
+    expect(directional.add(directional), directional * 2.0);
+  });
+
+  test('AlignmentGeometry operators', () {
+    expect(const AlignmentDirectional(1.0, 2.0) * 2.0, const AlignmentDirectional(2.0, 4.0));
+    expect(const AlignmentDirectional(1.0, 2.0) / 2.0, const AlignmentDirectional(0.5, 1.0));
+    expect(const AlignmentDirectional(1.0, 2.0) % 2.0, const AlignmentDirectional(1.0, 0.0));
+    expect(const AlignmentDirectional(1.0, 2.0) ~/ 2.0, const AlignmentDirectional(0.0, 1.0));
+    for (TextDirection direction in TextDirection.values) {
+      expect(Alignment.center.add(const AlignmentDirectional(1.0, 2.0) * 2.0).resolve(direction), const AlignmentDirectional(2.0, 4.0).resolve(direction));
+      expect(Alignment.center.add(const AlignmentDirectional(1.0, 2.0) / 2.0).resolve(direction), const AlignmentDirectional(0.5, 1.0).resolve(direction));
+      expect(Alignment.center.add(const AlignmentDirectional(1.0, 2.0) % 2.0).resolve(direction), const AlignmentDirectional(1.0, 0.0).resolve(direction));
+      expect(Alignment.center.add(const AlignmentDirectional(1.0, 2.0) ~/ 2.0).resolve(direction), const AlignmentDirectional(0.0, 1.0).resolve(direction));
+    }
+    expect(const Alignment(1.0, 2.0) * 2.0, const Alignment(2.0, 4.0));
+    expect(const Alignment(1.0, 2.0) / 2.0, const Alignment(0.5, 1.0));
+    expect(const Alignment(1.0, 2.0) % 2.0, const Alignment(1.0, 0.0));
+    expect(const Alignment(1.0, 2.0) ~/ 2.0, const Alignment(0.0, 1.0));
+  });
+
+  test('AlignmentGeometry operators', () {
+    expect(const Alignment(1.0, 2.0) + const Alignment(3.0, 5.0), const Alignment(4.0, 7.0));
+    expect(const Alignment(1.0, 2.0) - const Alignment(3.0, 5.0), const Alignment(-2.0, -3.0));
+    expect(const AlignmentDirectional(1.0, 2.0) + const AlignmentDirectional(3.0, 5.0), const AlignmentDirectional(4.0, 7.0));
+    expect(const AlignmentDirectional(1.0, 2.0) - const AlignmentDirectional(3.0, 5.0), const AlignmentDirectional(-2.0, -3.0));
+  });
+
+  test('AlignmentGeometry toString', () {
+    expect(const Alignment(1.0001, 2.0001).toString(), 'Alignment(1.0, 2.0)');
+    expect(const Alignment(0.0, 0.0).toString(), 'Alignment.center');
+    expect(const Alignment(-1.0, 1.0).add(const AlignmentDirectional(1.0, 0.0)).toString(), 'Alignment.bottomLeft + AlignmentDirectional.centerEnd');
+    expect(const Alignment(0.0001, 0.0001).toString(), 'Alignment(0.0, 0.0)');
+    expect(const Alignment(0.0, 0.0).toString(), 'Alignment.center');
+    expect(const AlignmentDirectional(0.0, 0.0).toString(), 'AlignmentDirectional.center');
+    expect(const Alignment(1.0, 1.0).add(const AlignmentDirectional(1.0, 1.0)).toString(), 'Alignment(1.0, 2.0) + AlignmentDirectional.centerEnd');
+  });
+}
diff --git a/packages/flutter/test/painting/decoration_test.dart b/packages/flutter/test/painting/decoration_test.dart
index 32b0ebd..9a09a9b 100644
--- a/packages/flutter/test/painting/decoration_test.dart
+++ b/packages/flutter/test/painting/decoration_test.dart
@@ -205,7 +205,7 @@
       image: new SynchronousTestImageProvider(),
       colorFilter: colorFilter,
       fit: BoxFit.contain,
-      alignment: FractionalOffset.bottomLeft,
+      alignment: Alignment.bottomLeft,
       centerSlice: new Rect.fromLTWH(10.0, 20.0, 30.0, 40.0),
       repeat: ImageRepeat.repeatY,
     );
diff --git a/packages/flutter/test/painting/fractional_offset_test.dart b/packages/flutter/test/painting/fractional_offset_test.dart
index a91fac3..5590974 100644
--- a/packages/flutter/test/painting/fractional_offset_test.dart
+++ b/packages/flutter/test/painting/fractional_offset_test.dart
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'dart:ui' show lerpDouble;
-
 import 'package:flutter/painting.dart';
 import 'package:flutter_test/flutter_test.dart';
 
@@ -14,9 +12,9 @@
     expect(offset, hasOneLineDescription);
     expect(offset.hashCode, equals(const FractionalOffset(0.5, 0.25).hashCode));
 
-    expect(offset / 2.0, const FractionalOffset(0.25, 0.125));
-    expect(offset ~/ 2.0, const FractionalOffset(0.0, 0.0));
-    expect(offset % 5.0, const FractionalOffset(0.5, 0.25));
+    expect(offset / 2.0, const Alignment(0.0, -0.25));
+    expect(offset ~/ 2.0, Alignment.center);
+    expect(offset % 5.0, const Alignment(0.0, 4.5));
   });
 
   test('FractionalOffset.lerp()', () {
@@ -38,137 +36,4 @@
     final FractionalOffset a = new FractionalOffset.fromOffsetAndRect(const Offset(150.0, 120.0), new Rect.fromLTWH(50.0, 20.0, 200.0, 400.0));
     expect(a, const FractionalOffset(0.5, 0.25));
   });
-
-  test('FractionalOffsetGeometry.resolve()', () {
-    expect(const FractionalOffsetDirectional(0.25, 0.3).resolve(TextDirection.ltr), const FractionalOffset(0.25, 0.3));
-    expect(const FractionalOffsetDirectional(0.25, 0.3).resolve(TextDirection.rtl), const FractionalOffset(0.75, 0.3));
-    expect(const FractionalOffsetDirectional(-0.25, 0.3).resolve(TextDirection.ltr), const FractionalOffset(-0.25, 0.3));
-    expect(const FractionalOffsetDirectional(-0.25, 0.3).resolve(TextDirection.rtl), const FractionalOffset(1.25, 0.3));
-    expect(const FractionalOffsetDirectional(1.25, 0.3).resolve(TextDirection.ltr), const FractionalOffset(1.25, 0.3));
-    expect(const FractionalOffsetDirectional(1.25, 0.3).resolve(TextDirection.rtl), const FractionalOffset(-0.25, 0.3));
-    expect(const FractionalOffsetDirectional(0.5, -0.3).resolve(TextDirection.ltr), const FractionalOffset(0.5, -0.3));
-    expect(const FractionalOffsetDirectional(0.5, -0.3).resolve(TextDirection.rtl), const FractionalOffset(0.5, -0.3));
-    expect(const FractionalOffsetDirectional(0.0, 0.0).resolve(TextDirection.ltr), const FractionalOffset(0.0, 0.0));
-    expect(const FractionalOffsetDirectional(0.0, 0.0).resolve(TextDirection.rtl), const FractionalOffset(1.0, 0.0));
-    expect(const FractionalOffsetDirectional(1.0, 1.0).resolve(TextDirection.ltr), const FractionalOffset(1.0, 1.0));
-    expect(const FractionalOffsetDirectional(1.0, 1.0).resolve(TextDirection.rtl), const FractionalOffset(0.0, 1.0));
-    final double $1 = 1.0; // we want these instances to be separate instances so that we're not just checking with a single object
-    expect(new FractionalOffsetDirectional($1, 2.0), new FractionalOffsetDirectional($1, 2.0));
-    expect(const FractionalOffsetDirectional(1.0, 2.0), isNot(const FractionalOffsetDirectional(2.0, 1.0)));
-    expect(const FractionalOffsetDirectional(0.0, 0.0).resolve(TextDirection.ltr),
-           const FractionalOffsetDirectional(1.0, 0.0).resolve(TextDirection.rtl));
-    expect(const FractionalOffsetDirectional(0.0, 0.0).resolve(TextDirection.ltr),
-     isNot(const FractionalOffsetDirectional(1.0, 0.0).resolve(TextDirection.ltr)));
-    expect(const FractionalOffsetDirectional(1.0, 0.0).resolve(TextDirection.ltr),
-     isNot(const FractionalOffsetDirectional(1.0, 0.0).resolve(TextDirection.rtl)));
-  });
-
-  test('FractionalOffsetGeometry.lerp', () {
-    final FractionalOffsetGeometry directional1 = const FractionalOffsetDirectional(0.125, 0.625);
-    final FractionalOffsetGeometry normal1 = const FractionalOffset(0.25, 0.875);
-    final FractionalOffsetGeometry mixed1 = const FractionalOffset(0.0625, 0.5625).add(const FractionalOffsetDirectional(0.1875, 0.6875));
-    final FractionalOffsetGeometry directional2 = const FractionalOffsetDirectional(2.0, 3.0);
-    final FractionalOffsetGeometry normal2 = const FractionalOffset(2.0, 3.0);
-    final FractionalOffsetGeometry mixed2 = const FractionalOffset(2.0, 3.0).add(const FractionalOffsetDirectional(5.0, 3.0));
-
-    expect(FractionalOffsetGeometry.lerp(directional1, directional2, 0.5), const FractionalOffsetDirectional(0.125 + (2.0 - 0.125) / 2.0, 0.625 + (3.0 - 0.625) / 2.0));
-    expect(FractionalOffsetGeometry.lerp(directional2, directional2, 0.5), directional2);
-    expect(FractionalOffsetGeometry.lerp(directional1, normal2, 0.5).resolve(TextDirection.ltr), const FractionalOffset(1.0 + 1.0 / 16.0, 0.625 + (3.0 - 0.625) / 2.0));
-    expect(FractionalOffsetGeometry.lerp(directional1, normal2, 0.5).resolve(TextDirection.rtl), new FractionalOffset(lerpDouble(0.875, 2.0, 0.5), 0.625 + (3.0 - 0.625) / 2.0));
-    expect(FractionalOffsetGeometry.lerp(directional1, mixed1, 0.5).resolve(TextDirection.ltr), new FractionalOffset(1.0 / 32.0 + 2.5 / 16.0, lerpDouble(0.625, 0.5625 + 0.6875, 0.5)));
-    expect(FractionalOffsetGeometry.lerp(directional1, mixed1, 0.5).resolve(TextDirection.rtl), new FractionalOffset(1.0 / 32.0 + 1.0 - 2.5 / 16.0, lerpDouble(0.625, 0.5625 + 0.6875, 0.5)));
-    expect(FractionalOffsetGeometry.lerp(mixed1, mixed2, 0.5).resolve(TextDirection.ltr), new FractionalOffset(3.0 + 5.0 / 8.0, lerpDouble(0.5625 + 0.6875, 6.0, 0.5)));
-    expect(FractionalOffsetGeometry.lerp(mixed1, mixed2, 0.5).resolve(TextDirection.rtl), new FractionalOffset(2.0 - 41.0 / 16.0, lerpDouble(0.5625 + 0.6875, 6.0, 0.5)));
-    expect(FractionalOffsetGeometry.lerp(normal1, normal2, 0.5), const FractionalOffset(0.25 + (2.0 - 0.25) / 2.0, 0.875 + (3.0 - 0.875) / 2.0));
-    expect(FractionalOffsetGeometry.lerp(normal1, mixed1, 0.5).resolve(TextDirection.ltr), new FractionalOffset(lerpDouble(0.25, 0.0625, 0.5) + lerpDouble(0.0, 0.1875, 0.5), lerpDouble(0.875, 0.5625 + 0.6875, 0.5)));
-    expect(FractionalOffsetGeometry.lerp(normal1, mixed1, 0.5).resolve(TextDirection.rtl), new FractionalOffset(lerpDouble(0.25, 0.0625 + 0.8125, 0.5), lerpDouble(0.875, 0.5625 + 0.6875, 0.5)));
-    expect(FractionalOffsetGeometry.lerp(null, mixed1, 0.5).resolve(TextDirection.ltr), FractionalOffsetGeometry.lerp(FractionalOffset.center, mixed1, 0.5).resolve(TextDirection.ltr));
-    expect(FractionalOffsetGeometry.lerp(mixed2, null, 0.25).resolve(TextDirection.ltr), FractionalOffsetGeometry.lerp(FractionalOffset.center, mixed2, 0.75).resolve(TextDirection.ltr));
-    expect(FractionalOffsetGeometry.lerp(directional1, null, 1.0), FractionalOffsetDirectional.center);
-    expect(FractionalOffsetGeometry.lerp(null, null, 0.5), isNull);
-  });
-
-  test('FractionalOffsetGeometry.lerp more', () {
-    final FractionalOffsetGeometry mixed1 = const FractionalOffset(10.0, 20.0).add(const FractionalOffsetDirectional(30.0, 50.0));
-    final FractionalOffsetGeometry mixed2 = const FractionalOffset(70.0, 110.0).add(const FractionalOffsetDirectional(130.0, 170.0));
-    final FractionalOffsetGeometry mixed3 = const FractionalOffset(25.0, 42.5).add(const FractionalOffsetDirectional(55.0, 80.0));
-
-    expect(FractionalOffsetGeometry.lerp(mixed1, mixed2, 0.0), mixed1);
-    expect(FractionalOffsetGeometry.lerp(mixed1, mixed2, 1.0), mixed2);
-    expect(FractionalOffsetGeometry.lerp(mixed1, mixed2, 0.25), mixed3);
-  });
-
-  test('lerp commutes with resolve', () {
-    final List<FractionalOffsetGeometry> offsets = <FractionalOffsetGeometry>[
-      const FractionalOffset(-1.0, 0.65),
-      const FractionalOffsetDirectional(-1.0, 0.45),
-      const FractionalOffsetDirectional(0.125, 0.625),
-      const FractionalOffset(0.25, 0.875),
-      const FractionalOffset(0.0625, 0.5625).add(const FractionalOffsetDirectional(0.1875, 0.6875)),
-      const FractionalOffsetDirectional(2.0, 3.0),
-      const FractionalOffset(2.0, 3.0),
-      const FractionalOffset(2.0, 3.0).add(const FractionalOffsetDirectional(5.0, 3.0)),
-      const FractionalOffset(10.0, 20.0).add(const FractionalOffsetDirectional(30.0, 50.0)),
-      const FractionalOffset(70.0, 110.0).add(const FractionalOffsetDirectional(130.0, 170.0)),
-      const FractionalOffset(25.0, 42.5).add(const FractionalOffsetDirectional(55.0, 80.0)),
-    ];
-
-    final List<double> times = <double>[ 0.0, 0.25, 0.5, 0.75, 1.0 ];
-
-    for (TextDirection direction in TextDirection.values) {
-      for (FractionalOffsetGeometry a in offsets) {
-        for (FractionalOffsetGeometry b in offsets) {
-          for (double t in times) {
-            expect(FractionalOffsetGeometry.lerp(a, b, t).resolve(direction),
-                   FractionalOffset.lerp(a.resolve(direction), b.resolve(direction), t));
-          }
-        }
-      }
-    }
-  });
-
-  test('FractionalOffsetGeometry add/subtract', () {
-    final FractionalOffsetGeometry directional = const FractionalOffsetDirectional(1.0, 2.0);
-    final FractionalOffsetGeometry normal = const FractionalOffset(3.0, 5.0);
-    expect(directional.add(normal).resolve(TextDirection.ltr), const FractionalOffset(4.0, 7.0));
-    expect(directional.add(normal).resolve(TextDirection.rtl), const FractionalOffset(3.0, 7.0));
-    expect(directional.subtract(normal).resolve(TextDirection.ltr), const FractionalOffset(-2.0, -3.0));
-    expect(directional.subtract(normal).resolve(TextDirection.rtl), const FractionalOffset(-3.0, -3.0));
-    expect(normal.add(normal), normal * 2.0);
-    expect(normal.subtract(normal), FractionalOffset.topLeft);
-    expect(directional.add(directional), directional * 2.0);
-    expect(directional.subtract(directional), FractionalOffsetDirectional.topStart);
-  });
-
-  test('FractionalOffsetGeometry operators', () {
-    expect(const FractionalOffsetDirectional(1.0, 2.0) * 2.0, const FractionalOffsetDirectional(2.0, 4.0));
-    expect(const FractionalOffsetDirectional(1.0, 2.0) / 2.0, const FractionalOffsetDirectional(0.5, 1.0));
-    expect(const FractionalOffsetDirectional(1.0, 2.0) % 2.0, const FractionalOffsetDirectional(1.0, 0.0));
-    expect(const FractionalOffsetDirectional(1.0, 2.0) ~/ 2.0, const FractionalOffsetDirectional(0.0, 1.0));
-    expect(FractionalOffset.topLeft.add(const FractionalOffsetDirectional(1.0, 2.0) * 2.0), const FractionalOffsetDirectional(2.0, 4.0));
-    expect(FractionalOffset.topLeft.add(const FractionalOffsetDirectional(1.0, 2.0) / 2.0), const FractionalOffsetDirectional(0.5, 1.0));
-    expect(FractionalOffset.topLeft.add(const FractionalOffsetDirectional(1.0, 2.0) % 2.0), const FractionalOffsetDirectional(1.0, 0.0));
-    expect(FractionalOffset.topLeft.add(const FractionalOffsetDirectional(1.0, 2.0) ~/ 2.0), const FractionalOffsetDirectional(0.0, 1.0));
-    expect(const FractionalOffset(1.0, 2.0) * 2.0, const FractionalOffset(2.0, 4.0));
-    expect(const FractionalOffset(1.0, 2.0) / 2.0, const FractionalOffset(0.5, 1.0));
-    expect(const FractionalOffset(1.0, 2.0) % 2.0, const FractionalOffset(1.0, 0.0));
-    expect(const FractionalOffset(1.0, 2.0) ~/ 2.0, const FractionalOffset(0.0, 1.0));
-  });
-
-  test('FractionalOffsetGeometry operators', () {
-    expect(const FractionalOffset(1.0, 2.0) + const FractionalOffset(3.0, 5.0), const FractionalOffset(4.0, 7.0));
-    expect(const FractionalOffset(1.0, 2.0) - const FractionalOffset(3.0, 5.0), const FractionalOffset(-2.0, -3.0));
-    expect(const FractionalOffsetDirectional(1.0, 2.0) + const FractionalOffsetDirectional(3.0, 5.0), const FractionalOffsetDirectional(4.0, 7.0));
-    expect(const FractionalOffsetDirectional(1.0, 2.0) - const FractionalOffsetDirectional(3.0, 5.0), const FractionalOffsetDirectional(-2.0, -3.0));
-  });
-
-  test('FractionalOffsetGeometry toString', () {
-    expect(const FractionalOffset(1.0001, 2.0001).toString(), 'FractionalOffset(1.0, 2.0)');
-    expect(const FractionalOffset(0.0, 0.0).toString(), 'FractionalOffset.topLeft');
-    expect(const FractionalOffset(0.0, 1.0).add(const FractionalOffsetDirectional(1.0, 0.0)).toString(), 'FractionalOffset.bottomLeft in RTL or FractionalOffset.bottomRight in LTR');
-    expect(const FractionalOffset(0.0001, 0.0001).toString(), 'FractionalOffset(0.0, 0.0)');
-    expect(const FractionalOffset(0.0, 0.0).toString(), 'FractionalOffset.topLeft');
-    expect(const FractionalOffsetDirectional(0.0, 0.0).toString(), 'FractionalOffsetDirectional.topStart');
-    expect(const FractionalOffset(1.0, 1.0).add(const FractionalOffsetDirectional(1.0, 1.0)).toString(), 'FractionalOffset(1.0, 2.0) in RTL or FractionalOffset(2.0, 2.0) in LTR');
-  });
 }
diff --git a/packages/flutter/test/painting/gradient_test.dart b/packages/flutter/test/painting/gradient_test.dart
index c861571..de87252 100644
--- a/packages/flutter/test/painting/gradient_test.dart
+++ b/packages/flutter/test/painting/gradient_test.dart
@@ -8,8 +8,8 @@
 void main() {
   test('LinearGradient scale test', () {
     final LinearGradient testGradient = const LinearGradient(
-      begin: FractionalOffset.bottomRight,
-      end: const FractionalOffset(0.7, 1.0),
+      begin: Alignment.bottomRight,
+      end: const Alignment(0.7, 1.0),
       colors: const <Color>[
         const Color(0x00FFFFFF),
         const Color(0x11777777),
@@ -19,8 +19,8 @@
     final LinearGradient actual = LinearGradient.lerp(null, testGradient, 0.25);
 
     expect(actual, const LinearGradient(
-      begin: FractionalOffset.bottomRight,
-      end: const FractionalOffset(0.7, 1.0),
+      begin: Alignment.bottomRight,
+      end: const Alignment(0.7, 1.0),
       colors: const <Color>[
         const Color(0x00FFFFFF),
         const Color(0x04777777),
@@ -31,8 +31,8 @@
 
   test('LinearGradient lerp test', () {
     final LinearGradient testGradient1 = const LinearGradient(
-      begin: FractionalOffset.topLeft,
-      end: FractionalOffset.bottomLeft,
+      begin: Alignment.topLeft,
+      end: Alignment.bottomLeft,
       colors: const <Color>[
         const Color(0x33333333),
         const Color(0x66666666),
@@ -40,8 +40,8 @@
     );
 
     final LinearGradient testGradient2 = const LinearGradient(
-      begin: FractionalOffset.topRight,
-      end: FractionalOffset.topLeft,
+      begin: Alignment.topRight,
+      end: Alignment.topLeft,
       colors: const <Color>[
         const Color(0x44444444),
         const Color(0x88888888),
@@ -50,8 +50,8 @@
     final LinearGradient actual = LinearGradient.lerp(testGradient1, testGradient2, 0.5);
 
     expect(actual, const LinearGradient(
-      begin: const FractionalOffset(0.5, 0.0),
-      end: const FractionalOffset(0.0, 0.5),
+      begin: const Alignment(0.0, -1.0),
+      end: const Alignment(-1.0, 0.0),
       colors: const <Color>[
         const Color(0x3B3B3B3B),
         const Color(0x77777777),
@@ -62,24 +62,24 @@
   test('LinearGradient toString', () {
     expect(
       const LinearGradient(
-        begin: FractionalOffset.topLeft,
-        end: FractionalOffset.bottomLeft,
+        begin: Alignment.topLeft,
+        end: Alignment.bottomLeft,
         colors: const <Color>[
           const Color(0x33333333),
           const Color(0x66666666),
         ],
       ).toString(),
       equals(
-        'LinearGradient(FractionalOffset.topLeft, FractionalOffset.bottomLeft, [Color(0x33333333), Color(0x66666666)], null, TileMode.clamp)',
+        'LinearGradient(Alignment.topLeft, Alignment.bottomLeft, [Color(0x33333333), Color(0x66666666)], null, TileMode.clamp)',
       ),
     );
   });
 
-  test('LinearGradient with FractionalOffsetDirectional', () {
+  test('LinearGradient with AlignmentDirectional', () {
     expect(
       () {
         return const LinearGradient(
-          begin: FractionalOffsetDirectional.topStart,
+          begin: AlignmentDirectional.topStart,
           colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
         ).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
       },
@@ -88,7 +88,7 @@
     expect(
       () {
         return const LinearGradient(
-          begin: FractionalOffsetDirectional.topStart,
+          begin: AlignmentDirectional.topStart,
           colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
         ).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.rtl);
       },
@@ -97,7 +97,7 @@
     expect(
       () {
         return const LinearGradient(
-          begin: FractionalOffsetDirectional.topStart,
+          begin: AlignmentDirectional.topStart,
           colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
         ).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.ltr);
       },
@@ -106,7 +106,7 @@
     expect(
       () {
         return const LinearGradient(
-          begin: FractionalOffset.topLeft,
+          begin: Alignment.topLeft,
           colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
         ).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
       },
@@ -114,11 +114,11 @@
     );
   });
 
-  test('RadialGradient with FractionalOffsetDirectional', () {
+  test('RadialGradient with AlignmentDirectional', () {
     expect(
       () {
         return const RadialGradient(
-          center: FractionalOffsetDirectional.topStart,
+          center: AlignmentDirectional.topStart,
           colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
         ).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
       },
@@ -127,7 +127,7 @@
     expect(
       () {
         return const RadialGradient(
-          center: FractionalOffsetDirectional.topStart,
+          center: AlignmentDirectional.topStart,
           colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
         ).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.rtl);
       },
@@ -136,7 +136,7 @@
     expect(
       () {
         return const RadialGradient(
-          center: FractionalOffsetDirectional.topStart,
+          center: AlignmentDirectional.topStart,
           colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
         ).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0), textDirection: TextDirection.ltr);
       },
@@ -145,7 +145,7 @@
     expect(
       () {
         return const RadialGradient(
-          center: FractionalOffset.topLeft,
+          center: Alignment.topLeft,
           colors: const <Color>[ const Color(0xFFFFFFFF), const Color(0xFFFFFFFF) ]
         ).createShader(new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
       },
diff --git a/packages/flutter/test/painting/paint_image_test.dart b/packages/flutter/test/painting/paint_image_test.dart
index fcadbe3..dd30a86 100644
--- a/packages/flutter/test/painting/paint_image_test.dart
+++ b/packages/flutter/test/painting/paint_image_test.dart
@@ -39,7 +39,7 @@
       rect: new Rect.fromLTWH(50.0, 75.0, 200.0, 100.0),
       image: image,
       fit: BoxFit.cover,
-      alignment: const FractionalOffset(0.0, 0.5)
+      alignment: const Alignment(-1.0, 0.0),
     );
 
     final Invocation command = canvas.invocations.firstWhere((Invocation invocation) {
diff --git a/packages/flutter/test/rendering/baseline_test.dart b/packages/flutter/test/rendering/baseline_test.dart
index 58ea6ea..2603dd1 100644
--- a/packages/flutter/test/rendering/baseline_test.dart
+++ b/packages/flutter/test/rendering/baseline_test.dart
@@ -13,7 +13,7 @@
     RenderBaseline parent;
     RenderSizedBox child;
     final RenderBox root = new RenderPositionedBox(
-      alignment: FractionalOffset.topLeft,
+      alignment: Alignment.topLeft,
       child: parent = new RenderBaseline(
         baseline: 0.0,
         baselineType: TextBaseline.alphabetic,
diff --git a/packages/flutter/test/rendering/box_test.dart b/packages/flutter/test/rendering/box_test.dart
index b959880..5ceee82 100644
--- a/packages/flutter/test/rendering/box_test.dart
+++ b/packages/flutter/test/rendering/box_test.dart
@@ -14,7 +14,7 @@
       decoration: new BoxDecoration(
         color: const Color(0xFF00FF00),
         gradient: new RadialGradient(
-          center: FractionalOffset.topLeft, radius: 1.8,
+          center: Alignment.topLeft, radius: 1.8,
           colors: <Color>[Colors.yellow[500], Colors.blue[500]],
         ),
         boxShadow: kElevationToShadow[3],
diff --git a/packages/flutter/test/rendering/image_test.dart b/packages/flutter/test/rendering/image_test.dart
index f9bedb5..a7142e4 100644
--- a/packages/flutter/test/rendering/image_test.dart
+++ b/packages/flutter/test/rendering/image_test.dart
@@ -74,7 +74,7 @@
         '   constraints: BoxConstraints(25.0<=w<=100.0, 25.0<=h<=100.0)\n'
         '   size: Size(25.0, 25.0)\n'
         '   image: [10×10]\n'
-        '   alignment: FractionalOffset.center\n'
+        '   alignment: Alignment.center\n'
       ),
     );
 
diff --git a/packages/flutter/test/rendering/limited_box_test.dart b/packages/flutter/test/rendering/limited_box_test.dart
index cb639b6..5b110ef 100644
--- a/packages/flutter/test/rendering/limited_box_test.dart
+++ b/packages/flutter/test/rendering/limited_box_test.dart
@@ -36,7 +36,7 @@
         ' │ parentData: <none>\n'
         ' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
         ' │ size: Size(800.0, 600.0)\n'
-        ' │ alignment: FractionalOffset.center\n'
+        ' │ alignment: Alignment.center\n'
         ' │ minWidth: 0.0\n'
         ' │ maxWidth: Infinity\n'
         ' │ minHeight: 0.0\n'
@@ -122,7 +122,7 @@
         ' │ parentData: <none>\n'
         ' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
         ' │ size: Size(800.0, 600.0)\n'
-        ' │ alignment: FractionalOffset.center\n'
+        ' │ alignment: Alignment.center\n'
         ' │ minWidth: 10.0\n'
         ' │ maxWidth: 500.0\n'
         ' │ minHeight: 0.0\n'
@@ -158,7 +158,7 @@
         ' │ parentData: <none>\n'
         ' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
         ' │ size: Size(800.0, 600.0)\n'
-        ' │ alignment: FractionalOffset.center\n'
+        ' │ alignment: Alignment.center\n'
         ' │ minWidth: 10.0\n'
         ' │ maxWidth: use parent maxWidth constraint\n'
         ' │ minHeight: use parent minHeight constraint\n'
diff --git a/packages/flutter/test/rendering/non_render_object_root_test.dart b/packages/flutter/test/rendering/non_render_object_root_test.dart
index 5172126..e227203 100644
--- a/packages/flutter/test/rendering/non_render_object_root_test.dart
+++ b/packages/flutter/test/rendering/non_render_object_root_test.dart
@@ -47,7 +47,7 @@
     RenderPositionedBox child;
     final RealRoot root = new RealRoot(
       child = new RenderPositionedBox(
-        alignment: FractionalOffset.center,
+        alignment: Alignment.center,
         child: new RenderSizedBox(const Size(100.0, 100.0))
       )
     );
diff --git a/packages/flutter/test/rendering/overflow_test.dart b/packages/flutter/test/rendering/overflow_test.dart
index cd0e947..b1c3c72 100644
--- a/packages/flutter/test/rendering/overflow_test.dart
+++ b/packages/flutter/test/rendering/overflow_test.dart
@@ -23,9 +23,9 @@
           onPaint: () {
             baseline1 = child.getDistanceToBaseline(TextBaseline.alphabetic);
             height1 = text.size.height;
-          }
-        )
-      )
+          },
+        ),
+      ),
     );
     layout(root, phase: EnginePhase.paint);
 
@@ -37,15 +37,15 @@
             textDirection: TextDirection.ltr,
           ),
           maxHeight: height1 / 2.0,
-          alignment: const FractionalOffset(0.0, 0.0)
+          alignment: Alignment.topLeft,
         ),
         painter: new TestCallbackPainter(
           onPaint: () {
             baseline2 = child.getDistanceToBaseline(TextBaseline.alphabetic);
             height2 = text.size.height;
-          }
-        )
-      )
+          },
+        ),
+      ),
     );
     layout(root, phase: EnginePhase.paint);
 
diff --git a/packages/flutter/test/rendering/rendering_tester.dart b/packages/flutter/test/rendering/rendering_tester.dart
index 238cb6f..8f778c2 100644
--- a/packages/flutter/test/rendering/rendering_tester.dart
+++ b/packages/flutter/test/rendering/rendering_tester.dart
@@ -57,7 +57,7 @@
 /// has no build phase.
 void layout(RenderBox box, {
   BoxConstraints constraints,
-  FractionalOffset alignment: FractionalOffset.center,
+  Alignment alignment: Alignment.center,
   EnginePhase phase: EnginePhase.layout,
 }) {
   assert(box != null); // If you want to just repump the last box, call pumpFrame().
diff --git a/packages/flutter/test/rendering/transform_test.dart b/packages/flutter/test/rendering/transform_test.dart
index 7b2da80..cad402a 100644
--- a/packages/flutter/test/rendering/transform_test.dart
+++ b/packages/flutter/test/rendering/transform_test.dart
@@ -18,10 +18,10 @@
     RenderBox inner;
     final RenderBox sizer = new RenderTransform(
       transform: new Matrix4.identity(),
-      alignment: FractionalOffset.center,
+      alignment: Alignment.center,
       child: inner = new RenderSizedBox(const Size(100.0, 100.0)),
     );
-    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: FractionalOffset.topLeft);
+    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: Alignment.topLeft);
     expect(inner.globalToLocal(const Offset(0.0, 0.0)), equals(const Offset(0.0, 0.0)));
     expect(inner.globalToLocal(const Offset(100.0, 100.0)), equals(const Offset(100.0, 100.0)));
     expect(inner.globalToLocal(const Offset(25.0, 75.0)), equals(const Offset(25.0, 75.0)));
@@ -36,13 +36,13 @@
     RenderBox inner;
     final RenderBox sizer = new RenderTransform(
       transform: new Matrix4.identity(),
-      alignment: FractionalOffset.center,
+      alignment: Alignment.center,
       child: new RenderPadding(
         padding: const EdgeInsets.only(left: 20.0),
         child: inner = new RenderSizedBox(const Size(80.0, 100.0)),
       ),
     );
-    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: FractionalOffset.topLeft);
+    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: Alignment.topLeft);
     expect(inner.globalToLocal(const Offset(0.0, 0.0)), equals(const Offset(-20.0, 0.0)));
     expect(inner.globalToLocal(const Offset(100.0, 100.0)), equals(const Offset(80.0, 100.0)));
     expect(inner.globalToLocal(const Offset(25.0, 75.0)), equals(const Offset(5.0, 75.0)));
@@ -57,10 +57,10 @@
     RenderBox inner;
     final RenderBox sizer = new RenderTransform(
       transform: new Matrix4.translationValues(50.0, 200.0, 0.0),
-      alignment: FractionalOffset.center,
+      alignment: Alignment.center,
       child: inner = new RenderSizedBox(const Size(100.0, 100.0)),
     );
-    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: FractionalOffset.topLeft);
+    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: Alignment.topLeft);
     expect(inner.globalToLocal(const Offset(0.0, 0.0)), equals(const Offset(-50.0, -200.0)));
     expect(inner.globalToLocal(const Offset(100.0, 100.0)), equals(const Offset(50.0, -100.0)));
     expect(inner.globalToLocal(const Offset(25.0, 75.0)), equals(const Offset(-25.0, -125.0)));
@@ -75,13 +75,13 @@
     RenderBox inner;
     final RenderBox sizer = new RenderTransform(
       transform: new Matrix4.translationValues(50.0, 200.0, 0.0),
-      alignment: FractionalOffset.center,
+      alignment: Alignment.center,
       child: new RenderPadding(
         padding: const EdgeInsets.only(left: 20.0),
         child: inner = new RenderSizedBox(const Size(80.0, 100.0)),
       ),
     );
-    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: FractionalOffset.topLeft);
+    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: Alignment.topLeft);
     expect(inner.globalToLocal(const Offset(0.0, 0.0)), equals(const Offset(-70.0, -200.0)));
     expect(inner.globalToLocal(const Offset(100.0, 100.0)), equals(const Offset(30.0, -100.0)));
     expect(inner.globalToLocal(const Offset(25.0, 75.0)), equals(const Offset(-45.0, -125.0)));
@@ -96,10 +96,10 @@
     RenderBox inner;
     final RenderBox sizer = new RenderTransform(
       transform: new Matrix4.rotationZ(math.PI),
-      alignment: FractionalOffset.center,
+      alignment: Alignment.center,
       child: inner = new RenderSizedBox(const Size(100.0, 100.0)),
     );
-    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: FractionalOffset.topLeft);
+    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: Alignment.topLeft);
     expect(round(inner.globalToLocal(const Offset(0.0, 0.0))), equals(const Offset(100.0, 100.0)));
     expect(round(inner.globalToLocal(const Offset(100.0, 100.0))), equals(const Offset(0.0, 0.0)));
     expect(round(inner.globalToLocal(const Offset(25.0, 75.0))), equals(const Offset(75.0, 25.0)));
@@ -114,13 +114,13 @@
     RenderBox inner;
     final RenderBox sizer = new RenderTransform(
       transform: new Matrix4.rotationZ(math.PI),
-      alignment: FractionalOffset.center,
+      alignment: Alignment.center,
       child: new RenderPadding(
         padding: const EdgeInsets.only(left: 20.0),
         child: inner = new RenderSizedBox(const Size(80.0, 100.0)),
       ),
     );
-    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: FractionalOffset.topLeft);
+    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: Alignment.topLeft);
     expect(round(inner.globalToLocal(const Offset(0.0, 0.0))), equals(const Offset(80.0, 100.0)));
     expect(round(inner.globalToLocal(const Offset(100.0, 100.0))), equals(const Offset(-20.0, 0.0)));
     expect(round(inner.globalToLocal(const Offset(25.0, 75.0))), equals(const Offset(55.0, 25.0)));
@@ -135,10 +135,10 @@
     RenderBox inner;
     final RenderBox sizer = new RenderTransform(
       transform: rotateAroundXAxis(math.PI * 0.25), // at pi/4, we are about 70 pixels high
-      alignment: FractionalOffset.center,
+      alignment: Alignment.center,
       child: inner = new RenderSizedBox(const Size(100.0, 100.0)),
     );
-    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: FractionalOffset.topLeft);
+    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: Alignment.topLeft);
 
     expect(round(inner.globalToLocal(const Offset(25.0, 50.0))), equals(const Offset(25.0, 50.0)));
     expect(inner.globalToLocal(const Offset(25.0, 17.0)).dy, greaterThan(0.0));
@@ -152,10 +152,10 @@
     RenderBox inner;
     final RenderBox sizer = new RenderTransform(
       transform: rotateAroundXAxis(math.PI * 0.4999), // at pi/2, we're seeing the box on its edge,
-      alignment: FractionalOffset.center,
+      alignment: Alignment.center,
       child: inner = new RenderSizedBox(const Size(100.0, 100.0)),
     );
-    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: FractionalOffset.topLeft);
+    layout(sizer, constraints: new BoxConstraints.tight(const Size(100.0, 100.0)), alignment: Alignment.topLeft);
 
     // the inner widget has a height of about half a pixel at this rotation, so
     // everything should end up around the middle of the outer box.
diff --git a/packages/flutter/test/widgets/align_test.dart b/packages/flutter/test/widgets/align_test.dart
index 8f25d42..342b61f 100644
--- a/packages/flutter/test/widgets/align_test.dart
+++ b/packages/flutter/test/widgets/align_test.dart
@@ -11,34 +11,34 @@
     await tester.pumpWidget(
       new Align(
         child: new Container(),
-        alignment: const FractionalOffset(0.75, 0.75),
+        alignment: const Alignment(0.50, 0.50),
       ),
     );
 
     await tester.pumpWidget(
       new Align(
         child: new Container(),
-        alignment: const FractionalOffset(0.5, 0.5),
+        alignment: const Alignment(0.0, 0.0),
       ),
     );
 
     await tester.pumpWidget(
       const Align(
         key: const GlobalObjectKey<Null>(null),
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
       ),
     );
     await tester.pumpWidget(const Directionality(
       textDirection: TextDirection.rtl,
       child: const Align(
         key: const GlobalObjectKey<Null>(null),
-        alignment: FractionalOffsetDirectional.topStart,
+        alignment: AlignmentDirectional.topStart,
       ),
     ));
     await tester.pumpWidget(
       const Align(
         key: const GlobalObjectKey<Null>(null),
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
       ),
     );
   });
@@ -48,7 +48,7 @@
       textDirection: TextDirection.ltr,
       child: new Align(
         child: new Container(width: 100.0, height: 80.0),
-        alignment: FractionalOffsetDirectional.topStart,
+        alignment: AlignmentDirectional.topStart,
       ),
     ));
 
@@ -59,7 +59,7 @@
       textDirection: TextDirection.ltr,
       child: new Align(
         child: new Container(width: 100.0, height: 80.0),
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
       ),
     ));
 
@@ -72,7 +72,7 @@
       textDirection: TextDirection.rtl,
       child: new Align(
         child: new Container(width: 100.0, height: 80.0),
-        alignment: FractionalOffsetDirectional.topStart,
+        alignment: AlignmentDirectional.topStart,
       ),
     ));
 
@@ -83,7 +83,7 @@
       textDirection: TextDirection.ltr,
       child: new Align(
         child: new Container(width: 100.0, height: 80.0),
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
       ),
     ));
 
@@ -101,7 +101,7 @@
             width: 10.0,
             height: 10.0
           ),
-          alignment: const FractionalOffset(0.50, 0.50),
+          alignment: const Alignment(0.0, 0.0),
         ),
       ),
     );
diff --git a/packages/flutter/test/widgets/animated_container_test.dart b/packages/flutter/test/widgets/animated_container_test.dart
index 4484dcf..b218480 100644
--- a/packages/flutter/test/widgets/animated_container_test.dart
+++ b/packages/flutter/test/widgets/animated_container_test.dart
@@ -183,7 +183,7 @@
         textDirection: TextDirection.rtl,
         child: new AnimatedContainer(
           duration: const Duration(milliseconds: 200),
-          alignment: FractionalOffset.topRight,
+          alignment: Alignment.topRight,
           child: new SizedBox(key: target, width: 100.0, height: 200.0),
         ),
       ),
@@ -197,7 +197,7 @@
         textDirection: TextDirection.rtl,
         child: new AnimatedContainer(
           duration: const Duration(milliseconds: 200),
-          alignment: FractionalOffsetDirectional.bottomStart,
+          alignment: AlignmentDirectional.bottomStart,
           child: new SizedBox(key: target, width: 100.0, height: 200.0),
         ),
       ),
diff --git a/packages/flutter/test/widgets/animated_cross_fade_test.dart b/packages/flutter/test/widgets/animated_cross_fade_test.dart
index 8c20294..bb23cb2 100644
--- a/packages/flutter/test/widgets/animated_cross_fade_test.dart
+++ b/packages/flutter/test/widgets/animated_cross_fade_test.dart
@@ -98,7 +98,7 @@
         textDirection: TextDirection.ltr,
         child: new Center(
           child: new AnimatedCrossFade(
-            alignment: FractionalOffset.bottomRight,
+            alignment: Alignment.bottomRight,
             firstChild: new SizedBox(
               key: firstKey,
               width: 100.0,
@@ -121,7 +121,7 @@
         textDirection: TextDirection.ltr,
         child: new Center(
           child: new AnimatedCrossFade(
-            alignment: FractionalOffset.bottomRight,
+            alignment: Alignment.bottomRight,
             firstChild: new SizedBox(
               key: firstKey,
               width: 100.0,
@@ -156,7 +156,7 @@
         textDirection: TextDirection.ltr,
         child: new Center(
           child: new AnimatedCrossFade(
-            alignment: FractionalOffsetDirectional.bottomEnd,
+            alignment: AlignmentDirectional.bottomEnd,
             firstChild: new SizedBox(
               key: firstKey,
               width: 100.0,
@@ -179,7 +179,7 @@
         textDirection: TextDirection.ltr,
         child: new Center(
           child: new AnimatedCrossFade(
-            alignment: FractionalOffsetDirectional.bottomEnd,
+            alignment: AlignmentDirectional.bottomEnd,
             firstChild: new SizedBox(
               key: firstKey,
               width: 100.0,
@@ -214,7 +214,7 @@
         textDirection: TextDirection.rtl,
         child: new Center(
           child: new AnimatedCrossFade(
-            alignment: FractionalOffsetDirectional.bottomEnd,
+            alignment: AlignmentDirectional.bottomEnd,
             firstChild: new SizedBox(
               key: firstKey,
               width: 100.0,
@@ -237,7 +237,7 @@
         textDirection: TextDirection.rtl,
         child: new Center(
           child: new AnimatedCrossFade(
-            alignment: FractionalOffsetDirectional.bottomEnd,
+            alignment: AlignmentDirectional.bottomEnd,
             firstChild: new SizedBox(
               key: firstKey,
               width: 100.0,
diff --git a/packages/flutter/test/widgets/clip_test.dart b/packages/flutter/test/widgets/clip_test.dart
index 8d64d5a..8eed51a 100644
--- a/packages/flutter/test/widgets/clip_test.dart
+++ b/packages/flutter/test/widgets/clip_test.dart
@@ -107,7 +107,7 @@
   testWidgets('ClipRect', (WidgetTester tester) async {
     await tester.pumpWidget(
       new Align(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         child: new SizedBox(
           width: 100.0,
           height: 100.0,
@@ -131,7 +131,7 @@
 
     await tester.pumpWidget(
       new Align(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         child: new SizedBox(
           width: 100.0,
           height: 100.0,
@@ -149,7 +149,7 @@
 
     await tester.pumpWidget(
       new Align(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         child: new SizedBox(
           width: 200.0,
           height: 200.0,
@@ -167,7 +167,7 @@
 
     await tester.pumpWidget(
       new Align(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         child: new SizedBox(
           width: 200.0,
           height: 200.0,
@@ -185,7 +185,7 @@
 
     await tester.pumpWidget(
       new Align(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         child: new SizedBox(
           width: 200.0,
           height: 200.0,
@@ -203,7 +203,7 @@
 
     await tester.pumpWidget(
       new Align(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         child: new SizedBox(
           width: 200.0,
           height: 200.0,
diff --git a/packages/flutter/test/widgets/container_test.dart b/packages/flutter/test/widgets/container_test.dart
index 208b89b..3ea47a5 100644
--- a/packages/flutter/test/widgets/container_test.dart
+++ b/packages/flutter/test/widgets/container_test.dart
@@ -10,7 +10,7 @@
 void main() {
   testWidgets('Container control test', (WidgetTester tester) async {
     final Container container = new Container(
-      alignment: FractionalOffset.bottomRight,
+      alignment: Alignment.bottomRight,
       padding: const EdgeInsets.all(7.0),
       // uses color, not decoration:
       color: const Color(0xFF00FF00),
@@ -37,7 +37,7 @@
     expect(container, hasOneLineDescription);
 
     await tester.pumpWidget(new Align(
-      alignment: FractionalOffset.topLeft,
+      alignment: Alignment.topLeft,
       child: container
     ));
 
@@ -96,7 +96,7 @@
         '           │ parentData: offset=Offset(7.0, 7.0) (can use size)\n'
         '           │ constraints: BoxConstraints(w=39.0, h=64.0)\n'
         '           │ size: Size(39.0, 64.0)\n'
-        '           │ alignment: FractionalOffset.bottomRight\n'
+        '           │ alignment: Alignment.bottomRight\n'
         '           │ widthFactor: expand\n'
         '           │ heightFactor: expand\n'
         '           │\n'
@@ -173,7 +173,7 @@
         '           │ parentData: offset=Offset(7.0, 7.0) (can use size)\n'
         '           │ constraints: BoxConstraints(w=39.0, h=64.0)\n'
         '           │ size: Size(39.0, 64.0)\n'
-        '           │ alignment: FractionalOffset.bottomRight\n'
+        '           │ alignment: Alignment.bottomRight\n'
         '           │ widthFactor: expand\n'
         '           │ heightFactor: expand\n'
         '           │\n'
@@ -281,7 +281,7 @@
         '           │ layer: null\n'
         '           │ semantics node: null\n'
         '           │ size: Size(39.0, 64.0)\n'
-        '           │ alignment: FractionalOffset.bottomRight\n'
+        '           │ alignment: Alignment.bottomRight\n'
         '           │ textDirection: null\n'
         '           │ widthFactor: expand\n'
         '           │ heightFactor: expand\n'
@@ -412,7 +412,7 @@
         '           │ isBlockingSemanticsOfPreviouslyPaintedNodes: false\n'
         '           │ isSemanticBoundary: false\n'
         '           │ size: Size(39.0, 64.0)\n'
-        '           │ alignment: FractionalOffset.bottomRight\n'
+        '           │ alignment: Alignment.bottomRight\n'
         '           │ textDirection: null\n'
         '           │ widthFactor: expand\n'
         '           │ heightFactor: expand\n'
diff --git a/packages/flutter/test/widgets/fractionally_sized_box_test.dart b/packages/flutter/test/widgets/fractionally_sized_box_test.dart
index 911d862..10e12f9 100644
--- a/packages/flutter/test/widgets/fractionally_sized_box_test.dart
+++ b/packages/flutter/test/widgets/fractionally_sized_box_test.dart
@@ -14,7 +14,7 @@
       maxWidth: 100.0,
       minHeight: 0.0,
       maxHeight: 100.0,
-      alignment: const FractionalOffset(0.0, 0.0),
+      alignment: const Alignment(-1.0, -1.0),
       child: new Center(
         child: new FractionallySizedBox(
           widthFactor: 0.5,
diff --git a/packages/flutter/test/widgets/heroes_test.dart b/packages/flutter/test/widgets/heroes_test.dart
index d6da2c0..631cb75 100644
--- a/packages/flutter/test/widgets/heroes_test.dart
+++ b/packages/flutter/test/widgets/heroes_test.dart
@@ -312,7 +312,7 @@
       routes: <String, WidgetBuilder>{
         '/next': (BuildContext context) {
           return new Align(
-            alignment: FractionalOffset.topLeft,
+            alignment: Alignment.topLeft,
             child: new Hero(
               tag: 'foo',
               child: new GestureDetector(
diff --git a/packages/flutter/test/widgets/image_rtl_test.dart b/packages/flutter/test/widgets/image_rtl_test.dart
index bb7e956..6403a7a 100644
--- a/packages/flutter/test/widgets/image_rtl_test.dart
+++ b/packages/flutter/test/widgets/image_rtl_test.dart
@@ -49,7 +49,7 @@
             decoration: new BoxDecoration(
               image: new DecorationImage(
                 image: new TestImageProvider(),
-                alignment: FractionalOffsetDirectional.topEnd,
+                alignment: AlignmentDirectional.topEnd,
                 repeat: ImageRepeat.repeatX,
                 matchTextDirection: true,
               ),
@@ -88,7 +88,7 @@
             decoration: new BoxDecoration(
               image: new DecorationImage(
                 image: new TestImageProvider(),
-                alignment: FractionalOffsetDirectional.topEnd,
+                alignment: AlignmentDirectional.topEnd,
                 repeat: ImageRepeat.repeatX,
                 matchTextDirection: true,
               ),
@@ -124,7 +124,7 @@
             decoration: new BoxDecoration(
               image: new DecorationImage(
                 image: new TestImageProvider(),
-                alignment: FractionalOffsetDirectional.topEnd,
+                alignment: AlignmentDirectional.topEnd,
                 repeat: ImageRepeat.repeatX,
               ),
             ),
@@ -159,7 +159,7 @@
             decoration: new BoxDecoration(
               image: new DecorationImage(
                 image: new TestImageProvider(),
-                alignment: FractionalOffsetDirectional.topEnd,
+                alignment: AlignmentDirectional.topEnd,
                 repeat: ImageRepeat.repeatX,
               ),
             ),
@@ -194,7 +194,7 @@
             decoration: new BoxDecoration(
               image: new DecorationImage(
                 image: new TestImageProvider(),
-                alignment: FractionalOffset.centerRight,
+                alignment: Alignment.centerRight,
                 matchTextDirection: true,
               ),
             ),
@@ -226,7 +226,7 @@
             decoration: new BoxDecoration(
               image: new DecorationImage(
                 image: new TestImageProvider(),
-                alignment: FractionalOffset.centerRight,
+                alignment: Alignment.centerRight,
               ),
             ),
           ),
@@ -253,7 +253,7 @@
             decoration: new BoxDecoration(
               image: new DecorationImage(
                 image: new TestImageProvider(),
-                alignment: FractionalOffset.centerRight,
+                alignment: Alignment.centerRight,
                 matchTextDirection: true
               ),
             ),
@@ -281,7 +281,7 @@
             decoration: new BoxDecoration(
               image: new DecorationImage(
                 image: new TestImageProvider(),
-                alignment: FractionalOffset.centerRight,
+                alignment: Alignment.centerRight,
                 matchTextDirection: true
               ),
             ),
@@ -308,7 +308,7 @@
             height: 50.0,
             child: new Image(
               image: new TestImageProvider(),
-              alignment: FractionalOffsetDirectional.topEnd,
+              alignment: AlignmentDirectional.topEnd,
               repeat: ImageRepeat.repeatX,
               matchTextDirection: true,
             ),
@@ -345,7 +345,7 @@
             height: 50.0,
             child: new Image(
               image: new TestImageProvider(),
-              alignment: FractionalOffsetDirectional.topEnd,
+              alignment: AlignmentDirectional.topEnd,
               repeat: ImageRepeat.repeatX,
               matchTextDirection: true,
             ),
@@ -379,7 +379,7 @@
             height: 50.0,
             child: new Image(
               image: new TestImageProvider(),
-              alignment: FractionalOffsetDirectional.topEnd,
+              alignment: AlignmentDirectional.topEnd,
               repeat: ImageRepeat.repeatX,
             ),
           ),
@@ -412,7 +412,7 @@
             height: 50.0,
             child: new Image(
               image: new TestImageProvider(),
-              alignment: FractionalOffsetDirectional.topEnd,
+              alignment: AlignmentDirectional.topEnd,
               repeat: ImageRepeat.repeatX,
             ),
           ),
@@ -445,7 +445,7 @@
             height: 50.0,
             child: new Image(
               image: new TestImageProvider(),
-              alignment: FractionalOffset.centerRight,
+              alignment: Alignment.centerRight,
               matchTextDirection: true,
             ),
           ),
@@ -475,7 +475,7 @@
             height: 50.0,
             child: new Image(
               image: new TestImageProvider(),
-              alignment: FractionalOffset.centerRight,
+              alignment: Alignment.centerRight,
             ),
           ),
         ),
@@ -500,7 +500,7 @@
             height: 50.0,
             child: new Image(
               image: new TestImageProvider(),
-              alignment: FractionalOffset.centerRight,
+              alignment: Alignment.centerRight,
               matchTextDirection: true
             ),
           ),
@@ -526,7 +526,7 @@
             height: 50.0,
             child: new Image(
               image: new TestImageProvider(),
-              alignment: FractionalOffset.centerRight,
+              alignment: Alignment.centerRight,
               matchTextDirection: true
             ),
           ),
@@ -548,7 +548,7 @@
         textDirection: TextDirection.ltr,
         child: new Image(
           image: new TestImageProvider(),
-          alignment: FractionalOffset.centerRight,
+          alignment: Alignment.centerRight,
           matchTextDirection: false,
         ),
       ),
@@ -560,7 +560,7 @@
         textDirection: TextDirection.ltr,
         child: new Image(
           image: new TestImageProvider(),
-          alignment: FractionalOffsetDirectional.centerEnd,
+          alignment: AlignmentDirectional.centerEnd,
           matchTextDirection: true,
         ),
       ),
@@ -572,7 +572,7 @@
         textDirection: TextDirection.ltr,
         child: new Image(
           image: new TestImageProvider(),
-          alignment: FractionalOffset.centerRight,
+          alignment: Alignment.centerRight,
           matchTextDirection: false,
         ),
       ),
diff --git a/packages/flutter/test/widgets/overflow_box_test.dart b/packages/flutter/test/widgets/overflow_box_test.dart
index 8bfe4e6..5861a98 100644
--- a/packages/flutter/test/widgets/overflow_box_test.dart
+++ b/packages/flutter/test/widgets/overflow_box_test.dart
@@ -10,7 +10,7 @@
   testWidgets('OverflowBox control test', (WidgetTester tester) async {
     final GlobalKey inner = new GlobalKey();
     await tester.pumpWidget(new Align(
-      alignment: const FractionalOffset(1.0, 1.0),
+      alignment: const Alignment(1.0, 1.0),
       child: new SizedBox(
         width: 10.0,
         height: 20.0,
@@ -42,7 +42,7 @@
         .where((DiagnosticsNode n) => !n.isFiltered(DiagnosticLevel.info))
         .map((DiagnosticsNode n) => n.toString()).toList();
     expect(description, <String>[
-      'alignment: FractionalOffset.center',
+      'alignment: Alignment.center',
       'minWidth: 1.0',
       'maxWidth: 2.0',
       'minHeight: 3.0',
diff --git a/packages/flutter/test/widgets/overlay_test.dart b/packages/flutter/test/widgets/overlay_test.dart
index 4447083..8ad1e5c 100644
--- a/packages/flutter/test/widgets/overlay_test.dart
+++ b/packages/flutter/test/widgets/overlay_test.dart
@@ -46,7 +46,7 @@
             ' ╎ │   size)\n'
             ' ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
             ' ╎ │ size: Size(800.0, 600.0)\n'
-            ' ╎ │ alignment: FractionalOffsetDirectional.topStart\n'
+            ' ╎ │ alignment: AlignmentDirectional.topStart\n'
             ' ╎ │ textDirection: ltr\n'
             ' ╎ │ fit: expand\n'
             ' ╎ │ overflow: clip\n'
@@ -113,7 +113,7 @@
         ' ╎ │   size)\n'
         ' ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
         ' ╎ │ size: Size(800.0, 600.0)\n'
-        ' ╎ │ alignment: FractionalOffsetDirectional.topStart\n'
+        ' ╎ │ alignment: AlignmentDirectional.topStart\n'
         ' ╎ │ textDirection: ltr\n'
         ' ╎ │ fit: expand\n'
         ' ╎ │ overflow: clip\n'
diff --git a/packages/flutter/test/widgets/shader_mask_test.dart b/packages/flutter/test/widgets/shader_mask_test.dart
index 7987139..cbce9fd 100644
--- a/packages/flutter/test/widgets/shader_mask_test.dart
+++ b/packages/flutter/test/widgets/shader_mask_test.dart
@@ -9,8 +9,8 @@
 
 Shader createShader(Rect bounds) {
   return new LinearGradient(
-    begin: FractionalOffset.topLeft,
-    end: FractionalOffset.bottomLeft,
+    begin: Alignment.topCenter,
+    end: Alignment.bottomCenter,
     colors: <Color>[const Color(0x00FFFFFF), const Color(0xFFFFFFFF)],
     stops: <double>[0.1, 0.35]
   ).createShader(bounds);
@@ -31,7 +31,7 @@
     }
 
     final Widget widget = new Align(
-      alignment: FractionalOffset.center,
+      alignment: Alignment.center,
       child: new SizedBox(
         width: 400.0,
         height: 400.0,
diff --git a/packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart b/packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart
index 943ba10..113f80d 100644
--- a/packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart
+++ b/packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart
@@ -15,7 +15,7 @@
     return new Container(
       width: width,
       height: height,
-      alignment: FractionalOffset.center,
+      alignment: Alignment.center,
       child: new Text('Item $item', textDirection: TextDirection.ltr),
     );
   }
diff --git a/packages/flutter/test/widgets/stack_test.dart b/packages/flutter/test/widgets/stack_test.dart
index b15e644..62652e4 100644
--- a/packages/flutter/test/widgets/stack_test.dart
+++ b/packages/flutter/test/widgets/stack_test.dart
@@ -41,7 +41,7 @@
 
     await tester.pumpWidget(
       new Stack(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         children: <Widget>[
           new Positioned(
             left: 10.0,
@@ -69,7 +69,7 @@
 
     await tester.pumpWidget(
       new Stack(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         children: <Widget>[
           new Positioned(
             right: 10.0,
@@ -140,7 +140,7 @@
         textDirection: TextDirection.ltr,
         child: new Center(
           child: new Stack(
-            alignment: FractionalOffset.center,
+            alignment: Alignment.center,
             children: <Widget>[
               new Container(key: child0Key, width: 20.0, height: 20.0),
               new Container(key: child1Key, width: 10.0, height: 10.0),
@@ -163,7 +163,7 @@
         textDirection: TextDirection.ltr,
         child: new Center(
           child: new Stack(
-            alignment: FractionalOffsetDirectional.bottomEnd,
+            alignment: AlignmentDirectional.bottomEnd,
             children: <Widget>[
               new Container(key: child0Key, width: 20.0, height: 20.0),
               new Container(key: child1Key, width: 10.0, height: 10.0),
@@ -186,7 +186,7 @@
         textDirection: TextDirection.rtl,
         child: new Center(
           child: new Stack(
-            alignment: FractionalOffset.center,
+            alignment: Alignment.center,
             children: <Widget>[
               new Container(key: child0Key, width: 20.0, height: 20.0),
               new Container(key: child1Key, width: 10.0, height: 10.0),
@@ -209,7 +209,7 @@
         textDirection: TextDirection.rtl,
         child: new Center(
           child: new Stack(
-            alignment: FractionalOffsetDirectional.bottomEnd,
+            alignment: AlignmentDirectional.bottomEnd,
             children: <Widget>[
               new Container(key: child0Key, width: 20.0, height: 20.0),
               new Container(key: child1Key, width: 10.0, height: 10.0),
@@ -257,7 +257,7 @@
       });
       return new Center(
         child: new IndexedStack(
-          alignment: FractionalOffset.topLeft,
+          alignment: Alignment.topLeft,
           children: items,
           index: index,
         ),
@@ -289,7 +289,7 @@
       });
       return new Center(
         child: new IndexedStack(
-          alignment: FractionalOffset.topLeft,
+          alignment: Alignment.topLeft,
           children: items,
           key: key,
           index: index,
@@ -614,18 +614,18 @@
   testWidgets('Can change the text direction of a Stack', (WidgetTester tester) async {
     await tester.pumpWidget(
       new Stack(
-        alignment: FractionalOffset.center,
+        alignment: Alignment.center,
       ),
     );
     await tester.pumpWidget(
       new Stack(
-        alignment: FractionalOffsetDirectional.topStart,
+        alignment: AlignmentDirectional.topStart,
         textDirection: TextDirection.rtl,
       ),
     );
     await tester.pumpWidget(
       new Stack(
-        alignment: FractionalOffset.center,
+        alignment: Alignment.center,
       ),
     );
   });
diff --git a/packages/flutter/test/widgets/transform_test.dart b/packages/flutter/test/widgets/transform_test.dart
index 59a8341..9714400 100644
--- a/packages/flutter/test/widgets/transform_test.dart
+++ b/packages/flutter/test/widgets/transform_test.dart
@@ -82,7 +82,7 @@
                 height: 100.0,
                 child: new Transform(
                   transform: new Matrix4.diagonal3Values(0.5, 0.5, 1.0),
-                  alignment: const FractionalOffset(1.0, 0.5),
+                  alignment: const Alignment(1.0, 0.0),
                   child: new GestureDetector(
                     onTap: () {
                       didReceiveTap = true;
@@ -131,7 +131,7 @@
                 child: new Transform(
                   transform: new Matrix4.diagonal3Values(0.5, 0.5, 1.0),
                   origin: const Offset(100.0, 0.0),
-                  alignment: const FractionalOffset(0.0, 0.5),
+                  alignment: const Alignment(-1.0, 0.0),
                   child: new GestureDetector(
                     onTap: () {
                       didReceiveTap = true;
diff --git a/packages/flutter/test/widgets/wrap_test.dart b/packages/flutter/test/widgets/wrap_test.dart
index fb6ec9f..0c9566e 100644
--- a/packages/flutter/test/widgets/wrap_test.dart
+++ b/packages/flutter/test/widgets/wrap_test.dart
@@ -585,7 +585,7 @@
   testWidgets('Shrink-wrapping Wrap test', (WidgetTester tester) async {
     await tester.pumpWidget(
       new Align(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         child: new Wrap(
           alignment: WrapAlignment.end,
           crossAxisAlignment: WrapCrossAlignment.end,
@@ -609,7 +609,7 @@
 
     await tester.pumpWidget(
       new Align(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         child: new Wrap(
           alignment: WrapAlignment.end,
           crossAxisAlignment: WrapCrossAlignment.end,
@@ -635,7 +635,7 @@
   testWidgets('Wrap spacing test', (WidgetTester tester) async {
     await tester.pumpWidget(
       new Align(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         child: new Wrap(
           runSpacing: 10.0,
           alignment: WrapAlignment.start,
@@ -662,7 +662,7 @@
   testWidgets('Vertical Wrap test with spacing', (WidgetTester tester) async {
     await tester.pumpWidget(
       new Align(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         child: new Wrap(
           direction: Axis.vertical,
           spacing: 10.0,
@@ -693,7 +693,7 @@
 
     await tester.pumpWidget(
       new Align(
-        alignment: FractionalOffset.topLeft,
+        alignment: Alignment.topLeft,
         child: new Wrap(
           direction: Axis.horizontal,
           spacing: 12.0,