anchor.diff:      return widths;
     }
   
  +  // cache the table geometry for painting purposes
  +  List<double> _rowTops = <double>[];
  +  List<double> _columnLefts;
  +
     @override
     void performLayout() {
       final List<double> widths = computeColumnWidths(constraints);
       final List<double> positions = new List<double>(columns);
  +    _rowTops.clear();
       positions[0] = 0.0;
       for (int x = 1; x < columns; x += 1)
         positions[x] = positions[x-1] + widths[x-1];
  +    _columnLefts = positions;
       assert(!positions.any((double value) => value == null));
  +    _baselineDistance = null;
       // then, lay out each row
       double rowTop = 0.0;
       for (int y = 0; y < rows; y += 1) {
  +      _rowTops.add(rowTop);
         double rowHeight = 0.0;
  +      bool haveBaseline = false;
  +      double beforeBaselineDistance = 0.0;
  +      double afterBaselineDistance = 0.0;
  +      List<double> baselines = new List<double>(columns);
         for (int x = 0; x < columns; x += 1) {
           final int xy = x + y * columns;
           RenderBox child = _children[xy];
           if (child != null) {
  -          child.layout(new BoxConstraints.tightFor(width: widths[x]), parentUsesSize: true);
  -          rowHeight = math.max(rowHeight, child.size.height);
  +          TableCellParentData childParentData = child.parentData;
  +          switch (childParentData.verticalAlignment) {
  +            case CellVerticalAlignment.baseline:
  +              assert(textBaseline != null);
  +              child.layout(new BoxConstraints.tightFor(width: widths[x]), parentUsesSize: true);
  +              double childBaseline = child.getDistanceToBaseline(textBaseline, onlyReal: true);
  +              if (childBaseline != null) {
  +                beforeBaselineDistance = math.max(beforeBaselineDistance, childBaseline);
  +                afterBaselineDistance = math.max(afterBaselineDistance, child.size.height - childBaseline);
  +                baselines[x] = childBaseline;
  +                haveBaseline = true;
  +              } else {
  +                rowHeight = math.max(rowHeight, child.size.height);
  +                childParentData.offset = new Offset(positions[x], rowTop);
  +              }
  +              break;
  +            case CellVerticalAlignment.top:
  +            case CellVerticalAlignment.middle:
  +            case CellVerticalAlignment.bottom:
  +              child.layout(new BoxConstraints.tightFor(width: widths[x]), parentUsesSize: true);
  +              rowHeight = math.max(rowHeight, child.size.height);
  +              break;
  +            case CellVerticalAlignment.fill:
  +              break;
  +          }
           }
  +      }
  +      if (haveBaseline) {
  +        if (y == 0)
  +          _baselineDistance = beforeBaselineDistance;
  +        rowHeight = math.max(rowHeight, beforeBaselineDistance + afterBaselineDistance);
         }
         for (int x = 0; x < columns; x += 1) {
           final int xy = x + y * columns;
           RenderBox child = _children[xy];
           if (child != null) {
  -          final BoxParentData childParentData = child.parentData;
  -          // TODO(ianh): cell vertical alignment in the row
  -          childParentData.offset = new Offset(positions[x], rowTop);
  +          final TableCellParentData childParentData = child.parentData;
  +          switch (childParentData.verticalAlignment) {
  +            case CellVerticalAlignment.baseline:
  +              if (baselines[x] != null)
  +                childParentData.offset = new Offset(positions[x], rowTop + beforeBaselineDistance - baselines[x]);
  +              break;
  +            case CellVerticalAlignment.top:
  +              childParentData.offset = new Offset(positions[x], rowTop);
  +              break;
  +            case CellVerticalAlignment.middle:
  +              childParentData.offset = new Offset(positions[x], rowTop + (rowHeight - child.size.height) / 2.0);
  +              break;
  +            case CellVerticalAlignment.bottom:
  +              childParentData.offset = new Offset(positions[x], rowTop + rowHeight - child.size.height);
  +              break;
  +            case CellVerticalAlignment.fill:
  +              child.layout(new BoxConstraints.tightFor(width: widths[x], height: rowHeight));
  +              childParentData.offset = new Offset(positions[x], rowTop);
  +              break;
  +          }
           }
         }
         rowTop += rowHeight;
       }
       size = constraints.constrain(new Size(positions.last + widths.last, rowTop));
  +    assert(_rowTops.length == rows);
     }
   
     @override
  
positive.code:         context.paintChild(child, childParentData.offset + offset);
        }
      }
      // TODO(ianh): paint borders
    }
  
    @override
  
negative.code:                 )
                ),
                new RenderTable(
                  border: new TableBorder.symmetric(inside: new BorderSide(width: 1.0)),
                  columnWidths: const <int, ColumnWidth>{
                    0: const IntrinsicColumnWidth(),
                    1: const MaxColumnWidth(const IntrinsicColumnWidth(), const FractionColumnWidth(0.4)),
  