Import Cobalt 12.89101

Change-Id: I225b849391c5f9c1632811b81ee2391ac2a44666
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index e6c9c94..06db324 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-88774
\ No newline at end of file
+89101
\ No newline at end of file
diff --git a/src/cobalt/input/input_poller_impl.cc b/src/cobalt/input/input_poller_impl.cc
index 008c249..847e4ef 100644
--- a/src/cobalt/input/input_poller_impl.cc
+++ b/src/cobalt/input/input_poller_impl.cc
@@ -63,30 +63,30 @@
       switch (input_event->key_code()) {
         case kSbKeyGamepadLeftStickUp: {
           key_offset_map_[kSbKeyGamepadLeftStickUp] =
-              input_event->position().y();
-          key_offset_map_[kSbKeyGamepadLeftStickDown] =
               -input_event->position().y();
+          key_offset_map_[kSbKeyGamepadLeftStickDown] =
+              input_event->position().y();
           break;
         }
         case kSbKeyGamepadLeftStickLeft: {
           key_offset_map_[kSbKeyGamepadLeftStickLeft] =
-              input_event->position().x();
-          key_offset_map_[kSbKeyGamepadLeftStickRight] =
               -input_event->position().x();
+          key_offset_map_[kSbKeyGamepadLeftStickRight] =
+              input_event->position().x();
           break;
         }
         case kSbKeyGamepadRightStickUp: {
           key_offset_map_[kSbKeyGamepadRightStickUp] =
-              input_event->position().y();
-          key_offset_map_[kSbKeyGamepadRightStickDown] =
               -input_event->position().y();
+          key_offset_map_[kSbKeyGamepadRightStickDown] =
+              input_event->position().y();
           break;
         }
         case kSbKeyGamepadRightStickLeft: {
           key_offset_map_[kSbKeyGamepadRightStickLeft] =
-              input_event->position().x();
-          key_offset_map_[kSbKeyGamepadRightStickRight] =
               -input_event->position().x();
+          key_offset_map_[kSbKeyGamepadRightStickRight] =
+              input_event->position().x();
           break;
         }
         default:
diff --git a/src/cobalt/layout/anonymous_block_box.cc b/src/cobalt/layout/anonymous_block_box.cc
index db8843f..4dd67af 100644
--- a/src/cobalt/layout/anonymous_block_box.cc
+++ b/src/cobalt/layout/anonymous_block_box.cc
@@ -40,6 +40,9 @@
 Box::Level AnonymousBlockBox::GetLevel() const { return kBlockLevel; }
 
 AnonymousBlockBox* AnonymousBlockBox::AsAnonymousBlockBox() { return this; }
+const AnonymousBlockBox* AnonymousBlockBox::AsAnonymousBlockBox() const {
+  return this;
+}
 
 void AnonymousBlockBox::SplitBidiLevelRuns() {
   ContainerBox::SplitBidiLevelRuns();
diff --git a/src/cobalt/layout/anonymous_block_box.h b/src/cobalt/layout/anonymous_block_box.h
index abaaf20..8aa09a9 100644
--- a/src/cobalt/layout/anonymous_block_box.h
+++ b/src/cobalt/layout/anonymous_block_box.h
@@ -40,6 +40,7 @@
   // From |Box|.
   Level GetLevel() const OVERRIDE;
   AnonymousBlockBox* AsAnonymousBlockBox() OVERRIDE;
+  const AnonymousBlockBox* AsAnonymousBlockBox() const OVERRIDE;
 
   void SplitBidiLevelRuns() OVERRIDE;
 
diff --git a/src/cobalt/layout/box.cc b/src/cobalt/layout/box.cc
index 1c3663f..921466e 100644
--- a/src/cobalt/layout/box.cc
+++ b/src/cobalt/layout/box.cc
@@ -142,7 +142,8 @@
   }
 }
 
