| Index: sky/sdk/lib/rendering/box.dart | 
| diff --git a/sky/sdk/lib/rendering/box.dart b/sky/sdk/lib/rendering/box.dart | 
| index 36d700aee1fdbfdd35f625c4cb84e58403955d24..0d0b624c4e88f8fb9830994ff4d19c44638b0e7f 100644 | 
| --- a/sky/sdk/lib/rendering/box.dart | 
| +++ b/sky/sdk/lib/rendering/box.dart | 
| @@ -225,6 +225,8 @@ class BoxParentData extends ParentData { | 
| String toString() => 'position=$position'; | 
| } | 
|  | 
| +enum TextBaseline { alphabetic, ideographic } | 
| + | 
| abstract class RenderBox extends RenderObject { | 
|  | 
| void setParentData(RenderObject child) { | 
| @@ -259,6 +261,31 @@ abstract class RenderBox extends RenderObject { | 
| return constraints.constrainHeight(0.0); | 
| } | 
|  | 
| +  // getDistanceToBaseline() should return the distance from the | 
| +  // y-coordinate of the position of the box to the y-coordinate of | 
| +  // the first given baseline in the box's contents. This is used by | 
| +  // certain layout models to align adjacent boxes on a common | 
| +  // baseline, regardless of padding, font size differences, etc. If | 
| +  // there is no baseline, then it should return the distance from the | 
| +  // y-coordinate of the position of the box to the y-coordinate of | 
| +  // the bottom of the box, i.e., the height of the box. | 
| +  // Only call this after layout has been performed. | 
| +  double getDistanceToBaseline(TextBaseline baseline) { | 
| +    assert(!needsLayout); | 
| +    double result = getDistanceToActualBaseline(baseline); | 
| +    if (result == null) | 
| +      return size.height; | 
| +    return result; | 
| +  } | 
| +  // getDistanceToActualBaseline() should return the distance from the | 
| +  // y-coordinate of the position of the box to the y-coordinate of | 
| +  // the first given baseline in the box's contents, if any, or null | 
| +  // otherwise. | 
| +  double getDistanceToActualBaseline(TextBaseline baseline) { | 
| +    assert(!needsLayout); | 
| +    return null; | 
| +  } | 
| + | 
| // This whole block should only be here in debug builds | 
| bool _debugDoingThisLayout = false; | 
| bool _debugCanParentUseSize; | 
| @@ -348,6 +375,12 @@ class RenderProxyBox extends RenderBox with RenderObjectWithChildMixin<RenderBox | 
| return super.getMaxIntrinsicHeight(constraints); | 
| } | 
|  | 
| +  double getDistanceToActualBaseline(TextBaseline baseline) { | 
| +    if (child != null) | 
| +      return child.getDistanceToActualBaseline(baseline); | 
| +    return super.getDistanceToActualBaseline(baseline); | 
| +  } | 
| + | 
| void performLayout() { | 
| if (child != null) { | 
| child.layout(constraints, parentUsesSize: true); | 
| @@ -585,6 +618,20 @@ abstract class RenderShiftedBox extends RenderBox with RenderObjectWithChildMixi | 
| canvas.paintChild(child, child.parentData.position); | 
| } | 
|  | 
| +  double getDistanceToActualBaseline(TextBaseline baseline) { | 
| +    double result; | 
| +    if (child != null) { | 
| +      assert(!needsLayout); | 
| +      result = child.getDistanceToActualBaseline(baseline); | 
| +      assert(child.parentData is BoxParentData); | 
| +      if (result != null) | 
| +        result += child.parentData.position.y; | 
| +    } else { | 
| +      result = super.getDistanceToActualBaseline(baseline); | 
| +    } | 
| +    return result; | 
| +  } | 
| + | 
| void hitTestChildren(HitTestResult result, { Point position }) { | 
| if (child != null) { | 
| assert(child.parentData is BoxParentData); | 
| @@ -1089,6 +1136,38 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox> | 
| // DEFAULT BEHAVIORS FOR RENDERBOX CONTAINERS | 
| abstract class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, ParentDataType extends ContainerParentDataMixin<ChildType>> implements ContainerRenderObjectMixin<ChildType, ParentDataType> { | 
|  | 
| +  double defaultGetDistanceToFirstActualBaseline(TextBaseline baseline) { | 
| +    assert(!needsLayout); | 
| +    RenderBox child = firstChild; | 
| +    while (child != null) { | 
| +      assert(child.parentData is ParentDataType); | 
| +      double result = child.getDistanceToActualBaseline(baseline); | 
| +      if (result != null) | 
| +        return result + child.parentData.position.y; | 
| +      child = child.parentData.nextSibling; | 
| +    } | 
| +    return null; | 
| +  } | 
| + | 
| +  double defaultGetDistanceToHighestActualBaseline(TextBaseline baseline) { | 
| +    assert(!needsLayout); | 
| +    double result; | 
| +    RenderBox child = firstChild; | 
| +    while (child != null) { | 
| +      assert(child.parentData is ParentDataType); | 
| +      double candidate = child.getDistanceToActualBaseline(baseline); | 
| +      if (candidate != null) { | 
| +        candidate += child.parentData.position.x; | 
| +        if (result != null) | 
| +          result = math.min(result, candidate); | 
| +        else | 
| +          result = candidate; | 
| +      } | 
| +      child = child.parentData.nextSibling; | 
| +    } | 
| +    return result; | 
| +  } | 
| + | 
| void defaultHitTestChildren(HitTestResult result, { Point position }) { | 
| // the x, y parameters have the top left of the node's box as the origin | 
| ChildType child = lastChild; | 
|  |