From 8fc1b372c1f74f06296a0eebee0d40dbd623332f Mon Sep 17 00:00:00 2001
From: "tfarina@chromium.org"
 <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Tue, 29 Nov 2011 20:25:29 +0000
Subject: views: Move the remaining files to ui/views/controls/.

BUG=104039
R=ben@chromium.org
TBR=stevenjb@chromium.org

Review URL: http://codereview.chromium.org/8687031

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112014 0039d316-1c4b-4281-b951-d872f2087c98
---
 ui/aura_shell/drag_image_view.h                    |   2 +-
 ui/views/controls/combobox/native_combobox_gtk.h   |   2 +-
 .../controls/combobox/native_combobox_views.cc     |   2 +-
 ui/views/controls/combobox/native_combobox_win.h   |   2 +-
 ui/views/controls/focusable_border.cc              |  73 +++
 ui/views/controls/focusable_border.h               |  47 ++
 ui/views/controls/image_view.cc                    | 174 +++++++
 ui/views/controls/image_view.h                     | 112 +++++
 ui/views/controls/message_box_view.cc              | 227 ++++++++++
 ui/views/controls/message_box_view.h               |  99 ++++
 ui/views/controls/native_control.cc                | 392 ++++++++++++++++
 ui/views/controls/native_control.h                 | 126 ++++++
 ui/views/controls/native_control_gtk.cc            |  93 ++++
 ui/views/controls/native_control_gtk.h             |  52 +++
 ui/views/controls/native_control_win.cc            | 226 ++++++++++
 ui/views/controls/native_control_win.h             | 101 +++++
 ui/views/controls/progress_bar.cc                  | 319 +++++++++++++
 ui/views/controls/progress_bar.h                   |  65 +++
 ui/views/controls/progress_bar_unittest.cc         |  35 ++
 ui/views/controls/resize_area.cc                   |  94 ++++
 ui/views/controls/resize_area.h                    |  54 +++
 ui/views/controls/resize_area_delegate.h           |  29 ++
 ui/views/controls/scroll_view.cc                   | 501 +++++++++++++++++++++
 ui/views/controls/scroll_view.h                    | 207 +++++++++
 ui/views/controls/scrollbar/base_scroll_bar.cc     |   2 +-
 ui/views/controls/scrollbar/bitmap_scroll_bar.cc   |   2 +-
 .../controls/scrollbar/native_scroll_bar_gtk.h     |   2 +-
 .../controls/scrollbar/native_scroll_bar_views.cc  |   2 +-
 .../controls/scrollbar/native_scroll_bar_win.h     |   2 +-
 ui/views/controls/separator.cc                     |  47 ++
 ui/views/controls/separator.h                      |  38 ++
 ui/views/controls/single_split_view.cc             | 263 +++++++++++
 ui/views/controls/single_split_view.h              | 134 ++++++
 ui/views/controls/single_split_view_listener.h     |  29 ++
 ui/views/controls/single_split_view_unittest.cc    | 180 ++++++++
 .../controls/tabbed_pane/native_tabbed_pane_gtk.h  |   2 +-
 .../controls/tabbed_pane/native_tabbed_pane_win.h  |   2 +-
 ui/views/controls/table/native_table_gtk.h         |   2 +-
 ui/views/controls/table/native_table_win.h         |   2 +-
 ui/views/controls/table/table_view.h               |   2 +-
 ui/views/controls/textfield/native_textfield_gtk.h |   2 +-
 .../controls/textfield/native_textfield_views.cc   |   2 +-
 ui/views/controls/throbber.cc                      | 178 ++++++++
 ui/views/controls/throbber.h                       | 128 ++++++
 ui/views/controls/tree/tree_view.h                 |   2 +-
 ui/views/examples/double_split_view_example.cc     |   2 +-
 ui/views/examples/message_box_example.cc           |   2 +-
 ui/views/examples/progress_bar_example.cc          |   2 +-
 ui/views/examples/scroll_view_example.h            |   2 +-
 ui/views/examples/single_split_view_example.cc     |   2 +-
 ui/views/examples/single_split_view_example.h      |   2 +-
 ui/views/examples/throbber_example.cc              |   2 +-
 ui/views/focus/focus_traversal_unittest.cc         |   2 +-
 ui/views/widget/native_widget_win.cc               |   2 +-
 54 files changed, 4049 insertions(+), 26 deletions(-)
 create mode 100644 ui/views/controls/focusable_border.cc
 create mode 100644 ui/views/controls/focusable_border.h
 create mode 100644 ui/views/controls/image_view.cc
 create mode 100644 ui/views/controls/image_view.h
 create mode 100644 ui/views/controls/message_box_view.cc
 create mode 100644 ui/views/controls/message_box_view.h
 create mode 100644 ui/views/controls/native_control.cc
 create mode 100644 ui/views/controls/native_control.h
 create mode 100644 ui/views/controls/native_control_gtk.cc
 create mode 100644 ui/views/controls/native_control_gtk.h
 create mode 100644 ui/views/controls/native_control_win.cc
 create mode 100644 ui/views/controls/native_control_win.h
 create mode 100644 ui/views/controls/progress_bar.cc
 create mode 100644 ui/views/controls/progress_bar.h
 create mode 100644 ui/views/controls/progress_bar_unittest.cc
 create mode 100644 ui/views/controls/resize_area.cc
 create mode 100644 ui/views/controls/resize_area.h
 create mode 100644 ui/views/controls/resize_area_delegate.h
 create mode 100644 ui/views/controls/scroll_view.cc
 create mode 100644 ui/views/controls/scroll_view.h
 create mode 100644 ui/views/controls/separator.cc
 create mode 100644 ui/views/controls/separator.h
 create mode 100644 ui/views/controls/single_split_view.cc
 create mode 100644 ui/views/controls/single_split_view.h
 create mode 100644 ui/views/controls/single_split_view_listener.h
 create mode 100644 ui/views/controls/single_split_view_unittest.cc
 create mode 100644 ui/views/controls/throbber.cc
 create mode 100644 ui/views/controls/throbber.h

(limited to 'ui')

diff --git a/ui/aura_shell/drag_image_view.h b/ui/aura_shell/drag_image_view.h
index ecc665c..6f92ea3 100644
--- a/ui/aura_shell/drag_image_view.h
+++ b/ui/aura_shell/drag_image_view.h
@@ -6,7 +6,7 @@
 #define UI_AURA_SHELL_DRAG_IMAGE_VIEW_H_
 #pragma once
 
