| Index: tools/dom/src/CssRectangle.dart
 | 
| diff --git a/tools/dom/src/CssRectangle.dart b/tools/dom/src/CssRectangle.dart
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..6808927349820367614c1c6218f425a4e0daf474
 | 
| --- /dev/null
 | 
| +++ b/tools/dom/src/CssRectangle.dart
 | 
| @@ -0,0 +1,261 @@
 | 
| +// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 | 
| +// for details. All rights reserved. Use of this source code is governed by a
 | 
| +// BSD-style license that can be found in the LICENSE file.
 | 
| +
 | 
| +part of html;
 | 
| +
 | 
| +/**
 | 
| + * A rectangle representing all the content of the element in the
 | 
| + * [box model](http://www.w3.org/TR/CSS2/box.html).
 | 
| + */
 | 
| +class _ContentCssRect extends CssRect {
 | 
| +
 | 
| +  _ContentCssRect(element) : super(element);
 | 
| +
 | 
| +  num get height => _element.offsetHeight +
 | 
| +      _addOrSubtractToBoxModel(_HEIGHT, _CONTENT);
 | 
| +
 | 
| +  num get width => _element.offsetWidth +
 | 
| +      _addOrSubtractToBoxModel(_WIDTH, _CONTENT);
 | 
| +
 | 
| +  /**
 | 
| +   * Set the height to `newHeight`.
 | 
| +   *
 | 
| +   * newHeight can be either a [num] representing the height in pixels or a
 | 
| +   * [Dimension] object. Values of newHeight that are less than zero are
 | 
| +   * converted to effectively setting the height to 0. This is equivalent to the
 | 
| +   * `height` function in jQuery and the calculated `height` CSS value,
 | 
| +   * converted to a num in pixels.
 | 
| +   */
 | 
| +  void set height(newHeight) {
 | 
| +    if (newHeight is Dimension) {
 | 
| +      if (newHeight.value < 0) newHeight = new Dimension.px(0);
 | 
| +      _element.style.height = newHeight.toString();
 | 
| +    } else {
 | 
| +      if (newHeight < 0) newHeight = 0;
 | 
| +      _element.style.height = '${newHeight}px';
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  /**
 | 
| +   * Set the current computed width in pixels of this element.
 | 
| +   *
 | 
| +   * newWidth can be either a [num] representing the width in pixels or a
 | 
| +   * [Dimension] object. This is equivalent to the `width` function in jQuery
 | 
| +   * and the calculated
 | 
| +   * `width` CSS value, converted to a dimensionless num in pixels.
 | 
| +   */
 | 
| +  void set width(newWidth) {
 | 
| +    if (newWidth is Dimension) {
 | 
| +      if (newWidth.value < 0) newWidth = new Dimension.px(0);
 | 
| +      _element.style.width = newWidth.toString();
 | 
| +    } else {
 | 
| +      if (newWidth < 0) newWidth = 0;
 | 
| +      _element.style.width = '${newWidth}px';
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  num get left => _element.getBoundingClientRect().left -
 | 
| +      _addOrSubtractToBoxModel(['left'], _CONTENT);
 | 
| +  num get top => _element.getBoundingClientRect().top -
 | 
| +      _addOrSubtractToBoxModel(['top'], _CONTENT);
 | 
| +}
 | 
| +
 | 
| +/**
 | 
| + * A list of element content rectangles in the
 | 
| + * [box model](http://www.w3.org/TR/CSS2/box.html).
 | 
| + */
 | 
| +class _ContentCssListRect extends _ContentCssRect {
 | 
| +  List<Element> _elementList;
 | 
| +
 | 
| +  _ContentCssListRect(elementList) : super(elementList.first) {
 | 
| +    _elementList = elementList;
 | 
| +  }
 | 
| +
 | 
| +  /**
 | 
| +   * Set the height to `newHeight`.
 | 
| +   *
 | 
| +   * Values of newHeight that are less than zero are converted to effectively
 | 
| +   * setting the height to 0. This is equivalent to the `height`
 | 
| +   * function in jQuery and the calculated `height` CSS value, converted to a
 | 
| +   * num in pixels.
 | 
| +   */
 | 
| +  void set height(newHeight) {
 | 
| +    _elementList.forEach((e) => e.contentEdge.height = newHeight);
 | 
| +  }
 | 
| +
 | 
| +  /**
 | 
| +   * Set the current computed width in pixels of this element.
 | 
| +   *
 | 
| +   * This is equivalent to the `width` function in jQuery and the calculated
 | 
| +   * `width` CSS value, converted to a dimensionless num in pixels.
 | 
| +   */
 | 
| +  void set width(newWidth) {
 | 
| +    _elementList.forEach((e) => e.contentEdge.width = newWidth);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +/**
 | 
| + * A rectangle representing the dimensions of the space occupied by the
 | 
| + * element's content + padding in the
 | 
| + * [box model](http://www.w3.org/TR/CSS2/box.html).
 | 
| + */
 | 
| +class _PaddingCssRect extends CssRect {
 | 
| +  _PaddingCssRect(element) : super(element);
 | 
| +  num get height => _element.offsetHeight +
 | 
| +      _addOrSubtractToBoxModel(_HEIGHT, _PADDING);
 | 
| +  num get width => _element.offsetWidth +
 | 
| +      _addOrSubtractToBoxModel(_WIDTH, _PADDING);
 | 
| +
 | 
| +  num get left => _element.getBoundingClientRect().left -
 | 
| +      _addOrSubtractToBoxModel(['left'], _PADDING);
 | 
| +  num get top => _element.getBoundingClientRect().top -
 | 
| +      _addOrSubtractToBoxModel(['top'], _PADDING);
 | 
| +}
 | 
| +
 | 
| +/**
 | 
| + * A rectangle representing the dimensions of the space occupied by the
 | 
| + * element's content + padding + border in the
 | 
| + * [box model](http://www.w3.org/TR/CSS2/box.html).
 | 
| + */
 | 
| +class _BorderCssRect extends CssRect {
 | 
| +  _BorderCssRect(element) : super(element);
 | 
| +  num get height => _element.offsetHeight;
 | 
| +  num get width => _element.offsetWidth;
 | 
| +
 | 
| +  num get left => _element.getBoundingClientRect().left;
 | 
| +  num get top => _element.getBoundingClientRect().top;
 | 
| +}
 | 
| +
 | 
| +/**
 | 
| + * A rectangle representing the dimensions of the space occupied by the
 | 
| + * element's content + padding + border + margin in the
 | 
| + * [box model](http://www.w3.org/TR/CSS2/box.html).
 | 
| + */
 | 
| +class _MarginCssRect extends CssRect {
 | 
| +  _MarginCssRect(element) : super(element);
 | 
| +  num get height => _element.offsetHeight +
 | 
| +      _addOrSubtractToBoxModel(_HEIGHT, _MARGIN);
 | 
| +  num get width =>
 | 
| +      _element.offsetWidth + _addOrSubtractToBoxModel(_WIDTH, _MARGIN);
 | 
| +
 | 
| +  num get left => _element.getBoundingClientRect().left -
 | 
| +      _addOrSubtractToBoxModel(['left'], _MARGIN);
 | 
| +  num get top => _element.getBoundingClientRect().top -
 | 
| +      _addOrSubtractToBoxModel(['top'], _MARGIN);
 | 
| +}
 | 
| +
 | 
| +/**
 | 
| + * A class for representing CSS dimensions.
 | 
| + *
 | 
| + * In contrast to the more general purpose [Rect] class, this class's values are
 | 
| + * mutable, so one can change the height of an element programmatically.
 | 
| + *
 | 
| + * _Important_ _note_: use of these methods will perform CSS calculations that
 | 
| + * can trigger a browser reflow. Therefore, use of these properties _during_ an
 | 
| + * animation frame is discouraged. See also:
 | 
| + * [Browser Reflow](https://developers.google.com/speed/articles/reflow)
 | 
| + */
 | 
| +abstract class CssRect extends RectBase implements Rect {
 | 
| +  Element _element;
 | 
| +
 | 
| +  CssRect(this._element);
 | 
| +
 | 
| +  num get left;
 | 
| +
 | 
| +  num get top;
 | 
| +
 | 
| +  /**
 | 
| +   * The height of this rectangle.
 | 
| +   *
 | 
| +   * This is equivalent to the `height` function in jQuery and the calculated
 | 
| +   * `height` CSS value, converted to a dimensionless num in pixels. Unlike
 | 
| +   * [getBoundingClientRect], `height` will return the same numerical width if
 | 
| +   * the element is hidden or not.
 | 
| +   */
 | 
| +  num get height;
 | 
| +
 | 
| +  /**
 | 
| +   * The width of this rectangle.
 | 
| +   *
 | 
| +   * This is equivalent to the `width` function in jQuery and the calculated
 | 
| +   * `width` CSS value, converted to a dimensionless num in pixels. Unlike
 | 
| +   * [getBoundingClientRect], `width` will return the same numerical width if
 | 
| +   * the element is hidden or not.
 | 
| +   */
 | 
| +  num get width;
 | 
| +
 | 
| +  /**
 | 
| +   * Set the height to `newHeight`.
 | 
| +   *
 | 
| +   * newHeight can be either a [num] representing the height in pixels or a
 | 
| +   * [Dimension] object. Values of newHeight that are less than zero are
 | 
| +   * converted to effectively setting the height to 0. This is equivalent to the
 | 
| +   * `height` function in jQuery and the calculated `height` CSS value,
 | 
| +   * converted to a num in pixels.
 | 
| +   *
 | 
| +   * Note that only the content height can actually be set via this method.
 | 
| +   */
 | 
| +  void set height(newHeight) {
 | 
| +    throw new UnsupportedError("Can only set height for content rect.");
 | 
| +  }
 | 
| +
 | 
| +  /**
 | 
| +   * Set the current computed width in pixels of this element.
 | 
| +   *
 | 
| +   * newWidth can be either a [num] representing the width in pixels or a
 | 
| +   * [Dimension] object. This is equivalent to the `width` function in jQuery
 | 
| +   * and the calculated
 | 
| +   * `width` CSS value, converted to a dimensionless num in pixels.
 | 
| +   *
 | 
| +   * Note that only the content width can be set via this method.
 | 
| +   */
 | 
| +  void set width(newWidth) {
 | 
| +    throw new UnsupportedError("Can only set width for content rect.");
 | 
| +  }
 | 
| +
 | 
| +  /**
 | 
| +   * Return a value that is used to modify the initial height or width
 | 
| +   * measurement of an element. Depending on the value (ideally an enum) passed
 | 
| +   * to augmentingMeasurement, we may need to add or subtract margin, padding,
 | 
| +   * or border values, depending on the measurement we're trying to obtain.
 | 
| +   */
 | 
| +  num _addOrSubtractToBoxModel(List<String> dimensions,
 | 
| +      String augmentingMeasurement) {
 | 
| +    // getComputedStyle always returns pixel values (hence, computed), so we're
 | 
| +    // always dealing with pixels in this method.
 | 
| +    var styles = _element.getComputedStyle();
 | 
| +
 | 
| +    var val = 0;
 | 
| +
 | 
| +    for (String measurement in dimensions) {
 | 
| +      // The border-box and default box model both exclude margin in the regular
 | 
| +      // height/width calculation, so add it if we want it for this measurement.
 | 
| +      if (augmentingMeasurement == _MARGIN) {
 | 
| +        val += new Dimension.css(styles.getPropertyValue(
 | 
| +            '$augmentingMeasurement-$measurement')).value;
 | 
| +      }
 | 
| +
 | 
| +      // The border-box includes padding and border, so remove it if we want
 | 
| +      // just the content itself.
 | 
| +      if (augmentingMeasurement == _CONTENT) {
 | 
| +      	val -= new Dimension.css(
 | 
| +            styles.getPropertyValue('${_PADDING}-$measurement')).value;
 | 
| +      }
 | 
| +
 | 
| +      // At this point, we don't wan't to augment with border or margin,
 | 
| +      // so remove border.
 | 
| +      if (augmentingMeasurement != _MARGIN) {
 | 
| +	      val -= new Dimension.css(styles.getPropertyValue(
 | 
| +            'border-${measurement}-width')).value;
 | 
| +      }
 | 
| +    }
 | 
| +    return val;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +final _HEIGHT = ['top', 'bottom'];
 | 
| +final _WIDTH = ['right', 'left'];
 | 
| +final _CONTENT = 'content';
 | 
| +final _PADDING = 'padding';
 | 
| +final _MARGIN = 'margin';
 | 
| 
 |