-LayoutUnit Box::GetContainingBlockLeftOffset(bool stop_at_transform) const {
+Vector2dLayoutUnit Box::GetContainingBlockOffsetFromRoot(
+    bool transform_forms_root) const {
   // If the box is absolutely positioned, then its containing block is formed by
   // the padding box instead of the content box, as described in
   // http://www.w3.org/TR/CSS21/visudet.html#containing-block-details.
@@ -151,27 +152,11 @@
   // all major browsers use the padding box of a transformed ancestor as the
   // containing block for 'fixed' position elements.
   return parent_ ? IsAbsolutelyPositioned()
-                       ? GetContainingBlock()->GetPaddingBoxLeftEdge(
-                             stop_at_transform)
-                       : GetContainingBlock()->GetContentBoxLeftEdge(
-                             stop_at_transform)
-                 : LayoutUnit();
-}
-
-LayoutUnit Box::GetContainingBlockTopOffset(bool stop_at_transform) const {
-  // If the box is absolutely positioned, then its containing block is formed by
-  // the padding box instead of the content box, as described in
-  // http://www.w3.org/TR/CSS21/visudet.html#containing-block-details.
-  // NOTE: While not explicitly stated in the spec, which specifies that the
-  // containing block of a 'fixed' position element must always be the viewport,
-  // all major browsers use the padding box of a transformed ancestor as the
-  // containing block for 'fixed' position elements.
-  return parent_ ? IsAbsolutelyPositioned()
-                       ? GetContainingBlock()->GetPaddingBoxTopEdge(
-                             stop_at_transform)
-                       : GetContainingBlock()->GetContentBoxTopEdge(
-                             stop_at_transform)
-                 : LayoutUnit();
+                       ? GetContainingBlock()->GetPaddingBoxOffsetFromRoot(
+                             transform_forms_root)
+                       : GetContainingBlock()->GetContentBoxOffsetFromRoot(
+                             transform_forms_root)
+                 : Vector2dLayoutUnit();
 }
 
 void Box::SetStaticPositionLeftFromParent(LayoutUnit left) {
@@ -247,20 +232,14 @@
   return margin_top() + GetBorderBoxHeight() + margin_bottom();
 }
 
-LayoutUnit Box::GetMarginBoxLeftEdge(bool stop_at_transform) const {
-  LayoutUnit containing_block_left_offset =
-      (!stop_at_transform || !IsTransformed())
-          ? GetContainingBlockLeftOffset(stop_at_transform)
-          : LayoutUnit();
-  return containing_block_left_offset + left();
-}
-
-LayoutUnit Box::GetMarginBoxTopEdge(bool stop_at_transform) const {
-  LayoutUnit containing_block_top_offset =
-      (!stop_at_transform || !IsTransformed())
-          ? GetContainingBlockTopOffset(stop_at_transform)
-          : LayoutUnit();
-  return containing_block_top_offset + top();
+Vector2dLayoutUnit Box::GetMarginBoxOffsetFromRoot(
+    bool transform_forms_root) const {
+  Vector2dLayoutUnit containing_block_offset_from_root =
+      (!transform_forms_root || !IsTransformed())
+          ? GetContainingBlockOffsetFromRoot(transform_forms_root)
+          : Vector2dLayoutUnit();
+  return containing_block_offset_from_root +
+         margin_box_offset_from_containing_block();
 }
 
 LayoutUnit Box::GetMarginBoxRightEdgeOffsetFromContainingBlock() const {
@@ -285,6 +264,52 @@
              : GetMarginBoxRightEdgeOffsetFromContainingBlock();
 }
 
+RectLayoutUnit Box::GetBorderBoxFromRoot(bool transform_forms_root) const {
+  Vector2dLayoutUnit border_box_offset =
+      GetBorderBoxOffsetFromRoot(transform_forms_root);
+  return RectLayoutUnit(border_box_offset.x(), border_box_offset.y(),
+                        GetBorderBoxWidth(), GetBorderBoxHeight());
+}
+
+RectLayoutUnit Box::GetTransformedBorderBoxFromRoot() const {
+  // Initialize the box corners to the border box.
+  RectLayoutUnit border_box =
+      GetBorderBoxFromRoot(true /*transform_forms_root*/);
+  std::vector<math::Vector2dF> box_corners;
+  box_corners.push_back(
+      math::Vector2dF(border_box.x().toFloat(), border_box.y().toFloat()));
+  box_corners.push_back(
+      math::Vector2dF((border_box.x() + border_box.width()).toFloat(),
+                      border_box.y().toFloat()));
+  box_corners.push_back(
+      math::Vector2dF(border_box.x().toFloat(),
+                      (border_box.y() + border_box.height()).toFloat()));
+  box_corners.push_back(
+      math::Vector2dF((border_box.x() + border_box.width()).toFloat(),
+                      (border_box.y() + border_box.height()).toFloat()));
+
+  // Update the coordinates of the 4 corners by walking up to root and removing
+  // any transforms that have been applied.
+  for (const Box* check_box = this; check_box != NULL;
+       check_box = check_box->GetContainingBlock()) {
+    check_box->ApplyTransformActionToCoordinates(kExitTransform, &box_corners);
+  }
+
+  // Generate the new box from the min and max values of all of the corners.
+  math::Vector2dF& current_corner = box_corners[0];
+  math::Vector2dF min_corner(current_corner);
+  math::Vector2dF max_corner(current_corner);
+  for (size_t i = 1; i < 4; ++i) {
+    current_corner = box_corners[i];
+    min_corner.SetToMin(current_corner);
+    max_corner.SetToMax(current_corner);
+  }
+
+  return RectLayoutUnit(LayoutUnit(min_corner.x()), LayoutUnit(min_corner.y()),
+                        LayoutUnit(max_corner.x() - min_corner.x()),
+                        LayoutUnit(max_corner.y() - min_corner.y()));
+}
+
 LayoutUnit Box::GetBorderBoxWidth() const {
   return border_left_width() + GetPaddingBoxWidth() + border_right_width();
 }
@@ -293,22 +318,18 @@
   return border_top_width() + GetPaddingBoxHeight() + border_bottom_width();
 }
 
-RectLayoutUnit Box::GetBorderBox(bool stop_at_transform) const {
-  return RectLayoutUnit(GetBorderBoxLeftEdge(stop_at_transform),
-                        GetBorderBoxTopEdge(stop_at_transform),
-                        GetBorderBoxWidth(), GetBorderBoxHeight());
-}
-
 SizeLayoutUnit Box::GetBorderBoxSize() const {
   return SizeLayoutUnit(GetBorderBoxWidth(), GetBorderBoxHeight());
 }
 
-LayoutUnit Box::GetBorderBoxLeftEdge(bool stop_at_transform) const {
-  return GetMarginBoxLeftEdge(stop_at_transform) + margin_left();
+Vector2dLayoutUnit Box::GetBorderBoxOffsetFromRoot(
+    bool transform_forms_root) const {
+  return GetMarginBoxOffsetFromRoot(transform_forms_root) +
+         GetBorderBoxOffsetFromMarginBox();
 }
 
-LayoutUnit Box::GetBorderBoxTopEdge(bool stop_at_transform) const {
-  return GetMarginBoxTopEdge(stop_at_transform) + margin_top();
+Vector2dLayoutUnit Box::GetBorderBoxOffsetFromMarginBox() const {
+  return Vector2dLayoutUnit(margin_left(), margin_top());
 }
 
 LayoutUnit Box::GetPaddingBoxWidth() const {
@@ -323,12 +344,20 @@
   return SizeLayoutUnit(GetPaddingBoxWidth(), GetPaddingBoxHeight());
 }
 
-LayoutUnit Box::GetPaddingBoxLeftEdge(bool stop_at_transform) const {
-  return GetBorderBoxLeftEdge(stop_at_transform) + border_left_width();
+Vector2dLayoutUnit Box::GetPaddingBoxOffsetFromRoot(
+    bool transform_forms_root) const {
+  return GetBorderBoxOffsetFromRoot(transform_forms_root) +
+         GetPaddingBoxOffsetFromBorderBox();
 }
 
-LayoutUnit Box::GetPaddingBoxTopEdge(bool stop_at_transform) const {
-  return GetBorderBoxTopEdge(stop_at_transform) + border_top_width();
+Vector2dLayoutUnit Box::GetPaddingBoxOffsetFromBorderBox() const {
+  return Vector2dLayoutUnit(border_left_width(), border_top_width());
+}
+
+Vector2dLayoutUnit Box::GetContentBoxOffsetFromRoot(
+    bool transform_forms_root) const {
+  return GetPaddingBoxOffsetFromRoot(transform_forms_root) +
+         GetContentBoxOffsetFromPaddingBox();
 }
 
 Vector2dLayoutUnit Box::GetContentBoxOffsetFromMarginBox() const {
@@ -370,14 +399,6 @@
   return Vector2dLayoutUnit(padding_left(), padding_top());
 }
 
-LayoutUnit Box::GetContentBoxLeftEdge(bool stop_at_transform) const {
-  return GetPaddingBoxLeftEdge(stop_at_transform) + padding_left();
-}
-
-LayoutUnit Box::GetContentBoxTopEdge(bool stop_at_transform) const {
-  return GetPaddingBoxTopEdge(stop_at_transform) + padding_top();
-}
-
 LayoutUnit Box::GetInlineLevelBoxHeight() const { return GetMarginBoxHeight(); }
 
 LayoutUnit Box::GetInlineLevelTopMargin() const { return LayoutUnit(); }
@@ -649,8 +670,11 @@
 }
 
 AnonymousBlockBox* Box::AsAnonymousBlockBox() { return NULL; }
+const AnonymousBlockBox* Box::AsAnonymousBlockBox() const { return NULL; }
 ContainerBox* Box::AsContainerBox() { return NULL; }
 const ContainerBox* Box::AsContainerBox() const { return NULL; }
+TextBox* Box::AsTextBox() { return NULL; }
+const TextBox* Box::AsTextBox() const { return NULL; }
 
 #ifdef COBALT_BOX_DUMP_ENABLED
 
@@ -922,7 +946,7 @@
 }
 
 bool Box::IsUnderCoordinate(const Vector2dLayoutUnit& coordinate) const {
-  RectLayoutUnit rect = GetBorderBox(true /*stop_at_transform*/);
+  RectLayoutUnit rect = GetBorderBoxFromRoot(true /*transform_forms_root*/);
   bool res =
       coordinate.x() >= rect.x() && coordinate.x() <= rect.x() + rect.width() &&
       coordinate.y() >= rect.y() && coordinate.y() <= rect.y() + rect.height();
@@ -1589,40 +1613,69 @@
   }
 }
 
-void Box::UpdateCoordinateForTransform(math::Vector2dF* coordinate) const {
-  // If the element has a transform, it needs to be applied.
-  if (!computed_style()) {
-    return;
-  }
+void Box::ApplyTransformActionToCoordinate(TransformAction action,
+                                           math::Vector2dF* coordinate) const {
+  std::vector<math::Vector2dF> coordinate_vector;
+  coordinate_vector.push_back(*coordinate);
+  ApplyTransformActionToCoordinates(action, &coordinate_vector);
+  *coordinate = coordinate_vector[0];
+}
+
+void Box::ApplyTransformActionToCoordinates(
+    TransformAction action, std::vector<math::Vector2dF>* coordinates) const {
   const scoped_refptr<cssom::PropertyValue>& transform =
       computed_style()->transform();
-  if (transform != cssom::KeywordValue::GetNone()) {
-    LayoutUnit containing_block_left_offset =
-        GetContainingBlockLeftOffset(true /*stop_at_transform*/);
-    LayoutUnit containing_block_top_offset =
-        GetContainingBlockTopOffset(true /*stop_at_transform*/);
+  if (transform == cssom::KeywordValue::GetNone()) {
+    return;
+  }
 
-    math::Vector2dF border_box_offset(
-        (containing_block_left_offset + left() + margin_left()).toFloat(),
-        (containing_block_top_offset + top() + margin_top()).toFloat());
+  // The border box offset is calculated in two steps because we want to
+  // stop at the second transform and not the first (which is this box).
+  Vector2dLayoutUnit containing_block_offset_from_root =
+      GetContainingBlockOffsetFromRoot(true /*transform_forms_root*/);
+  Vector2dLayoutUnit border_box_offset_from_root =
+      (containing_block_offset_from_root +
+       margin_box_offset_from_containing_block() +
+       GetBorderBoxOffsetFromMarginBox());
 
-    math::RectF rect = math::RectF(PointAtOffsetFromOrigin(border_box_offset),
-                                   GetBorderBoxSize());
-    math::Matrix3F matrix =
-        GetCSSTransform(transform, computed_style()->transform_origin(), rect);
-    if (!matrix.IsIdentity()) {
-      // Transform the coordinate.
-      math::PointF transformed_point =
-          matrix.Inverse() * math::PointF(coordinate->x(), coordinate->y());
-      coordinate->set_x(transformed_point.x());
-      coordinate->set_y(transformed_point.y());
+  // Transform the coordinates.
+  math::Matrix3F matrix =
+      GetCSSTransform(transform, computed_style()->transform_origin(),
+                      math::RectF(border_box_offset_from_root.x().toFloat(),
+                                  border_box_offset_from_root.y().toFloat(),
+                                  GetBorderBoxWidth().toFloat(),
+                                  GetBorderBoxHeight().toFloat()));
+  if (!matrix.IsIdentity()) {
+    if (action == kEnterTransform) {
+      matrix = matrix.Inverse();
     }
 
-    // The transformed box forms a new coordinate system and its containing
-    // block's offset is considered (0,0) within it. Convert the coordinate to
-    // the new system.
-    *coordinate -= math::Vector2dF(containing_block_left_offset.toFloat(),
-                                   containing_block_top_offset.toFloat());
+    for (std::vector<math::Vector2dF>::iterator coordinate_iter =
+             coordinates->begin();
+         coordinate_iter != coordinates->end(); ++coordinate_iter) {
+      math::Vector2dF& coordinate = *coordinate_iter;
+      math::PointF transformed_point =
+          matrix * math::PointF(coordinate.x(), coordinate.y());
+      coordinate.set_x(transformed_point.x());
+      coordinate.set_y(transformed_point.y());
+    }
+  }
+
+  // The transformed box forms a new coordinate system and its containing
+  // block's offset is the origin within it. Update the coordinates for their
+  // new origin.
+  math::Vector2dF containing_block_offset_from_root_as_float(
+      containing_block_offset_from_root.x().toFloat(),
+      containing_block_offset_from_root.y().toFloat());
+  for (std::vector<math::Vector2dF>::iterator coordinate_iter =
+           coordinates->begin();
+       coordinate_iter != coordinates->end(); ++coordinate_iter) {
+    math::Vector2dF& coordinate = *coordinate_iter;
+    if (action == kEnterTransform) {
+      coordinate -= containing_block_offset_from_root_as_float;
+    } else {
+      coordinate += containing_block_offset_from_root_as_float;
+    }
   }
 }
 
diff --git a/src/cobalt/layout/box.h b/src/cobalt/layout/box.h
index 7686c84..580ccbd 100644
--- a/src/cobalt/layout/box.h
+++ b/src/cobalt/layout/box.h
@@ -50,6 +50,7 @@
 
 class AnonymousBlockBox;
 class ContainerBox;
+class TextBox;
 class UsedStyleProvider;
 
 struct LayoutParams {
@@ -115,6 +116,11 @@
     kIsBoxDescendant,
   };
 
+  enum TransformAction {
+    kEnterTransform,
+    kExitTransform,
+  };
+
   // Info tracked on container boxes encountered when a stacking context is
   // generating its cross references.
   struct StackingContextContainerBoxInfo {
@@ -213,13 +219,9 @@
   // out-of-flow descendants. Does not update the position of the box.
   void UpdateSize(const LayoutParams& layout_params);
 
-  // Returns the left offset from root (or a transform if |stop_at_transform| is
-  // true) to this box's containing block.
-  LayoutUnit GetContainingBlockLeftOffset(bool stop_at_transform) const;
-
-  // Returns the top offset from root (or a transform if |stop_at_transform| is
-  // true) to this box's containing block.
-  LayoutUnit GetContainingBlockTopOffset(bool stop_at_transform) const;
+  // Returns the offset from root to this box's containing block.
+  Vector2dLayoutUnit GetContainingBlockOffsetFromRoot(
+      bool transform_forms_root) const;
 
   // Used values of "left" and "top" are publicly readable and writable so that
   // they can be calculated and adjusted by the formatting context of
@@ -270,43 +272,53 @@
   // border, padding, and content boxes.
 
   // Margin box.
+  LayoutUnit margin_left() const { return margin_insets_.left(); }
+  LayoutUnit margin_top() const { return margin_insets_.top(); }
+  LayoutUnit margin_right() const { return margin_insets_.right(); }
+  LayoutUnit margin_bottom() const { return margin_insets_.bottom(); }
   LayoutUnit GetMarginBoxWidth() const;
   LayoutUnit GetMarginBoxHeight() const;
+
+  Vector2dLayoutUnit GetMarginBoxOffsetFromRoot(
+      bool transform_forms_root) const;
   const Vector2dLayoutUnit& margin_box_offset_from_containing_block() const {
     return margin_box_offset_from_containing_block_;
   }
-  LayoutUnit GetMarginBoxLeftEdge(bool stop_at_transform) const;
-  LayoutUnit GetMarginBoxTopEdge(bool stop_at_transform) const;
   LayoutUnit GetMarginBoxRightEdgeOffsetFromContainingBlock() const;
   LayoutUnit GetMarginBoxBottomEdgeOffsetFromContainingBlock() const;
   LayoutUnit GetMarginBoxStartEdgeOffsetFromContainingBlock(
       BaseDirection base_direction) const;
   LayoutUnit GetMarginBoxEndEdgeOffsetFromContainingBlock(
       BaseDirection base_direction) const;
-  LayoutUnit margin_left() const { return margin_insets_.left(); }
-  LayoutUnit margin_top() const { return margin_insets_.top(); }
-  LayoutUnit margin_right() const { return margin_insets_.right(); }
-  LayoutUnit margin_bottom() const { return margin_insets_.bottom(); }
 
   // Border box.
+  RectLayoutUnit GetBorderBoxFromRoot(bool transform_forms_root) const;
+  RectLayoutUnit GetTransformedBorderBoxFromRoot() const;
+
   LayoutUnit GetBorderBoxWidth() const;
   LayoutUnit GetBorderBoxHeight() const;
-  RectLayoutUnit GetBorderBox(bool stop_at_transform) const;
   SizeLayoutUnit GetBorderBoxSize() const;
-  LayoutUnit GetBorderBoxLeftEdge(bool stop_at_transform) const;
-  LayoutUnit GetBorderBoxTopEdge(bool stop_at_transform) const;
+
+  Vector2dLayoutUnit GetBorderBoxOffsetFromRoot(
+      bool transform_forms_root) const;
+  Vector2dLayoutUnit GetBorderBoxOffsetFromMarginBox() const;
 
   // Padding box.
   LayoutUnit GetPaddingBoxWidth() const;
   LayoutUnit GetPaddingBoxHeight() const;
   SizeLayoutUnit GetPaddingBoxSize() const;
-  LayoutUnit GetPaddingBoxLeftEdge(bool stop_at_transform) const;
-  LayoutUnit GetPaddingBoxTopEdge(bool stop_at_transform) const;
+
+  Vector2dLayoutUnit GetPaddingBoxOffsetFromRoot(
+      bool transform_forms_root) const;
+  Vector2dLayoutUnit GetPaddingBoxOffsetFromBorderBox() const;
 
   // Content box.
   LayoutUnit width() const { return content_size_.width(); }
   LayoutUnit height() const { return content_size_.height(); }
   const SizeLayoutUnit& content_box_size() const { return content_size_; }
+
+  Vector2dLayoutUnit GetContentBoxOffsetFromRoot(
+      bool transform_forms_root) const;
   Vector2dLayoutUnit GetContentBoxOffsetFromMarginBox() const;
   Vector2dLayoutUnit GetContentBoxOffsetFromPaddingBox() const;
   LayoutUnit GetContentBoxLeftEdgeOffsetFromMarginBox() const;
@@ -317,8 +329,6 @@
       BaseDirection base_direction) const;
   LayoutUnit GetContentBoxEndEdgeOffsetFromContainingBlock(
       BaseDirection base_direction) const;
-  LayoutUnit GetContentBoxLeftEdge(bool stop_at_transform) const;
-  LayoutUnit GetContentBoxTopEdge(bool stop_at_transform) const;
 
   // The height of each inline-level box in the line box is calculated. For
   // replaced elements, inline-block elements, and inline-table elements, this
@@ -486,8 +496,11 @@
 
   // Poor man's reflection.
   virtual AnonymousBlockBox* AsAnonymousBlockBox();
+  virtual const AnonymousBlockBox* AsAnonymousBlockBox() const;
   virtual ContainerBox* AsContainerBox();
   virtual const ContainerBox* AsContainerBox() const;
+  virtual TextBox* AsTextBox();
+  virtual const TextBox* AsTextBox() const;
 
 #ifdef COBALT_BOX_DUMP_ENABLED
   // Used by box generator to set a DOM node that produced this box.
@@ -549,9 +562,11 @@
   static bool IsRenderedLater(RenderSequence render_sequence,
                               RenderSequence other_render_sequence);
 
-  // Updates the passed coordinate corresponding to the transform applied to
-  // this box.
-  void UpdateCoordinateForTransform(math::Vector2dF* coordinate) const;
+  // Applies the specified transform action to the provided coordinates.
+  void ApplyTransformActionToCoordinate(TransformAction action,
+                                        math::Vector2dF* coordinate) const;
+  void ApplyTransformActionToCoordinates(
+      TransformAction action, std::vector<math::Vector2dF>* coordinates) const;
 
  protected:
   UsedStyleProvider* used_style_provider() const {
diff --git a/src/cobalt/layout/container_box.h b/src/cobalt/layout/container_box.h
index 3d184c4..a5b823f 100644
--- a/src/cobalt/layout/container_box.h
+++ b/src/cobalt/layout/container_box.h
@@ -240,6 +240,7 @@
   // This mutual friendship is a result of the need to maintain 2-way links
   // between boxes and containers.
   friend class Box;
+  friend class LayoutBoxes;
 
   DISALLOW_COPY_AND_ASSIGN(ContainerBox);
 };
diff --git a/src/cobalt/layout/layout_boxes.cc b/src/cobalt/layout/layout_boxes.cc
index 6068bac..99787b8 100644
--- a/src/cobalt/layout/layout_boxes.cc
+++ b/src/cobalt/layout/layout_boxes.cc
@@ -15,6 +15,7 @@
 #include "cobalt/layout/layout_boxes.h"
 
 #include "cobalt/cssom/keyword_value.h"
+#include "cobalt/layout/anonymous_block_box.h"
 #include "cobalt/layout/container_box.h"
 #include "cobalt/layout/rect_layout_unit.h"
 #include "cobalt/layout/size_layout_unit.h"
@@ -50,28 +51,19 @@
   //  . Replace each anonymous block box with its child box(es) and repeat this
   //    until no anonymous block boxes are left in the final list.
 
+  Boxes client_rect_boxes;
+  GetClientRectBoxes(boxes_, &client_rect_boxes);
+
   scoped_refptr<dom::DOMRectList> dom_rect_list(new dom::DOMRectList());
-  for (Boxes::const_iterator box_iterator = boxes_.begin();
-       box_iterator != boxes_.end(); ++box_iterator) {
-    Box* box = *box_iterator;
-    do {
-      scoped_refptr<dom::DOMRect> dom_rect(new dom::DOMRect());
-
-      // TODO: Take transforms into account and recurse into anonymous block
-      // boxes. Our current clients don't currently rely on GetClientRects() to
-      // do that.
-
-      dom_rect->set_x(
-          box->GetBorderBoxLeftEdge(false /*stop_at_transform*/).toFloat());
-      dom_rect->set_y(
-          box->GetBorderBoxTopEdge(false /*stop_at_transform*/).toFloat());
-      SizeLayoutUnit box_size = box->GetBorderBoxSize();
-      dom_rect->set_width(box_size.width().toFloat());
-      dom_rect->set_height(box_size.height().toFloat());
-      dom_rect_list->AppendDOMRect(dom_rect);
-
-      box = box->GetSplitSibling();
-    } while (box != NULL);
+  for (Boxes::const_iterator box_iterator = client_rect_boxes.begin();
+       box_iterator != client_rect_boxes.end(); ++box_iterator) {
+    RectLayoutUnit transformed_border_box(
+        (*box_iterator)->GetTransformedBorderBoxFromRoot());
+    dom_rect_list->AppendDOMRect(
+        new dom::DOMRect(transformed_border_box.x().toFloat(),
+                         transformed_border_box.y().toFloat(),
+                         transformed_border_box.width().toFloat(),
+                         transformed_border_box.height().toFloat()));
   }
 
   return dom_rect_list;
@@ -122,14 +114,16 @@
 float LayoutBoxes::GetPaddingEdgeLeft() const {
   DCHECK(!boxes_.empty());
   return boxes_.front()
-      ->GetPaddingBoxLeftEdge(false /*stop_at_transform*/)
+      ->GetPaddingBoxOffsetFromRoot(false /*transform_forms_root*/)
+      .x()
       .toFloat();
 }
 
 float LayoutBoxes::GetPaddingEdgeTop() const {
   DCHECK(!boxes_.empty());
   return boxes_.front()
-      ->GetPaddingBoxTopEdge(false /*stop_at_transform*/)
+      ->GetPaddingBoxOffsetFromRoot(false /*transform_forms_root*/)
+      .y()
       .toFloat();
 }
 
@@ -193,7 +187,8 @@
        box_iterator != boxes_.end(); ++box_iterator) {
     Box* box = *box_iterator;
     do {
-      bounding_rectangle.Union(box->GetBorderBox(false /*stop_at_transform*/));
+      bounding_rectangle.Union(
+          box->GetBorderBoxFromRoot(false /*transform_forms_root*/));
       box = box->GetSplitSibling();
     } while (box != NULL);
   }
@@ -204,5 +199,28 @@
                      bounding_rectangle.height().toFloat());
 }
 
+void LayoutBoxes::GetClientRectBoxes(const Boxes& boxes,
+                                     Boxes* client_rect_boxes) const {
+  for (Boxes::const_iterator box_iterator = boxes.begin();
+       box_iterator != boxes.end(); ++box_iterator) {
+    Box* box = *box_iterator;
+    do {
+      // Replace each anonymous block box with its child box(es) and repeat this
+      // until no anonymous block boxes are left in the final list.
+      const AnonymousBlockBox* anonymous_block_box = box->AsAnonymousBlockBox();
+      if (anonymous_block_box) {
+        GetClientRectBoxes(anonymous_block_box->child_boxes(),
+                           client_rect_boxes);
+      } else if (!box->AsTextBox()) {
+        // Only add the box if it isn't a text box. Text boxes are anonymous
+        // inline boxes and shouldn't be included.
+        client_rect_boxes->push_back(box);
+      }
+
+      box = box->GetSplitSibling();
+    } while (box != NULL);
+  }
+}
+
 }  // namespace layout
 }  // namespace cobalt
diff --git a/src/cobalt/layout/layout_boxes.h b/src/cobalt/layout/layout_boxes.h
index 1d49883..e2733b1 100644
--- a/src/cobalt/layout/layout_boxes.h
+++ b/src/cobalt/layout/layout_boxes.h
@@ -67,6 +67,8 @@
   // Returns the bounding rectangle of the border edges of the boxes.
   math::RectF GetBoundingBorderRectangle() const;
 
+  void GetClientRectBoxes(const Boxes& boxes, Boxes* client_rect_boxes) const;
+
   Boxes boxes_;
 };
 