-#include "views/controls/image_view.h"
+#include "ui/views/controls/image_view.h"
 
 namespace views {
 class Widget;
diff --git a/ui/views/controls/combobox/native_combobox_gtk.h b/ui/views/controls/combobox/native_combobox_gtk.h
index 9466dcd..7b08410 100644
--- a/ui/views/controls/combobox/native_combobox_gtk.h
+++ b/ui/views/controls/combobox/native_combobox_gtk.h
@@ -8,7 +8,7 @@
 
 #include "ui/base/gtk/gtk_signal.h"
 #include "ui/views/controls/combobox/native_combobox_wrapper.h"
-#include "views/controls/native_control_gtk.h"
+#include "ui/views/controls/native_control_gtk.h"
 
 namespace views {
 
diff --git a/ui/views/controls/combobox/native_combobox_views.cc b/ui/views/controls/combobox/native_combobox_views.cc
index 4c3bc63..4311b8f 100644
--- a/ui/views/controls/combobox/native_combobox_views.cc
+++ b/ui/views/controls/combobox/native_combobox_views.cc
@@ -16,13 +16,13 @@
 #include "ui/gfx/font.h"
 #include "ui/gfx/path.h"
 #include "ui/views/controls/combobox/combobox.h"
+#include "ui/views/controls/focusable_border.h"
 #include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/controls/menu/submenu_view.h"
 #include "ui/views/widget/root_view.h"
 #include "ui/views/widget/widget.h"
 #include "views/background.h"
 #include "views/border.h"
-#include "views/controls/focusable_border.h"
 
 #if defined(OS_LINUX)
 #include "ui/gfx/gtk_util.h"
diff --git a/ui/views/controls/combobox/native_combobox_win.h b/ui/views/controls/combobox/native_combobox_win.h
index ee22cee..e71e3fe 100644
--- a/ui/views/controls/combobox/native_combobox_win.h
+++ b/ui/views/controls/combobox/native_combobox_win.h
@@ -7,7 +7,7 @@
 #pragma once
 
 #include "ui/views/controls/combobox/native_combobox_wrapper.h"
-#include "views/controls/native_control_win.h"
+#include "ui/views/controls/native_control_win.h"
 
 namespace views {
 
diff --git a/ui/views/controls/focusable_border.cc b/ui/views/controls/focusable_border.cc
new file mode 100644
index 0000000..c90ee67
--- /dev/null
+++ b/ui/views/controls/focusable_border.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2011 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.
+
+#include "ui/views/controls/focusable_border.h"
+
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/insets.h"
+
+namespace {
+
+// Define the size of the insets
+const int kTopInsetSize = 4;
+const int kLeftInsetSize = 4;
+const int kBottomInsetSize = 4;
+const int kRightInsetSize = 4;
+
+// Color settings for border.
+// These are tentative, and should be derived from theme, system
+// settings and current settings.
+const SkColor kFocusedBorderColor = SK_ColorCYAN;
+const SkColor kDefaultBorderColor = SK_ColorGRAY;
+
+}  // namespace
+
+namespace views {
+
+FocusableBorder::FocusableBorder()
+    : has_focus_(false),
+      insets_(kTopInsetSize, kLeftInsetSize,
+              kBottomInsetSize, kRightInsetSize) {
+}
+
+void FocusableBorder::Paint(const View& view, gfx::Canvas* canvas) const {
+  SkRect rect;
+  rect.set(SkIntToScalar(0), SkIntToScalar(0),
+           SkIntToScalar(view.width()), SkIntToScalar(view.height()));
+  SkScalar corners[8] = {
+    // top-left
+    SkIntToScalar(insets_.left()),
+    SkIntToScalar(insets_.top()),
+    // top-right
+    SkIntToScalar(insets_.right()),
+    SkIntToScalar(insets_.top()),
+    // bottom-right
+    SkIntToScalar(insets_.right()),
+    SkIntToScalar(insets_.bottom()),
+    // bottom-left
+    SkIntToScalar(insets_.left()),
+    SkIntToScalar(insets_.bottom()),
+  };
+  SkPath path;
+  path.addRoundRect(rect, corners);
+  SkPaint paint;
+  paint.setStyle(SkPaint::kStroke_Style);
+  paint.setFlags(SkPaint::kAntiAlias_Flag);
+  // TODO(oshima): Copy what WebKit does for focused border.
+  paint.setColor(has_focus_ ? kFocusedBorderColor : kDefaultBorderColor);
+  paint.setStrokeWidth(SkIntToScalar(has_focus_ ? 2 : 1));
+
+  canvas->GetSkCanvas()->drawPath(path, paint);
+}
+
+void FocusableBorder::GetInsets(gfx::Insets* insets) const {
+  *insets = insets_;
+}
+
+void FocusableBorder::SetInsets(int top, int left, int bottom, int right) {
+  insets_.Set(top, left, bottom, right);
+}
+
+}  // namespace views
diff --git a/ui/views/controls/focusable_border.h b/ui/views/controls/focusable_border.h
new file mode 100644
index 0000000..098809b
--- /dev/null
+++ b/ui/views/controls/focusable_border.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_FOCUSABLE_BORDER_H_
+#define UI_VIEWS_CONTROLS_FOCUSABLE_BORDER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "views/border.h"
+#include "views/view.h"
+
+namespace gfx {
+class Canvas;
+class Insets;
+}
+
+namespace views {
+
+// A Border class to draw a focused border around a field (e.g textfield).
+class FocusableBorder : public Border {
+ public:
+  FocusableBorder();
+
+  // Sets the insets of the border.
+  void SetInsets(int top, int left, int bottom, int right);
+
+  // Sets the focus state.
+  void set_has_focus(bool has_focus) {
+    has_focus_ = has_focus;
+  }
+
+  // Overridden from Border:
+  virtual void Paint(const View& view, gfx::Canvas* canvas) const OVERRIDE;
+  virtual void GetInsets(gfx::Insets* insets) const OVERRIDE;
+
+ private:
+  bool has_focus_;
+  gfx::Insets insets_;
+
+  DISALLOW_COPY_AND_ASSIGN(FocusableBorder);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_FOCUSABLE_BORDER_H_
diff --git a/ui/views/controls/image_view.cc b/ui/views/controls/image_view.cc
new file mode 100644
index 0000000..92c1513
--- /dev/null
+++ b/ui/views/controls/image_view.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2011 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.
+
+#include "ui/views/controls/image_view.h"
+
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/insets.h"
+
+namespace views {
+
+ImageView::ImageView()
+    : image_size_set_(false),
+      horiz_alignment_(CENTER),
+      vert_alignment_(CENTER) {
+}
+
+ImageView::~ImageView() {
+}
+
+void ImageView::SetImage(const SkBitmap& bm) {
+  image_ = bm;
+  PreferredSizeChanged();
+  SchedulePaint();
+}
+
+void ImageView::SetImage(const SkBitmap* bm) {
+  if (bm) {
+    SetImage(*bm);
+  } else {
+    SkBitmap t;
+    SetImage(t);
+  }
+}
+
+const SkBitmap& ImageView::GetImage() {
+  return image_;
+}
+
+void ImageView::SetImageSize(const gfx::Size& image_size) {
+  image_size_set_ = true;
+  image_size_ = image_size;
+  PreferredSizeChanged();
+}
+
+bool ImageView::GetImageSize(gfx::Size* image_size) {
+  DCHECK(image_size);
+  if (image_size_set_)
+    *image_size = image_size_;
+  return image_size_set_;
+}
+
+gfx::Rect ImageView::GetImageBounds() const {
+  gfx::Size image_size(image_size_set_ ?
+    image_size_ : gfx::Size(image_.width(), image_.height()));
+  return gfx::Rect(ComputeImageOrigin(image_size), image_size);
+}
+
+void ImageView::ResetImageSize() {
+  image_size_set_ = false;
+}
+
+gfx::Size ImageView::GetPreferredSize() {
+  gfx::Insets insets = GetInsets();
+  if (image_size_set_) {
+    gfx::Size image_size;
+    GetImageSize(&image_size);
+    image_size.Enlarge(insets.width(), insets.height());
+    return image_size;
+  }
+  return gfx::Size(image_.width() + insets.width(),
+                   image_.height() + insets.height());
+}
+
+gfx::Point ImageView::ComputeImageOrigin(const gfx::Size& image_size) const {
+  gfx::Insets insets = GetInsets();
+
+  int x;
+  // In order to properly handle alignment of images in RTL locales, we need
+  // to flip the meaning of trailing and leading. For example, if the
+  // horizontal alignment is set to trailing, then we'll use left alignment for
+  // the image instead of right alignment if the UI layout is RTL.
+  Alignment actual_horiz_alignment = horiz_alignment_;
+  if (base::i18n::IsRTL() && (horiz_alignment_ != CENTER))
+    actual_horiz_alignment = (horiz_alignment_ == LEADING) ? TRAILING : LEADING;
+  switch (actual_horiz_alignment) {
+    case LEADING:  x = insets.left();                                 break;
+    case TRAILING: x = width() - insets.right() - image_size.width(); break;
+    case CENTER:   x = (width() - image_size.width()) / 2;            break;
+    default:       NOTREACHED(); x = 0;                               break;
+  }
+
+  int y;
+  switch (vert_alignment_) {
+    case LEADING:  y = insets.top();                                     break;
+    case TRAILING: y = height() - insets.bottom() - image_size.height(); break;
+    case CENTER:   y = (height() - image_size.height()) / 2;             break;
+    default:       NOTREACHED(); y = 0;                                  break;
+  }
+
+  return gfx::Point(x, y);
+}
+
+void ImageView::OnPaint(gfx::Canvas* canvas) {
+  View::OnPaint(canvas);
+
+  if (image_.empty())
+    return;
+
+  gfx::Rect image_bounds(GetImageBounds());
+  if (image_bounds.IsEmpty())
+    return;
+
+  if (image_bounds.size() != gfx::Size(image_.width(), image_.height())) {
+    // Resize case
+    image_.buildMipMap(false);
+    SkPaint paint;
+    paint.setFilterBitmap(true);
+    canvas->DrawBitmapInt(image_, 0, 0, image_.width(), image_.height(),
+        image_bounds.x(), image_bounds.y(), image_bounds.width(),
+        image_bounds.height(), true, paint);
+  } else {
+    canvas->DrawBitmapInt(image_, image_bounds.x(), image_bounds.y());
+  }
+}
+
+void ImageView::GetAccessibleState(ui::AccessibleViewState* state) {
+  state->role = ui::AccessibilityTypes::ROLE_GRAPHIC;
+  state->name = tooltip_text_;
+}
+
+void ImageView::SetHorizontalAlignment(Alignment ha) {
+  if (ha != horiz_alignment_) {
+    horiz_alignment_ = ha;
+    SchedulePaint();
+  }
+}
+
+ImageView::Alignment ImageView::GetHorizontalAlignment() const {
+  return horiz_alignment_;
+}
+
+void ImageView::SetVerticalAlignment(Alignment va) {
+  if (va != vert_alignment_) {
+    vert_alignment_ = va;
+    SchedulePaint();
+  }
+}
+
+ImageView::Alignment ImageView::GetVerticalAlignment() const {
+  return vert_alignment_;
+}
+
+void ImageView::SetTooltipText(const string16& tooltip) {
+  tooltip_text_ = tooltip;
+}
+
+string16 ImageView::GetTooltipText() const {
+  return tooltip_text_;
+}
+
+bool ImageView::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+  if (tooltip_text_.empty())
+    return false;
+
+  *tooltip = GetTooltipText();
+  return true;
+}
+
+}  // namespace views
diff --git a/ui/views/controls/image_view.h b/ui/views/controls/image_view.h
new file mode 100644
index 0000000..1149c8d
--- /dev/null
+++ b/ui/views/controls/image_view.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_IMAGE_VIEW_H_
+#define UI_VIEWS_CONTROLS_IMAGE_VIEW_H_
+#pragma once
+
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "views/view.h"
+
+namespace gfx {
+class Canvas;
+}
+
+namespace views {
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ImageView class.
+//
+// An ImageView can display an image from an SkBitmap. If a size is provided,
+// the ImageView will resize the provided image to fit if it is too big or will
+// center the image if smaller. Otherwise, the preferred size matches the
+// provided image size.
+//
+/////////////////////////////////////////////////////////////////////////////
+class VIEWS_EXPORT ImageView : public View {
+ public:
+  enum Alignment {
+    LEADING = 0,
+    CENTER,
+    TRAILING
+  };
+
+  ImageView();
+  virtual ~ImageView();
+
+  // Set the bitmap that should be displayed.
+  void SetImage(const SkBitmap& bm);
+
+  // Set the bitmap that should be displayed from a pointer. Reset the image
+  // if the pointer is NULL. The pointer contents is copied in the receiver's
+  // bitmap.
+  void SetImage(const SkBitmap* bm);
+
+  // Returns the bitmap currently displayed or NULL of none is currently set.
+  // The returned bitmap is still owned by the ImageView.
+  const SkBitmap& GetImage();
+
+  // Set the desired image size for the receiving ImageView.
+  void SetImageSize(const gfx::Size& image_size);
+
+  // Return the preferred size for the receiving view. Returns false if the
+  // preferred size is not defined, which means that the view uses the image
+  // size.
+  bool GetImageSize(gfx::Size* image_size);
+
+  // Returns the actual bounds of the visible image inside the view.
+  gfx::Rect GetImageBounds() const;
+
+  // Reset the image size to the current image dimensions.
+  void ResetImageSize();
+
+  // Set / Get the horizontal alignment.
+  void SetHorizontalAlignment(Alignment ha);
+  Alignment GetHorizontalAlignment() const;
+
+  // Set / Get the vertical alignment.
+  void SetVerticalAlignment(Alignment va);
+  Alignment GetVerticalAlignment() const;
+
+  // Set / Get the tooltip text.
+  void SetTooltipText(const string16& tooltip);
+  string16 GetTooltipText() const;
+
+  // Overriden from View
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+  virtual bool GetTooltipText(const gfx::Point& p,
+                              string16* tooltip) const OVERRIDE;
+
+ private:
+  // Compute the image origin given the desired size and the receiver alignment
+  // properties.
+  gfx::Point ComputeImageOrigin(const gfx::Size& image_size) const;
+
+  // Whether the image size is set.
+  bool image_size_set_;
+
+  // The actual image size.
+  gfx::Size image_size_;
+
+  // The underlying bitmap.
+  SkBitmap image_;
+
+  // Horizontal alignment.
+  Alignment horiz_alignment_;
+
+  // Vertical alignment.
+  Alignment vert_alignment_;
+
+  // The current tooltip text.
+  string16 tooltip_text_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImageView);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_IMAGE_VIEW_H_
diff --git a/ui/views/controls/message_box_view.cc b/ui/views/controls/message_box_view.cc
new file mode 100644
index 0000000..b9564fe
--- /dev/null
+++ b/ui/views/controls/message_box_view.cc
@@ -0,0 +1,227 @@
+// Copyright (c) 2011 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.
+
+#include "ui/views/controls/message_box_view.h"
+
+#include "base/i18n/rtl.h"
+#include "base/message_loop.h"
+#include "base/utf_string_conversions.h"
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/scoped_clipboard_writer.h"
+#include "ui/base/message_box_flags.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/layout_constants.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/window/client_view.h"
+#include "views/views_delegate.h"
+
+const int kDefaultMessageWidth = 320;
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+// MessageBoxView, public:
+
+MessageBoxView::MessageBoxView(int dialog_flags,
+                               const string16& message,
+                               const string16& default_prompt,
+                               int message_width)
+    : message_label_(new Label(message)),
+      prompt_field_(NULL),
+      icon_(NULL),
+      checkbox_(NULL),
+      message_width_(message_width) {
+  Init(dialog_flags, default_prompt);
+}
+
+MessageBoxView::MessageBoxView(int dialog_flags,
+                               const string16& message,
+                               const string16& default_prompt)
+    : message_label_(new Label(message)),
+      prompt_field_(NULL),
+      icon_(NULL),
+      checkbox_(NULL),
+      message_width_(kDefaultMessageWidth) {
+  Init(dialog_flags, default_prompt);
+}
+
+MessageBoxView::~MessageBoxView() {}
+
+string16 MessageBoxView::GetInputText() {
+  return prompt_field_ ? prompt_field_->text() : string16();
+}
+
+bool MessageBoxView::IsCheckBoxSelected() {
+  return checkbox_ ? checkbox_->checked() : false;
+}
+
+void MessageBoxView::SetIcon(const SkBitmap& icon) {
+  if (!icon_)
+    icon_ = new ImageView();
+  icon_->SetImage(icon);
+  icon_->SetBounds(0, 0, icon.width(), icon.height());
+  ResetLayoutManager();
+}
+
+void MessageBoxView::SetCheckBoxLabel(const string16& label) {
+  if (!checkbox_)
+    checkbox_ = new Checkbox(label);
+  else
+    checkbox_->SetText(label);
+  ResetLayoutManager();
+}
+
+void MessageBoxView::SetCheckBoxSelected(bool selected) {
+  if (!checkbox_)
+    return;
+  checkbox_->SetChecked(selected);
+}
+
+void MessageBoxView::GetAccessibleState(ui::AccessibleViewState* state) {
+  state->role = ui::AccessibilityTypes::ROLE_ALERT;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MessageBoxView, View overrides:
+
+void MessageBoxView::ViewHierarchyChanged(bool is_add,
+                                          View* parent,
+                                          View* child) {
+  if (child == this && is_add) {
+    if (prompt_field_)
+      prompt_field_->SelectAll();
+
+    GetWidget()->NotifyAccessibilityEvent(
+        this, ui::AccessibilityTypes::EVENT_ALERT, true);
+  }
+}
+
+bool MessageBoxView::AcceleratorPressed(const ui::Accelerator& accelerator) {
+  // We only accepts Ctrl-C.
+  DCHECK(accelerator.key_code() == 'C' && accelerator.IsCtrlDown());
+
+  // We must not intercept Ctrl-C when we have a text box and it's focused.
+  if (prompt_field_ && prompt_field_->HasFocus())
+    return false;
+
+  if (!ViewsDelegate::views_delegate)
+    return false;
+
+  ui::Clipboard* clipboard = ViewsDelegate::views_delegate->GetClipboard();
+  if (!clipboard)
+    return false;
+
+  ui::ScopedClipboardWriter scw(clipboard);
+  scw.WriteText(message_label_->GetText());
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MessageBoxView, private:
+
+void MessageBoxView::Init(int dialog_flags,
+                          const string16& default_prompt) {
+  message_label_->SetMultiLine(true);
+  message_label_->SetAllowCharacterBreak(true);
+  if (dialog_flags & ui::MessageBoxFlags::kAutoDetectAlignment) {
+    // Determine the alignment and directionality based on the first character
+    // with strong directionality.
+    base::i18n::TextDirection direction =
+        base::i18n::GetFirstStrongCharacterDirection(
+            message_label_->GetText());
+    Label::Alignment alignment;
+    if (direction == base::i18n::RIGHT_TO_LEFT)
+      alignment = Label::ALIGN_RIGHT;
+    else
+      alignment = Label::ALIGN_LEFT;
+    // In addition, we should set the RTL alignment mode as
+    // AUTO_DETECT_ALIGNMENT so that the alignment will not be flipped around
+    // in RTL locales.
+    message_label_->set_rtl_alignment_mode(Label::AUTO_DETECT_ALIGNMENT);
+    message_label_->SetHorizontalAlignment(alignment);
+  } else {
+    message_label_->SetHorizontalAlignment(Label::ALIGN_LEFT);
+  }
+
+  if (dialog_flags & ui::MessageBoxFlags::kFlagHasPromptField) {
+    prompt_field_ = new Textfield;
+    prompt_field_->SetText(default_prompt);
+  }
+
+  ResetLayoutManager();
+}
+
+void MessageBoxView::ResetLayoutManager() {
+  // Initialize the Grid Layout Manager used for this dialog box.
+  GridLayout* layout = GridLayout::CreatePanel(this);
+  SetLayoutManager(layout);
+
+  gfx::Size icon_size;
+  if (icon_)
+    icon_size = icon_->GetPreferredSize();
+
+  // Add the column set for the message displayed at the top of the dialog box.
+  // And an icon, if one has been set.
+  const int message_column_view_set_id = 0;
+  ColumnSet* column_set = layout->AddColumnSet(message_column_view_set_id);
+  if (icon_) {
+    column_set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
+                          GridLayout::FIXED, icon_size.width(),
+                          icon_size.height());
+    column_set->AddPaddingColumn(0, kUnrelatedControlHorizontalSpacing);
+  }
+  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+                        GridLayout::FIXED, message_width_, 0);
+
+  // Column set for prompt Textfield, if one has been set.
+  const int textfield_column_view_set_id = 1;
+  if (prompt_field_) {
+    column_set = layout->AddColumnSet(textfield_column_view_set_id);
+    if (icon_) {
+      column_set->AddPaddingColumn(
+          0, icon_size.width() + kUnrelatedControlHorizontalSpacing);
+    }
+    column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+                          GridLayout::USE_PREF, 0, 0);
+  }
+
+  // Column set for checkbox, if one has been set.
+  const int checkbox_column_view_set_id = 2;
+  if (checkbox_) {
+    column_set = layout->AddColumnSet(checkbox_column_view_set_id);
+    if (icon_) {
+      column_set->AddPaddingColumn(
+          0, icon_size.width() + kUnrelatedControlHorizontalSpacing);
+    }
+    column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+                          GridLayout::USE_PREF, 0, 0);
+  }
+
+  layout->StartRow(0, message_column_view_set_id);
+  if (icon_)
+    layout->AddView(icon_);
+
+  layout->AddView(message_label_);
+
+  if (prompt_field_) {
+    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+    layout->StartRow(0, textfield_column_view_set_id);
+    layout->AddView(prompt_field_);
+  }
+
+  if (checkbox_) {
+    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+    layout->StartRow(0, checkbox_column_view_set_id);
+    layout->AddView(checkbox_);
+  }
+
+  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
+}
+
+}  // namespace views
diff --git a/ui/views/controls/message_box_view.h b/ui/views/controls/message_box_view.h
new file mode 100644
index 0000000..64e1f27
--- /dev/null
+++ b/ui/views/controls/message_box_view.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_MESSAGE_BOX_VIEW_H_
+#define UI_VIEWS_CONTROLS_MESSAGE_BOX_VIEW_H_
+#pragma once
+
+#include <string>
+
+#include "base/string16.h"
+#include "views/view.h"
+
+namespace views {
+
+class Checkbox;
+class ImageView;
+class Label;
+class Textfield;
+
+// This class displays the contents of a message box. It is intended for use
+// within a constrained window, and has options for a message, prompt, OK
+// and Cancel buttons.
+class VIEWS_EXPORT MessageBoxView : public View {
+ public:
+  MessageBoxView(int dialog_flags,
+                 const string16& message,
+                 const string16& default_prompt,
+                 int message_width);
+
+  MessageBoxView(int dialog_flags,
+                 const string16& message,
+                 const string16& default_prompt);
+
+  virtual ~MessageBoxView();
+
+  // Returns the text box.
+  views::Textfield* text_box() { return prompt_field_; }
+
+  // Returns user entered data in the prompt field.
+  string16 GetInputText();
+
+  // Returns true if a checkbox is selected, false otherwise. (And false if
+  // the message box has no checkbox.)
+  bool IsCheckBoxSelected();
+
+  // Adds |icon| to the upper left of the message box or replaces the current
+  // icon. To start out, the message box has no icon.
+  void SetIcon(const SkBitmap& icon);
+
+  // Adds a checkbox with the specified label to the message box if this is the
+  // first call. Otherwise, it changes the label of the current checkbox. To
+  // start, the message box has no checkbox until this function is called.
+  void SetCheckBoxLabel(const string16& label);
+
+  // Sets the state of the check-box.
+  void SetCheckBoxSelected(bool selected);
+
+  // View:
+  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+
+ protected:
+  // View:
+  virtual void ViewHierarchyChanged(bool is_add,
+                                    views::View* parent,
+                                    views::View* child) OVERRIDE;
+  // Handles Ctrl-C and writes the message in the system clipboard.
+  virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
+
+ private:
+  // Sets up the layout manager and initializes the prompt field. This should
+  // only be called once, from the constructor.
+  void Init(int dialog_flags, const string16& default_prompt);
+
+  // Sets up the layout manager based on currently initialized views. Should be
+  // called when a view is initialized or changed.
+  void ResetLayoutManager();
+
+  // Message for the message box.
+  Label* message_label_;
+
+  // Input text field for the message box.
+  Textfield* prompt_field_;
+
+  // Icon displayed in the upper left corner of the message box.
+  ImageView* icon_;
+
+  // Checkbox for the message box.
+  Checkbox* checkbox_;
+
+  // Maximum width of the message label.
+  int message_width_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageBoxView);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_MESSAGE_BOX_VIEW_H_
diff --git a/ui/views/controls/native_control.cc b/ui/views/controls/native_control.cc
new file mode 100644
index 0000000..7edbda6
--- /dev/null
+++ b/ui/views/controls/native_control.cc
@@ -0,0 +1,392 @@
+// Copyright (c) 2011 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.
+
+#include "ui/views/controls/native_control.h"
+
+#include <atlbase.h>
+#include <atlapp.h>
+#include <atlcrack.h>
+#include <atlframe.h>
+#include <atlmisc.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/base/keycodes/keyboard_code_conversion_win.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+#include "ui/base/l10n/l10n_util_win.h"
+#include "ui/base/view_prop.h"
+#include "ui/base/win/hwnd_util.h"
+#include "ui/views/controls/native/native_view_host.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/widget/widget.h"
+#include "views/background.h"
+#include "views/border.h"
+
+using ui::ViewProp;
+
+namespace views {
+
+// Maps to the NativeControl.
+static const char* const kNativeControlKey = "__NATIVE_CONTROL__";
+
+class NativeControlContainer : public CWindowImpl<NativeControlContainer,
+                               CWindow,
+                               CWinTraits<WS_CHILD | WS_CLIPSIBLINGS |
+                                          WS_CLIPCHILDREN>> {
+ public:
+  explicit NativeControlContainer(NativeControl* parent)
+      : parent_(parent),
+        control_(NULL),
+        original_handler_(NULL) {
+  }
+
+  void Init() {
+    Create(parent_->GetWidget()->GetNativeView());
+    ::ShowWindow(m_hWnd, SW_SHOW);
+  }
+
+  virtual ~NativeControlContainer() {
+  }
+
+  // NOTE: If you add a new message, be sure and verify parent_ is valid before
+  // calling into parent_.
+  DECLARE_FRAME_WND_CLASS(L"ChromeViewsNativeControlContainer", NULL);
+  BEGIN_MSG_MAP(NativeControlContainer);
+    MSG_WM_CREATE(OnCreate);
+    MSG_WM_ERASEBKGND(OnEraseBkgnd);
+    MSG_WM_PAINT(OnPaint);
+    MSG_WM_SIZE(OnSize);
+    MSG_WM_NOTIFY(OnNotify);
+    MSG_WM_COMMAND(OnCommand);
+    MSG_WM_DESTROY(OnDestroy);
+    MSG_WM_CONTEXTMENU(OnContextMenu);
+    MSG_WM_CTLCOLORBTN(OnCtlColorBtn);
+    MSG_WM_CTLCOLORSTATIC(OnCtlColorStatic)
+  END_MSG_MAP();
+
+  HWND GetControl() {
+    return control_;
+  }
+
+  // Called when the parent is getting deleted. This control stays around until
+  // it gets the OnFinalMessage call.
+  void ResetParent() {
+    parent_ = NULL;
+  }
+
+  void OnFinalMessage(HWND hwnd) {
+    if (parent_)
+      parent_->NativeControlDestroyed();
+    delete this;
+  }
+
+ private:
+  friend class NativeControl;
+
+  LRESULT OnCreate(LPCREATESTRUCT create_struct) {
+    control_ = parent_->CreateNativeControl(m_hWnd);
+
+    // We subclass the control hwnd so we get the WM_KEYDOWN messages.
+    original_handler_ = ui::SetWindowProc(
+        control_, &NativeControl::NativeControlWndProc);
+    prop_.reset(new ViewProp(control_, kNativeControlKey , parent_));
+
+    ::ShowWindow(control_, SW_SHOW);
+    return 1;
+  }
+
+  LRESULT OnEraseBkgnd(HDC dc) {
+    return 1;
+  }
+
+  void OnPaint(HDC ignore) {
+    PAINTSTRUCT ps;
+    HDC dc = ::BeginPaint(*this, &ps);
+    ::EndPaint(*this, &ps);
+  }
+
+  void OnSize(int type, const CSize& sz) {
+    ::MoveWindow(control_, 0, 0, sz.cx, sz.cy, TRUE);
+  }
+
+  LRESULT OnCommand(UINT code, int id, HWND source) {
+    return parent_ ? parent_->OnCommand(code, id, source) : 0;
+  }
+
+  LRESULT OnNotify(int w_param, LPNMHDR l_param) {
+    if (parent_)
+      return parent_->OnNotify(w_param, l_param);
+    else
+      return 0;
+  }
+
+  void OnDestroy() {
+    if (parent_)
+      parent_->OnDestroy();
+  }
+
+  void OnContextMenu(HWND window, const POINT& location) {
+    if (parent_)
+      parent_->OnContextMenu(location);
+  }
+
+  // We need to find an ancestor with a non-null background, and
+  // ask it for a (solid color) brush that approximates
+  // the background.  The caller will use this when drawing
+  // the native control as a background color, particularly
+  // for radiobuttons and XP style pushbuttons.
+  LRESULT OnCtlColor(UINT msg, HDC dc, HWND control) {
+    const View *ancestor = parent_;
+    while (ancestor) {
+      const Background *background = ancestor->background();
+      if (background) {
+        HBRUSH brush = background->GetNativeControlBrush();
+        if (brush)
+          return reinterpret_cast<LRESULT>(brush);
+      }
+      ancestor = ancestor->parent();
+    }
+
+    // COLOR_BTNFACE is the default for dialog box backgrounds.
+    return reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_BTNFACE));
+  }
+
+  LRESULT OnCtlColorBtn(HDC dc, HWND control) {
+    return OnCtlColor(WM_CTLCOLORBTN, dc, control);
+  }
+
+  LRESULT OnCtlColorStatic(HDC dc, HWND control) {
+    return OnCtlColor(WM_CTLCOLORSTATIC, dc, control);
+  }
+
+  NativeControl* parent_;
+  HWND control_;
+
+  // Message handler that was set before we reset it.
+  WNDPROC original_handler_;
+
+  scoped_ptr<ViewProp> prop_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeControlContainer);
+};
+
+NativeControl::NativeControl() : hwnd_view_(NULL),
+                                 container_(NULL),
+                                 fixed_width_(-1),
+                                 horizontal_alignment_(CENTER),
+                                 fixed_height_(-1),
+                                 vertical_alignment_(CENTER) {
+  set_focusable(true);
+}
+
+NativeControl::~NativeControl() {
+  if (container_) {
+    container_->ResetParent();
+    ::DestroyWindow(*container_);
+  }
+}
+
+void NativeControl::ValidateNativeControl() {
+  if (hwnd_view_ == NULL) {
+    hwnd_view_ = new NativeViewHost;
+    AddChildView(hwnd_view_);
+  }
+
+  if (!container_ && IsVisible()) {
+    container_ = new NativeControlContainer(this);
+    container_->Init();
+    hwnd_view_->Attach(*container_);
+    if (!IsEnabled())
+      EnableWindow(GetNativeControlHWND(), IsEnabled());
+
+    // This message ensures that the focus border is shown.
+    ::SendMessage(container_->GetControl(),
+                  WM_CHANGEUISTATE,
+                  MAKELPARAM(UIS_CLEAR, UISF_HIDEFOCUS),
+                  0);
+  }
+}
+
+void NativeControl::ViewHierarchyChanged(bool is_add, View *parent,
+                                         View *child) {
+  if (is_add && parent != this && !container_ && GetWidget()) {
+    ValidateNativeControl();
+    Layout();
+  }
+}
+
+void NativeControl::Layout() {
+  if (!container_ && GetWidget())
+    ValidateNativeControl();
+
+  if (hwnd_view_) {
+    gfx::Rect lb = GetLocalBounds();
+
+    int x = lb.x();
+    int y = lb.y();
+    int width = lb.width();
+    int height = lb.height();
+    if (fixed_width_ > 0) {
+      width = std::min(fixed_width_, width);
+      switch (horizontal_alignment_) {
+        case LEADING:
+          // Nothing to do.
+          break;
+        case CENTER:
+          x += (lb.width() - width) / 2;
+          break;
+        case TRAILING:
+          x = x + lb.width() - width;
+          break;
+        default:
+          NOTREACHED();
+      }
+    }
+
+    if (fixed_height_ > 0) {
+      height = std::min(fixed_height_, height);
+      switch (vertical_alignment_) {
+        case LEADING:
+          // Nothing to do.
+          break;
+        case CENTER:
+          y += (lb.height() - height) / 2;
+          break;
+        case TRAILING:
+          y = y + lb.height() - height;
+          break;
+        default:
+          NOTREACHED();
+      }
+    }
+
+    hwnd_view_->SetBounds(x, y, width, height);
+  }
+}
+
+void NativeControl::OnContextMenu(const POINT& location) {
+  if (!context_menu_controller())
+    return;
+
+  if (location.x == -1 && location.y == -1)
+    ShowContextMenu(GetKeyboardContextMenuLocation(), false);
+  else
+    ShowContextMenu(gfx::Point(location), true);
+}
+
+void NativeControl::OnFocus() {
+  if (container_) {
+    DCHECK(container_->GetControl());
+    ::SetFocus(container_->GetControl());
+    if (GetWidget()) {
+      GetWidget()->NotifyAccessibilityEvent(
+          this, ui::AccessibilityTypes::EVENT_FOCUS, false);
+    }
+  }
+}
+
+HWND NativeControl::GetNativeControlHWND() {
+  if (container_)
+    return container_->GetControl();
+  else
+    return NULL;
+}
+
+void NativeControl::NativeControlDestroyed() {
+  if (hwnd_view_)
+    hwnd_view_->Detach();
+  container_ = NULL;
+}
+
+void NativeControl::SetVisible(bool f) {
+  if (f != IsVisible()) {
+    View::SetVisible(f);
+    if (!f && container_) {
+      ::DestroyWindow(*container_);
+    } else if (f && !container_) {
+      ValidateNativeControl();
+    }
+  }
+}
+
+void NativeControl::OnEnabledChanged() {
+  View::OnEnabledChanged();
+  if (GetNativeControlHWND())
+    EnableWindow(GetNativeControlHWND(), IsEnabled());
+}
+
+void NativeControl::OnPaint(gfx::Canvas* canvas) {
+}
+
+void NativeControl::VisibilityChanged(View* starting_from, bool is_visible) {
+  SetVisible(is_visible);
+}
+
+void NativeControl::SetFixedWidth(int width, Alignment alignment) {
+  DCHECK_GT(width, 0);
+  fixed_width_ = width;
+  horizontal_alignment_ = alignment;
+}
+
+void NativeControl::SetFixedHeight(int height, Alignment alignment) {
+  DCHECK_GT(height, 0);
+  fixed_height_ = height;
+  vertical_alignment_ = alignment;
+}
+
+DWORD NativeControl::GetAdditionalExStyle() const {
+  // If the UI for the view is mirrored, we should make sure we add the
+  // extended window style for a right-to-left layout so the subclass creates
+  // a mirrored HWND for the underlying control.
+  DWORD ex_style = 0;
+  if (base::i18n::IsRTL())
+    ex_style |= l10n_util::GetExtendedStyles();
+
+  return ex_style;
+}
+
+DWORD NativeControl::GetAdditionalRTLStyle() const {
+  // If the UI for the view is mirrored, we should make sure we add the
+  // extended window style for a right-to-left layout so the subclass creates
+  // a mirrored HWND for the underlying control.
+  DWORD ex_style = 0;
+  if (base::i18n::IsRTL())
+    ex_style |= l10n_util::GetExtendedTooltipStyles();
+
+  return ex_style;
+}
+
+// static
+LRESULT CALLBACK NativeControl::NativeControlWndProc(HWND window,
+                                                     UINT message,
+                                                     WPARAM w_param,
+                                                     LPARAM l_param) {
+  NativeControl* native_control = static_cast<NativeControl*>(
+      ViewProp::GetValue(window, kNativeControlKey));
+  DCHECK(native_control);
+  WNDPROC original_handler = native_control->container_->original_handler_;
+  DCHECK(original_handler);
+
+  if (message == WM_KEYDOWN &&
+      native_control->OnKeyDown(ui::KeyboardCodeForWindowsKeyCode(w_param))) {
+    return 0;
+  } else if (message == WM_SETFOCUS) {
+    // Let the focus manager know that the focus changed.
+    FocusManager* focus_manager = native_control->GetFocusManager();
+    if (focus_manager) {
+      focus_manager->SetFocusedView(native_control);
+    } else {
+      NOTREACHED();
+    }
+  } else if (message == WM_DESTROY) {
+    ui::SetWindowProc(window, reinterpret_cast<WNDPROC>(original_handler));
+    native_control->container_->prop_.reset();
+  }
+
+  return CallWindowProc(reinterpret_cast<WNDPROC>(original_handler), window,
+                        message, w_param, l_param);
+}
+
+}  // namespace views
diff --git a/ui/views/controls/native_control.h b/ui/views/controls/native_control.h
new file mode 100644
index 0000000..ba419c1
--- /dev/null
+++ b/ui/views/controls/native_control.h
@@ -0,0 +1,126 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_NATIVE_CONTROL_H_
+#define UI_VIEWS_CONTROLS_NATIVE_CONTROL_H_
+#pragma once
+
+#include <windows.h>
+
+#include "ui/base/keycodes/keyboard_codes.h"
+#include "views/view.h"
+
+namespace views {
+
+class NativeViewHost;
+class NativeControlContainer;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// NativeControl is an abstract view that is used to implement views wrapping
+// native controls. Subclasses can simply implement CreateNativeControl() to
+// wrap a new kind of control
+//
+////////////////////////////////////////////////////////////////////////////////
+class VIEWS_EXPORT NativeControl : public View {
+ public:
+   enum Alignment {
+     LEADING = 0,
+     CENTER,
+     TRAILING };
+
+  NativeControl();
+  virtual ~NativeControl();
+
+  virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
+  virtual void Layout();
+
+  // Overridden to properly set the native control state.
+  virtual void SetVisible(bool f);
+  virtual void OnEnabledChanged();
+
+  // Overridden to do nothing.
+  virtual void OnPaint(gfx::Canvas* canvas);
+
+ protected:
+  friend class NativeControlContainer;
+
+  // Overridden by sub-classes to create the windows control which is wrapped
+  virtual HWND CreateNativeControl(HWND parent_container) = 0;
+
+  // Invoked when the native control sends a WM_NOTIFY message to its parent
+  virtual LRESULT OnNotify(int w_param, LPNMHDR l_param) = 0;
+
+  // Invoked when the native control sends a WM_COMMAND message to its parent
+  virtual LRESULT OnCommand(UINT code, int id, HWND source) { return 0; }
+
+  // Invoked when the appropriate gesture for a context menu is issued.
+  virtual void OnContextMenu(const POINT& location);
+
+  // Overridden so to set the native focus to the native control.
+  virtual void OnFocus();
+
+  // Invoked when the native control sends a WM_DESTORY message to its parent.
+  virtual void OnDestroy() { }
+
+  // Return the native control
+  virtual HWND GetNativeControlHWND();
+
+  // Invoked by the native windows control when it has been destroyed. This is
+  // invoked AFTER WM_DESTORY has been sent. Any window commands send to the
+  // HWND will most likely fail.
+  void NativeControlDestroyed();
+
+  // Overridden so that the control properly reflects parent's visibility.
+  virtual void VisibilityChanged(View* starting_from, bool is_visible);
+
+  // Controls that have fixed sizes should call these methods to specify the
+  // actual size and how they should be aligned within their parent.
+  void SetFixedWidth(int width, Alignment alignment);
+  void SetFixedHeight(int height, Alignment alignment);
+
+  // Invoked when a key is pressed on the control.
+  // Should return true if the key message was processed, false otherwise.
+  virtual bool OnKeyDown(ui::KeyboardCode virtual_key_code) { return false; }
+
+  // Returns additional extended style flags. When subclasses call
+  // CreateWindowEx in order to create the underlying control, they must OR the
+  // ExStyle parameter with the value returned by this function.
+  //
+  // We currently use this method in order to add flags such as WS_EX_LAYOUTRTL
+  // to the HWND for views with right-to-left UI layout.
+  DWORD GetAdditionalExStyle() const;
+
+  // TODO(xji): we use the following temporary function as we transition the
+  // various native controls to use the right set of RTL flags. This function
+  // will go away (and be replaced by GetAdditionalExStyle()) once all the
+  // controls are properly transitioned.
+  DWORD GetAdditionalRTLStyle() const;
+
+  // This variable is protected to provide subclassers direct access. However
+  // subclassers should always check for NULL since this variable is only
+  // initialized in ValidateNativeControl().
+  NativeViewHost* hwnd_view_;
+
+  // Fixed size information.  -1 for a size means no fixed size.
+  int fixed_width_;
+  Alignment horizontal_alignment_;
+  int fixed_height_;
+  Alignment vertical_alignment_;
+
+ private:
+
+  void ValidateNativeControl();
+
+  static LRESULT CALLBACK NativeControlWndProc(HWND window, UINT message,
+                                               WPARAM w_param, LPARAM l_param);
+
+  NativeControlContainer* container_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeControl);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_NATIVE_CONTROL_H_
diff --git a/ui/views/controls/native_control_gtk.cc b/ui/views/controls/native_control_gtk.cc
new file mode 100644
index 0000000..417e8a8
--- /dev/null
+++ b/ui/views/controls/native_control_gtk.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2011 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.
+
+#include "ui/views/controls/native_control_gtk.h"
+
+#include <gtk/gtk.h>
+
+#include "base/logging.h"
+#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+
+NativeControlGtk::NativeControlGtk() {
+}
+
+NativeControlGtk::~NativeControlGtk() {
+  if (native_view())
+    gtk_widget_destroy(native_view());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlGtk, View overrides:
+
+void NativeControlGtk::OnEnabledChanged() {
+  View::OnEnabledChanged();
+  if (native_view())
+    gtk_widget_set_sensitive(native_view(), IsEnabled());
+}
+
+void NativeControlGtk::ViewHierarchyChanged(bool is_add, View* parent,
+                                            View* child) {
+  // Call the base class to hide the view if we're being removed.
+  NativeViewHost::ViewHierarchyChanged(is_add, parent, child);
+
+  if (!is_add && child == this && native_view()) {
+    Detach();
+  } else if (is_add && GetWidget() && !native_view()) {
+    // Create the widget when we're added to a valid Widget. Many
+    // controls need a parent widget to function properly.
+    CreateNativeControl();
+  }
+}
+
+void NativeControlGtk::VisibilityChanged(View* starting_from, bool is_visible) {
+  if (!native_view()) {
+    if (GetWidget())
+      CreateNativeControl();
+  } else {
+    // The view becomes visible after native control is created.
+    // Layout now.
+    Layout();
+  }
+}
+
+void NativeControlGtk::OnFocus() {
+  DCHECK(native_view());
+  gtk_widget_grab_focus(native_view());
+  GetWidget()->NotifyAccessibilityEvent(
+      parent(), ui::AccessibilityTypes::EVENT_FOCUS, true);
+}
+
+void NativeControlGtk::NativeControlCreated(GtkWidget* native_control) {
+  Attach(native_control);
+
+  // Update the newly created GtkWidget with any resident enabled state.
+  gtk_widget_set_sensitive(native_view(), IsEnabled());
+
+  // Listen for focus change event to update the FocusManager focused view.
+  g_signal_connect(native_control, "focus-in-event",
+                   G_CALLBACK(CallFocusIn), this);
+}
+
+// static
+gboolean NativeControlGtk::CallFocusIn(GtkWidget* gtk_widget,
+                                       GdkEventFocus* event,
+                                       NativeControlGtk* control) {
+  Widget* widget = Widget::GetTopLevelWidgetForNativeView(gtk_widget);
+  FocusManager* focus_manager = widget ? widget->GetFocusManager() : NULL;
+  if (!focus_manager) {
+    // TODO(jcampan): http://crbug.com/21378 Reenable this NOTREACHED() when the
+    // options page is only based on views.
+    // NOTREACHED();
+    NOTIMPLEMENTED();
+    return false;
+  }
+  focus_manager->SetFocusedView(control->focus_view());
+  return false;
+}
+
+}  // namespace views
diff --git a/ui/views/controls/native_control_gtk.h b/ui/views/controls/native_control_gtk.h
new file mode 100644
index 0000000..a72c943
--- /dev/null
+++ b/ui/views/controls/native_control_gtk.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_NATIVE_CONTROL_GTK_H_
+#define UI_VIEWS_CONTROLS_NATIVE_CONTROL_GTK_H_
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include "base/compiler_specific.h"
+#include "ui/views/controls/native/native_view_host.h"
+
+namespace views {
+
+// A View that hosts a native control.
+class NativeControlGtk : public NativeViewHost {
+ public:
+  NativeControlGtk();
+  virtual ~NativeControlGtk();
+
+  // Overridden from View:
+  virtual void OnEnabledChanged() OVERRIDE;
+
+ protected:
+  virtual void ViewHierarchyChanged(bool is_add,
+                                    View *parent,
+                                    View *child) OVERRIDE;
+  virtual void VisibilityChanged(View* starting_from, bool is_visible) OVERRIDE;
+  virtual void OnFocus() OVERRIDE;
+
+  // Called when the NativeControlGtk is attached to a View hierarchy with a
+  // valid Widget. The NativeControlGtk should use this opportunity to create
+  // its associated GtkWidget.
+  virtual void CreateNativeControl() = 0;
+
+  // MUST be called by the subclass implementation of |CreateNativeControl|
+  // immediately after creating the control GtkWidget, otherwise it won't be
+  // attached to the GtkView and will be effectively orphaned.
+  virtual void NativeControlCreated(GtkWidget* widget);
+
+ private:
+  static gboolean CallFocusIn(GtkWidget* gtk_widget,
+                              GdkEventFocus* event,
+                              NativeControlGtk* button);
+
+  DISALLOW_COPY_AND_ASSIGN(NativeControlGtk);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_NATIVE_CONTROL_GTK_H_
diff --git a/ui/views/controls/native_control_win.cc b/ui/views/controls/native_control_win.cc
new file mode 100644
index 0000000..2b71964
--- /dev/null
+++ b/ui/views/controls/native_control_win.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2011 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.
+
+#include "ui/views/controls/native_control_win.h"
+
+#include <windowsx.h>
+
+#include "base/logging.h"
+#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/base/l10n/l10n_util_win.h"
+#include "ui/base/view_prop.h"
+#include "ui/base/win/hwnd_util.h"
+#include "ui/views/controls/combobox/combobox.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/widget/widget.h"
+
+using ui::ViewProp;
+
+const char kNativeControlWinKey[] = "__NATIVE_CONTROL_WIN__";
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlWin, public:
+
+NativeControlWin::NativeControlWin() {
+}
+
+NativeControlWin::~NativeControlWin() {
+  HWND hwnd = native_view();
+  if (hwnd) {
+    // Destroy the hwnd if it still exists. Otherwise we won't have shut things
+    // down correctly, leading to leaking and crashing if another message
+    // comes in for the hwnd.
+    Detach();
+    DestroyWindow(hwnd);
+  }
+}
+
+bool NativeControlWin::ProcessMessage(UINT message,
+                                      WPARAM w_param,
+                                      LPARAM l_param,
+                                      LRESULT* result) {
+  switch (message) {
+    case WM_CONTEXTMENU:
+      ShowContextMenu(gfx::Point(GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param)));
+      *result = 0;
+      return true;
+    case WM_CTLCOLORBTN:
+    case WM_CTLCOLORSTATIC:
+      *result = GetControlColor(message, reinterpret_cast<HDC>(w_param),
+                                native_view());
+      return true;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlWin, View overrides:
+
+void NativeControlWin::OnEnabledChanged() {
+  View::OnEnabledChanged();
+  if (native_view())
+    EnableWindow(native_view(), IsEnabled());
+}
+
+void NativeControlWin::ViewHierarchyChanged(bool is_add, View* parent,
+                                            View* child) {
+  // Call the base class to hide the view if we're being removed.
+  NativeViewHost::ViewHierarchyChanged(is_add, parent, child);
+
+  // Create the HWND when we're added to a valid Widget. Many controls need a
+  // parent HWND to function properly.
+  if (is_add && GetWidget() && !native_view())
+    CreateNativeControl();
+}
+
+void NativeControlWin::VisibilityChanged(View* starting_from, bool is_visible) {
+  // We might get called due to visibility changes at any point in the
+  // hierarchy, lets check whether we are really visible or not.
+  bool visible = IsVisibleInRootView();
+  if (!visible && native_view()) {
+    // We destroy the child control HWND when we become invisible because of the
+    // performance cost of maintaining many HWNDs.
+    HWND hwnd = native_view();
+    Detach();
+    DestroyWindow(hwnd);
+  } else if (visible && !native_view()) {
+    if (GetWidget())
+      CreateNativeControl();
+  }
+  if (visible) {
+    // The view becomes visible after native control is created.
+    // Layout now.
+    Layout();
+  }
+}
+
+void NativeControlWin::OnFocus() {
+  DCHECK(native_view());
+  SetFocus(native_view());
+
+  // Since we are being wrapped by a view, accessibility should receive
+  // the super class as the focused view.
+  View* parent_view = parent();
+
+  // Due to some controls not behaving as expected without having
+  // a native win32 control, we don't always send a native (MSAA)
+  // focus notification.
+  bool send_native_event =
+      parent_view->GetClassName() != Combobox::kViewClassName &&
+      parent_view->HasFocus();
+
+  // Send the accessibility focus notification.
+  if (parent_view->GetWidget()) {
+    parent_view->GetWidget()->NotifyAccessibilityEvent(
+        parent_view, ui::AccessibilityTypes::EVENT_FOCUS, send_native_event);
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlWin, protected:
+
+void NativeControlWin::ShowContextMenu(const gfx::Point& location) {
+  if (!context_menu_controller())
+    return;
+
+  if (location.x() == -1 && location.y() == -1)
+    View::ShowContextMenu(GetKeyboardContextMenuLocation(), false);
+  else
+    View::ShowContextMenu(location, true);
+}
+
+void NativeControlWin::NativeControlCreated(HWND native_control) {
+  // Associate this object with the control's HWND so that NativeWidgetWin can
+  // find this object when it receives messages from it.
+  props_.push_back(new ViewProp(native_control, kNativeControlWinKey, this));
+  props_.push_back(ChildWindowMessageProcessor::Register(native_control, this));
+
+  // Subclass so we get WM_KEYDOWN and WM_SETFOCUS messages.
+  original_wndproc_ = ui::SetWindowProc(
+      native_control, &NativeControlWin::NativeControlWndProc);
+
+  Attach(native_control);
+  // native_view() is now valid.
+
+  // Update the newly created HWND with any resident enabled state.
+  EnableWindow(native_view(), IsEnabled());
+
+  // This message ensures that the focus border is shown.
+  SendMessage(native_view(), WM_CHANGEUISTATE,
+              MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0);
+}
+
+DWORD NativeControlWin::GetAdditionalExStyle() const {
+  // If the UI for the view is mirrored, we should make sure we add the
+  // extended window style for a right-to-left layout so the subclass creates
+  // a mirrored HWND for the underlying control.
+  DWORD ex_style = 0;
+  if (base::i18n::IsRTL())
+    ex_style |= l10n_util::GetExtendedStyles();
+
+  return ex_style;
+}
+
+DWORD NativeControlWin::GetAdditionalRTLStyle() const {
+  // If the UI for the view is mirrored, we should make sure we add the
+  // extended window style for a right-to-left layout so the subclass creates
+  // a mirrored HWND for the underlying control.
+  DWORD ex_style = 0;
+  if (base::i18n::IsRTL())
+    ex_style |= l10n_util::GetExtendedTooltipStyles();
+
+  return ex_style;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlWin, private:
+
+LRESULT NativeControlWin::GetControlColor(UINT message, HDC dc, HWND sender) {
+  View *ancestor = this;
+  while (ancestor) {
+    const Background* background = ancestor->background();
+    if (background) {
+      HBRUSH brush = background->GetNativeControlBrush();
+      if (brush)
+        return reinterpret_cast<LRESULT>(brush);
+    }
+    ancestor = ancestor->parent();
+  }
+
+  // COLOR_BTNFACE is the default for dialog box backgrounds.
+  return reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_BTNFACE));
+}
+
+// static
+LRESULT NativeControlWin::NativeControlWndProc(HWND window,
+                                               UINT message,
+                                               WPARAM w_param,
+                                               LPARAM l_param) {
+  NativeControlWin* native_control = reinterpret_cast<NativeControlWin*>(
+      ViewProp::GetValue(window, kNativeControlWinKey));
+  DCHECK(native_control);
+
+  if (message == WM_KEYDOWN &&
+      native_control->OnKeyDown(static_cast<int>(w_param))) {
+      return 0;
+  } else if (message == WM_SETFOCUS) {
+    // Let the focus manager know that the focus changed.
+    FocusManager* focus_manager = native_control->GetFocusManager();
+    if (focus_manager) {
+      focus_manager->SetFocusedView(native_control->focus_view());
+    } else {
+      NOTREACHED();
+    }
+  } else if (message == WM_DESTROY) {
+    native_control->props_.reset();
+    ui::SetWindowProc(window, native_control->original_wndproc_);
+  }
+
+  return CallWindowProc(native_control->original_wndproc_, window, message,
+                        w_param, l_param);
+}
+
+}  // namespace views
diff --git a/ui/views/controls/native_control_win.h b/ui/views/controls/native_control_win.h
new file mode 100644
index 0000000..f8a002b
--- /dev/null
+++ b/ui/views/controls/native_control_win.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
+#define UI_VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/views/controls/native/native_view_host.h"
+#include "ui/views/widget/child_window_message_processor.h"
+
+namespace ui {
+class ViewProp;
+}
+
+namespace views {
+
+// A View that hosts a native Windows control.
+class NativeControlWin : public ChildWindowMessageProcessor,
+                         public NativeViewHost {
+ public:
+  NativeControlWin();
+  virtual ~NativeControlWin();
+
+  // Called by our subclassed window procedure when a WM_KEYDOWN message is
+  // received by the HWND created by an object derived from NativeControlWin.
+  // Returns true if the key was processed, false otherwise.
+  virtual bool OnKeyDown(int vkey) { return false; }
+
+  // Overridden from ChildWindowMessageProcessor:
+  virtual bool ProcessMessage(UINT message,
+                              WPARAM w_param,
+                              LPARAM l_param,
+                              LRESULT* result) OVERRIDE;
+
+  // Overridden from View:
+  virtual void OnEnabledChanged() OVERRIDE;
+
+ protected:
+  virtual void ViewHierarchyChanged(bool is_add,
+                                    View* parent,
+                                    View* child) OVERRIDE;
+  virtual void VisibilityChanged(View* starting_from, bool is_visible) OVERRIDE;
+  virtual void OnFocus() OVERRIDE;
+
+  // Called by the containing NativeWidgetWin when a WM_CONTEXTMENU message is
+  // received from the HWND created by an object derived from NativeControlWin.
+  virtual void ShowContextMenu(const gfx::Point& location);
+
+  // Called when the NativeControlWin is attached to a View hierarchy with a
+  // valid Widget. The NativeControlWin should use this opportunity to create
+  // its associated HWND.
+  virtual void CreateNativeControl() = 0;
+
+  // MUST be called by the subclass implementation of |CreateNativeControl|
+  // immediately after creating the control HWND, otherwise it won't be attached
+  // to the NativeViewHost and will be effectively orphaned.
+  virtual void NativeControlCreated(HWND native_control);
+
+  // Returns additional extended style flags. When subclasses call
+  // CreateWindowEx in order to create the underlying control, they must OR the
+  // ExStyle parameter with the value returned by this function.
+  //
+  // We currently use this method in order to add flags such as WS_EX_LAYOUTRTL
+  // to the HWND for views with right-to-left UI layout.
+  DWORD GetAdditionalExStyle() const;
+
+  // TODO(xji): we use the following temporary function as we transition the
+  // various native controls to use the right set of RTL flags. This function
+  // will go away (and be replaced by GetAdditionalExStyle()) once all the
+  // controls are properly transitioned.
+  DWORD GetAdditionalRTLStyle() const;
+
+ private:
+  typedef ScopedVector<ui::ViewProp> ViewProps;
+
+  // Called by the containing NativeWidgetWin when a message of type
+  // WM_CTLCOLORBTN or WM_CTLCOLORSTATIC is sent from the HWND created by an
+  // object derived from NativeControlWin.
+  LRESULT GetControlColor(UINT message, HDC dc, HWND sender);
+
+  // Our subclass window procedure for the attached control.
+  static LRESULT CALLBACK NativeControlWndProc(HWND window,
+                                               UINT message,
+                                               WPARAM w_param,
+                                               LPARAM l_param);
+
+  // The window procedure before we subclassed.
+  WNDPROC original_wndproc_;
+
+  ViewProps props_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeControlWin);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
diff --git a/ui/views/controls/progress_bar.cc b/ui/views/controls/progress_bar.cc
new file mode 100644
index 0000000..74943bb
--- /dev/null
+++ b/ui/views/controls/progress_bar.cc
@@ -0,0 +1,319 @@
+// Copyright (c) 2011 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.
+
+#include "ui/views/controls/progress_bar.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
+#include "third_party/skia/include/effects/SkGradientShader.h"
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/gfx/canvas_skia.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/insets.h"
+#include "views/background.h"
+#include "views/border.h"
+#include "views/painter.h"
+
+namespace {
+
+// Corner radius for the progress bar's border.
+const int kCornerRadius = 3;
+
+// Progress bar's border width
+const int kBorderWidth = 1;
+
+void AddRoundRectPathWithPadding(int x, int y,
+                                 int w, int h,
+                                 int corner_radius,
+                                 SkScalar padding,
+                                 SkPath* path) {
+  DCHECK(path);
+  if (path == NULL)
+    return;
+  SkRect rect;
+  rect.set(
+      SkIntToScalar(x) + padding, SkIntToScalar(y) + padding,
+      SkIntToScalar(x + w) - padding, SkIntToScalar(y + h) - padding);
+  path->addRoundRect(
+      rect,
+      SkIntToScalar(corner_radius) - padding,
+      SkIntToScalar(corner_radius) - padding);
+}
+
+void AddRoundRectPath(int x, int y,
+                      int w, int h,
+                      int corner_radius,
+                      SkPath* path) {
+  static const SkScalar half = SkIntToScalar(1) / 2;
+  AddRoundRectPathWithPadding(x, y, w, h, corner_radius, half, path);
+}
+
+void FillRoundRect(gfx::Canvas* canvas,
+                   int x, int y,
+                   int w, int h,
+                   int corner_radius,
+                   const SkColor colors[],
+                   const SkScalar points[],
+                   int count,
+                   bool gradient_horizontal) {
+  SkPath path;
+  AddRoundRectPath(x, y, w, h, corner_radius, &path);
+  SkPaint paint;
+  paint.setStyle(SkPaint::kFill_Style);
+  paint.setFlags(SkPaint::kAntiAlias_Flag);
+
+  SkPoint p[2];
+  p[0].set(SkIntToScalar(x), SkIntToScalar(y));
+  if (gradient_horizontal) {
+    p[1].set(SkIntToScalar(x + w), SkIntToScalar(y));
+  } else {
+    p[1].set(SkIntToScalar(x), SkIntToScalar(y + h));
+  }
+  SkShader* s = SkGradientShader::CreateLinear(
+      p, colors, points, count, SkShader::kClamp_TileMode, NULL);
+  paint.setShader(s);
+  // Need to unref shader, otherwise never deleted.
+  s->unref();
+
+  canvas->GetSkCanvas()->drawPath(path, paint);
+}
+
+void FillRoundRect(gfx::Canvas* canvas,
+                   int x, int y,
+                   int w, int h,
+                   int corner_radius,
+                   SkColor gradient_start_color,
+                   SkColor gradient_end_color,
+                   bool gradient_horizontal) {
+  if (gradient_start_color != gradient_end_color) {
+    SkColor colors[2] = { gradient_start_color, gradient_end_color };
+    FillRoundRect(canvas, x, y, w, h, corner_radius,
+                  colors, NULL, 2, gradient_horizontal);
+  } else {
+    SkPath path;
+    AddRoundRectPath(x, y, w, h, corner_radius, &path);
+    SkPaint paint;
+    paint.setStyle(SkPaint::kFill_Style);
+    paint.setFlags(SkPaint::kAntiAlias_Flag);
+    paint.setColor(gradient_start_color);
+    canvas->GetSkCanvas()->drawPath(path, paint);
+  }
+}
+
+void StrokeRoundRect(gfx::Canvas* canvas,
+                     int x, int y,
+                     int w, int h,
+                     int corner_radius,
+                     SkColor stroke_color,
+                     int stroke_width) {
+  SkPath path;
+  AddRoundRectPath(x, y, w, h, corner_radius, &path);
+  SkPaint paint;
+  paint.setShader(NULL);
+  paint.setColor(stroke_color);
+  paint.setStyle(SkPaint::kStroke_Style);
+  paint.setFlags(SkPaint::kAntiAlias_Flag);
+  paint.setStrokeWidth(SkIntToScalar(stroke_width));
+  canvas->GetSkCanvas()->drawPath(path, paint);
+}
+
+}  // namespace
+
+namespace views {
+
+// static
+const char ProgressBar::kViewClassName[] = "views/ProgressBar";
+
+ProgressBar::ProgressBar()
+    : min_display_value_(0.0),
+      max_display_value_(1.0),
+      current_value_(0.0) {
+}
+
+ProgressBar::~ProgressBar() {
+}
+
+void ProgressBar::SetDisplayRange(double min_display_value,
+                                  double max_display_value) {
+  if (min_display_value != min_display_value_ ||
+      max_display_value != max_display_value_) {
+    DCHECK(min_display_value < max_display_value);
+    min_display_value_ = min_display_value;
+    max_display_value_ = max_display_value;
+    SchedulePaint();
+  }
+}
+
+void ProgressBar::SetValue(double value) {
+  if (value != current_value_) {
+    current_value_ = value;
+    SchedulePaint();
+  }
+}
+
+void ProgressBar::SetTooltipText(const string16& tooltip_text) {
+  tooltip_text_ = tooltip_text;
+}
+
+bool ProgressBar::GetTooltipText(const gfx::Point& p, string16* tooltip) const {
+  DCHECK(tooltip);
+  if (tooltip == NULL)
+    return false;
+  tooltip->assign(tooltip_text_);
+  return !tooltip_text_.empty();
+}
+
+void ProgressBar::GetAccessibleState(ui::AccessibleViewState* state) {
+  state->role = ui::AccessibilityTypes::ROLE_PROGRESSBAR;
+  state->state = ui::AccessibilityTypes::STATE_READONLY;
+}
+
+gfx::Size ProgressBar::GetPreferredSize() {
+  return gfx::Size(100, 16);
+}
+
+std::string ProgressBar::GetClassName() const {
+  return kViewClassName;
+}
+
+void ProgressBar::OnPaint(gfx::Canvas* canvas) {
+  const double capped_value = std::min(
+      std::max(current_value_, min_display_value_), max_display_value_);
+  const double capped_fraction =
+      (capped_value - min_display_value_) /
+      (max_display_value_ - min_display_value_);
+  const int progress_width = static_cast<int>(width() * capped_fraction + 0.5);
+
+#if defined(OS_CHROMEOS)
+  const SkColor background_colors[] = {
+    SkColorSetRGB(0xBB, 0xBB, 0xBB),
+    SkColorSetRGB(0xE7, 0xE7, 0xE7),
+    SkColorSetRGB(0xFE, 0xFE, 0xFE)
+  };
+
+  const SkScalar background_points[] = {
+    SkDoubleToScalar(0),
+    SkDoubleToScalar(0.1),
+    SkDoubleToScalar(1)
+  };
+  const SkColor background_border_color = SkColorSetRGB(0xA1, 0xA1, 0xA1);
+
+  // Draw background.
+  FillRoundRect(canvas,
+                0, 0, width(), height(),
+                kCornerRadius,
+                background_colors,
+                background_points,
+                arraysize(background_colors),
+                false);
+  StrokeRoundRect(canvas,
+                  0, 0,
+                  width(), height(),
+                  kCornerRadius,
+                  background_border_color,
+                  kBorderWidth);
+
+  if (progress_width > 1) {
+    const bool enabled = IsEnabled();
+
+    const SkColor bar_color_start = enabled ?
+        SkColorSetRGB(100, 116, 147) :
+        SkColorSetRGB(229, 232, 237);
+    const SkColor bar_color_end = enabled ?
+        SkColorSetRGB(65, 73, 87) :
+        SkColorSetRGB(224, 225, 227);
+
+    const SkColor bar_outer_color = enabled ?
+        SkColorSetRGB(0x4A, 0x4A, 0x4A) :
+        SkColorSetARGB(0x80, 0x4A, 0x4A, 0x4A);
+
+    const SkColor bar_inner_border_color =
+        SkColorSetARGB(0x3F, 0xFF, 0xFF, 0xFF);  // 0.25 white
+    const SkColor bar_inner_shadow_color =
+        SkColorSetARGB(0x54, 0xFF, 0xFF, 0xFF);  // 0.33 white
+
+    // Draw bar background
+    FillRoundRect(canvas,
+                  0, 0, progress_width, height(),
+                  kCornerRadius,
+                  bar_color_start,
+                  bar_color_end,
+                  false);
+
+    // Draw inner stroke and shadow if wide enough.
+    if (progress_width > 2 * kBorderWidth) {
+      canvas->GetSkCanvas()->save();
+
+      SkPath inner_path;
+      AddRoundRectPathWithPadding(
+          0, 0, progress_width, height(),
+          kCornerRadius,
+          SkIntToScalar(kBorderWidth),
+          &inner_path);
+      canvas->GetSkCanvas()->clipPath(inner_path);
+
+      // Draw bar inner stroke
+      StrokeRoundRect(canvas,
+                      kBorderWidth, kBorderWidth,
+                      progress_width - 2 * kBorderWidth,
+                      height() - 2 * kBorderWidth,
+                      kCornerRadius - kBorderWidth,
+                      bar_inner_border_color,
+                      kBorderWidth);
+
+      // Draw bar inner shadow
+      StrokeRoundRect(canvas,
+                      0, kBorderWidth, progress_width, height(),
+                      kCornerRadius,
+                      bar_inner_shadow_color,
+                      kBorderWidth);
+
+      canvas->GetSkCanvas()->restore();
+    }
+
+    // Draw bar stroke
+    StrokeRoundRect(canvas,
+                    0, 0, progress_width, height(),
+                    kCornerRadius,
+                    bar_outer_color,
+                    kBorderWidth);
+  }
+#else
+  SkColor bar_color_start = SkColorSetRGB(81, 138, 223);
+  SkColor bar_color_end = SkColorSetRGB(51, 103, 205);
+  SkColor background_color_start = SkColorSetRGB(212, 212, 212);
+  SkColor background_color_end = SkColorSetRGB(252, 252, 252);
+  SkColor border_color = SkColorSetRGB(144, 144, 144);
+
+  FillRoundRect(canvas,
+                0, 0, width(), height(),
+                kCornerRadius,
+                background_color_start,
+                background_color_end,
+                false);
+  if (progress_width > 1) {
+    FillRoundRect(canvas,
+                  0, 0,
+                  progress_width, height(),
+                  kCornerRadius,
+                  bar_color_start,
+                  bar_color_end,
+                  false);
+  }
+  StrokeRoundRect(canvas,
+                  0, 0,
+                  width(), height(),
+                  kCornerRadius,
+                  border_color,
+                  kBorderWidth);
+#endif
+}
+
+}  // namespace views
diff --git a/ui/views/controls/progress_bar.h b/ui/views/controls/progress_bar.h
new file mode 100644
index 0000000..02674de
--- /dev/null
+++ b/ui/views/controls/progress_bar.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_PROGRESS_BAR_H_
+#define UI_VIEWS_CONTROLS_PROGRESS_BAR_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "views/view.h"
+
+namespace views {
+
+// Progress bar is a control that indicates progress visually.
+class VIEWS_EXPORT ProgressBar : public View {
+ public:
+  // The value range defaults to [0.0, 1.0].
+  ProgressBar();
+  virtual ~ProgressBar();
+
+  double current_value() const { return current_value_; }
+
+  // Sets the inclusive range of values to be displayed.  Values outside of the
+  // range will be capped when displayed.
+  void SetDisplayRange(double min_display_value, double max_display_value);
+
+  // Sets the current value.  Values outside of the range [min_display_value_,
+  // max_display_value_] will be stored unmodified and capped for display.
+  void SetValue(double value);
+
+  // Sets the tooltip text.  Default behavior for a progress bar is to show no
+  // tooltip on mouse hover. Calling this lets you set a custom tooltip.  To
+  // revert to default behavior, call this with an empty string.
+  void SetTooltipText(const string16& tooltip_text);
+
+  // Overridden from View:
+  virtual bool GetTooltipText(const gfx::Point& p,
+                              string16* tooltip) const OVERRIDE;
+  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+
+ private:
+  static const char kViewClassName[];
+
+  // Overridden from View:
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+  virtual std::string GetClassName() const OVERRIDE;
+  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+
+  // Inclusive range used when displaying values.
+  double min_display_value_;
+  double max_display_value_;
+
+  // Current value.  May be outside of [min_display_value_, max_display_value_].
+  double current_value_;
+
+  // Tooltip text.
+  string16 tooltip_text_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProgressBar);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_PROGRESS_BAR_H_
diff --git a/ui/views/controls/progress_bar_unittest.cc b/ui/views/controls/progress_bar_unittest.cc
new file mode 100644
index 0000000..71cdb20
--- /dev/null
+++ b/ui/views/controls/progress_bar_unittest.cc
@@ -0,0 +1,35 @@
+// Copyright (c) 2011 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.
+
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/views/controls/progress_bar.h"
+
+namespace views {
+
+TEST(ProgressBarTest, TooltipTextProperty) {
+  ProgressBar bar;
+  string16 tooltip = ASCIIToUTF16("Some text");
+  EXPECT_FALSE(bar.GetTooltipText(gfx::Point(), &tooltip));
+  EXPECT_EQ(string16(), tooltip);
+  string16 tooltip_text = ASCIIToUTF16("My progress");
+  bar.SetTooltipText(tooltip_text);
+  EXPECT_TRUE(bar.GetTooltipText(gfx::Point(), &tooltip));
+  EXPECT_EQ(tooltip_text, tooltip);
+}
+
+TEST(ProgressBarTest, Accessibility) {
+  ProgressBar bar;
+  bar.SetValue(62);
+
+  ui::AccessibleViewState state;
+  bar.GetAccessibleState(&state);
+  EXPECT_EQ(ui::AccessibilityTypes::ROLE_PROGRESSBAR, state.role);
+  EXPECT_EQ(string16(), state.name);
+  EXPECT_TRUE(ui::AccessibilityTypes::STATE_READONLY & state.state);
+}
+
+}  // namespace views
diff --git a/ui/views/controls/resize_area.cc b/ui/views/controls/resize_area.cc
new file mode 100644
index 0000000..832ebec
--- /dev/null
+++ b/ui/views/controls/resize_area.cc
@@ -0,0 +1,94 @@
+// Copyright (c) 2011 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.
+
+#include "ui/views/controls/resize_area.h"
+
+#include "base/logging.h"
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/views/controls/resize_area_delegate.h"
+
+#if defined(OS_LINUX)
+#include "ui/gfx/gtk_util.h"
+#endif
+
+#if defined(USE_AURA)
+#include "ui/aura/cursor.h"
+#endif
+
+namespace views {
+
+const char ResizeArea::kViewClassName[] = "views/ResizeArea";
+
+////////////////////////////////////////////////////////////////////////////////
+// ResizeArea
+
+ResizeArea::ResizeArea(ResizeAreaDelegate* delegate)
+    : delegate_(delegate),
+      initial_position_(0) {
+}
+
+ResizeArea::~ResizeArea() {
+}
+
+std::string ResizeArea::GetClassName() const {
+  return kViewClassName;
+}
+
+gfx::NativeCursor ResizeArea::GetCursor(const MouseEvent& event) {
+  if (!IsEnabled())
+    return gfx::kNullCursor;
+#if defined(USE_AURA)
+  return aura::kCursorEastWestResize;
+#elif defined(OS_WIN)
+  static HCURSOR g_resize_cursor = LoadCursor(NULL, IDC_SIZEWE);
+  return g_resize_cursor;
+#elif defined(OS_LINUX)
+  return gfx::GetCursor(GDK_SB_H_DOUBLE_ARROW);
+#endif
+}
+
+bool ResizeArea::OnMousePressed(const views::MouseEvent& event) {
+  if (!event.IsOnlyLeftMouseButton())
+    return false;
+
+  // The resize area obviously will move once you start dragging so we need to
+  // convert coordinates to screen coordinates so that we don't lose our
+  // bearings.
+  gfx::Point point(event.x(), 0);
+  View::ConvertPointToScreen(this, &point);
+  initial_position_ = point.x();
+
+  return true;
+}
+
+bool ResizeArea::OnMouseDragged(const views::MouseEvent& event) {
+  if (!event.IsLeftMouseButton())
+    return false;
+
+  ReportResizeAmount(event.x(), false);
+  return true;
+}
+
+void ResizeArea::OnMouseReleased(const views::MouseEvent& event) {
+  ReportResizeAmount(event.x(), true);
+}
+
+void ResizeArea::OnMouseCaptureLost() {
+  ReportResizeAmount(initial_position_, true);
+}
+
+void ResizeArea::GetAccessibleState(ui::AccessibleViewState* state) {
+  state->role = ui::AccessibilityTypes::ROLE_SEPARATOR;
+}
+
+void ResizeArea::ReportResizeAmount(int resize_amount, bool last_update) {
+  gfx::Point point(resize_amount, 0);
+  View::ConvertPointToScreen(this, &point);
+  resize_amount = point.x() - initial_position_;
+  delegate_->OnResize(base::i18n::IsRTL() ? -resize_amount : resize_amount,
+                      last_update);
+}
+
+}  // namespace views
diff --git a/ui/views/controls/resize_area.h b/ui/views/controls/resize_area.h
new file mode 100644
index 0000000..1cebd9d
--- /dev/null
+++ b/ui/views/controls/resize_area.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_RESIZE_AREA_H_
+#define UI_VIEWS_CONTROLS_RESIZE_AREA_H_
+#pragma once
+
+#include <string>
+
+#include "views/view.h"
+
+namespace views {
+
+class ResizeAreaDelegate;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// An invisible area that acts like a horizontal resizer.
+//
+////////////////////////////////////////////////////////////////////////////////
+class VIEWS_EXPORT ResizeArea : public View {
+ public:
+  static const char kViewClassName[];
+
+  explicit ResizeArea(ResizeAreaDelegate* delegate);
+  virtual ~ResizeArea();
+
+  // Overridden from views::View:
+  virtual std::string GetClassName() const OVERRIDE;
+  virtual gfx::NativeCursor GetCursor(const views::MouseEvent& event) OVERRIDE;
+  virtual bool OnMousePressed(const views::MouseEvent& event) OVERRIDE;
+  virtual bool OnMouseDragged(const views::MouseEvent& event) OVERRIDE;
+  virtual void OnMouseReleased(const views::MouseEvent& event) OVERRIDE;
+  virtual void OnMouseCaptureLost() OVERRIDE;
+  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+
+ private:
+  // Report the amount the user resized by to the delegate, accounting for
+  // directionality.
+  void ReportResizeAmount(int resize_amount, bool last_update);
+
+  // The delegate to notify when we have updates.
+  ResizeAreaDelegate* delegate_;
+
+  // The mouse position at start (in screen coordinates).
+  int initial_position_;
+
+  DISALLOW_COPY_AND_ASSIGN(ResizeArea);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_RESIZE_AREA_H_
diff --git a/ui/views/controls/resize_area_delegate.h b/ui/views/controls/resize_area_delegate.h
new file mode 100644
index 0000000..ad8b3bf
--- /dev/null
+++ b/ui/views/controls/resize_area_delegate.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_RESIZE_AREA_DELEGATE_H_
+#define UI_VIEWS_CONTROLS_RESIZE_AREA_DELEGATE_H_
+#pragma once
+
+namespace views {
+
+// An interface implemented by objects that want to be notified about the resize
+// event.
+class ResizeAreaDelegate {
+ public:
+  // OnResize is sent when resizing is detected. |resize_amount| specifies the
+  // number of pixels that the user wants to resize by, and can be negative or
+  // positive (depending on direction of dragging and flips according to
+  // locale directionality: dragging to the left in LTR locales gives negative
+  // |resize_amount| but positive amount for RTL). |done_resizing| is true if
+  // the user has released the mouse.
+  virtual void OnResize(int resize_amount, bool done_resizing) = 0;
+
+ protected:
+  virtual ~ResizeAreaDelegate() {}
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_RESIZE_AREA_DELEGATE_H_
diff --git a/ui/views/controls/scroll_view.cc b/ui/views/controls/scroll_view.cc
new file mode 100644
index 0000000..8d67d28
--- /dev/null
+++ b/ui/views/controls/scroll_view.cc
@@ -0,0 +1,501 @@
+// Copyright (c) 2011 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.
+
+#include "ui/views/controls/scroll_view.h"
+
+#include "base/logging.h"
+#include "ui/views/controls/scrollbar/native_scroll_bar.h"
+#include "ui/views/widget/root_view.h"
+
+namespace views {
+
+const char* const ScrollView::kViewClassName = "views/ScrollView";
+
+// Viewport contains the contents View of the ScrollView.
+class Viewport : public View {
+ public:
+  Viewport() {}
+  virtual ~Viewport() {}
+
+  virtual std::string GetClassName() const {
+    return "views/Viewport";
+  }
+
+  virtual void ScrollRectToVisible(const gfx::Rect& rect) {
+    if (!has_children() || !parent())
+      return;
+
+    View* contents = child_at(0);
+    gfx::Rect scroll_rect(rect);
+    scroll_rect.Offset(-contents->x(), -contents->y());
+    static_cast<ScrollView*>(parent())->ScrollContentsRegionToBeVisible(
+        scroll_rect);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Viewport);
+};
+
+
+ScrollView::ScrollView() {
+  Init(new NativeScrollBar(true), new NativeScrollBar(false), NULL);
+}
+
+ScrollView::ScrollView(ScrollBar* horizontal_scrollbar,
+                       ScrollBar* vertical_scrollbar,
+                       View* resize_corner) {
+  Init(horizontal_scrollbar, vertical_scrollbar, resize_corner);
+}
+
+ScrollView::~ScrollView() {
+  // If scrollbars are currently not used, delete them
+  if (!horiz_sb_->parent())
+    delete horiz_sb_;
+
+  if (!vert_sb_->parent())
+    delete vert_sb_;
+
+  if (resize_corner_ && !resize_corner_->parent())
+    delete resize_corner_;
+}
+
+void ScrollView::SetContents(View* a_view) {
+  if (contents_ && contents_ != a_view) {
+    viewport_->RemoveChildView(contents_);
+    delete contents_;
+    contents_ = NULL;
+  }
+
+  if (a_view) {
+    contents_ = a_view;
+    viewport_->AddChildView(contents_);
+  }
+
+  Layout();
+}
+
+View* ScrollView::GetContents() const {
+  return contents_;
+}
+
+void ScrollView::Init(ScrollBar* horizontal_scrollbar,
+                      ScrollBar* vertical_scrollbar,
+                      View* resize_corner) {
+  DCHECK(horizontal_scrollbar && vertical_scrollbar);
+
+  contents_ = NULL;
+  horiz_sb_ = horizontal_scrollbar;
+  vert_sb_ = vertical_scrollbar;
+  resize_corner_ = resize_corner;
+
+  viewport_ = new Viewport();
+  AddChildView(viewport_);
+
+  // Don't add the scrollbars as children until we discover we need them
+  // (ShowOrHideScrollBar).
+  horiz_sb_->SetVisible(false);
+  horiz_sb_->set_controller(this);
+  vert_sb_->SetVisible(false);
+  vert_sb_->set_controller(this);
+  if (resize_corner_)
+    resize_corner_->SetVisible(false);
+}
+
+// Make sure that a single scrollbar is created and visible as needed
+void ScrollView::SetControlVisibility(View* control, bool should_show) {
+  if (!control)
+    return;
+  if (should_show) {
+    if (!control->IsVisible()) {
+      AddChildView(control);
+      control->SetVisible(true);
+    }
+  } else {
+    RemoveChildView(control);
+    control->SetVisible(false);
+  }
+}
+
+void ScrollView::ComputeScrollBarsVisibility(const gfx::Size& vp_size,
+                                             const gfx::Size& content_size,
+                                             bool* horiz_is_shown,
+                                             bool* vert_is_shown) const {
+  // Try to fit both ways first, then try vertical bar only, then horizontal
+  // bar only, then defaults to both shown.
+  if (content_size.width() <= vp_size.width() &&
+      content_size.height() <= vp_size.height()) {
+    *horiz_is_shown = false;
+    *vert_is_shown = false;
+  } else if (content_size.width() <= vp_size.width() - GetScrollBarWidth()) {
+    *horiz_is_shown = false;
+    *vert_is_shown = true;
+  } else if (content_size.height() <= vp_size.height() - GetScrollBarHeight()) {
+    *horiz_is_shown = true;
+    *vert_is_shown = false;
+  } else {
+    *horiz_is_shown = true;
+    *vert_is_shown = true;
+  }
+}
+
+void ScrollView::Layout() {
+  // Most views will want to auto-fit the available space. Most of them want to
+  // use the all available width (without overflowing) and only overflow in
+  // height. Examples are HistoryView, MostVisitedView, DownloadTabView, etc.
+  // Other views want to fit in both ways. An example is PrintView. To make both
+  // happy, assume a vertical scrollbar but no horizontal scrollbar. To
+  // override this default behavior, the inner view has to calculate the
+  // available space, used ComputeScrollBarsVisibility() to use the same
+  // calculation that is done here and sets its bound to fit within.
+  gfx::Rect viewport_bounds = GetLocalBounds();
+  // Realign it to 0 so it can be used as-is for SetBounds().
+  viewport_bounds.set_origin(gfx::Point(0, 0));
+  // viewport_size is the total client space available.
+  gfx::Size viewport_size = viewport_bounds.size();
+  if (viewport_bounds.IsEmpty()) {
+    // There's nothing to layout.
+    return;
+  }
+
+  // Assumes a vertical scrollbar since most the current views are designed for
+  // this.
+  int horiz_sb_height = GetScrollBarHeight();
+  int vert_sb_width = GetScrollBarWidth();
+  viewport_bounds.set_width(viewport_bounds.width() - vert_sb_width);
+  // Update the bounds right now so the inner views can fit in it.
+  viewport_->SetBoundsRect(viewport_bounds);
+
+  // Give contents_ a chance to update its bounds if it depends on the
+  // viewport.
+  if (contents_)
+    contents_->Layout();
+
+  bool should_layout_contents = false;
+  bool horiz_sb_required = false;
+  bool vert_sb_required = false;
+  if (contents_) {
+    gfx::Size content_size = contents_->size();
+    ComputeScrollBarsVisibility(viewport_size,
+                                content_size,
+                                &horiz_sb_required,
+                                &vert_sb_required);
+  }
+  bool resize_corner_required = resize_corner_ && horiz_sb_required &&
+                                vert_sb_required;
+  // Take action.
+  SetControlVisibility(horiz_sb_, horiz_sb_required);
+  SetControlVisibility(vert_sb_, vert_sb_required);
+  SetControlVisibility(resize_corner_, resize_corner_required);
+
+  // Non-default.
+  if (horiz_sb_required) {
+    viewport_bounds.set_height(
+        std::max(0, viewport_bounds.height() - horiz_sb_height));
+    should_layout_contents = true;
+  }
+  // Default.
+  if (!vert_sb_required) {
+    viewport_bounds.set_width(viewport_bounds.width() + vert_sb_width);
+    should_layout_contents = true;
+  }
+
+  if (horiz_sb_required) {
+    horiz_sb_->SetBounds(0,
+                         viewport_bounds.bottom(),
+                         viewport_bounds.right(),
+                         horiz_sb_height);
+  }
+  if (vert_sb_required) {
+    vert_sb_->SetBounds(viewport_bounds.right(),
+                        0,
+                        vert_sb_width,
+                        viewport_bounds.bottom());
+  }
+  if (resize_corner_required) {
+    // Show the resize corner.
+    resize_corner_->SetBounds(viewport_bounds.right(),
+                              viewport_bounds.bottom(),
+                              vert_sb_width,
+                              horiz_sb_height);
+  }
+
+  // Update to the real client size with the visible scrollbars.
+  viewport_->SetBoundsRect(viewport_bounds);
+  if (should_layout_contents && contents_)
+    contents_->Layout();
+
+  CheckScrollBounds();
+  SchedulePaint();
+  UpdateScrollBarPositions();
+}
+
+int ScrollView::CheckScrollBounds(int viewport_size,
+                                  int content_size,
+                                  int current_pos) {
+  int max = std::max(content_size - viewport_size, 0);
+  if (current_pos < 0)
+    current_pos = 0;
+  else if (current_pos > max)
+    current_pos = max;
+  return current_pos;
+}
+
+void ScrollView::CheckScrollBounds() {
+  if (contents_) {
+    int x, y;
+
+    x = CheckScrollBounds(viewport_->width(),
+                          contents_->width(),
+                          -contents_->x());
+    y = CheckScrollBounds(viewport_->height(),
+                          contents_->height(),
+                          -contents_->y());
+
+    // This is no op if bounds are the same
+    contents_->SetBounds(-x, -y, contents_->width(), contents_->height());
+  }
+}
+
+gfx::Rect ScrollView::GetVisibleRect() const {
+  if (!contents_)
+    return gfx::Rect();
+
+  const int x =
+      (horiz_sb_ && horiz_sb_->IsVisible()) ? horiz_sb_->GetPosition() : 0;
+  const int y =
+      (vert_sb_ && vert_sb_->IsVisible()) ? vert_sb_->GetPosition() : 0;
+  return gfx::Rect(x, y, viewport_->width(), viewport_->height());
+}
+
+void ScrollView::ScrollContentsRegionToBeVisible(const gfx::Rect& rect) {
+  if (!contents_ || ((!horiz_sb_ || !horiz_sb_->IsVisible()) &&
+                     (!vert_sb_ || !vert_sb_->IsVisible()))) {
+    return;
+  }
+
+  // Figure out the maximums for this scroll view.
+  const int contents_max_x =
+      std::max(viewport_->width(), contents_->width());
+  const int contents_max_y =
+      std::max(viewport_->height(), contents_->height());
+
+  // Make sure x and y are within the bounds of [0,contents_max_*].
+  int x = std::max(0, std::min(contents_max_x, rect.x()));
+  int y = std::max(0, std::min(contents_max_y, rect.y()));
+
+  // Figure out how far and down the rectangle will go taking width
+  // and height into account.  This will be "clipped" by the viewport.
+  const int max_x = std::min(contents_max_x,
+                             x + std::min(rect.width(), viewport_->width()));
+  const int max_y = std::min(contents_max_y,
+                             y + std::min(rect.height(), viewport_->height()));
+
+  // See if the rect is already visible. Note the width is (max_x - x)
+  // and the height is (max_y - y) to take into account the clipping of
+  // either viewport or the content size.
+  const gfx::Rect vis_rect = GetVisibleRect();
+  if (vis_rect.Contains(gfx::Rect(x, y, max_x - x, max_y - y)))
+    return;
+
+  // Shift contents_'s X and Y so that the region is visible. If we
+  // need to shift up or left from where we currently are then we need
+  // to get it so that the content appears in the upper/left
+  // corner. This is done by setting the offset to -X or -Y.  For down
+  // or right shifts we need to make sure it appears in the
+  // lower/right corner. This is calculated by taking max_x or max_y
+  // and scaling it back by the size of the viewport.
+  const int new_x =
+      (vis_rect.x() > x) ? x : std::max(0, max_x - viewport_->width());
+  const int new_y =
+      (vis_rect.y() > y) ? y : std::max(0, max_y - viewport_->height());
+
+  contents_->SetX(-new_x);
+  contents_->SetY(-new_y);
+  UpdateScrollBarPositions();
+}
+
+void ScrollView::UpdateScrollBarPositions() {
+  if (!contents_) {
+    return;
+  }
+
+  if (horiz_sb_->IsVisible()) {
+    int vw = viewport_->width();
+    int cw = contents_->width();
+    int origin = contents_->x();
+    horiz_sb_->Update(vw, cw, -origin);
+  }
+  if (vert_sb_->IsVisible()) {
+    int vh = viewport_->height();
+    int ch = contents_->height();
+    int origin = contents_->y();
+    vert_sb_->Update(vh, ch, -origin);
+  }
+}
+
+// TODO(ACW): We should really use ScrollWindowEx as needed
+void ScrollView::ScrollToPosition(ScrollBar* source, int position) {
+  if (!contents_)
+    return;
+
+  if (source == horiz_sb_ && horiz_sb_->IsVisible()) {
+    int vw = viewport_->width();
+    int cw = contents_->width();
+    int origin = contents_->x();
+    if (-origin != position) {
+      int max_pos = std::max(0, cw - vw);
+      if (position < 0)
+        position = 0;
+      else if (position > max_pos)
+        position = max_pos;
+      contents_->SetX(-position);
+      contents_->SchedulePaintInRect(contents_->GetVisibleBounds());
+    }
+  } else if (source == vert_sb_ && vert_sb_->IsVisible()) {
+    int vh = viewport_->height();
+    int ch = contents_->height();
+    int origin = contents_->y();
+    if (-origin != position) {
+      int max_pos = std::max(0, ch - vh);
+      if (position < 0)
+        position = 0;
+      else if (position > max_pos)
+        position = max_pos;
+      contents_->SetY(-position);
+      contents_->SchedulePaintInRect(contents_->GetVisibleBounds());
+    }
+  }
+}
+
+int ScrollView::GetScrollIncrement(ScrollBar* source, bool is_page,
+                                   bool is_positive) {
+  bool is_horizontal = source->IsHorizontal();
+  int amount = 0;
+  View* view = GetContents();
+  if (view) {
+    if (is_page)
+      amount = view->GetPageScrollIncrement(this, is_horizontal, is_positive);
+    else
+      amount = view->GetLineScrollIncrement(this, is_horizontal, is_positive);
+    if (amount > 0)
+      return amount;
+  }
+  // No view, or the view didn't return a valid amount.
+  if (is_page)
+    return is_horizontal ? viewport_->width() : viewport_->height();
+  return is_horizontal ? viewport_->width() / 5 : viewport_->height() / 5;
+}
+
+bool ScrollView::OnKeyPressed(const KeyEvent& event) {
+  bool processed = false;
+
+  // Give vertical scrollbar priority
+  if (vert_sb_->IsVisible()) {
+    processed = vert_sb_->OnKeyPressed(event);
+  }
+
+  if (!processed && horiz_sb_->IsVisible()) {
+    processed = horiz_sb_->OnKeyPressed(event);
+  }
+  return processed;
+}
+
+bool ScrollView::OnMouseWheel(const MouseWheelEvent& e) {
+  bool processed = false;
+  // Give vertical scrollbar priority
+  if (vert_sb_->IsVisible()) {
+    processed = vert_sb_->OnMouseWheel(e);
+  }
+  if (!processed && horiz_sb_->IsVisible()) {
+    processed = horiz_sb_->OnMouseWheel(e);
+  }
+  return processed;
+}
+
+std::string ScrollView::GetClassName() const {
+  return kViewClassName;
+}
+
+int ScrollView::GetScrollBarWidth() const {
+  return vert_sb_->GetLayoutSize();
+}
+
+int ScrollView::GetScrollBarHeight() const {
+  return horiz_sb_->GetLayoutSize();
+}
+
+// VariableRowHeightScrollHelper ----------------------------------------------
+
+VariableRowHeightScrollHelper::VariableRowHeightScrollHelper(
+    Controller* controller) : controller_(controller) {
+}
+
+VariableRowHeightScrollHelper::~VariableRowHeightScrollHelper() {
+}
+
+int VariableRowHeightScrollHelper::GetPageScrollIncrement(
+    ScrollView* scroll_view, bool is_horizontal, bool is_positive) {
+  if (is_horizontal)
+    return 0;
+  // y coordinate is most likely negative.
+  int y = abs(scroll_view->GetContents()->y());
+  int vis_height = scroll_view->GetContents()->parent()->height();
+  if (is_positive) {
+    // Align the bottom most row to the top of the view.
+    int bottom = std::min(scroll_view->GetContents()->height() - 1,
+                          y + vis_height);
+    RowInfo bottom_row_info = GetRowInfo(bottom);
+    // If 0, ScrollView will provide a default value.
+    return std::max(0, bottom_row_info.origin - y);
+  } else {
+    // Align the row on the previous page to to the top of the view.
+    int last_page_y = y - vis_height;
+    RowInfo last_page_info = GetRowInfo(std::max(0, last_page_y));
+    if (last_page_y != last_page_info.origin)
+      return std::max(0, y - last_page_info.origin - last_page_info.height);
+    return std::max(0, y - last_page_info.origin);
+  }
+}
+
+int VariableRowHeightScrollHelper::GetLineScrollIncrement(
+    ScrollView* scroll_view, bool is_horizontal, bool is_positive) {
+  if (is_horizontal)
+    return 0;
+  // y coordinate is most likely negative.
+  int y = abs(scroll_view->GetContents()->y());
+  RowInfo row = GetRowInfo(y);
+  if (is_positive) {
+    return row.height - (y - row.origin);
+  } else if (y == row.origin) {
+    row = GetRowInfo(std::max(0, row.origin - 1));
+    return y - row.origin;
+  } else {
+    return y - row.origin;
+  }
+}
+
+VariableRowHeightScrollHelper::RowInfo
+    VariableRowHeightScrollHelper::GetRowInfo(int y) {
+  return controller_->GetRowInfo(y);
+}
+
+// FixedRowHeightScrollHelper -----------------------------------------------
+
+FixedRowHeightScrollHelper::FixedRowHeightScrollHelper(int top_margin,
+                                                       int row_height)
+    : VariableRowHeightScrollHelper(NULL),
+      top_margin_(top_margin),
+      row_height_(row_height) {
+  DCHECK_GT(row_height, 0);
+}
+
+VariableRowHeightScrollHelper::RowInfo
+    FixedRowHeightScrollHelper::GetRowInfo(int y) {
+  if (y < top_margin_)
+    return RowInfo(0, top_margin_);
+  return RowInfo((y - top_margin_) / row_height_ * row_height_ + top_margin_,
+                 row_height_);
+}
+
+}  // namespace views
diff --git a/ui/views/controls/scroll_view.h b/ui/views/controls/scroll_view.h
new file mode 100644
index 0000000..a7f84fd
--- /dev/null
+++ b/ui/views/controls/scroll_view.h
@@ -0,0 +1,207 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_SCROLL_VIEW_H_
+#define UI_VIEWS_CONTROLS_SCROLL_VIEW_H_
+#pragma once
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "ui/views/controls/scrollbar/scroll_bar.h"
+
+namespace views {
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ScrollView class
+//
+// A ScrollView is used to make any View scrollable. The view is added to
+// a viewport which takes care of clipping.
+//
+// In this current implementation both horizontal and vertical scrollbars are
+// added as needed.
+//
+// The scrollview supports keyboard UI and mousewheel.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+class VIEWS_EXPORT ScrollView : public View, public ScrollBarController {
+ public:
+  static const char* const kViewClassName;
+
+  ScrollView();
+  // Initialize with specific views. resize_corner is optional.
+  ScrollView(ScrollBar* horizontal_scrollbar,
+             ScrollBar* vertical_scrollbar,
+             View* resize_corner);
+  virtual ~ScrollView();
+
+  // Set the contents. Any previous contents will be deleted. The contents
+  // is the view that needs to scroll.
+  void SetContents(View* a_view);
+  View* GetContents() const;
+
+  // Overridden to layout the viewport and scrollbars.
+  virtual void Layout() OVERRIDE;
+
+  // Returns the visible region of the content View.
+  gfx::Rect GetVisibleRect() const;
+
+  // Scrolls the minimum amount necessary to make the specified rectangle
+  // visible, in the coordinates of the contents view. The specified rectangle
+  // is constrained by the bounds of the contents view. This has no effect if
+  // the contents have not been set.
+  //
+  // Client code should use ScrollRectToVisible, which invokes this
+  // appropriately.
+  void ScrollContentsRegionToBeVisible(const gfx::Rect& rect);
+
+  // ScrollBarController.
+  // NOTE: this is intended to be invoked by the ScrollBar, and NOT general
+  // client code.
+  // See also ScrollRectToVisible.
+  virtual void ScrollToPosition(ScrollBar* source, int position) OVERRIDE;
+
+  // Returns the amount to scroll relative to the visible bounds. This invokes
+  // either GetPageScrollIncrement or GetLineScrollIncrement to determine the
+  // amount to scroll. If the view returns 0 (or a negative value) a default
+  // value is used.
+  virtual int GetScrollIncrement(ScrollBar* source,
+                                 bool is_page,
+                                 bool is_positive) OVERRIDE;
+
+  // Keyboard events
+  virtual bool OnKeyPressed(const KeyEvent& event) OVERRIDE;
+  virtual bool OnMouseWheel(const MouseWheelEvent& e) OVERRIDE;
+
+  virtual std::string GetClassName() const OVERRIDE;
+
+  // Retrieves the vertical scrollbar width.
+  int GetScrollBarWidth() const;
+
+  // Retrieves the horizontal scrollbar height.
+  int GetScrollBarHeight() const;
+
+  // Computes the visibility of both scrollbars, taking in account the view port
+  // and content sizes.
+  void ComputeScrollBarsVisibility(const gfx::Size& viewport_size,
+                                   const gfx::Size& content_size,
+                                   bool* horiz_is_shown,
+                                   bool* vert_is_shown) const;
+
+  ScrollBar* horizontal_scroll_bar() const { return horiz_sb_; }
+
+  ScrollBar* vertical_scroll_bar() const { return vert_sb_; }
+
+ private:
+  // Initialize the ScrollView. resize_corner is optional.
+  void Init(ScrollBar* horizontal_scrollbar,
+            ScrollBar* vertical_scrollbar,
+            View* resize_corner);
+
+  // Shows or hides the scrollbar/resize_corner based on the value of
+  // |should_show|.
+  void SetControlVisibility(View* control, bool should_show);
+
+  // Update the scrollbars positions given viewport and content sizes.
+  void UpdateScrollBarPositions();
+
+  // Make sure the content is not scrolled out of bounds
+  void CheckScrollBounds();
+
+  // Make sure the content is not scrolled out of bounds in one dimension
+  int CheckScrollBounds(int viewport_size, int content_size, int current_pos);
+
+  // The clipping viewport. Content is added to that view.
+  View* viewport_;
+
+  // The current contents
+  View* contents_;
+
+  // Horizontal scrollbar.
+  ScrollBar* horiz_sb_;
+
+  // Vertical scrollbar.
+  ScrollBar* vert_sb_;
+
+  // Resize corner.
+  View* resize_corner_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScrollView);
+};
+
+// VariableRowHeightScrollHelper is intended for views that contain rows of
+// varying height. To use a VariableRowHeightScrollHelper create one supplying
+// a Controller and delegate GetPageScrollIncrement and GetLineScrollIncrement
+// to the helper. VariableRowHeightScrollHelper calls back to the
+// Controller to determine row boundaries.
+class VariableRowHeightScrollHelper {
+ public:
+  // The origin and height of a row.
+  struct RowInfo {
+    RowInfo(int origin, int height) : origin(origin), height(height) {}
+
+    // Origin of the row.
+    int origin;
+
+    // Height of the row.
+    int height;
+  };
+
+  // Used to determine row boundaries.
+  class Controller {
+   public:
+    // Returns the origin and size of the row at the specified location.
+    virtual VariableRowHeightScrollHelper::RowInfo GetRowInfo(int y) = 0;
+  };
+
+  // Creates a new VariableRowHeightScrollHelper. Controller is
+  // NOT deleted by this VariableRowHeightScrollHelper.
+  explicit VariableRowHeightScrollHelper(Controller* controller);
+  virtual ~VariableRowHeightScrollHelper();
+
+  // Delegate the View methods of the same name to these. The scroll amount is
+  // determined by querying the Controller for the appropriate row to scroll
+  // to.
+  int GetPageScrollIncrement(ScrollView* scroll_view,
+                             bool is_horizontal, bool is_positive);
+  int GetLineScrollIncrement(ScrollView* scroll_view,
+                             bool is_horizontal, bool is_positive);
+
+ protected:
+  // Returns the row information for the row at the specified location. This
+  // calls through to the method of the same name on the controller.
+  virtual RowInfo GetRowInfo(int y);
+
+ private:
+  Controller* controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(VariableRowHeightScrollHelper);
+};
+
+// FixedRowHeightScrollHelper is intended for views that contain fixed height
+// height rows. To use a FixedRowHeightScrollHelper delegate
+// GetPageScrollIncrement and GetLineScrollIncrement to it.
+class FixedRowHeightScrollHelper : public VariableRowHeightScrollHelper {
+ public:
+  // Creates a FixedRowHeightScrollHelper. top_margin gives the distance from
+  // the top of the view to the first row, and may be 0. row_height gives the
+  // height of each row.
+  FixedRowHeightScrollHelper(int top_margin, int row_height);
+
+ protected:
+  // Calculates the bounds of the row from the top margin and row height.
+  virtual RowInfo GetRowInfo(int y) OVERRIDE;
+
+ private:
+  int top_margin_;
+  int row_height_;
+
+  DISALLOW_COPY_AND_ASSIGN(FixedRowHeightScrollHelper);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_SCROLL_VIEW_H_
diff --git a/ui/views/controls/scrollbar/base_scroll_bar.cc b/ui/views/controls/scrollbar/base_scroll_bar.cc
index 3afb238..54d4b44 100644
--- a/ui/views/controls/scrollbar/base_scroll_bar.cc
+++ b/ui/views/controls/scrollbar/base_scroll_bar.cc
@@ -18,9 +18,9 @@
 #include "ui/gfx/canvas.h"
 #include "ui/views/controls/menu/menu_item_view.h"
 #include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
 #include "ui/views/widget/widget.h"
-#include "views/controls/scroll_view.h"
 
 #if defined(OS_LINUX)
 #include "ui/gfx/screen.h"
diff --git a/ui/views/controls/scrollbar/bitmap_scroll_bar.cc b/ui/views/controls/scrollbar/bitmap_scroll_bar.cc
index 6aa44d5..47c8f13 100644
--- a/ui/views/controls/scrollbar/bitmap_scroll_bar.cc
+++ b/ui/views/controls/scrollbar/bitmap_scroll_bar.cc
@@ -18,9 +18,9 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/canvas.h"
 #include "ui/views/controls/menu/menu.h"
+#include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
 #include "ui/views/widget/widget.h"
-#include "views/controls/scroll_view.h"
 
 #if defined(OS_LINUX)
 #include "views/screen.h"
diff --git a/ui/views/controls/scrollbar/native_scroll_bar_gtk.h b/ui/views/controls/scrollbar/native_scroll_bar_gtk.h
index 909adfe..e9a5ed5 100644
--- a/ui/views/controls/scrollbar/native_scroll_bar_gtk.h
+++ b/ui/views/controls/scrollbar/native_scroll_bar_gtk.h
@@ -7,8 +7,8 @@
 #pragma once
 
 #include "base/compiler_specific.h"
+#include "ui/views/controls/native_control_gtk.h"
 #include "ui/views/controls/scrollbar/native_scroll_bar_wrapper.h"
-#include "views/controls/native_control_gtk.h"
 
 namespace views {
 
diff --git a/ui/views/controls/scrollbar/native_scroll_bar_views.cc b/ui/views/controls/scrollbar/native_scroll_bar_views.cc
index 29c5f6f..fba93d09 100644
--- a/ui/views/controls/scrollbar/native_scroll_bar_views.cc
+++ b/ui/views/controls/scrollbar/native_scroll_bar_views.cc
@@ -10,11 +10,11 @@
 #include "ui/gfx/canvas_skia.h"
 #include "ui/gfx/path.h"
 #include "ui/views/controls/button/custom_button.h"
+#include "ui/views/controls/focusable_border.h"
 #include "ui/views/controls/scrollbar/base_scroll_bar_button.h"
 #include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
 #include "ui/views/controls/scrollbar/native_scroll_bar.h"
 #include "ui/views/controls/scrollbar/scroll_bar.h"
-#include "views/controls/focusable_border.h"
 
 namespace views {
 
diff --git a/ui/views/controls/scrollbar/native_scroll_bar_win.h b/ui/views/controls/scrollbar/native_scroll_bar_win.h
index 33e369e..1f7ec36 100644
--- a/ui/views/controls/scrollbar/native_scroll_bar_win.h
+++ b/ui/views/controls/scrollbar/native_scroll_bar_win.h
@@ -6,8 +6,8 @@
 #define UI_VIEWS_CONTROLS_SCROLLBAR_NATIVE_SCROLL_BAR_WIN_H_
 #pragma once
 
+#include "ui/views/controls/native_control_win.h"
 #include "ui/views/controls/scrollbar/native_scroll_bar_wrapper.h"
-#include "views/controls/native_control_win.h"
 
 namespace views {
 
diff --git a/ui/views/controls/separator.cc b/ui/views/controls/separator.cc
new file mode 100644
index 0000000..2842068
--- /dev/null
+++ b/ui/views/controls/separator.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 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.
+
+#include "ui/views/controls/separator.h"
+
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/gfx/canvas.h"
+
+namespace views {
+
+// static
+const char Separator::kViewClassName[] = "views/Separator";
+
+// The separator height in pixels.
+const int kSeparatorHeight = 1;
+
+// Default color of the separator.
+const SkColor kDefaultColor = SkColorSetARGB(255, 233, 233, 233);
+
+Separator::Separator() {
+  set_focusable(false);
+}
+
+Separator::~Separator() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Separator, View overrides:
+
+gfx::Size Separator::GetPreferredSize() {
+  return gfx::Size(width(), kSeparatorHeight);
+}
+
+void Separator::GetAccessibleState(ui::AccessibleViewState* state) {
+  state->role = ui::AccessibilityTypes::ROLE_SEPARATOR;
+}
+
+void Separator::Paint(gfx::Canvas* canvas) {
+  canvas->FillRect(kDefaultColor, bounds());
+}
+
+std::string Separator::GetClassName() const {
+  return kViewClassName;
+}
+
+}  // namespace views
diff --git a/ui/views/controls/separator.h b/ui/views/controls/separator.h
new file mode 100644
index 0000000..f47d238
--- /dev/null
+++ b/ui/views/controls/separator.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_SEPARATOR_H_
+#define UI_VIEWS_CONTROLS_SEPARATOR_H_
+#pragma once
+
+#include <string>
+
+#include "views/view.h"
+
+namespace views {
+
+// The Separator class is a view that shows a line used to visually separate
+// other views.  The current implementation is only horizontal.
+
+class VIEWS_EXPORT Separator : public View {
+ public:
+  // The separator's class name.
+  static const char kViewClassName[];
+
+  Separator();
+  virtual ~Separator();
+
+  // Overridden from View:
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+  virtual void Paint(gfx::Canvas* canvas) OVERRIDE;
+  virtual std::string GetClassName() const OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Separator);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_SEPARATOR_H_
diff --git a/ui/views/controls/single_split_view.cc b/ui/views/controls/single_split_view.cc
new file mode 100644
index 0000000..333c388
--- /dev/null
+++ b/ui/views/controls/single_split_view.cc
@@ -0,0 +1,263 @@
+// Copyright (c) 2011 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.
+
+#include "ui/views/controls/single_split_view.h"
+
+#if defined(TOOLKIT_USES_GTK)
+#include <gdk/gdk.h>
+#endif
+
+#include "skia/ext/skia_utils_win.h"
+#include "ui/base/accessibility/accessible_view_state.h"
+#include "ui/gfx/canvas.h"
+#include "ui/views/controls/single_split_view_listener.h"
+#include "views/background.h"
+
+#if defined(TOOLKIT_USES_GTK)
+#include "ui/gfx/gtk_util.h"
+#endif
+
+#if defined(USE_AURA)
+#include "ui/aura/cursor.h"
+#endif
+
+namespace views {
+
+// static
+const char SingleSplitView::kViewClassName[] =
+    "ui/views/controls/SingleSplitView";
+
+// Size of the divider in pixels.
+static const int kDividerSize = 4;
+
+SingleSplitView::SingleSplitView(View* leading,
+                                 View* trailing,
+                                 Orientation orientation,
+                                 SingleSplitViewListener* listener)
+    : is_horizontal_(orientation == HORIZONTAL_SPLIT),
+      divider_offset_(-1),
+      resize_leading_on_bounds_change_(true),
+      listener_(listener) {
+  AddChildView(leading);
+  AddChildView(trailing);
+#if defined(OS_WIN)
+  set_background(
+      views::Background::CreateSolidBackground(
+          skia::COLORREFToSkColor(GetSysColor(COLOR_3DFACE))));
+#endif
+}
+
+void SingleSplitView::Layout() {
+  gfx::Rect leading_bounds;
+  gfx::Rect trailing_bounds;
+  CalculateChildrenBounds(bounds(), &leading_bounds, &trailing_bounds);
+
+  if (has_children()) {
+    if (child_at(0)->IsVisible())
+      child_at(0)->SetBoundsRect(leading_bounds);
+    if (child_count() > 1) {
+      if (child_at(1)->IsVisible())
+        child_at(1)->SetBoundsRect(trailing_bounds);
+    }
+  }
+
+  SchedulePaint();
+
+  // Invoke super's implementation so that the children are layed out.
+  View::Layout();
+}
+
+std::string SingleSplitView::GetClassName() const {
+  return kViewClassName;
+}
+
+void SingleSplitView::GetAccessibleState(ui::AccessibleViewState* state) {
+  state->role = ui::AccessibilityTypes::ROLE_GROUPING;
+  state->name = accessible_name_;
+}
+
+gfx::Size SingleSplitView::GetPreferredSize() {
+  int width = 0;
+  int height = 0;
+  for (int i = 0; i < 2 && i < child_count(); ++i) {
+    View* view = child_at(i);
+    gfx::Size pref = view->GetPreferredSize();
+    if (is_horizontal_) {
+      width += pref.width();
+      height = std::max(height, pref.height());
+    } else {
+      width = std::max(width, pref.width());
+      height += pref.height();
+    }
+  }
+  if (is_horizontal_)
+    width += kDividerSize;
+  else
+    height += kDividerSize;
+  return gfx::Size(width, height);
+}
+
+gfx::NativeCursor SingleSplitView::GetCursor(const MouseEvent& event) {
+  if (!IsPointInDivider(event.location()))
+    return gfx::kNullCursor;
+#if defined(USE_AURA)
+  return is_horizontal_ ?
+      aura::kCursorEastWestResize : aura::kCursorNorthSouthResize;
+#elif defined(OS_WIN)
+  static HCURSOR we_resize_cursor = LoadCursor(NULL, IDC_SIZEWE);
+  static HCURSOR ns_resize_cursor = LoadCursor(NULL, IDC_SIZENS);
+  return is_horizontal_ ? we_resize_cursor : ns_resize_cursor;
+#elif defined(TOOLKIT_USES_GTK)
+  return gfx::GetCursor(is_horizontal_ ? GDK_SB_H_DOUBLE_ARROW :
+                                         GDK_SB_V_DOUBLE_ARROW);
+#endif
+}
+
+void SingleSplitView::CalculateChildrenBounds(
+    const gfx::Rect& bounds,
+    gfx::Rect* leading_bounds,
+    gfx::Rect* trailing_bounds) const {
+  bool is_leading_visible = has_children() && child_at(0)->IsVisible();
+  bool is_trailing_visible = child_count() > 1 && child_at(1)->IsVisible();
+
+  if (!is_leading_visible && !is_trailing_visible) {
+    *leading_bounds = gfx::Rect();
+    *trailing_bounds = gfx::Rect();
+    return;
+  }
+
+  int divider_at;
+
+  if (!is_trailing_visible) {
+    divider_at = GetPrimaryAxisSize(bounds.width(), bounds.height());
+  } else if (!is_leading_visible) {
+    divider_at = 0;
+  } else {
+    divider_at =
+        CalculateDividerOffset(divider_offset_, this->bounds(), bounds);
+    divider_at = NormalizeDividerOffset(divider_at, bounds);
+  }
+
+  int divider_size =
+      !is_leading_visible || !is_trailing_visible ? 0 : kDividerSize;
+
+  if (is_horizontal_) {
+    *leading_bounds = gfx::Rect(0, 0, divider_at, bounds.height());
+    *trailing_bounds =
+        gfx::Rect(divider_at + divider_size, 0,
+                  std::max(0, bounds.width() - divider_at - divider_size),
+                  bounds.height());
+  } else {
+    *leading_bounds = gfx::Rect(0, 0, bounds.width(), divider_at);
+    *trailing_bounds =
+        gfx::Rect(0, divider_at + divider_size, bounds.width(),
+                  std::max(0, bounds.height() - divider_at - divider_size));
+  }
+}
+
+void SingleSplitView::SetAccessibleName(const string16& name) {
+  accessible_name_ = name;
+}
+
+bool SingleSplitView::OnMousePressed(const MouseEvent& event) {
+  if (!IsPointInDivider(event.location()))
+    return false;
+  drag_info_.initial_mouse_offset = GetPrimaryAxisSize(event.x(), event.y());
+  drag_info_.initial_divider_offset =
+      NormalizeDividerOffset(divider_offset_, bounds());
+  return true;
+}
+
+bool SingleSplitView::OnMouseDragged(const MouseEvent& event) {
+  if (child_count() < 2)
+    return false;
+
+  int delta_offset = GetPrimaryAxisSize(event.x(), event.y()) -
+      drag_info_.initial_mouse_offset;
+  if (is_horizontal_ && base::i18n::IsRTL())
+    delta_offset *= -1;
+  // Honor the minimum size when resizing.
+  gfx::Size min = child_at(0)->GetMinimumSize();
+  int new_size = std::max(GetPrimaryAxisSize(min.width(), min.height()),
+                          drag_info_.initial_divider_offset + delta_offset);
+
+  // And don't let the view get bigger than our width.
+  new_size = std::min(GetPrimaryAxisSize() - kDividerSize, new_size);
+
+  if (new_size != divider_offset_) {
+    set_divider_offset(new_size);
+    if (!listener_ || listener_->SplitHandleMoved(this))
+      Layout();
+  }
+  return true;
+}
+
+void SingleSplitView::OnMouseCaptureLost() {
+  if (child_count() < 2)
+    return;
+
+  if (drag_info_.initial_divider_offset != divider_offset_) {
+    set_divider_offset(drag_info_.initial_divider_offset);
+    if (!listener_ || listener_->SplitHandleMoved(this))
+      Layout();
+  }
+}
+
+void SingleSplitView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  divider_offset_ = CalculateDividerOffset(divider_offset_, previous_bounds,
+                                           bounds());
+}
+
+bool SingleSplitView::IsPointInDivider(const gfx::Point& p) {
+  if (child_count() < 2)
+    return false;
+
+  if (!child_at(0)->IsVisible() || !child_at(1)->IsVisible())
+    return false;
+
+  int divider_relative_offset;
+  if (is_horizontal_) {
+    divider_relative_offset =
+        p.x() - child_at(base::i18n::IsRTL() ? 1 : 0)->width();
+  } else {
+    divider_relative_offset = p.y() - child_at(0)->height();
+  }
+  return (divider_relative_offset >= 0 &&
+      divider_relative_offset < kDividerSize);
+}
+
+int SingleSplitView::CalculateDividerOffset(
+    int divider_offset,
+    const gfx::Rect& previous_bounds,
+    const gfx::Rect& new_bounds) const {
+  if (resize_leading_on_bounds_change_ && divider_offset != -1) {
+    // We do not update divider_offset on minimize (to zero) and on restore
+    // (to largest value). As a result we get back to the original value upon
+    // window restore.
+    bool is_minimize_or_restore =
+        previous_bounds.height() == 0 || new_bounds.height() == 0;
+    if (!is_minimize_or_restore) {
+      if (is_horizontal_)
+        divider_offset += new_bounds.width() - previous_bounds.width();
+      else
+        divider_offset += new_bounds.height() - previous_bounds.height();
+
+      if (divider_offset < 0)
+        divider_offset = kDividerSize;
+    }
+  }
+  return divider_offset;
+}
+
+int SingleSplitView::NormalizeDividerOffset(int divider_offset,
+                                            const gfx::Rect& bounds) const {
+  int primary_axis_size = GetPrimaryAxisSize(bounds.width(), bounds.height());
+  if (divider_offset < 0)
+    // primary_axis_size may < kDividerSize during initial layout.
+    return std::max(0, (primary_axis_size - kDividerSize) / 2);
+  return std::min(divider_offset,
+                  std::max(primary_axis_size - kDividerSize, 0));
+}
+
+}  // namespace views
diff --git a/ui/views/controls/single_split_view.h b/ui/views/controls/single_split_view.h
new file mode 100644
index 0000000..c3f2bc3
--- /dev/null
+++ b/ui/views/controls/single_split_view.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_H_
+#define UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_H_
+#pragma once
+
+#include "base/gtest_prod_util.h"
+#include "views/view.h"
+
+namespace views {
+
+class SingleSplitViewListener;
+
+// SingleSplitView lays out two views next to each other, either horizontally
+// or vertically. A splitter exists between the two views that the user can
+// drag around to resize the views.
+// SingleSplitViewListener's SplitHandleMoved notification helps to monitor user
+// initiated layout changes.
+class VIEWS_EXPORT SingleSplitView : public View {
+ public:
+  enum Orientation {
+    HORIZONTAL_SPLIT,
+    VERTICAL_SPLIT
+  };
+
+  static const char kViewClassName[];
+
+  SingleSplitView(View* leading,
+                  View* trailing,
+                  Orientation orientation,
+                  SingleSplitViewListener* listener);
+
+  virtual void Layout() OVERRIDE;
+  virtual std::string GetClassName() const OVERRIDE;
+
+  virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
+
+  // SingleSplitView's preferred size is the sum of the preferred widths
+  // and the max of the heights.
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+
+  // Overriden to return a resize cursor when over the divider.
+  virtual gfx::NativeCursor GetCursor(const MouseEvent& event) OVERRIDE;
+
+  Orientation orientation() const {
+    return is_horizontal_ ? HORIZONTAL_SPLIT : VERTICAL_SPLIT;
+  }
+
+  void set_divider_offset(int divider_offset) {
+    divider_offset_ = divider_offset;
+  }
+  int divider_offset() const { return divider_offset_; }
+
+  // Sets whether the leading component is resized when the split views size
+  // changes. The default is true. A value of false results in the trailing
+  // component resizing on a bounds change.
+  void set_resize_leading_on_bounds_change(bool resize) {
+    resize_leading_on_bounds_change_ = resize;
+  }
+
+  // Calculates ideal leading and trailing view bounds according to the given
+  // split view |bounds|, current divider offset and children visiblity.
+  // Does not change children view bounds.
+  void CalculateChildrenBounds(const gfx::Rect& bounds,
+                               gfx::Rect* leading_bounds,
+                               gfx::Rect* trailing_bounds) const;
+
+  void SetAccessibleName(const string16& name);
+
+ protected:
+  // View overrides.
+  virtual bool OnMousePressed(const MouseEvent& event) OVERRIDE;
+  virtual bool OnMouseDragged(const MouseEvent& event) OVERRIDE;
+  virtual void OnMouseCaptureLost() OVERRIDE;
+  virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
+
+ private:
+  // This test calls OnMouse* functions.
+  FRIEND_TEST_ALL_PREFIXES(SingleSplitViewTest, MouseDrag);
+
+  // Returns true if |x| or |y| is over the divider.
+  bool IsPointInDivider(const gfx::Point& p);
+
+  // Calculates the new |divider_offset| based on the changes of split view
+  // bounds.
+  int CalculateDividerOffset(int divider_offset,
+                             const gfx::Rect& previous_bounds,
+                             const gfx::Rect& new_bounds) const;
+
+  // Returns divider offset within primary axis size range for given split
+  // view |bounds|.
+  int NormalizeDividerOffset(int divider_offset, const gfx::Rect& bounds) const;
+
+  // Returns width in case of horizontal split and height otherwise.
+  int GetPrimaryAxisSize() const {
+    return GetPrimaryAxisSize(width(), height());
+  }
+
+  int GetPrimaryAxisSize(int h, int v) const {
+    return is_horizontal_ ? h : v;
+  }
+
+  // Used to track drag info.
+  struct DragInfo {
+    // The initial coordinate of the mouse when the user started the drag.
+    int initial_mouse_offset;
+    // The initial position of the divider when the user started the drag.
+    int initial_divider_offset;
+  };
+
+  DragInfo drag_info_;
+
+  // Orientation of the split view.
+  bool is_horizontal_;
+
+  // Position of the divider.
+  int divider_offset_;
+
+  bool resize_leading_on_bounds_change_;
+
+  // Listener to notify about user initiated handle movements. Not owned.
+  SingleSplitViewListener* listener_;
+
+  // The accessible name of this view.
+  string16 accessible_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(SingleSplitView);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_H_
diff --git a/ui/views/controls/single_split_view_listener.h b/ui/views/controls/single_split_view_listener.h
new file mode 100644
index 0000000..580ac82
--- /dev/null
+++ b/ui/views/controls/single_split_view_listener.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_LISTENER_H_
+#define UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_LISTENER_H_
+#pragma once
+
+namespace views {
+
+class SingleSplitView;
+
+// An interface implemented by objects that want to be notified when the
+// splitter moves.
+class SingleSplitViewListener {
+ public:
+  // Invoked when split handle is moved by the user. |sender|'s divider_offset
+  // is already set to the new value, but Layout has not happened yet.
+  // Returns false if the layout has been handled by the listener, returns
+  // true if |sender| should do it by itself.
+  virtual bool SplitHandleMoved(SingleSplitView* sender) = 0;
+
+ protected:
+  virtual ~SingleSplitViewListener() {}
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_LISTENER_H_
diff --git a/ui/views/controls/single_split_view_unittest.cc b/ui/views/controls/single_split_view_unittest.cc
new file mode 100644
index 0000000..891a877
--- /dev/null
+++ b/ui/views/controls/single_split_view_unittest.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2011 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.
+
+#include "base/logging.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/controls/single_split_view.h"
+#include "ui/views/controls/single_split_view_listener.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace {
+
+static void VerifySplitViewLayout(const views::SingleSplitView& split) {
+  ASSERT_EQ(2, split.child_count());
+
+  const views::View* leading = split.child_at(0);
+  const views::View* trailing = split.child_at(1);
+
+  if (split.bounds().IsEmpty()) {
+    EXPECT_TRUE(leading->bounds().IsEmpty());
+    EXPECT_TRUE(trailing->bounds().IsEmpty());
+    return;
+  }
+
+  EXPECT_FALSE(leading->bounds().IsEmpty());
+  EXPECT_FALSE(trailing->bounds().IsEmpty());
+  EXPECT_FALSE(leading->bounds().Intersects(trailing->bounds()));
+
+  if (split.orientation() == views::SingleSplitView::HORIZONTAL_SPLIT) {
+    EXPECT_EQ(leading->bounds().height(), split.bounds().height());
+    EXPECT_EQ(trailing->bounds().height(), split.bounds().height());
+    EXPECT_LT(leading->bounds().width() + trailing->bounds().width(),
+              split.bounds().width());
+  } else if (split.orientation() == views::SingleSplitView::VERTICAL_SPLIT) {
+    EXPECT_EQ(leading->bounds().width(), split.bounds().width());
+    EXPECT_EQ(trailing->bounds().width(), split.bounds().width());
+    EXPECT_LT(leading->bounds().height() + trailing->bounds().height(),
+              split.bounds().height());
+  } else {
+    NOTREACHED();
+  }
+}
+
+class MockObserver : public views::SingleSplitViewListener {
+ public:
+  MOCK_METHOD1(SplitHandleMoved, bool(views::SingleSplitView*));
+};
+
+}  // namespace
+
+namespace views {
+
+TEST(SingleSplitViewTest, Resize) {
+  // Test cases to iterate through for horizontal and vertical split views.
+  struct TestCase {
+    // Split view resize policy for this test case.
+    bool resize_leading_on_bounds_change;
+    // Split view size to set.
+    int primary_axis_size;
+    int secondary_axis_size;
+    // Expected divider offset.
+    int divider_offset;
+  } test_cases[] = {
+    // The initial split size is 100x100, divider at 33.
+    { true, 100, 100, 33 },
+    // Grow the split view, leading view should grow.
+    { true, 1000, 100, 933 },
+    // Shrink the split view, leading view should shrink.
+    { true, 200, 100, 133 },
+    // Minimize the split view, divider should not move.
+    { true, 0, 0, 133 },
+    // Restore the split view, divider should not move.
+    { false, 500, 100, 133 },
+    // Resize the split view by secondary axis, divider should not move.
+    { false,  500, 600, 133 }
+  };
+
+  SingleSplitView::Orientation orientations[] = {
+    SingleSplitView::HORIZONTAL_SPLIT,
+    SingleSplitView::VERTICAL_SPLIT
+  };
+
+  for (size_t orientation = 0; orientation < arraysize(orientations);
+       ++orientation) {
+    // Create a split view.
+    SingleSplitView split(
+        new View(), new View(), orientations[orientation], NULL);
+
+    // Set initial size and divider offset.
+    EXPECT_EQ(test_cases[0].primary_axis_size,
+              test_cases[0].secondary_axis_size);
+    split.SetBounds(0, 0, test_cases[0].primary_axis_size,
+                    test_cases[0].secondary_axis_size);
+    split.set_divider_offset(test_cases[0].divider_offset);
+    split.Layout();
+
+    // Run all test cases.
+    for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
+      split.set_resize_leading_on_bounds_change(
+          test_cases[i].resize_leading_on_bounds_change);
+      if (split.orientation() == SingleSplitView::HORIZONTAL_SPLIT) {
+        split.SetBounds(0, 0, test_cases[i].primary_axis_size,
+                        test_cases[i].secondary_axis_size);
+      } else {
+        split.SetBounds(0, 0, test_cases[i].secondary_axis_size,
+                        test_cases[i].primary_axis_size);
+      }
+
+      EXPECT_EQ(test_cases[i].divider_offset, split.divider_offset());
+      VerifySplitViewLayout(split);
+    }
+
+    // Special cases, one of the child views is hidden.
+    split.child_at(0)->SetVisible(false);
+    split.Layout();
+
+    EXPECT_EQ(split.size(), split.child_at(1)->size());
+
+    split.child_at(0)->SetVisible(true);
+    split.child_at(1)->SetVisible(false);
+    split.Layout();
+
+    EXPECT_EQ(split.size(), split.child_at(0)->size());
+  }
+}
+
+TEST(SingleSplitViewTest, MouseDrag) {
+  MockObserver observer;
+  SingleSplitView split(
+      new View(), new View(), SingleSplitView::VERTICAL_SPLIT, &observer);
+
+  ON_CALL(observer, SplitHandleMoved(_))
+      .WillByDefault(Return(true));
+  // SplitHandleMoved is called for two mouse moves and one mouse capture loss.
+  EXPECT_CALL(observer, SplitHandleMoved(_))
+      .Times(3);
+
+  split.SetBounds(0, 0, 10, 100);
+  const int kInitialDividerOffset = 33;
+  const int kMouseOffset = 2;  // Mouse offset in the divider.
+  const int kMouseMoveDelta = 7;
+  split.set_divider_offset(kInitialDividerOffset);
+  split.Layout();
+
+  // Drag divider to the right, in 2 steps.
+  MouseEvent mouse_pressed(
+      ui::ET_MOUSE_PRESSED, 7, kInitialDividerOffset + kMouseOffset, 0);
+  ASSERT_TRUE(split.OnMousePressed(mouse_pressed));
+  EXPECT_EQ(kInitialDividerOffset, split.divider_offset());
+
+  MouseEvent mouse_dragged_1(
+      ui::ET_MOUSE_DRAGGED, 5,
+      kInitialDividerOffset + kMouseOffset + kMouseMoveDelta, 0);
+  ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_1));
+  EXPECT_EQ(kInitialDividerOffset + kMouseMoveDelta, split.divider_offset());
+
+  MouseEvent mouse_dragged_2(
+      ui::ET_MOUSE_DRAGGED, 6,
+      kInitialDividerOffset + kMouseOffset + kMouseMoveDelta * 2, 0);
+  ASSERT_TRUE(split.OnMouseDragged(mouse_dragged_2));
+  EXPECT_EQ(kInitialDividerOffset + kMouseMoveDelta * 2,
+            split.divider_offset());
+
+  MouseEvent mouse_released(
+      ui::ET_MOUSE_RELEASED, 7,
+      kInitialDividerOffset + kMouseOffset + kMouseMoveDelta * 2, 0);
+  split.OnMouseReleased(mouse_released);
+  EXPECT_EQ(kInitialDividerOffset + kMouseMoveDelta * 2,
+            split.divider_offset());
+
+  // Expect intial offset after a system/user gesture cancels the drag.
+  // This shouldn't occur after mouse release, but it's sufficient for testing.
+  split.OnMouseCaptureLost();
+  EXPECT_EQ(kInitialDividerOffset, split.divider_offset());
+}
+
+}  // namespace views
diff --git a/ui/views/controls/tabbed_pane/native_tabbed_pane_gtk.h b/ui/views/controls/tabbed_pane/native_tabbed_pane_gtk.h
index c37af6c..b937cb2 100644
--- a/ui/views/controls/tabbed_pane/native_tabbed_pane_gtk.h
+++ b/ui/views/controls/tabbed_pane/native_tabbed_pane_gtk.h
@@ -8,8 +8,8 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "ui/views/controls/native_control_gtk.h"
 #include "ui/views/controls/tabbed_pane/native_tabbed_pane_wrapper.h"
-#include "views/controls/native_control_gtk.h"
 
 namespace views {
 
diff --git a/ui/views/controls/tabbed_pane/native_tabbed_pane_win.h b/ui/views/controls/tabbed_pane/native_tabbed_pane_win.h
index 8935c1a..6532438 100644
--- a/ui/views/controls/tabbed_pane/native_tabbed_pane_win.h
+++ b/ui/views/controls/tabbed_pane/native_tabbed_pane_win.h
@@ -8,8 +8,8 @@
 
 #include <vector>
 
+#include "ui/views/controls/native_control_win.h"
 #include "ui/views/controls/tabbed_pane/native_tabbed_pane_wrapper.h"
-#include "views/controls/native_control_win.h"
 
 namespace views {
 
diff --git a/ui/views/controls/table/native_table_gtk.h b/ui/views/controls/table/native_table_gtk.h
index 3ebb51f..df63faf 100644
--- a/ui/views/controls/table/native_table_gtk.h
+++ b/ui/views/controls/table/native_table_gtk.h
@@ -9,8 +9,8 @@
 #include "base/compiler_specific.h"
 #include "ui/base/gtk/gtk_signal.h"
 #include "ui/base/models/table_model.h"
+#include "ui/views/controls/native_control_gtk.h"
 #include "ui/views/controls/table/native_table_wrapper.h"
-#include "views/controls/native_control_gtk.h"
 
 namespace views {
 
diff --git a/ui/views/controls/table/native_table_win.h b/ui/views/controls/table/native_table_win.h
index 810eb94..432b30c 100644
--- a/ui/views/controls/table/native_table_win.h
+++ b/ui/views/controls/table/native_table_win.h
@@ -9,8 +9,8 @@
 #include <windows.h>
 
 #include "ui/base/models/table_model.h"
+#include "ui/views/controls/native_control_win.h"
 #include "ui/views/controls/table/native_table_wrapper.h"
-#include "views/controls/native_control_win.h"
 
 typedef struct tagNMLVCUSTOMDRAW NMLVCUSTOMDRAW;
 
diff --git a/ui/views/controls/table/table_view.h b/ui/views/controls/table/table_view.h
index e226f10..78a0f55 100644
--- a/ui/views/controls/table/table_view.h
+++ b/ui/views/controls/table/table_view.h
@@ -21,7 +21,7 @@
 #include <windows.h>
 
 // TODO(port): remove the ifdef when native_control.h is ported.
-#include "views/controls/native_control.h"
+#include "ui/views/controls/native_control.h"
 
 typedef struct tagNMLVCUSTOMDRAW NMLVCUSTOMDRAW;
 #endif  // defined(OS_WIN)
diff --git a/ui/views/controls/textfield/native_textfield_gtk.h b/ui/views/controls/textfield/native_textfield_gtk.h
index ea3151c..42a9680 100644
--- a/ui/views/controls/textfield/native_textfield_gtk.h
+++ b/ui/views/controls/textfield/native_textfield_gtk.h
@@ -10,8 +10,8 @@
 
 #include "base/string16.h"
 #include "ui/base/gtk/gtk_signal.h"
+#include "ui/views/controls/native_control_gtk.h"
 #include "ui/views/controls/textfield/native_textfield_wrapper.h"
-#include "views/controls/native_control_gtk.h"
 
 namespace gfx {
 class SelectionModel;
diff --git a/ui/views/controls/textfield/native_textfield_views.cc b/ui/views/controls/textfield/native_textfield_views.cc
index 3e6a5f8..d5d0b56 100644
--- a/ui/views/controls/textfield/native_textfield_views.cc
+++ b/ui/views/controls/textfield/native_textfield_views.cc
@@ -18,6 +18,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/insets.h"
 #include "ui/gfx/render_text.h"
+#include "ui/views/controls/focusable_border.h"
 #include "ui/views/controls/menu/menu_item_view.h"
 #include "ui/views/controls/menu/menu_model_adapter.h"
 #include "ui/views/controls/menu/menu_runner.h"
@@ -29,7 +30,6 @@
 #include "ui/views/widget/widget.h"
 #include "views/background.h"
 #include "views/border.h"
-#include "views/controls/focusable_border.h"
 #include "views/metrics.h"
 #include "views/views_delegate.h"
 
diff --git a/ui/views/controls/throbber.cc b/ui/views/controls/throbber.cc
new file mode 100644
index 0000000..d323c00
--- /dev/null
+++ b/ui/views/controls/throbber.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2011 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.
+
+#include "ui/views/controls/throbber.h"
+
+#include "base/time.h"
+#include "grit/ui_resources.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+
+using base::Time;
+using base::TimeDelta;
+
+namespace views {
+
+Throbber::Throbber(int frame_time_ms,
+                   bool paint_while_stopped)
+    : running_(false),
+      paint_while_stopped_(paint_while_stopped),
+      frames_(NULL),
+      frame_time_(TimeDelta::FromMilliseconds(frame_time_ms)) {
+  SetFrames(ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_THROBBER));
+}
+
+Throbber::~Throbber() {
+  Stop();
+}
+
+void Throbber::Start() {
+  if (running_)
+    return;
+
+  start_time_ = Time::Now();
+
+  timer_.Start(FROM_HERE, frame_time_ - TimeDelta::FromMilliseconds(10),
+               this, &Throbber::Run);
+
+  running_ = true;
+
+  SchedulePaint();  // paint right away
+}
+
+void Throbber::Stop() {
+  if (!running_)
+    return;
+
+  timer_.Stop();
+
+  running_ = false;
+  SchedulePaint();  // Important if we're not painting while stopped
+}
+
+void Throbber::SetFrames(SkBitmap* frames) {
+  frames_ = frames;
+  DCHECK(frames_->width() > 0 && frames_->height() > 0);
+  DCHECK(frames_->width() % frames_->height() == 0);
+  frame_count_ = frames_->width() / frames_->height();
+  PreferredSizeChanged();
+}
+
+void Throbber::Run() {
+  DCHECK(running_);
+
+  SchedulePaint();
+}
+
+gfx::Size Throbber::GetPreferredSize() {
+  return gfx::Size(frames_->height(), frames_->height());
+}
+
+void Throbber::OnPaint(gfx::Canvas* canvas) {
+  if (!running_ && !paint_while_stopped_)
+    return;
+
+  const TimeDelta elapsed_time = Time::Now() - start_time_;
+  const int current_frame =
+      static_cast<int>(elapsed_time / frame_time_) % frame_count_;
+
+  int image_size = frames_->height();
+  int image_offset = current_frame * image_size;
+  canvas->DrawBitmapInt(*frames_,
+                        image_offset, 0, image_size, image_size,
+                        0, 0, image_size, image_size,
+                        false);
+}
+
+
+
+// Smoothed throbber ---------------------------------------------------------
+
+
+// Delay after work starts before starting throbber, in milliseconds.
+static const int kStartDelay = 200;
+
+// Delay after work stops before stopping, in milliseconds.
+static const int kStopDelay = 50;
+
+
+SmoothedThrobber::SmoothedThrobber(int frame_time_ms)
+    : Throbber(frame_time_ms, /* paint_while_stopped= */ false),
+      start_delay_ms_(kStartDelay),
+      stop_delay_ms_(kStopDelay) {
+}
+
+SmoothedThrobber::~SmoothedThrobber() {}
+
+void SmoothedThrobber::Start() {
+  stop_timer_.Stop();
+
+  if (!running_ && !start_timer_.IsRunning()) {
+    start_timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(start_delay_ms_),
+                       this, &SmoothedThrobber::StartDelayOver);
+  }
+}
+
+void SmoothedThrobber::StartDelayOver() {
+  Throbber::Start();
+}
+
+void SmoothedThrobber::Stop() {
+  if (!running_)
+    start_timer_.Stop();
+
+  stop_timer_.Stop();
+  stop_timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(stop_delay_ms_),
+                    this, &SmoothedThrobber::StopDelayOver);
+}
+
+void SmoothedThrobber::StopDelayOver() {
+  Throbber::Stop();
+}
+
+// Checkmark throbber ---------------------------------------------------------
+
+CheckmarkThrobber::CheckmarkThrobber()
+    : Throbber(kFrameTimeMs, false),
+      checked_(false) {
+  InitClass();
+}
+
+void CheckmarkThrobber::SetChecked(bool checked) {
+  bool changed = checked != checked_;
+  if (changed) {
+    checked_ = checked;
+    SchedulePaint();
+  }
+}
+
+void CheckmarkThrobber::OnPaint(gfx::Canvas* canvas) {
+  if (running_) {
+    // Let the throbber throb...
+    Throbber::OnPaint(canvas);
+    return;
+  }
+  // Otherwise we paint our tick mark or nothing depending on our state.
+  if (checked_) {
+    int checkmark_x = (width() - checkmark_->width()) / 2;
+    int checkmark_y = (height() - checkmark_->height()) / 2;
+    canvas->DrawBitmapInt(*checkmark_, checkmark_x, checkmark_y);
+  }
+}
+
+// static
+void CheckmarkThrobber::InitClass() {
+  static bool initialized = false;
+  if (!initialized) {
+    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+    checkmark_ = rb.GetBitmapNamed(IDR_CHECKMARK);
+    initialized = true;
+  }
+}
+
+// static
+SkBitmap* CheckmarkThrobber::checkmark_ = NULL;
+
+}  // namespace views
diff --git a/ui/views/controls/throbber.h b/ui/views/controls/throbber.h
new file mode 100644
index 0000000..e40828f
--- /dev/null
+++ b/ui/views/controls/throbber.h
@@ -0,0 +1,128 @@
+// Copyright (c) 2011 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.
+
+#ifndef UI_VIEWS_CONTROLS_THROBBER_H_
+#define UI_VIEWS_CONTROLS_THROBBER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/time.h"
+#include "base/timer.h"
+#include "views/view.h"
+
+class SkBitmap;
+
+namespace views {
+
+// Throbbers display an animation, usually used as a status indicator.
+
+class VIEWS_EXPORT Throbber : public View {
+ public:
+  // |frame_time_ms| is the amount of time that should elapse between frames
+  //                 (in milliseconds)
+  // If |paint_while_stopped| is false, this view will be invisible when not
+  // running.
+  Throbber(int frame_time_ms, bool paint_while_stopped);
+  Throbber(int frame_time_ms, bool paint_while_stopped, SkBitmap* frames);
+  virtual ~Throbber();
+
+  // Start and stop the throbber animation
+  virtual void Start();
+  virtual void Stop();
+
+  // Set custom throbber frames. Otherwise IDR_THROBBER is loaded.
+  void SetFrames(SkBitmap* frames);
+
+  // overridden from View
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+
+ protected:
+  // Specifies whether the throbber is currently animating or not
+  bool running_;
+
+ private:
+  void Run();
+
+  bool paint_while_stopped_;
+  int frame_count_;  // How many frames we have.
+  base::Time start_time_;  // Time when Start was called.
+  SkBitmap* frames_;  // Frames bitmaps.
+  base::TimeDelta frame_time_;  // How long one frame is displayed.
+  base::RepeatingTimer<Throbber> timer_;  // Used to schedule Run calls.
+
+  DISALLOW_COPY_AND_ASSIGN(Throbber);
+};
+
+// A SmoothedThrobber is a throbber that is representing potentially short
+// and nonoverlapping bursts of work.  SmoothedThrobber ignores small
+// pauses in the work stops and starts, and only starts its throbber after
+// a small amount of work time has passed.
+class VIEWS_EXPORT SmoothedThrobber : public Throbber {
+ public:
+  SmoothedThrobber(int frame_delay_ms);
+  SmoothedThrobber(int frame_delay_ms, SkBitmap* frames);
+  virtual ~SmoothedThrobber();
+
+  virtual void Start() OVERRIDE;
+  virtual void Stop() OVERRIDE;
+
+  void set_start_delay_ms(int value) { start_delay_ms_ = value; }
+  void set_stop_delay_ms(int value) { stop_delay_ms_ = value; }
+
+ private:
+  // Called when the startup-delay timer fires
+  // This function starts the actual throbbing.
+  void StartDelayOver();
+
+  // Called when the shutdown-delay timer fires.
+  // This function stops the actual throbbing.
+  void StopDelayOver();
+
+  // Delay after work starts before starting throbber, in milliseconds.
+  int start_delay_ms_;
+
+  // Delay after work stops before stopping, in milliseconds.
+  int stop_delay_ms_;
+
+  base::OneShotTimer<SmoothedThrobber> start_timer_;
+  base::OneShotTimer<SmoothedThrobber> stop_timer_;
+
+  DISALLOW_COPY_AND_ASSIGN(SmoothedThrobber);
+};
+
+// A CheckmarkThrobber is a special variant of throbber that has three states:
+//   1. not yet completed (which paints nothing)
+//   2. working (which paints the throbber animation)
+//   3. completed (which paints a checkmark)
+//
+class VIEWS_EXPORT CheckmarkThrobber : public Throbber {
+ public:
+  CheckmarkThrobber();
+
+  // If checked is true, the throbber stops spinning and displays a checkmark.
+  // If checked is false, the throbber stops spinning and displays nothing.
+  void SetChecked(bool checked);
+
+  // Overridden from Throbber:
+  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+
+ private:
+  static const int kFrameTimeMs = 30;
+
+  static void InitClass();
+
+  // Whether or not we should display a checkmark.
+  bool checked_;
+
+  // The checkmark image.
+  static SkBitmap* checkmark_;
+
+  DISALLOW_COPY_AND_ASSIGN(CheckmarkThrobber);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_THROBBER_H_
diff --git a/ui/views/controls/tree/tree_view.h b/ui/views/controls/tree/tree_view.h
index 9b1fd75..035d3f6 100644
--- a/ui/views/controls/tree/tree_view.h
+++ b/ui/views/controls/tree/tree_view.h
@@ -15,7 +15,7 @@
 #include "base/compiler_specific.h"
 #include "ui/base/keycodes/keyboard_codes.h"
 #include "ui/base/models/tree_model.h"
-#include "views/controls/native_control.h"
+#include "ui/views/controls/native_control.h"
 
 namespace views {
 
diff --git a/ui/views/examples/double_split_view_example.cc b/ui/views/examples/double_split_view_example.cc
index 516c191..4620f72 100644
--- a/ui/views/examples/double_split_view_example.cc
+++ b/ui/views/examples/double_split_view_example.cc
@@ -4,8 +4,8 @@
 
 #include "ui/views/examples/double_split_view_example.h"
 
+#include "ui/views/controls/single_split_view.h"
 #include "ui/views/layout/grid_layout.h"
-#include "views/controls/single_split_view.h"
 
 namespace {
 
diff --git a/ui/views/examples/message_box_example.cc b/ui/views/examples/message_box_example.cc
index e1b1542..942f22b 100644
--- a/ui/views/examples/message_box_example.cc
+++ b/ui/views/examples/message_box_example.cc
@@ -5,8 +5,8 @@
 #include "ui/views/examples/message_box_example.h"
 
 #include "base/utf_string_conversions.h"
+#include "ui/views/controls/message_box_view.h"
 #include "ui/views/layout/grid_layout.h"
-#include "views/controls/message_box_view.h"
 #include "views/view.h"
 
 namespace views {
diff --git a/ui/views/examples/progress_bar_example.cc b/ui/views/examples/progress_bar_example.cc
index e28cad3..f355007 100644
--- a/ui/views/examples/progress_bar_example.cc
+++ b/ui/views/examples/progress_bar_example.cc
@@ -6,8 +6,8 @@
 
 #include "base/utf_string_conversions.h"
 #include "ui/views/controls/button/text_button.h"
+#include "ui/views/controls/progress_bar.h"
 #include "ui/views/layout/grid_layout.h"
-#include "views/controls/progress_bar.h"
 #include "views/view.h"
 
 namespace {
diff --git a/ui/views/examples/scroll_view_example.h b/ui/views/examples/scroll_view_example.h
index 62de4e8..d18eac9 100644
--- a/ui/views/examples/scroll_view_example.h
+++ b/ui/views/examples/scroll_view_example.h
@@ -11,8 +11,8 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "ui/views/controls/button/text_button.h"
+#include "ui/views/controls/scroll_view.h"
 #include "ui/views/examples/example_base.h"
-#include "views/controls/scroll_view.h"
 
 namespace views {
 namespace examples {
diff --git a/ui/views/examples/single_split_view_example.cc b/ui/views/examples/single_split_view_example.cc
index 6b703e3..70e4b19 100644
--- a/ui/views/examples/single_split_view_example.cc
+++ b/ui/views/examples/single_split_view_example.cc
@@ -4,8 +4,8 @@
 
 #include "ui/views/examples/single_split_view_example.h"
 
+#include "ui/views/controls/single_split_view.h"
 #include "ui/views/layout/grid_layout.h"
-#include "views/controls/single_split_view.h"
 
 namespace views {
 namespace examples {
diff --git a/ui/views/examples/single_split_view_example.h b/ui/views/examples/single_split_view_example.h
index 9c9d919..c3a95be 100644
--- a/ui/views/examples/single_split_view_example.h
+++ b/ui/views/examples/single_split_view_example.h
@@ -8,8 +8,8 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "ui/views/controls/single_split_view_listener.h"
 #include "ui/views/examples/example_base.h"
-#include "views/controls/single_split_view_listener.h"
 
 namespace views {
 namespace examples {
diff --git a/ui/views/examples/throbber_example.cc b/ui/views/examples/throbber_example.cc
index f25152a0..a3af5cf 100644
--- a/ui/views/examples/throbber_example.cc
+++ b/ui/views/examples/throbber_example.cc
@@ -4,8 +4,8 @@
 
 #include "ui/views/examples/throbber_example.h"
 
+#include "ui/views/controls/throbber.h"
 #include "ui/views/layout/fill_layout.h"
-#include "views/controls/throbber.h"
 #include "views/view.h"
 
 namespace views {
diff --git a/ui/views/focus/focus_traversal_unittest.cc b/ui/views/focus/focus_traversal_unittest.cc
index 3605015..fc58df8 100644
--- a/ui/views/focus/focus_traversal_unittest.cc
+++ b/ui/views/focus/focus_traversal_unittest.cc
@@ -14,11 +14,11 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/link.h"
 #include "ui/views/controls/native/native_view_host.h"
+#include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/focus/focus_manager_test.h"
 #include "ui/views/widget/root_view.h"
 #include "ui/views/widget/widget.h"
-#include "views/controls/scroll_view.h"
 
 #if !defined(USE_AURA)
 #include "ui/views/controls/tabbed_pane/tabbed_pane.h"
diff --git a/ui/views/widget/native_widget_win.cc b/ui/views/widget/native_widget_win.cc
index ce5ad17..f328ecb 100644
--- a/ui/views/widget/native_widget_win.cc
+++ b/ui/views/widget/native_widget_win.cc
@@ -33,6 +33,7 @@
 #include "ui/gfx/path.h"
 #include "ui/gfx/screen.h"
 #include "ui/views/accessibility/native_view_accessibility_win.h"
+#include "ui/views/controls/native_control_win.h"
 #include "ui/views/controls/textfield/native_textfield_views.h"
 #include "ui/views/focus/accelerator_handler.h"
 #include "ui/views/focus/view_storage.h"
@@ -45,7 +46,6 @@
 #include "ui/views/widget/root_view.h"
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/views/window/native_frame_view.h"
-#include "views/controls/native_control_win.h"
 #include "views/views_delegate.h"
 
 #pragma comment(lib, "dwmapi.lib")
-- 
cgit v1.1