diff --git a/src/cobalt/layout/text_box.cc b/src/cobalt/layout/text_box.cc
index 79d8ba6..127b1d3 100644
--- a/src/cobalt/layout/text_box.cc
+++ b/src/cobalt/layout/text_box.cc
@@ -66,6 +66,9 @@
 
 Box::Level TextBox::GetLevel() const { return kInlineLevel; }
 
+TextBox* TextBox::AsTextBox() { return this; }
+const TextBox* TextBox::AsTextBox() const { return this; }
+
 bool TextBox::ValidateUpdateSizeInputs(const LayoutParams& params) {
   // Also take into account mutable local state about (at least) whether white
   // space should be collapsed or not.
diff --git a/src/cobalt/layout/text_box.h b/src/cobalt/layout/text_box.h
index 7fb798e..240fed1 100644
--- a/src/cobalt/layout/text_box.h
+++ b/src/cobalt/layout/text_box.h
@@ -43,6 +43,8 @@
 
   // From |Box|.
   Level GetLevel() const OVERRIDE;
+  TextBox* AsTextBox() OVERRIDE;
+  const TextBox* AsTextBox() const OVERRIDE;
 
   void UpdateContentSizeAndMargins(const LayoutParams& layout_params) OVERRIDE;
 
diff --git a/src/cobalt/layout/topmost_event_target.cc b/src/cobalt/layout/topmost_event_target.cc
index 83cd9cc..44f2eb8 100644
--- a/src/cobalt/layout/topmost_event_target.cc
+++ b/src/cobalt/layout/topmost_event_target.cc
@@ -73,7 +73,10 @@
       const Boxes& boxes = layout_boxes->boxes();
       if (!boxes.empty()) {
         const Box* box = boxes.front();
-        box->UpdateCoordinateForTransform(&element_coordinate);
+        if (box->computed_style() && box->IsTransformed()) {
+          box->ApplyTransformActionToCoordinate(Box::kEnterTransform,
+                                                &element_coordinate);
+        }
         ConsiderBoxes(html_element, layout_boxes, element_coordinate);
       }
     }
diff --git a/src/cobalt/layout_tests/testdata/cssom-view/extensions_to_the_element_interface_get_bounding_client_rect_with_transform-expected.png b/src/cobalt/layout_tests/testdata/cssom-view/extensions_to_the_element_interface_get_bounding_client_rect_with_transform-expected.png
new file mode 100644
index 0000000..ae9f398
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/cssom-view/extensions_to_the_element_interface_get_bounding_client_rect_with_transform-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/cssom-view/extensions_to_the_element_interface_get_bounding_client_rect_with_transform.html b/src/cobalt/layout_tests/testdata/cssom-view/extensions_to_the_element_interface_get_bounding_client_rect_with_transform.html
new file mode 100644
index 0000000..e44fa3f
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/cssom-view/extensions_to_the_element_interface_get_bounding_client_rect_with_transform.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<!--
+ | Test CSSOM View extensions to the Element Interface, verifying that
+ | getBoundingClientRect() works properly with transforms.
+ -->
+<html>
+<head>
+  <style>
+    body {
+      background-color: #FFFFFF;
+      margin: 0px;
+      font-family: Roboto;
+      font-size: 40px;
+    }
+    .absolutely-positioned-1 {
+      position: absolute;
+      transform: translateX(100px) translateY(50px);
+      left: 30px;
+      top: 10px;
+      width: 100px;
+    }
+    .absolutely-positioned-2 {
+      position: absolute;
+      transform: translateX(10px) translateY(-50px);
+      left: 120px;
+      top: 110px;
+      width: 150px;
+    }
+  </style>
+  <script>
+    if (window.testRunner) {
+      window.testRunner.waitUntilDone();
+    }
+
+    function verifyGetBoundingClientRectAttributesAreCorrect(id) {
+      var element = document.getElementById(id);
+      if (!element) {
+        document.body.style.backgroundColor = "#F44336";
+      } else {
+        var expected_left = 130;
+        var expected_top = 60;
+
+        bounding_rect = element.getBoundingClientRect();
+        if (bounding_rect["left"] != expected_left) {
+          console.log("getElementById(\'" + id +
+                      "\').getBoundingClientRect()." + "left" + " == " +
+                      bounding_rect["left"] + " != " + expected_left);
+          element.style.backgroundColor = "#F44336";
+        }
+
+        if (bounding_rect["top"] != expected_top) {
+          console.log("getElementById(\'" + id +
+                      "\').getBoundingClientRect()." + "top" + " == " +
+                      bounding_rect["top"] + " != " + expected_top);
+          element.style.backgroundColor = "#F44336";
+        }
+      }
+    }
+
+    function runTest() {
+      verifyGetBoundingClientRectAttributesAreCorrect("span-1");
+      verifyGetBoundingClientRectAttributesAreCorrect("span-2");
+    }
+
+    window.onload = function() {
+      runTest();
+
+      if (window.testRunner) {
+        window.testRunner.notifyDone();
+      }
+    }
+  </script>
+</head>
+<body>
+  <div id="div-1" class="absolutely-positioned-1">
+    <span id="span-1">Yes</span>
+  </div>
+  <div id="div-2" class="absolutely-positioned-2">
+    <span id="span-2">Yes</span>
+  </div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/cssom-view/layout_tests.txt b/src/cobalt/layout_tests/testdata/cssom-view/layout_tests.txt
index 7c45b36..88679e8 100644
--- a/src/cobalt/layout_tests/testdata/cssom-view/layout_tests.txt
+++ b/src/cobalt/layout_tests/testdata/cssom-view/layout_tests.txt
@@ -1,4 +1,5 @@
 extensions_to_the_element_interface_client_top_left_width_height
 extensions_to_the_element_interface_get_bounding_client_rect_with_box_splitting
+extensions_to_the_element_interface_get_bounding_client_rect_with_transform
 extensions_to_the_html_element_interface_offset_top_left_width_height
-extensions_to_the_html_element_interface_offset_width_height_with_box_splitting
\ No newline at end of file
+extensions_to_the_html_element_interface_offset_width_height_with_box_splitting
diff --git a/src/cobalt/renderer/rasterizer/blitter/image.cc b/src/cobalt/renderer/rasterizer/blitter/image.cc
index f51569e..21a6b1c 100644
--- a/src/cobalt/renderer/rasterizer/blitter/image.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/image.cc
@@ -96,7 +96,8 @@
     SubmitOffscreenCallback submit_offscreen_callback, SbBlitterDevice device)
     : size_(static_cast<int>(root->GetBounds().right()),
             static_cast<int>(root->GetBounds().bottom())),
-      is_opaque_(false) {
+      is_opaque_(false),
+      surface_(kSbBlitterInvalidSurface) {
   initialize_image_ = base::Bind(
       &SinglePlaneImage::InitializeImageFromRenderTree, base::Unretained(this),
       root, submit_offscreen_callback, device);
diff --git a/src/starboard/CHANGELOG.md b/src/starboard/CHANGELOG.md
index 6bcc0d7..4b2c85c 100644
--- a/src/starboard/CHANGELOG.md
+++ b/src/starboard/CHANGELOG.md
@@ -69,6 +69,11 @@
 Add `key_statuses_changed_callback` parameter to `SbDrmCreateSystem()` to
 support MediaKeySession::keyStatuses and MediaKeySession::onkeystatuseschange.
 
+### Changes thumbstick direction
+
+Change the meaning of negative values for thumbstick position from bottom
+right to upper left.
+
 ## Version 5
 
 ### Add Speech Recognizer API
diff --git a/src/starboard/input.h b/src/starboard/input.h
index 9c1e2cc..3510230 100644
--- a/src/starboard/input.h
+++ b/src/starboard/input.h
@@ -176,7 +176,7 @@
   // The value is |0| if this data is not applicable. For events with type
   // kSbInputEventTypeMove and device_type kSbInputDeviceTypeGamepad, this field
   // is interpreted as a stick position with the range [-1, 1], with positive
-  // values for the up and left direction.
+  // values for the down and right direction.
   SbInputVector position;
 
   // The relative motion vector of this input. The value is |0| if this data is
diff --git a/src/starboard/shared/linux/dev_input/dev_input.cc b/src/starboard/shared/linux/dev_input/dev_input.cc
index d0bd7fe..27a6d10 100644
--- a/src/starboard/shared/linux/dev_input/dev_input.cc
+++ b/src/starboard/shared/linux/dev_input/dev_input.cc
@@ -987,36 +987,33 @@
   SbInputVector input_vector;
   // The mapping for the axis codes can vary from controller to controller.
   // TODO: Include axis mapping for controllers with different layout.
+  // Report up and left as negative values.
   switch (event.code) {
     case ABS_X:
-      // Report up and left as positive values.
-      input_vector.x = -axis_value;
-      input_vector.y = -device_info->axis_value[ABS_Y];
+      input_vector.x = axis_value;
+      input_vector.y = device_info->axis_value[ABS_Y];
       key = kSbKeyGamepadLeftStickLeft;
       location = kSbKeyLocationLeft;
       return CreateMoveEventWithKey(window_, key, location, modifiers,
                                     input_vector);
     case ABS_Y: {
-      // Report up and left as positive values.
-      input_vector.x = -device_info->axis_value[ABS_X];
-      input_vector.y = -axis_value;
+      input_vector.x = device_info->axis_value[ABS_X];
+      input_vector.y = axis_value;
       key = kSbKeyGamepadLeftStickUp;
       location = kSbKeyLocationLeft;
       return CreateMoveEventWithKey(window_, key, location, modifiers,
                                     input_vector);
     }
     case ABS_Z:
-      // Report up and left as positive values.
-      input_vector.x = -axis_value;
-      input_vector.y = -device_info->axis_value[ABS_RZ];
+      input_vector.x = axis_value;
+      input_vector.y = device_info->axis_value[ABS_RZ];
       key = kSbKeyGamepadRightStickLeft;
       location = kSbKeyLocationRight;
       return CreateMoveEventWithKey(window_, key, location, modifiers,
                                     input_vector);
     case ABS_RZ:
-      // Report up and left as positive values.
-      input_vector.x = -device_info->axis_value[ABS_Z];
-      input_vector.y = -axis_value;
+      input_vector.x = device_info->axis_value[ABS_Z];
+      input_vector.y = axis_value;
       key = kSbKeyGamepadRightStickUp;
       location = kSbKeyLocationRight;
       return CreateMoveEventWithKey(window_, key, location, modifiers,
@@ -1065,8 +1062,8 @@
         device_info->touchpad_position_state = kTouchPadPositionNone;
         if (touchpad_position_is_known) {
           // Touch point is released, report last known position as unpress.
-          input_vector.x = (device_info->axis_value[ABS_MT_POSITION_X] + 1 / 2);
-          input_vector.y = (device_info->axis_value[ABS_MT_POSITION_Y] + 1 / 2);
+          input_vector.x = device_info->axis_value[ABS_MT_POSITION_X] * 2;
+          input_vector.y = device_info->axis_value[ABS_MT_POSITION_Y];
           return CreateTouchPadEvent(window_, kSbInputEventTypeUnpress, key,
                                      location, modifiers, input_vector);
         }
@@ -1080,9 +1077,10 @@
                                   : kSbInputEventTypePress;
       device_info->touchpad_position_state |= kTouchPadPositionX;
       if (IsTouchpadPositionKnown(device_info)) {
-        // For touchpads, the range is [0..1].
-        input_vector.x = (axis_value + 1) / 2;
-        input_vector.y = (device_info->axis_value[ABS_MT_POSITION_Y] + 1) / 2;
+        // For touchpads, the unit range is [-1..1]. Negative values for top
+        // left.
+        input_vector.x = axis_value * 2;  // Touch are is twice as wide.
+        input_vector.y = device_info->axis_value[ABS_MT_POSITION_Y];
         return CreateTouchPadEvent(window_, type, key, location, modifiers,
                                    input_vector);
       }
@@ -1097,9 +1095,9 @@
                                   : kSbInputEventTypePress;
       device_info->touchpad_position_state |= kTouchPadPositionY;
       if (IsTouchpadPositionKnown(device_info)) {
-        // For touchpads, the range is [0..1].
-        input_vector.x = (device_info->axis_value[ABS_MT_POSITION_X] + 1) / 2;
-        input_vector.y = (axis_value + 1) / 2;
+        // For touchpads, the range is [-1..1]. Negative values for top left.
+        input_vector.x = device_info->axis_value[ABS_MT_POSITION_X] * 2;
+        input_vector.y = axis_value;
         return CreateTouchPadEvent(window_, type, key, location, modifiers,
                                    input_vector);
       }
diff --git a/src/starboard/shared/uwp/application_uwp_key_event.cc b/src/starboard/shared/uwp/application_uwp_key_event.cc
index 73b7d27..abc3ef3 100644
--- a/src/starboard/shared/uwp/application_uwp_key_event.cc
+++ b/src/starboard/shared/uwp/application_uwp_key_event.cc
@@ -207,8 +207,8 @@
     case VirtualKey::GamepadDPadDown: return kSbKeyGamepadDPadDown;
     case VirtualKey::GamepadDPadLeft: return kSbKeyGamepadDPadLeft;
     case VirtualKey::GamepadDPadRight: return kSbKeyGamepadDPadRight;
-    case VirtualKey::GamepadMenu: return kSbKeyGamepad6;
-    case VirtualKey::GamepadView: return kSbKeyGamepad5;
+    case VirtualKey::GamepadMenu: return kSbKeyMediaLaunchMediaSelect;
+    case VirtualKey::GamepadView: return kSbKeyF1;
     case VirtualKey::GamepadLeftThumbstickButton:
       return kSbKeyGamepadLeftStick;
     case VirtualKey::GamepadRightThumbstickButton:
diff --git a/src/starboard/shared/win32/audio_sink.cc b/src/starboard/shared/win32/audio_sink.cc
index 5967211..7097582 100644
--- a/src/starboard/shared/win32/audio_sink.cc
+++ b/src/starboard/shared/win32/audio_sink.cc
@@ -183,6 +183,7 @@
   uint64_t samples_played = 0;
   int queued_buffers = 0;
   bool was_playing = false;  // The player starts out playing by default.
+  double current_volume = 1.0;
   for (;;) {
     {
       ScopedLock lock(mutex_);
@@ -193,11 +194,18 @@
     int frames_in_buffer, offset_in_frames;
     bool is_playing, is_eos_reached;
     bool is_playback_rate_zero;
-    // TODO: Support |volume_| here as well...
+    bool should_set_volume;
     {
       ScopedLock lock(mutex_);
       is_playback_rate_zero = playback_rate_ == 0.0;
+      should_set_volume = current_volume != volume_;
+      current_volume = volume_;
     }
+
+    if (should_set_volume) {
+      CHECK_HRESULT_OK(source_voice_->SetVolume(current_volume));
+    }
+
     update_source_status_func_(&frames_in_buffer, &offset_in_frames,
                                &is_playing, &is_eos_reached, context_);
     if (is_playback_rate_zero) {