Move src/chrome/views to src/views. RS=darin http://crbug.com/11387

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15604 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/views/DEPS b/views/DEPS
new file mode 100644
index 0000000..8ff5f48
--- /dev/null
+++ b/views/DEPS
@@ -0,0 +1,12 @@
+include_rules = [

+  "+app",

+  "+chrome/app",

+  "+chrome/app/theme",

+  "+chrome/browser",

+  "+chrome/browser/views",

+  "+chrome/common",

+  "+grit",  # For generated headers

+  "+skia/ext",

+  "+skia/include",

+  "+webkit/glue",

+]

diff --git a/views/accelerator.cc b/views/accelerator.cc
new file mode 100644
index 0000000..b9a474a
--- /dev/null
+++ b/views/accelerator.cc
@@ -0,0 +1,130 @@
+// Copyright (c) 2006-2008 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 "views/accelerator.h"
+
+#include <windows.h>
+
+#include "app/l10n_util.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "grit/generated_resources.h"
+
+namespace views {
+
+std::wstring Accelerator::GetShortcutText() const {
+  int string_id = 0;
+  switch(key_code_) {
+  case VK_TAB:
+    string_id = IDS_TAB_KEY;
+    break;
+  case VK_RETURN:
+    string_id = IDS_ENTER_KEY;
+    break;
+  case VK_ESCAPE:
+    string_id = IDS_ESC_KEY;
+    break;
+  case VK_PRIOR:
+    string_id = IDS_PAGEUP_KEY;
+    break;
+  case VK_NEXT:
+    string_id = IDS_PAGEDOWN_KEY;
+    break;
+  case VK_END:
+    string_id = IDS_END_KEY;
+    break;
+  case VK_HOME:
+    string_id = IDS_HOME_KEY;
+    break;
+  case VK_INSERT:
+    string_id = IDS_INSERT_KEY;
+    break;
+  case VK_DELETE:
+    string_id = IDS_DELETE_KEY;
+    break;
+  case VK_F1:
+    string_id = IDS_F1_KEY;
+    break;
+  case VK_F11:
+    string_id = IDS_F11_KEY;
+    break;
+  }
+
+  std::wstring shortcut;
+  if (!string_id) {
+    // Our fallback is to try translate the key code to a regular character
+    // unless it is one of digits (VK_0 to VK_9). Some keyboard
+    // layouts have characters other than digits assigned in
+    // an unshifted mode (e.g. French AZERY layout has 'a with grave
+    // accent' for '0'). For display in the menu (e.g. Ctrl-0 for the
+    // default zoom level), we leave VK_[0-9] alone without translation.
+    wchar_t key;
+    if (key_code_ >= '0' && key_code_ <= '9')
+      key = key_code_;
+    else
+      key = LOWORD(::MapVirtualKeyW(key_code_, MAPVK_VK_TO_CHAR));
+    shortcut += key;
+  } else {
+    shortcut = l10n_util::GetString(string_id);
+  }
+
+  // Checking whether the character used for the accelerator is alphanumeric.
+  // If it is not, then we need to adjust the string later on if the locale is
+  // right-to-left. See below for more information of why such adjustment is
+  // required.
+  std::wstring shortcut_rtl;
+  bool adjust_shortcut_for_rtl = false;
+  if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT &&
+      shortcut.length() == 1 &&
+      !IsAsciiAlpha(shortcut.at(0)) &&
+      !IsAsciiDigit(shortcut.at(0))) {
+    adjust_shortcut_for_rtl = true;
+    shortcut_rtl.assign(shortcut);
+  }
+
+  if (IsShiftDown())
+    shortcut = l10n_util::GetStringF(IDS_SHIFT_MODIFIER, shortcut);
+
+  // Note that we use 'else-if' in order to avoid using Ctrl+Alt as a shortcut.
+  // See http://blogs.msdn.com/oldnewthing/archive/2004/03/29/101121.aspx for
+  // more information.
+  if (IsCtrlDown())
+    shortcut = l10n_util::GetStringF(IDS_CONTROL_MODIFIER, shortcut);
+  else if (IsAltDown())
+    shortcut = l10n_util::GetStringF(IDS_ALT_MODIFIER, shortcut);
+
+  // For some reason, menus in Windows ignore standard Unicode directionality
+  // marks (such as LRE, PDF, etc.). On RTL locales, we use RTL menus and
+  // therefore any text we draw for the menu items is drawn in an RTL context.
+  // Thus, the text "Ctrl++" (which we currently use for the Zoom In option)
+  // appears as "++Ctrl" in RTL because the Unicode BiDi algorithm puts
+  // punctuations on the left when the context is right-to-left. Shortcuts that
+  // do not end with a punctuation mark (such as "Ctrl+H" do not have this
+  // problem).
+  //
+  // The only way to solve this problem is to adjust the string if the locale
+  // is RTL so that it is drawn correnctly in an RTL context. Instead of
+  // returning "Ctrl++" in the above example, we return "++Ctrl". This will
+  // cause the text to appear as "Ctrl++" when Windows draws the string in an
+  // RTL context because the punctunation no longer appears at the end of the
+  // string.
+  //
+  // TODO(idana) bug# 1232732: this hack can be avoided if instead of using
+  // views::Menu we use views::MenuItemView because the latter is a View
+  // subclass and therefore it supports marking text as RTL or LTR using
+  // standard Unicode directionality marks.
+  if (adjust_shortcut_for_rtl) {
+    int key_length = static_cast<int>(shortcut_rtl.length());
+    DCHECK_GT(key_length, 0);
+    shortcut_rtl.append(L"+");
+
+    // Subtracting the size of the shortcut key and 1 for the '+' sign.
+    shortcut_rtl.append(shortcut, 0, shortcut.length() - key_length - 1);
+    shortcut.swap(shortcut_rtl);
+  }
+
+  return shortcut;
+}
+
+}  // namespace views
diff --git a/views/accelerator.h b/views/accelerator.h
new file mode 100644
index 0000000..bb8f91f
--- /dev/null
+++ b/views/accelerator.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2006-2008 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.
+
+// This class describe a keyboard accelerator (or keyboard shortcut).
+// Keyboard accelerators are registered with the FocusManager.
+// It has a copy constructor and assignment operator so that it can be copied.
+// It also defines the < operator so that it can be used as a key in a std::map.
+//
+
+#ifndef VIEWS_ACCELERATOR_H_
+#define VIEWS_ACCELERATOR_H_
+
+#include <string>
+
+#include "views/event.h"
+
+namespace views {
+
+class Accelerator {
+ public:
+  Accelerator(int keycode,
+              bool shift_pressed, bool ctrl_pressed, bool alt_pressed)
+      : key_code_(keycode) {
+    modifiers_ = 0;
+    if (shift_pressed)
+      modifiers_ |= Event::EF_SHIFT_DOWN;
+    if (ctrl_pressed)
+      modifiers_ |= Event::EF_CONTROL_DOWN;
+    if (alt_pressed)
+      modifiers_ |= Event::EF_ALT_DOWN;
+  }
+
+  Accelerator(const Accelerator& accelerator) {
+    key_code_ = accelerator.key_code_;
+    modifiers_ = accelerator.modifiers_;
+  }
+
+  ~Accelerator() { };
+
+  Accelerator& operator=(const Accelerator& accelerator) {
+    if (this != &accelerator) {
+      key_code_ = accelerator.key_code_;
+      modifiers_ = accelerator.modifiers_;
+    }
+    return *this;
+  }
+
+  // We define the < operator so that the KeyboardShortcut can be used as a key
+  // in a std::map.
+  bool operator <(const Accelerator& rhs) const {
+    if (key_code_ != rhs.key_code_)
+      return key_code_ < rhs.key_code_;
+    return modifiers_ < rhs.modifiers_;
+  }
+
+  bool operator ==(const Accelerator& rhs) const {
+    return (key_code_ == rhs.key_code_) && (modifiers_ == rhs.modifiers_);
+  }
+
+  bool operator !=(const Accelerator& rhs) const {
+    return !(*this == rhs);
+  }
+
+  bool IsShiftDown() const {
+    return (modifiers_ & Event::EF_SHIFT_DOWN) == Event::EF_SHIFT_DOWN;
+  }
+
+  bool IsCtrlDown() const {
+    return (modifiers_ & Event::EF_CONTROL_DOWN) == Event::EF_CONTROL_DOWN;
+  }
+
+  bool IsAltDown() const {
+    return (modifiers_ & Event::EF_ALT_DOWN) == Event::EF_ALT_DOWN;
+  }
+
+  int GetKeyCode() const {
+    return key_code_;
+  }
+
+  // Returns a string with the localized shortcut if any.
+  std::wstring GetShortcutText() const;
+
+ private:
+  // The window keycode (VK_...).
+  int key_code_;
+
+  // The state of the Shift/Ctrl/Alt keys (see event.h).
+  int modifiers_;
+};
+
+// An interface that classes that want to register for keyboard accelerators
+// should implement.
+class AcceleratorTarget {
+ public:
+  // This method should return true if the accelerator was processed.
+  virtual bool AcceleratorPressed(const Accelerator& accelerator) = 0;
+};
+}
+
+#endif  // VIEWS_ACCELERATOR_H_
diff --git a/views/accessibility/view_accessibility.cc b/views/accessibility/view_accessibility.cc
new file mode 100644
index 0000000..0e2f8748
--- /dev/null
+++ b/views/accessibility/view_accessibility.cc
@@ -0,0 +1,698 @@
+// Copyright (c) 2006-2008 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 "views/accessibility/view_accessibility.h"
+
+#include "views/accessibility/view_accessibility_wrapper.h"
+#include "views/widget/widget.h"
+
+HRESULT ViewAccessibility::Initialize(views::View* view) {
+  if (!view) {
+    return E_INVALIDARG;
+  }
+
+  view_ = view;
+  return S_OK;
+}
+
+// TODO(klink): Handle case where child View is not contained by parent.
+STDMETHODIMP ViewAccessibility::accHitTest(LONG x_left, LONG y_top,
+                                           VARIANT* child) {
+  if (!child) {
+    return E_INVALIDARG;
+  }
+
+  gfx::Point pt(x_left, y_top);
+  views::View::ConvertPointToView(NULL, view_, &pt);
+
+  if (!view_->HitTest(pt)) {
+    // If containing parent is not hit, return with failure.
+    child->vt = VT_EMPTY;
+    return S_FALSE;
+  }
+
+  int child_count = view_->GetChildViewCount();
+  bool child_hit = false;
+  views::View* child_view = NULL;
+  for (int child_id = 0; child_id < child_count; ++child_id) {
+    // Search for hit within any of the children.
+    child_view = view_->GetChildViewAt(child_id);
+    views::View::ConvertPointToView(view_, child_view, &pt);
+    if (child_view->HitTest(pt)) {
+      // Store child_id (adjusted with +1 to convert to MSAA indexing).
+      child->lVal = child_id + 1;
+      child_hit = true;
+      break;
+    }
+    // Convert point back to parent view to test next child.
+    views::View::ConvertPointToView(child_view, view_, &pt);
+  }
+
+  child->vt = VT_I4;
+
+  if (!child_hit) {
+    // No child hit, return parent id.
+    child->lVal = CHILDID_SELF;
+  } else {
+    if (child_view == NULL) {
+      return E_FAIL;
+    } else if (child_view->GetChildViewCount() != 0) {
+      // Retrieve IDispatch for child, if it is not a leaf.
+      child->vt = VT_DISPATCH;
+      if ((GetViewAccessibilityWrapper(child_view))->
+          GetInstance(IID_IAccessible,
+                      reinterpret_cast<void**>(&child->pdispVal)) == S_OK) {
+        // Increment the reference count for the retrieved interface.
+        child->pdispVal->AddRef();
+        return S_OK;
+      } else {
+        return E_NOINTERFACE;
+      }
+    }
+  }
+
+  return S_OK;
+}
+
+STDMETHODIMP ViewAccessibility::accLocation(LONG* x_left, LONG* y_top,
+                                            LONG* width, LONG* height,
+                                            VARIANT var_id) {
+  if (var_id.vt != VT_I4 || !x_left || !y_top || !width || !height) {
+    return E_INVALIDARG;
+  }
+
+  gfx::Rect view_bounds;
+  // Retrieving the parent View to be used for converting from view-to-screen
+  // coordinates.
+  views::View* parent = view_->GetParent();
+
+  if (parent == NULL) {
+    // If no parent, remain within the same View.
+    parent = view_;
+  }
+
+  if (var_id.lVal == CHILDID_SELF) {
+    // Retrieve active View's bounds.
+    view_bounds = view_->bounds();
+  } else {
+    // Check to see if child is out-of-bounds.
+    if (!IsValidChild((var_id.lVal - 1), view_)) {
+      return E_INVALIDARG;
+    }
+    // Retrieve child bounds.
+    view_bounds = view_->GetChildViewAt(var_id.lVal - 1)->bounds();
+    // Parent View is current View.
+    parent = view_;
+  }
+
+  if (!view_bounds.IsEmpty()) {
+    *width  = view_bounds.width();
+    *height = view_bounds.height();
+
+    gfx::Point topleft(view_bounds.origin());
+    views::View::ConvertPointToScreen(parent, &topleft);
+    *x_left = topleft.x();
+    *y_top  = topleft.y();
+  } else {
+    return E_FAIL;
+  }
+  return S_OK;
+}
+
+STDMETHODIMP ViewAccessibility::accNavigate(LONG nav_dir, VARIANT start,
+                                            VARIANT* end) {
+  if (start.vt != VT_I4 || !end) {
+    return E_INVALIDARG;
+  }
+
+  switch (nav_dir) {
+    case NAVDIR_FIRSTCHILD:
+    case NAVDIR_LASTCHILD: {
+      if (start.lVal != CHILDID_SELF) {
+        // Start of navigation must be on the View itself.
+        return E_INVALIDARG;
+      } else if (view_->GetChildViewCount() == 0) {
+        // No children found.
+        return S_FALSE;
+      }
+
+      // Set child_id based on first or last child.
+      int child_id = 0;
+      if (nav_dir == NAVDIR_LASTCHILD) {
+        child_id = view_->GetChildViewCount() - 1;
+      }
+
+      views::View* child = view_->GetChildViewAt(child_id);
+
+      if (child->GetChildViewCount() != 0) {
+        end->vt = VT_DISPATCH;
+        if ((GetViewAccessibilityWrapper(child))->
+            GetInstance(IID_IAccessible,
+                        reinterpret_cast<void**>(&end->pdispVal)) == S_OK) {
+          // Increment the reference count for the retrieved interface.
+          end->pdispVal->AddRef();
+          return S_OK;
+        } else {
+          return E_NOINTERFACE;
+        }
+      } else {
+        end->vt = VT_I4;
+        // Set return child lVal, adjusted for MSAA indexing. (MSAA
+        // child indexing starts with 1, whereas View indexing starts with 0).
+        end->lVal = child_id + 1;
+      }
+      break;
+    }
+    case NAVDIR_LEFT:
+    case NAVDIR_UP:
+    case NAVDIR_PREVIOUS:
+    case NAVDIR_RIGHT:
+    case NAVDIR_DOWN:
+    case NAVDIR_NEXT: {
+      // Retrieve parent to access view index and perform bounds checking.
+      views::View* parent = view_->GetParent();
+      if (!parent) {
+        return E_FAIL;
+      }
+
+      if (start.lVal == CHILDID_SELF) {
+        int view_index = parent->GetChildIndex(view_);
+        // Check navigation bounds, adjusting for View child indexing (MSAA
+        // child indexing starts with 1, whereas View indexing starts with 0).
+        if (!IsValidNav(nav_dir, view_index, -1,
+                        parent->GetChildViewCount())) {
+          // Navigation attempted to go out-of-bounds.
+          end->vt = VT_EMPTY;
+          return S_FALSE;
+        } else {
+          if (IsNavDirNext(nav_dir)) {
+            view_index += 1;
+          } else {
+            view_index -=1;
+          }
+        }
+
+        views::View* child = parent->GetChildViewAt(view_index);
+        if (child->GetChildViewCount() != 0) {
+          end->vt = VT_DISPATCH;
+          // Retrieve IDispatch for non-leaf child.
+          if ((GetViewAccessibilityWrapper(child))->
+              GetInstance(IID_IAccessible,
+                          reinterpret_cast<void**>(&end->pdispVal)) == S_OK) {
+            // Increment the reference count for the retrieved interface.
+            end->pdispVal->AddRef();
+            return S_OK;
+          } else {
+            return E_NOINTERFACE;
+          }
+        } else {
+          end->vt = VT_I4;
+          // Modifying view_index to give lVal correct MSAA-based value. (MSAA
+          // child indexing starts with 1, whereas View indexing starts with 0).
+          end->lVal = view_index + 1;
+        }
+      } else {
+        // Check navigation bounds, adjusting for MSAA child indexing (MSAA
+        // child indexing starts with 1, whereas View indexing starts with 0).
+        if (!IsValidNav(nav_dir, start.lVal, 0,
+                        parent->GetChildViewCount() + 1)) {
+            // Navigation attempted to go out-of-bounds.
+            end->vt = VT_EMPTY;
+            return S_FALSE;
+          } else {
+            if (IsNavDirNext(nav_dir)) {
+              start.lVal += 1;
+            } else {
+              start.lVal -= 1;
+            }
+        }
+
+        HRESULT result = this->get_accChild(start, &end->pdispVal);
+        if (result == S_FALSE) {
+          // Child is a leaf.
+          end->vt = VT_I4;
+          end->lVal = start.lVal;
+        } else if (result == E_INVALIDARG) {
+          return E_INVALIDARG;
+        } else {
+          // Child is not a leaf.
+          end->vt = VT_DISPATCH;
+        }
+      }
+      break;
+    }
+    default:
+      return E_INVALIDARG;
+  }
+  // Navigation performed correctly. Global return for this function, if no
+  // error triggered an escape earlier.
+  return S_OK;
+}
+
+STDMETHODIMP ViewAccessibility::get_accChild(VARIANT var_child,
+                                             IDispatch** disp_child) {
+  if (var_child.vt != VT_I4 || !disp_child) {
+    return E_INVALIDARG;
+  }
+
+  // If var_child is the parent, remain with the same IDispatch.
+  if (var_child.lVal == CHILDID_SELF) {
+    return S_OK;
+  }
+
+  views::View* child_view = NULL;
+  bool get_iaccessible = false;
+
+  // Check to see if child is out-of-bounds.
+  if (IsValidChild((var_child.lVal - 1), view_)) {
+    child_view = view_->GetChildViewAt(var_child.lVal - 1);
+  } else {
+    // Child is located elsewhere in the hierarchy, get ID and adjust for MSAA.
+    child_view = view_->GetViewByID(static_cast<int>(var_child.lVal));
+    get_iaccessible = true;
+  }
+
+  if (!child_view) {
+    // No child found.
+    *disp_child = NULL;
+    return E_FAIL;
+  }
+
+  if (get_iaccessible || child_view->GetChildViewCount() != 0) {
+    // Retrieve the IUnknown interface for the requested child view, and
+    // assign the IDispatch returned.
+    if ((GetViewAccessibilityWrapper(child_view))->
+        GetInstance(IID_IAccessible,
+                    reinterpret_cast<void**>(disp_child)) == S_OK) {
+      // Increment the reference count for the retrieved interface.
+      (*disp_child)->AddRef();
+      return S_OK;
+    } else {
+      // No interface, return failure.
+      return E_NOINTERFACE;
+    }
+  } else {
+    // When at a leaf, children are handled by the parent object.
+    *disp_child = NULL;
+    return S_FALSE;
+  }
+}
+
+STDMETHODIMP ViewAccessibility::get_accChildCount(LONG* child_count) {
+  if (!child_count || !view_) {
+    return E_INVALIDARG;
+  }
+
+  *child_count = view_->GetChildViewCount();
+  return S_OK;
+}
+
+STDMETHODIMP ViewAccessibility::get_accDefaultAction(VARIANT var_id,
+                                                     BSTR* def_action) {
+  if (var_id.vt != VT_I4 || !def_action) {
+    return E_INVALIDARG;
+  }
+
+  std::wstring temp_action;
+
+  if (var_id.lVal == CHILDID_SELF) {
+    view_->GetAccessibleDefaultAction(&temp_action);
+  } else {
+    if (!IsValidChild((var_id.lVal - 1), view_)) {
+      return E_INVALIDARG;
+    }
+    view_->GetChildViewAt(var_id.lVal - 1)->
+        GetAccessibleDefaultAction(&temp_action);
+  }
+  if (!temp_action.empty()) {
+    *def_action = CComBSTR(temp_action.c_str()).Detach();
+  } else {
+    return S_FALSE;
+  }
+
+  return S_OK;
+}
+
+STDMETHODIMP ViewAccessibility::get_accDescription(VARIANT var_id, BSTR* desc) {
+  if (var_id.vt != VT_I4 || !desc) {
+    return E_INVALIDARG;
+  }
+
+  std::wstring temp_desc;
+
+  if (var_id.lVal == CHILDID_SELF) {
+    view_->GetTooltipText(0, 0, &temp_desc);
+  } else {
+    if (!IsValidChild((var_id.lVal - 1), view_)) {
+      return E_INVALIDARG;
+    }
+    view_->GetChildViewAt(var_id.lVal - 1)->GetTooltipText(0, 0, &temp_desc);
+  }
+  if (!temp_desc.empty()) {
+    *desc = CComBSTR(temp_desc.c_str()).Detach();
+  } else {
+    return S_FALSE;
+  }
+
+  return S_OK;
+}
+
+STDMETHODIMP ViewAccessibility::get_accFocus(VARIANT* focus_child) {
+  if (!focus_child) {
+    return E_INVALIDARG;
+  }
+
+  if (view_->GetChildViewCount() == 0 && view_->HasFocus()) {
+    // Parent view has focus.
+    focus_child->vt = VT_I4;
+    focus_child->lVal = CHILDID_SELF;
+  } else {
+    bool has_focus = false;
+    int child_count = view_->GetChildViewCount();
+    // Search for child view with focus.
+    for (int child_id = 0; child_id < child_count; ++child_id) {
+      if (view_->GetChildViewAt(child_id)->HasFocus()) {
+        focus_child->vt = VT_I4;
+        focus_child->lVal = child_id + 1;
+
+        // If child view is no leaf, retrieve IDispatch.
+        if (view_->GetChildViewAt(child_id)->GetChildViewCount() != 0) {
+          focus_child->vt = VT_DISPATCH;
+          this->get_accChild(*focus_child, &focus_child->pdispVal);
+        }
+        has_focus = true;
+        break;
+      }
+    }
+    // No current focus on any of the children.
+    if (!has_focus) {
+      focus_child->vt = VT_EMPTY;
+      return S_FALSE;
+    }
+  }
+
+  return S_OK;
+}
+
+STDMETHODIMP ViewAccessibility::get_accKeyboardShortcut(VARIANT var_id,
+                                                        BSTR* acc_key) {
+  if (var_id.vt != VT_I4 || !acc_key) {
+    return E_INVALIDARG;
+  }
+
+  std::wstring temp_key;
+
+  if (var_id.lVal == CHILDID_SELF) {
+    view_->GetAccessibleKeyboardShortcut(&temp_key);
+  } else {
+    if (!IsValidChild((var_id.lVal - 1), view_)) {
+      return E_INVALIDARG;
+    }
+    view_->GetChildViewAt(var_id.lVal - 1)->
+        GetAccessibleKeyboardShortcut(&temp_key);
+  }
+  if (!temp_key.empty()) {
+    *acc_key = CComBSTR(temp_key.c_str()).Detach();
+  } else {
+    return S_FALSE;
+  }
+
+  return S_OK;
+}
+
+STDMETHODIMP ViewAccessibility::get_accName(VARIANT var_id, BSTR* name) {
+  if (var_id.vt != VT_I4 || !name) {
+    return E_INVALIDARG;
+  }
+
+  std::wstring temp_name;
+
+  if (var_id.lVal == CHILDID_SELF) {
+    // Retrieve the parent view's name.
+    view_->GetAccessibleName(&temp_name);
+  } else {
+    if (!IsValidChild((var_id.lVal - 1), view_)) {
+      return E_INVALIDARG;
+    }
+    // Retrieve the child view's name.
+    view_->GetChildViewAt(var_id.lVal - 1)->GetAccessibleName(&temp_name);
+  }
+  if (!temp_name.empty()) {
+    // Return name retrieved.
+    *name = CComBSTR(temp_name.c_str()).Detach();
+  } else {
+    // If view has no name, return S_FALSE.
+    return S_FALSE;
+  }
+
+  return S_OK;
+}
+
+STDMETHODIMP ViewAccessibility::get_accParent(IDispatch** disp_parent) {
+  if (!disp_parent) {
+    return E_INVALIDARG;
+  }
+
+  views::View* parent_view = view_->GetParent();
+
+  if (!parent_view) {
+    // This function can get called during teardown of WidetWin so we
+    // should bail out if we fail to get the HWND.
+    if (!view_->GetWidget() || !view_->GetWidget()->GetNativeView()) {
+      *disp_parent = NULL;
+      return S_FALSE;
+    }
+
+    // For a View that has no parent (e.g. root), point the accessible parent to
+    // the default implementation, to interface with Windows' hierarchy and to
+    // support calls from e.g. WindowFromAccessibleObject.
+    HRESULT hr =
+        ::AccessibleObjectFromWindow(view_->GetWidget()->GetNativeView(),
+                                     OBJID_WINDOW, IID_IAccessible,
+                                     reinterpret_cast<void**>(disp_parent));
+
+    if (!SUCCEEDED(hr)) {
+      *disp_parent = NULL;
+      return S_FALSE;
+    }
+
+    return S_OK;
+  }
+
+  // Retrieve the IUnknown interface for the parent view, and assign the
+  // IDispatch returned.
+  if ((GetViewAccessibilityWrapper(parent_view))->
+      GetInstance(IID_IAccessible,
+                  reinterpret_cast<void**>(disp_parent)) == S_OK) {
+    // Increment the reference count for the retrieved interface.
+    (*disp_parent)->AddRef();
+    return S_OK;
+  } else {
+    return E_NOINTERFACE;
+  }
+}
+
+STDMETHODIMP ViewAccessibility::get_accRole(VARIANT var_id, VARIANT* role) {
+  if (var_id.vt != VT_I4 || !role) {
+    return E_INVALIDARG;
+  }
+
+  AccessibilityTypes::Role acc_role;
+
+  if (var_id.lVal == CHILDID_SELF) {
+    // Retrieve parent role.
+    if (!view_->GetAccessibleRole(&acc_role)) {
+      return E_FAIL;
+    }
+  } else {
+    if (!IsValidChild((var_id.lVal - 1), view_)) {
+      return E_INVALIDARG;
+    }
+    // Retrieve child role.
+    if (!view_->GetChildViewAt(var_id.lVal - 1)->GetAccessibleRole(&acc_role)) {
+      role->vt = VT_EMPTY;
+      return E_FAIL;
+    }
+  }
+
+  role->vt = VT_I4;
+  role->lVal = MSAARole(acc_role);
+  return S_OK;
+}
+
+STDMETHODIMP ViewAccessibility::get_accState(VARIANT var_id, VARIANT* state) {
+  if (var_id.vt != VT_I4 || !state) {
+    return E_INVALIDARG;
+  }
+
+  state->vt = VT_I4;
+
+  if (var_id.lVal == CHILDID_SELF) {
+    // Retrieve all currently applicable states of the parent.
+    this->SetState(state, view_);
+  } else {
+    if (!IsValidChild((var_id.lVal - 1), view_)) {
+      return E_INVALIDARG;
+    }
+    // Retrieve all currently applicable states of the child.
+    this->SetState(state, view_->GetChildViewAt(var_id.lVal - 1));
+  }
+
+  // Make sure that state is not empty, and has the proper type.
+  if (state->vt == VT_EMPTY)
+    return E_FAIL;
+
+  return S_OK;
+}
+
+// Helper functions.
+
+bool ViewAccessibility::IsValidChild(int child_id, views::View* view) const {
+  if (((child_id) < 0) ||
+      ((child_id) >= view->GetChildViewCount())) {
+    return false;
+  }
+  return true;
+}
+
+bool ViewAccessibility::IsNavDirNext(int nav_dir) const {
+  if (nav_dir == NAVDIR_RIGHT || nav_dir == NAVDIR_DOWN ||
+      nav_dir == NAVDIR_NEXT) {
+      return true;
+  }
+  return false;
+}
+
+bool ViewAccessibility::IsValidNav(int nav_dir, int start_id, int lower_bound,
+                                   int upper_bound) const {
+  if (IsNavDirNext(nav_dir)) {
+    if ((start_id + 1) > upper_bound) {
+      return false;
+    }
+  } else {
+    if ((start_id - 1) <= lower_bound) {
+      return false;
+    }
+  }
+  return true;
+}
+
+void ViewAccessibility::SetState(VARIANT* msaa_state, views::View* view) {
+  // Default state; all views can have accessibility focus.
+  msaa_state->lVal |= STATE_SYSTEM_FOCUSABLE;
+
+  if (!view)
+    return;
+
+  if (!view->IsEnabled()) {
+    msaa_state->lVal |= STATE_SYSTEM_UNAVAILABLE;
+  }
+  if (!view->IsVisible()) {
+    msaa_state->lVal |= STATE_SYSTEM_INVISIBLE;
+  }
+  if (view->IsHotTracked()) {
+    msaa_state->lVal |= STATE_SYSTEM_HOTTRACKED;
+  }
+  if (view->IsPushed()) {
+    msaa_state->lVal |= STATE_SYSTEM_PRESSED;
+  }
+  // Check both for actual View focus, as well as accessibility focus.
+  views::View* parent = view->GetParent();
+
+  if (view->HasFocus() ||
+      (parent && parent->GetAccFocusedChildView() == view)) {
+    msaa_state->lVal |= STATE_SYSTEM_FOCUSED;
+  }
+
+  // Add on any view-specific states.
+  AccessibilityTypes::State state;
+  view->GetAccessibleState(&state);
+
+  msaa_state->lVal |= MSAAState(state);
+}
+
+long ViewAccessibility::MSAARole(AccessibilityTypes::Role role) {
+  switch (role) {
+    case AccessibilityTypes::ROLE_APPLICATION :
+      return ROLE_SYSTEM_APPLICATION;
+    case AccessibilityTypes::ROLE_BUTTONDROPDOWN :
+      return ROLE_SYSTEM_BUTTONDROPDOWN;
+    case AccessibilityTypes::ROLE_GROUPING :
+      return ROLE_SYSTEM_GROUPING;
+    case AccessibilityTypes::ROLE_PAGETAB :
+      return ROLE_SYSTEM_PAGETAB;
+    case AccessibilityTypes::ROLE_PUSHBUTTON :
+      return ROLE_SYSTEM_PUSHBUTTON;
+    case AccessibilityTypes::ROLE_TEXT :
+      return ROLE_SYSTEM_TEXT;
+    case AccessibilityTypes::ROLE_TOOLBAR :
+      return ROLE_SYSTEM_TOOLBAR;
+    case AccessibilityTypes::ROLE_CLIENT :
+    default:
+      // This is the default role for MSAA.
+      return ROLE_SYSTEM_CLIENT;
+  }
+}
+
+long ViewAccessibility::MSAAState(AccessibilityTypes::State state) {
+  switch (state) {
+    case AccessibilityTypes::STATE_HASPOPUP :
+      return STATE_SYSTEM_HASPOPUP;
+    case AccessibilityTypes::STATE_READONLY :
+      return STATE_SYSTEM_READONLY;
+    default :
+      // No default state in MSAA.
+      return 0;
+  }
+}
+
+// IAccessible functions not supported.
+
+HRESULT ViewAccessibility::accDoDefaultAction(VARIANT var_id) {
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP ViewAccessibility::get_accValue(VARIANT var_id, BSTR* value) {
+  if (value)
+    *value = NULL;
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP ViewAccessibility::get_accSelection(VARIANT* selected) {
+  if (selected)
+    selected->vt = VT_EMPTY;
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP ViewAccessibility::accSelect(LONG flagsSelect, VARIANT var_id) {
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP ViewAccessibility::get_accHelp(VARIANT var_id, BSTR* help) {
+  if (help)
+    *help = NULL;
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP ViewAccessibility::get_accHelpTopic(BSTR* help_file,
+                                                 VARIANT var_id,
+                                                 LONG* topic_id) {
+  if (help_file) {
+    *help_file = NULL;
+  }
+  if (topic_id) {
+    *topic_id = static_cast<LONG>(-1);
+  }
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP ViewAccessibility::put_accName(VARIANT var_id, BSTR put_name) {
+  // Deprecated.
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP ViewAccessibility::put_accValue(VARIANT var_id, BSTR put_val) {
+  // Deprecated.
+  return E_NOTIMPL;
+}
diff --git a/views/accessibility/view_accessibility.h b/views/accessibility/view_accessibility.h
new file mode 100644
index 0000000..840a685
--- /dev/null
+++ b/views/accessibility/view_accessibility.h
@@ -0,0 +1,144 @@
+// Copyright (c) 2006-2008 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 VIEWS_ACCESSIBILITY_VIEW_ACCESSIBILITY_H_
+#define VIEWS_ACCESSIBILITY_VIEW_ACCESSIBILITY_H_
+
+#include <atlbase.h>
+#include <atlcom.h>
+
+#include <oleacc.h>
+
+#include "views/view.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ViewAccessibility
+//
+// Class implementing the MSAA IAccessible COM interface for a generic View,
+// providing accessibility to be used by screen readers and other assistive
+// technology (AT).
+//
+////////////////////////////////////////////////////////////////////////////////
+class ATL_NO_VTABLE ViewAccessibility
+  : public CComObjectRootEx<CComMultiThreadModel>,
+    public IDispatchImpl<IAccessible, &IID_IAccessible, &LIBID_Accessibility> {
+ public:
+  BEGIN_COM_MAP(ViewAccessibility)
+    COM_INTERFACE_ENTRY2(IDispatch, IAccessible)
+    COM_INTERFACE_ENTRY(IAccessible)
+  END_COM_MAP()
+
+  ViewAccessibility() {}
+  ~ViewAccessibility() {}
+
+  HRESULT Initialize(views::View* view);
+
+  // Supported IAccessible methods.
+
+  // Retrieves the child element or child object at a given point on the screen.
+  STDMETHODIMP accHitTest(LONG x_left, LONG y_top, VARIANT* child);
+
+  // Retrieves the specified object's current screen location.
+  STDMETHODIMP accLocation(LONG* x_left,
+                           LONG* y_top,
+                           LONG* width,
+                           LONG* height,
+                           VARIANT var_id);
+
+  // Traverses to another UI element and retrieves the object.
+  STDMETHODIMP accNavigate(LONG nav_dir, VARIANT start, VARIANT* end);
+
+  // Retrieves an IDispatch interface pointer for the specified child.
+  STDMETHODIMP get_accChild(VARIANT var_child, IDispatch** disp_child);
+
+  // Retrieves the number of accessible children.
+  STDMETHODIMP get_accChildCount(LONG* child_count);
+
+  // Retrieves a string that describes the object's default action.
+  STDMETHODIMP get_accDefaultAction(VARIANT var_id, BSTR* default_action);
+
+  // Retrieves the tooltip description.
+  STDMETHODIMP get_accDescription(VARIANT var_id, BSTR* desc);
+
+  // Retrieves the object that has the keyboard focus.
+  STDMETHODIMP get_accFocus(VARIANT* focus_child);
+
+  // Retrieves the specified object's shortcut.
+  STDMETHODIMP get_accKeyboardShortcut(VARIANT var_id, BSTR* access_key);
+
+  // Retrieves the name of the specified object.
+  STDMETHODIMP get_accName(VARIANT var_id, BSTR* name);
+
+  // Retrieves the IDispatch interface of the object's parent.
+  STDMETHODIMP get_accParent(IDispatch** disp_parent);
+
+  // Retrieves information describing the role of the specified object.
+  STDMETHODIMP get_accRole(VARIANT var_id, VARIANT* role);
+
+  // Retrieves the current state of the specified object.
+  STDMETHODIMP get_accState(VARIANT var_id, VARIANT* state);
+
+  // Non-supported IAccessible methods.
+
+  // Out-dated and can be safely said to be very rarely used.
+  STDMETHODIMP accDoDefaultAction(VARIANT var_id);
+
+  // No value associated with views.
+  STDMETHODIMP get_accValue(VARIANT var_id, BSTR* value);
+
+  // Selections not applicable to views.
+  STDMETHODIMP get_accSelection(VARIANT* selected);
+  STDMETHODIMP accSelect(LONG flags_sel, VARIANT var_id);
+
+  // Help functions not supported.
+  STDMETHODIMP get_accHelp(VARIANT var_id, BSTR* help);
+  STDMETHODIMP get_accHelpTopic(BSTR* help_file,
+                                VARIANT var_id,
+                                LONG* topic_id);
+
+  // Deprecated functions, not implemented here.
+  STDMETHODIMP put_accName(VARIANT var_id, BSTR put_name);
+  STDMETHODIMP put_accValue(VARIANT var_id, BSTR put_val);
+
+ private:
+  // Checks to see if child_id is within the child bounds of view. Returns true
+  // if the child is within the bounds, false otherwise.
+  bool IsValidChild(int child_id, views::View* view) const;
+
+  // Determines navigation direction for accNavigate, based on left, up and
+  // previous being mapped all to previous and right, down, next being mapped
+  // to next. Returns true if navigation direction is next, false otherwise.
+  bool IsNavDirNext(int nav_dir) const;
+
+  // Determines if the navigation target is within the allowed bounds. Returns
+  // true if it is, false otherwise.
+  bool IsValidNav(int nav_dir,
+                  int start_id,
+                  int lower_bound,
+                  int upper_bound) const;
+
+  // Wrapper to retrieve the view's instance of IAccessible.
+  ViewAccessibilityWrapper* GetViewAccessibilityWrapper(views::View* v) const {
+    return v->GetViewAccessibilityWrapper();
+  }
+
+  // Helper function which sets applicable states of view.
+  void SetState(VARIANT* msaa_state, views::View* view);
+
+  // Returns a conversion from the Role (as defined in
+  // chrome/common/accessibility_types.h) to an MSAA role.
+  long MSAARole(AccessibilityTypes::Role role);
+
+  // Returns a conversion from the State (as defined in
+  // chrome/common/accessibility_types.h) to MSAA states set.
+  long MSAAState(AccessibilityTypes::State state);
+
+  // Member View needed for view-specific calls.
+  views::View* view_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ViewAccessibility);
+};
+
+#endif  // VIEWS_ACCESSIBILITY_VIEW_ACCESSIBILITY_H_
diff --git a/views/accessibility/view_accessibility_wrapper.cc b/views/accessibility/view_accessibility_wrapper.cc
new file mode 100644
index 0000000..ff336ae
--- /dev/null
+++ b/views/accessibility/view_accessibility_wrapper.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2006-2008 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 "views/accessibility/view_accessibility_wrapper.h"
+
+#include "views/accessibility/view_accessibility.h"
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ViewAccessibilityWrapper - constructors, destructors
+//
+////////////////////////////////////////////////////////////////////////////////
+
+ViewAccessibilityWrapper::ViewAccessibilityWrapper(views::View* view)
+    : accessibility_info_(NULL),
+      view_(view) {
+}
+
+STDMETHODIMP ViewAccessibilityWrapper::CreateDefaultInstance(REFIID iid) {
+  if (IID_IUnknown == iid || IID_IDispatch == iid || IID_IAccessible == iid) {
+    // If there is no instance of ViewAccessibility created, create it
+    // now. Otherwise reuse previous instance.
+    if (!accessibility_info_) {
+      CComObject<ViewAccessibility>* instance = NULL;
+
+      HRESULT hr = CComObject<ViewAccessibility>::CreateInstance(&instance);
+
+      if (!SUCCEEDED(hr) || !instance)
+        return E_FAIL;
+
+      CComPtr<IAccessible> accessibility_instance(instance);
+
+      if (!SUCCEEDED(instance->Initialize(view_)))
+        return E_FAIL;
+
+      // All is well, assign the temp instance to the class smart pointer.
+      accessibility_info_.Attach(accessibility_instance.Detach());
+    }
+    return S_OK;
+  }
+  // Interface not supported.
+  return E_NOINTERFACE;
+}
+
+STDMETHODIMP ViewAccessibilityWrapper::GetInstance(REFIID iid,
+                                                   void** interface_ptr) {
+  if (IID_IUnknown == iid || IID_IDispatch == iid || IID_IAccessible == iid) {
+    // If there is no accessibility instance created, create a default now.
+    // Otherwise reuse previous instance.
+    if (!accessibility_info_) {
+      HRESULT hr = CreateDefaultInstance(iid);
+
+      if (hr != S_OK) {
+        // Interface creation failed.
+        *interface_ptr = NULL;
+        return E_NOINTERFACE;
+      }
+    }
+    *interface_ptr = static_cast<IAccessible*>(accessibility_info_);
+    return S_OK;
+  }
+  // No supported interface found, return error.
+  *interface_ptr = NULL;
+  return E_NOINTERFACE;
+}
+
+STDMETHODIMP ViewAccessibilityWrapper::SetInstance(IAccessible* interface_ptr) {
+  if (!interface_ptr)
+    return E_NOINTERFACE;
+
+  accessibility_info_.Attach(interface_ptr);
+
+  // Paranoia check, to make sure we do have a valid IAccessible pointer stored.
+  if (!accessibility_info_)
+    return E_FAIL;
+
+  return S_OK;
+}
diff --git a/views/accessibility/view_accessibility_wrapper.h b/views/accessibility/view_accessibility_wrapper.h
new file mode 100644
index 0000000..4390662
--- /dev/null
+++ b/views/accessibility/view_accessibility_wrapper.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2006-2008 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 VIEWS_ACCESSIBILITY_VIEW_ACCESSIBILITY_WRAPPER_H_
+#define VIEWS_ACCESSIBILITY_VIEW_ACCESSIBILITY_WRAPPER_H_
+
+#include <atlcomcli.h>
+#include <oleacc.h>
+
+#include "base/basictypes.h"
+
+namespace views {
+class View;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ViewAccessibilityWrapper
+//
+// Wrapper class for returning a pointer to the appropriate (platform-specific)
+// accessibility interface for a given View. Needed to keep platform-specific
+// code out of the View class, when answering calls for child/parent IAccessible
+// implementations, for instance.
+//
+////////////////////////////////////////////////////////////////////////////////
+class ViewAccessibilityWrapper {
+ public:
+  explicit ViewAccessibilityWrapper(views::View* view);
+  ~ViewAccessibilityWrapper() {}
+
+  STDMETHODIMP CreateDefaultInstance(REFIID iid);
+
+  // Returns a pointer to a specified interface on an object to which a client
+  // currently holds an interface pointer. If pointer exists, it is reused,
+  // otherwise a new pointer is created. Used by accessibility implementation to
+  // retrieve MSAA implementation for child or parent, when navigating MSAA
+  // hierarchy.
+  STDMETHODIMP GetInstance(REFIID iid, void** interface_ptr);
+
+  // Sets the accessibility interface implementation of this wrapper to be
+  // anything the user specifies.
+  STDMETHODIMP SetInstance(IAccessible* interface_ptr);
+
+ private:
+  // Instance of accessibility information and handling for a View.
+  CComPtr<IAccessible> accessibility_info_;
+
+  // View needed to initialize IAccessible.
+  views::View* view_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewAccessibilityWrapper);
+};
+
+#endif  // VIEWS_ACCESSIBILITY_VIEW_ACCESSIBILITY_WRAPPER_H_
diff --git a/views/background.cc b/views/background.cc
new file mode 100644
index 0000000..f2bd176
--- /dev/null
+++ b/views/background.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2006-2008 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 "views/background.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "base/logging.h"
+#include "skia/ext/skia_utils_win.h"
+#include "skia/include/SkPaint.h"
+#include "views/painter.h"
+#include "views/view.h"
+
+namespace views {
+
+// SolidBackground is a trivial Background implementation that fills the
+// background in a solid color.
+class SolidBackground : public Background {
+ public:
+  explicit SolidBackground(const SkColor& color) :
+      color_(color) {
+    SetNativeControlColor(color_);
+  }
+
+  void Paint(ChromeCanvas* canvas, View* view) const {
+    // Fill the background. Note that we don't constrain to the bounds as
+    // canvas is already clipped for us.
+    canvas->drawColor(color_);
+  }
+
+ private:
+  const SkColor color_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(SolidBackground);
+};
+
+class BackgroundPainter : public Background {
+ public:
+  BackgroundPainter(bool owns_painter, Painter* painter)
+      : owns_painter_(owns_painter), painter_(painter) {
+    DCHECK(painter);
+  }
+
+  virtual ~BackgroundPainter() {
+    if (owns_painter_)
+      delete painter_;
+  }
+
+
+  void Paint(ChromeCanvas* canvas, View* view) const {
+    Painter::PaintPainterAt(0, 0, view->width(), view->height(), canvas,
+                            painter_);
+  }
+
+ private:
+  bool owns_painter_;
+  Painter* painter_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(BackgroundPainter);
+};
+
+Background::Background()
+#if defined(OS_WIN)
+    : native_control_brush_(NULL)
+#endif
+{
+}
+
+Background::~Background() {
+#if defined(OS_WIN)
+  DeleteObject(native_control_brush_);
+#endif
+}
+
+void Background::SetNativeControlColor(SkColor color) {
+#if defined(OS_WIN)
+  DeleteObject(native_control_brush_);
+  native_control_brush_ = CreateSolidBrush(skia::SkColorToCOLORREF(color));
+#endif
+}
+
+//static
+Background* Background::CreateSolidBackground(const SkColor& color) {
+  return new SolidBackground(color);
+}
+
+//static
+Background* Background::CreateStandardPanelBackground() {
+  return CreateVerticalGradientBackground(SkColorSetRGB(246, 250, 255),
+                                          SkColorSetRGB(219, 235, 255));
+}
+
+//static
+Background* Background::CreateVerticalGradientBackground(
+    const SkColor& color1, const SkColor& color2) {
+    Background *background =
+        CreateBackgroundPainter(true, Painter::CreateVerticalGradient(color1,
+                                                                      color2));
+    background->SetNativeControlColor(  // 50% blend of colors 1 & 2
+        SkColorSetRGB((SkColorGetR(color1) + SkColorGetR(color2)) / 2,
+                      (SkColorGetG(color1) + SkColorGetG(color2)) / 2,
+                      (SkColorGetB(color1) + SkColorGetB(color2)) / 2));
+
+    return background;
+}
+
+//static
+Background* Background::CreateBackgroundPainter(bool owns_painter,
+                                                Painter* painter) {
+  return new BackgroundPainter(owns_painter, painter);
+}
+
+}  // namespace views
diff --git a/views/background.h b/views/background.h
new file mode 100644
index 0000000..acc3948
--- /dev/null
+++ b/views/background.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2006-2008 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 VIEWS_BACKGROUND_H_
+#define VIEWS_BACKGROUND_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif  // defined(OS_WIN)
+
+#include "base/basictypes.h"
+#include "skia/include/SkColor.h"
+
+class ChromeCanvas;
+
+namespace views {
+
+class Painter;
+class View;
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Background class
+//
+// A background implements a way for views to paint a background. The
+// background can be either solid or based on a gradient. Of course,
+// Background can be subclassed to implement various effects.
+//
+// Any View can have a background. See View::SetBackground() and
+// View::PaintBackground()
+//
+/////////////////////////////////////////////////////////////////////////////
+class Background {
+ public:
+  Background();
+  virtual ~Background();
+
+  // Creates a background that fills the canvas in the specified color.
+  static Background* CreateSolidBackground(const SkColor& color);
+
+  // Creates a background that fills the canvas in the specified color.
+  static Background* CreateSolidBackground(int r, int g, int b) {
+    return CreateSolidBackground(SkColorSetRGB(r, g, b));
+  }
+
+  // Creates a background that fills the canvas in the specified color.
+  static Background* CreateSolidBackground(int r, int g, int b, int a) {
+    return CreateSolidBackground(SkColorSetARGB(a, r, g, b));
+  }
+
+  // Creates a background that contains a vertical gradient that varies
+  // from |color1| to |color2|
+  static Background* CreateVerticalGradientBackground(const SkColor& color1,
+                                                      const SkColor& color2);
+
+  // Creates Chrome's standard panel background
+  static Background* CreateStandardPanelBackground();
+
+  // Creates a Background from the specified Painter. If owns_painter is
+  // true, the Painter is deleted when the Border is deleted.
+  static Background* CreateBackgroundPainter(bool owns_painter,
+                                             Painter* painter);
+
+  // Render the background for the provided view
+  virtual void Paint(ChromeCanvas* canvas, View* view) const = 0;
+
+  // Set a solid, opaque color to be used when drawing backgrounds of native
+  // controls.  Unfortunately alpha=0 is not an option.
+  void SetNativeControlColor(SkColor color);
+
+#if defined(OS_WIN)
+  // TODO(port): Make GetNativeControlBrush portable (currently uses HBRUSH).
+
+  // Get the brush that was specified by SetNativeControlColor
+  HBRUSH GetNativeControlBrush() const { return native_control_brush_; };
+#endif  // defined(OS_WIN)
+
+ private:
+#if defined(OS_WIN)
+  // TODO(port): Create portable replacement for HBRUSH.
+  HBRUSH native_control_brush_;
+#endif  // defined(OS_WIN)
+  DISALLOW_COPY_AND_ASSIGN(Background);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_BACKGROUND_H_
diff --git a/views/border.cc b/views/border.cc
new file mode 100644
index 0000000..9127bce
--- /dev/null
+++ b/views/border.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2006-2008 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 "views/border.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "base/logging.h"
+
+namespace views {
+
+namespace {
+
+// A simple border with a fixed thickness and single color.
+class SolidBorder : public Border {
+ public:
+  SolidBorder(int thickness, SkColor color);
+
+  virtual void Paint(const View& view, ChromeCanvas* canvas) const;
+  virtual void GetInsets(gfx::Insets* insets) const;
+
+ private:
+  int thickness_;
+  SkColor color_;
+  gfx::Insets insets_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(SolidBorder);
+};
+
+SolidBorder::SolidBorder(int thickness, SkColor color)
+    : thickness_(thickness),
+      color_(color),
+      insets_(thickness, thickness, thickness, thickness) {
+}
+
+void SolidBorder::Paint(const View& view, ChromeCanvas* canvas) const {
+  gfx::Rect clip_rect;
+  if (!canvas->GetClipRect(&clip_rect))
+    return;  // Empty clip rectangle, nothing to paint.
+
+  // Top border.
+  gfx::Rect border_bounds(0, 0, view.width(), insets_.top());
+  if (clip_rect.Intersects(border_bounds))
+    canvas->FillRectInt(color_, 0, 0, view.width(), insets_.top());
+  // Left border.
+  border_bounds.SetRect(0, 0, insets_.left(), view.height());
+  if (clip_rect.Intersects(border_bounds))
+    canvas->FillRectInt(color_, 0, 0, insets_.left(), view.height());
+  // Bottom border.
+  border_bounds.SetRect(0, view.height() - insets_.bottom(),
+                        view.width(), insets_.bottom());
+  if (clip_rect.Intersects(border_bounds))
+    canvas->FillRectInt(color_, 0, view.height() - insets_.bottom(),
+                        view.width(), insets_.bottom());
+  // Right border.
+  border_bounds.SetRect(view.width() - insets_.right(), 0,
+                       insets_.right(), view.height());
+  if (clip_rect.Intersects(border_bounds))
+    canvas->FillRectInt(color_, view.width() - insets_.right(), 0,
+                        insets_.right(), view.height());
+}
+
+void SolidBorder::GetInsets(gfx::Insets* insets) const {
+  DCHECK(insets);
+  insets->Set(insets_.top(), insets_.left(), insets_.bottom(), insets_.right());
+}
+
+class EmptyBorder : public Border {
+ public:
+  EmptyBorder(int top, int left, int bottom, int right)
+      : top_(top), left_(left), bottom_(bottom), right_(right) {}
+
+  virtual void Paint(const View& view, ChromeCanvas* canvas) const {}
+
+  virtual void GetInsets(gfx::Insets* insets) const {
+    DCHECK(insets);
+    insets->Set(top_, left_, bottom_, right_);
+  }
+
+ private:
+  int top_;
+  int left_;
+  int bottom_;
+  int right_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(EmptyBorder);
+};
+}
+
+Border::Border() {
+}
+
+Border::~Border() {
+}
+
+// static
+Border* Border::CreateSolidBorder(int thickness, SkColor color) {
+  return new SolidBorder(thickness, color);
+}
+
+// static
+Border* Border::CreateEmptyBorder(int top, int left, int bottom, int right) {
+  return new EmptyBorder(top, left, bottom, right);
+}
+
+}  // namespace views
diff --git a/views/border.h b/views/border.h
new file mode 100644
index 0000000..7e7e2bd
--- /dev/null
+++ b/views/border.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2006-2008 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 VIEWS_BORDER_H_
+#define VIEWS_BORDER_H_
+
+#include "app/gfx/insets.h"
+#include "skia/include/SkColor.h"
+#include "views/view.h"
+
+class ChromeCanvas;
+
+namespace views {
+
+class View;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Border class.
+//
+// The border class is used to display a border around a view.
+// To set a border on a view, just call SetBorder on the view, for example:
+// view->SetBorder(Border::CreateSolidBorder(1, SkColorSetRGB(25, 25, 112));
+// Once set on a view, the border is owned by the view.
+//
+// IMPORTANT NOTE: not all views support borders at this point. In order to
+// support the border, views should make sure to use bounds excluding the
+// border (by calling View::GetLocalBoundsExcludingBorder) when doing layout and
+// painting.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+class Border {
+ public:
+  Border();
+  virtual ~Border();
+
+  // Creates a border that is a simple line of the specified thickness and
+  // color.
+  static Border* CreateSolidBorder(int thickness, SkColor color);
+
+  // Creates a border for reserving space. The returned border does not
+  // paint anything.
+  static Border* CreateEmptyBorder(int top, int left, int bottom, int right);
+
+  // Renders the border for the specified view.
+  virtual void Paint(const View& view, ChromeCanvas* canvas) const = 0;
+
+  // Sets the specified insets to the the border insets.
+  virtual void GetInsets(gfx::Insets* insets) const = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Border);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_BORDER_H_
diff --git a/views/controls/button/button.cc b/views/controls/button/button.cc
new file mode 100644
index 0000000..cbb42bf
--- /dev/null
+++ b/views/controls/button/button.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2006-2008 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 "views/controls/button/button.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// Button, public:
+
+Button::~Button() {
+}
+
+void Button::SetTooltipText(const std::wstring& tooltip_text) {
+  tooltip_text_ = tooltip_text;
+  TooltipTextChanged();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Button, View overrides:
+
+bool Button::GetTooltipText(int x, int y, std::wstring* tooltip) {
+  if (!tooltip_text_.empty()) {
+    *tooltip = tooltip_text_;
+    return true;
+  }
+  return false;
+}
+
+bool Button::GetAccessibleKeyboardShortcut(std::wstring* shortcut) {
+  if (!accessible_shortcut_.empty()) {
+    *shortcut = accessible_shortcut_;
+    return true;
+  }
+  return false;
+}
+
+bool Button::GetAccessibleName(std::wstring* name) {
+  if (!accessible_name_.empty()) {
+    *name = accessible_name_;
+    return true;
+  }
+  return false;
+}
+
+bool Button::GetAccessibleRole(AccessibilityTypes::Role* role) {
+  *role = AccessibilityTypes::ROLE_PUSHBUTTON;
+  return true;
+}
+
+void Button::SetAccessibleKeyboardShortcut(const std::wstring& shortcut) {
+  accessible_shortcut_.assign(shortcut);
+}
+
+void Button::SetAccessibleName(const std::wstring& name) {
+  accessible_name_.assign(name);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Button, protected:
+
+Button::Button(ButtonListener* listener)
+    : listener_(listener),
+      tag_(-1),
+      mouse_event_flags_(0) {
+}
+
+void Button::NotifyClick(int mouse_event_flags) {
+  mouse_event_flags_ = mouse_event_flags;
+  // We can be called when there is no listener, in cases like double clicks on
+  // menu buttons etc.
+  if (listener_)
+    listener_->ButtonPressed(this);
+  // NOTE: don't attempt to reset mouse_event_flags_ as the listener may have
+  // deleted us.
+}
+
+}  // namespace views
diff --git a/views/controls/button/button.h b/views/controls/button/button.h
new file mode 100644
index 0000000..514758f5
--- /dev/null
+++ b/views/controls/button/button.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_BUTTON_BUTTON_H_
+#define VIEWS_CONTROLS_BUTTON_BUTTON_H_
+
+#include "views/view.h"
+
+namespace views {
+
+class Button;
+
+// An interface implemented by an object to let it know that a button was
+// pressed.
+class ButtonListener {
+ public:
+  virtual void ButtonPressed(Button* sender) = 0;
+};
+
+// A View representing a button. Depending on the specific type, the button
+// could be implemented by a native control or custom rendered.
+class Button : public View {
+ public:
+  virtual ~Button();
+
+  void SetTooltipText(const std::wstring& tooltip_text);
+
+  int tag() const { return tag_; }
+  void set_tag(int tag) { tag_ = tag; }
+
+  int mouse_event_flags() const { return mouse_event_flags_; }
+
+  // Overridden from View:
+  virtual bool GetTooltipText(int x, int y, std::wstring* tooltip);
+  virtual bool GetAccessibleKeyboardShortcut(std::wstring* shortcut);
+  virtual bool GetAccessibleName(std::wstring* name);
+  virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+  virtual void SetAccessibleKeyboardShortcut(const std::wstring& shortcut);
+  virtual void SetAccessibleName(const std::wstring& name);
+
+ protected:
+  // Construct the Button with a Listener. The listener can be NULL. This can be
+  // true of buttons that don't have a listener - e.g. menubuttons where there's
+  // no default action and checkboxes.
+  explicit Button(ButtonListener* listener);
+
+  // Cause the button to notify the listener that a click occurred.
+  virtual void NotifyClick(int mouse_event_flags);
+
+  // The button's listener. Notified when clicked.
+  ButtonListener* listener_;
+
+ private:
+  // The text shown in a tooltip.
+  std::wstring tooltip_text_;
+
+  // Accessibility data.
+  std::wstring accessible_shortcut_;
+  std::wstring accessible_name_;
+
+  // The id tag associated with this button. Used to disambiguate buttons in
+  // the ButtonListener implementation.
+  int tag_;
+
+  // Event flags present when the button was clicked.
+  int mouse_event_flags_;
+
+  DISALLOW_COPY_AND_ASSIGN(Button);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_BUTTON_BUTTON_H_
diff --git a/views/controls/button/button_dropdown.cc b/views/controls/button/button_dropdown.cc
new file mode 100644
index 0000000..270894b
--- /dev/null
+++ b/views/controls/button/button_dropdown.cc
@@ -0,0 +1,192 @@
+// Copyright (c) 2006-2008 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 "views/controls/button/button_dropdown.h"
+
+#include "app/l10n_util.h"
+#include "base/message_loop.h"
+#include "grit/generated_resources.h"
+#include "views/controls/menu/view_menu_delegate.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+// How long to wait before showing the menu
+static const int kMenuTimerDelay = 500;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ButtonDropDown - constructors, destructors, initialization, cleanup
+//
+////////////////////////////////////////////////////////////////////////////////
+
+ButtonDropDown::ButtonDropDown(ButtonListener* listener,
+                               Menu::Delegate* menu_delegate)
+    : ImageButton(listener),
+      menu_delegate_(menu_delegate),
+      y_position_on_lbuttondown_(0),
+      show_menu_factory_(this) {
+}
+
+ButtonDropDown::~ButtonDropDown() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ButtonDropDown - Events
+//
+////////////////////////////////////////////////////////////////////////////////
+
+bool ButtonDropDown::OnMousePressed(const MouseEvent& e) {
+  if (IsEnabled() && e.IsLeftMouseButton() && HitTest(e.location())) {
+    // Store the y pos of the mouse coordinates so we can use them later to
+    // determine if the user dragged the mouse down (which should pop up the
+    // drag down menu immediately, instead of waiting for the timer)
+    y_position_on_lbuttondown_ = e.y();
+
+    // Schedule a task that will show the menu.
+    MessageLoop::current()->PostDelayedTask(FROM_HERE,
+        show_menu_factory_.NewRunnableMethod(&ButtonDropDown::ShowDropDownMenu,
+                                             GetWidget()->GetNativeView()),
+        kMenuTimerDelay);
+  }
+
+  return ImageButton::OnMousePressed(e);
+}
+
+void ButtonDropDown::OnMouseReleased(const MouseEvent& e, bool canceled) {
+  ImageButton::OnMouseReleased(e, canceled);
+
+  if (canceled)
+    return;
+
+  if (e.IsLeftMouseButton())
+    show_menu_factory_.RevokeAll();
+
+  if (IsEnabled() && e.IsRightMouseButton() && HitTest(e.location())) {
+    show_menu_factory_.RevokeAll();
+    // Make the button look depressed while the menu is open.
+    // NOTE: SetState() schedules a paint, but it won't occur until after the
+    //       context menu message loop has terminated, so we PaintNow() to
+    //       update the appearance synchronously.
+    SetState(BS_PUSHED);
+    PaintNow();
+    ShowDropDownMenu(GetWidget()->GetNativeView());
+  }
+}
+
+bool ButtonDropDown::OnMouseDragged(const MouseEvent& e) {
+  bool result = ImageButton::OnMouseDragged(e);
+
+  if (!show_menu_factory_.empty()) {
+    // SM_CYDRAG is a pixel value for minimum dragging distance before operation
+    // counts as a drag, and not just as a click and accidental move of a mouse.
+    // See http://msdn2.microsoft.com/en-us/library/ms724385.aspx for details.
+    int dragging_threshold = GetSystemMetrics(SM_CYDRAG);
+
+    // If the mouse is dragged to a y position lower than where it was when
+    // clicked then we should not wait for the menu to appear but show
+    // it immediately.
+    if (e.y() > y_position_on_lbuttondown_ + dragging_threshold) {
+      show_menu_factory_.RevokeAll();
+      ShowDropDownMenu(GetWidget()->GetNativeView());
+    }
+  }
+
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ButtonDropDown - Menu functions
+//
+////////////////////////////////////////////////////////////////////////////////
+
+void ButtonDropDown::ShowContextMenu(int x, int y, bool is_mouse_gesture) {
+  show_menu_factory_.RevokeAll();
+  // Make the button look depressed while the menu is open.
+  // NOTE: SetState() schedules a paint, but it won't occur until after the
+  //       context menu message loop has terminated, so we PaintNow() to
+  //       update the appearance synchronously.
+  SetState(BS_PUSHED);
+  PaintNow();
+  ShowDropDownMenu(GetWidget()->GetNativeView());
+  SetState(BS_HOT);
+}
+
+void ButtonDropDown::ShowDropDownMenu(HWND window) {
+  if (menu_delegate_) {
+    gfx::Rect lb = GetLocalBounds(true);
+
+    // Both the menu position and the menu anchor type change if the UI layout
+    // is right-to-left.
+    gfx::Point menu_position(lb.origin());
+    menu_position.Offset(0, lb.height() - 1);
+    if (UILayoutIsRightToLeft())
+      menu_position.Offset(lb.width() - 1, 0);
+
+    Menu::AnchorPoint anchor = Menu::TOPLEFT;
+    if (UILayoutIsRightToLeft())
+      anchor = Menu::TOPRIGHT;
+
+    View::ConvertPointToScreen(this, &menu_position);
+
+    int left_bound = GetSystemMetrics(SM_XVIRTUALSCREEN);
+    if (menu_position.x() < left_bound)
+      menu_position.set_x(left_bound);
+
+    Menu menu(menu_delegate_, anchor, window);
+
+    // ID's for AppendMenu is 1-based because RunMenu will ignore the user
+    // selection if id=0 is selected (0 = NO-OP) so we add 1 here and subtract 1
+    // in the handlers above to get the actual index
+    int item_count = menu_delegate_->GetItemCount();
+    for (int i = 0; i < item_count; i++) {
+      if (menu_delegate_->IsItemSeparator(i + 1)) {
+        menu.AppendSeparator();
+      } else {
+        if (menu_delegate_->HasIcon(i + 1))
+          menu.AppendMenuItemWithIcon(i + 1, L"", SkBitmap());
+        else
+          menu.AppendMenuItem(i+1, L"", Menu::NORMAL);
+      }
+    }
+
+    menu.RunMenuAt(menu_position.x(), menu_position.y());
+
+    // Need to explicitly clear mouse handler so that events get sent
+    // properly after the menu finishes running. If we don't do this, then
+    // the first click to other parts of the UI is eaten.
+    SetMouseHandler(NULL);
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ButtonDropDown - Accessibility
+//
+////////////////////////////////////////////////////////////////////////////////
+
+bool ButtonDropDown::GetAccessibleDefaultAction(std::wstring* action) {
+  DCHECK(action);
+
+  action->assign(l10n_util::GetString(IDS_ACCACTION_PRESS));
+  return true;
+}
+
+bool ButtonDropDown::GetAccessibleRole(AccessibilityTypes::Role* role) {
+  DCHECK(role);
+
+  *role = AccessibilityTypes::ROLE_BUTTONDROPDOWN;
+  return true;
+}
+
+bool ButtonDropDown::GetAccessibleState(AccessibilityTypes::State* state) {
+  DCHECK(state);
+
+  *state = AccessibilityTypes::STATE_HASPOPUP;
+  return true;
+}
+
+}  // namespace views
diff --git a/views/controls/button/button_dropdown.h b/views/controls/button/button_dropdown.h
new file mode 100644
index 0000000..feb5b5c
--- /dev/null
+++ b/views/controls/button/button_dropdown.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_BUTTON_BUTTON_DROPDOWN_H_
+#define VIEWS_CONTROLS_BUTTON_BUTTON_DROPDOWN_H_
+
+#include "base/task.h"
+#include "views/controls/button/image_button.h"
+#include "views/controls/menu/menu.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ButtonDropDown
+//
+// A button class that when pressed (and held) or pressed (and drag down) will
+// display a menu
+//
+////////////////////////////////////////////////////////////////////////////////
+class ButtonDropDown : public ImageButton {
+ public:
+  ButtonDropDown(ButtonListener* listener, Menu::Delegate* menu_delegate);
+  virtual ~ButtonDropDown();
+
+  // Accessibility accessors, overridden from View.
+  virtual bool GetAccessibleDefaultAction(std::wstring* action);
+  virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+  virtual bool GetAccessibleState(AccessibilityTypes::State* state);
+
+ private:
+  // Overridden from Button
+  virtual bool OnMousePressed(const MouseEvent& e);
+  virtual void OnMouseReleased(const MouseEvent& e, bool canceled);
+  virtual bool OnMouseDragged(const MouseEvent& e);
+
+  // Overridden from View. Used to display the right-click menu, as triggered
+  // by the keyboard, for instance. Using the member function ShowDropDownMenu
+  // for the actual display.
+  virtual void ShowContextMenu(int x,
+                               int y,
+                               bool is_mouse_gesture);
+
+  // Internal function to show the dropdown menu
+  void ShowDropDownMenu(HWND window);
+
+  // Specifies who to delegate populating the menu
+  Menu::Delegate* menu_delegate_;
+
+  // Y position of mouse when left mouse button is pressed
+  int y_position_on_lbuttondown_;
+
+  // A factory for tasks that show the dropdown context menu for the button.
+  ScopedRunnableMethodFactory<ButtonDropDown> show_menu_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ButtonDropDown);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_BUTTON_BUTTON_DROPDOWN_H_
diff --git a/views/controls/button/checkbox.cc b/views/controls/button/checkbox.cc
new file mode 100644
index 0000000..8783bcf
--- /dev/null
+++ b/views/controls/button/checkbox.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2009 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 "views/controls/button/checkbox.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "views/controls/label.h"
+
+namespace views {
+
+// static
+const char Checkbox::kViewClassName[] = "views/Checkbox";
+
+static const int kCheckboxLabelSpacing = 4;
+static const int kLabelFocusPaddingHorizontal = 2;
+static const int kLabelFocusPaddingVertical = 1;
+
+////////////////////////////////////////////////////////////////////////////////
+// Checkbox, public:
+
+Checkbox::Checkbox() : NativeButton(NULL), checked_(false) {
+  Init(std::wstring());
+}
+
+Checkbox::Checkbox(const std::wstring& label)
+    : NativeButton(NULL, label),
+      checked_(false) {
+  Init(label);
+}
+
+Checkbox::~Checkbox() {
+}
+
+void Checkbox::SetMultiLine(bool multiline) {
+  label_->SetMultiLine(multiline);
+}
+
+void Checkbox::SetChecked(bool checked) {
+  if (checked_ == checked)
+    return;
+  checked_ = checked;
+  if (native_wrapper_)
+    native_wrapper_->UpdateChecked();
+}
+
+// static
+int Checkbox::GetTextIndent() {
+  return NativeButtonWrapper::GetFixedWidth() + kCheckboxLabelSpacing;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Checkbox, View overrides:
+
+gfx::Size Checkbox::GetPreferredSize() {
+  gfx::Size prefsize = native_wrapper_->GetView()->GetPreferredSize();
+  prefsize.set_width(
+      prefsize.width() + kCheckboxLabelSpacing +
+          kLabelFocusPaddingHorizontal * 2);
+  gfx::Size label_prefsize = label_->GetPreferredSize();
+  prefsize.set_width(prefsize.width() + label_prefsize.width());
+  prefsize.set_height(
+      std::max(prefsize.height(),
+               label_prefsize.height() + kLabelFocusPaddingVertical * 2));
+  return prefsize;
+}
+
+void Checkbox::Layout() {
+  if (!native_wrapper_)
+    return;
+
+  gfx::Size checkmark_prefsize = native_wrapper_->GetView()->GetPreferredSize();
+  int label_x = checkmark_prefsize.width() + kCheckboxLabelSpacing +
+      kLabelFocusPaddingHorizontal;
+  label_->SetBounds(
+      label_x, 0, std::max(0, width() - label_x - kLabelFocusPaddingHorizontal),
+      height());
+  int first_line_height = label_->GetFont().height();
+  native_wrapper_->GetView()->SetBounds(
+      0, ((first_line_height - checkmark_prefsize.height()) / 2),
+      checkmark_prefsize.width(), checkmark_prefsize.height());
+  native_wrapper_->GetView()->Layout();
+}
+
+void Checkbox::PaintFocusBorder(ChromeCanvas* canvas) {
+  // Our focus border is rendered by the label, so we don't do anything here.
+}
+
+View* Checkbox::GetViewForPoint(const gfx::Point& point) {
+  return GetViewForPoint(point, false);
+}
+
+View* Checkbox::GetViewForPoint(const gfx::Point& point,
+                                bool can_create_floating) {
+  return GetLocalBounds(true).Contains(point) ? this : NULL;
+}
+
+void Checkbox::OnMouseEntered(const MouseEvent& e) {
+  native_wrapper_->SetPushed(HitTestLabel(e));
+}
+
+void Checkbox::OnMouseMoved(const MouseEvent& e) {
+  native_wrapper_->SetPushed(HitTestLabel(e));
+}
+
+void Checkbox::OnMouseExited(const MouseEvent& e) {
+  native_wrapper_->SetPushed(false);
+}
+
+bool Checkbox::OnMousePressed(const MouseEvent& e) {
+  native_wrapper_->SetPushed(HitTestLabel(e));
+  return true;
+}
+
+void Checkbox::OnMouseReleased(const MouseEvent& e, bool canceled) {
+  native_wrapper_->SetPushed(false);
+  if (!canceled && HitTestLabel(e)) {
+    SetChecked(!checked());
+    ButtonPressed();
+  }
+}
+
+bool Checkbox::OnMouseDragged(const MouseEvent& e) {
+  return false;
+}
+
+void Checkbox::WillGainFocus() {
+  label_->set_paint_as_focused(true);
+}
+
+void Checkbox::WillLoseFocus() {
+  label_->set_paint_as_focused(false);
+}
+
+std::string Checkbox::GetClassName() const {
+  return kViewClassName;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Checkbox, NativeButton overrides:
+
+void Checkbox::CreateWrapper() {
+  native_wrapper_ = NativeButtonWrapper::CreateCheckboxWrapper(this);
+  native_wrapper_->UpdateLabel();
+  native_wrapper_->UpdateChecked();
+}
+
+void Checkbox::InitBorder() {
+  // No border, so we do nothing.
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Checkbox, protected:
+
+bool Checkbox::HitTestLabel(const MouseEvent& e) {
+  gfx::Point tmp(e.location());
+  ConvertPointToView(this, label_, &tmp);
+  return label_->HitTest(tmp);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Checkbox, private:
+
+void Checkbox::Init(const std::wstring& label_text) {
+  set_minimum_size(gfx::Size(0, 0));
+  label_ = new Label(label_text);
+  label_->set_has_focus_border(true);
+  label_->SetHorizontalAlignment(Label::ALIGN_LEFT);
+  AddChildView(label_);
+}
+
+}  // namespace views
diff --git a/views/controls/button/checkbox.h b/views/controls/button/checkbox.h
new file mode 100644
index 0000000..db6706b
--- /dev/null
+++ b/views/controls/button/checkbox.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2009 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 VIEWS_CONTROLS_BUTTON_CHECKBOX_H_
+#define VIEWS_CONTROLS_BUTTON_CHECKBOX_H_
+
+#include "views/controls/button/native_button.h"
+
+namespace views {
+
+class Label;
+
+// A NativeButton subclass representing a checkbox.
+class Checkbox : public NativeButton {
+ public:
+  // The button's class name.
+  static const char kViewClassName[];
+
+  Checkbox();
+  Checkbox(const std::wstring& label);
+  virtual ~Checkbox();
+
+  // Sets a listener for this checkbox. Checkboxes aren't required to have them
+  // since their state can be read independently of them being toggled.
+  void set_listener(ButtonListener* listener) { listener_ = listener; }
+
+  // Sets whether or not the checkbox label should wrap multiple lines of text.
+  // If true, long lines are wrapped, and this is reflected in the preferred
+  // size returned by GetPreferredSize. If false, text that will not fit within
+  // the available bounds for the label will be cropped.
+  void SetMultiLine(bool multiline);
+
+  // Sets/Gets whether or not the checkbox is checked.
+  virtual void SetChecked(bool checked);
+  bool checked() const { return checked_; }
+
+  // Returns the indentation of the text from the left edge of the view.
+  static int GetTextIndent();
+
+  // Overridden from View:
+  virtual gfx::Size GetPreferredSize();
+  virtual void Layout();
+  virtual void PaintFocusBorder(ChromeCanvas* canvas);
+  virtual View* GetViewForPoint(const gfx::Point& point);
+  virtual View* GetViewForPoint(const gfx::Point& point,
+                                bool can_create_floating);
+  virtual void OnMouseEntered(const MouseEvent& e);
+  virtual void OnMouseMoved(const MouseEvent& e);
+  virtual void OnMouseExited(const MouseEvent& e);
+  virtual bool OnMousePressed(const MouseEvent& e);
+  virtual void OnMouseReleased(const MouseEvent& e, bool canceled);
+  virtual bool OnMouseDragged(const MouseEvent& e);
+  virtual void WillGainFocus();
+  virtual void WillLoseFocus();
+
+ protected:
+  virtual std::string GetClassName() const;
+
+  // Overridden from NativeButton2:
+  virtual void CreateWrapper();
+  virtual void InitBorder();
+
+  // Returns true if the event (in Checkbox coordinates) is within the bounds of
+  // the label.
+  bool HitTestLabel(const MouseEvent& e);
+
+ private:
+  // Called from the constructor to create and configure the checkbox label.
+  void Init(const std::wstring& label_text);
+
+  // The checkbox's label. We don't use the OS version because of transparency
+  // and sizing issues.
+  Label* label_;
+
+  // True if the checkbox is checked.
+  bool checked_;
+
+  DISALLOW_COPY_AND_ASSIGN(Checkbox);
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_CONTROLS_BUTTON_CHECKBOX_H_
diff --git a/views/controls/button/custom_button.cc b/views/controls/button/custom_button.cc
new file mode 100644
index 0000000..2b5f43da
--- /dev/null
+++ b/views/controls/button/custom_button.cc
@@ -0,0 +1,236 @@
+// Copyright (c) 2006-2008 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 "views/controls/button/custom_button.h"
+
+#include "app/throb_animation.h"
+#include "base/keyboard_codes.h"
+
+namespace views {
+
+// How long the hover animation takes if uninterrupted.
+static const int kHoverFadeDurationMs = 150;
+
+////////////////////////////////////////////////////////////////////////////////
+// CustomButton, public:
+
+CustomButton::~CustomButton() {
+}
+
+void CustomButton::SetState(ButtonState state) {
+  if (state != state_) {
+    if (animate_on_state_change_ || !hover_animation_->IsAnimating()) {
+      animate_on_state_change_ = true;
+      if (state_ == BS_NORMAL && state == BS_HOT) {
+        // Button is hovered from a normal state, start hover animation.
+        hover_animation_->Show();
+      } else if (state_ == BS_HOT && state == BS_NORMAL) {
+        // Button is returning to a normal state from hover, start hover
+        // fade animation.
+        hover_animation_->Hide();
+      } else {
+        hover_animation_->Stop();
+      }
+    }
+
+    state_ = state;
+    SchedulePaint();
+  }
+}
+
+void CustomButton::StartThrobbing(int cycles_til_stop) {
+  animate_on_state_change_ = false;
+  hover_animation_->StartThrobbing(cycles_til_stop);
+}
+
+void CustomButton::SetAnimationDuration(int duration) {
+  hover_animation_->SetSlideDuration(duration);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CustomButton, View overrides:
+
+void CustomButton::SetEnabled(bool enabled) {
+  if (enabled && state_ == BS_DISABLED) {
+    SetState(BS_NORMAL);
+  } else if (!enabled && state_ != BS_DISABLED) {
+    SetState(BS_DISABLED);
+  }
+}
+
+bool CustomButton::IsEnabled() const {
+  return state_ != BS_DISABLED;
+}
+
+bool CustomButton::IsFocusable() const {
+  return (state_ != BS_DISABLED) && View::IsFocusable();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CustomButton, protected:
+
+CustomButton::CustomButton(ButtonListener* listener)
+    : Button(listener),
+      state_(BS_NORMAL),
+      animate_on_state_change_(true),
+      triggerable_event_flags_(MouseEvent::EF_LEFT_BUTTON_DOWN) {
+  hover_animation_.reset(new ThrobAnimation(this));
+  hover_animation_->SetSlideDuration(kHoverFadeDurationMs);
+}
+
+bool CustomButton::IsTriggerableEvent(const MouseEvent& e) {
+  return (triggerable_event_flags_ & e.GetFlags()) != 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CustomButton, View overrides (protected):
+
+bool CustomButton::AcceleratorPressed(const Accelerator& accelerator) {
+  if (enabled_) {
+    SetState(BS_NORMAL);
+    NotifyClick(0);
+    return true;
+  }
+  return false;
+}
+
+bool CustomButton::OnMousePressed(const MouseEvent& e) {
+  if (state_ != BS_DISABLED) {
+    if (IsTriggerableEvent(e) && HitTest(e.location()))
+      SetState(BS_PUSHED);
+    RequestFocus();
+  }
+  return true;
+}
+
+bool CustomButton::OnMouseDragged(const MouseEvent& e) {
+  if (state_ != BS_DISABLED) {
+    if (!HitTest(e.location()))
+      SetState(BS_NORMAL);
+    else if (IsTriggerableEvent(e))
+      SetState(BS_PUSHED);
+    else
+      SetState(BS_HOT);
+  }
+  return true;
+}
+
+void CustomButton::OnMouseReleased(const MouseEvent& e, bool canceled) {
+  if (InDrag()) {
+    // Starting a drag results in a MouseReleased, we need to ignore it.
+    return;
+  }
+
+  if (state_ != BS_DISABLED) {
+    if (canceled || !HitTest(e.location())) {
+      SetState(BS_NORMAL);
+    } else {
+      SetState(BS_HOT);
+      if (IsTriggerableEvent(e)) {
+        NotifyClick(e.GetFlags());
+        // We may be deleted at this point (by the listener's notification
+        // handler) so no more doing anything, just return.
+        return;
+      }
+    }
+  }
+}
+
+void CustomButton::OnMouseEntered(const MouseEvent& e) {
+  if (state_ != BS_DISABLED)
+    SetState(BS_HOT);
+}
+
+void CustomButton::OnMouseMoved(const MouseEvent& e) {
+  if (state_ != BS_DISABLED) {
+    if (HitTest(e.location())) {
+      SetState(BS_HOT);
+    } else {
+      SetState(BS_NORMAL);
+    }
+  }
+}
+
+void CustomButton::OnMouseExited(const MouseEvent& e) {
+  // Starting a drag results in a MouseExited, we need to ignore it.
+  if (state_ != BS_DISABLED && !InDrag())
+    SetState(BS_NORMAL);
+}
+
+bool CustomButton::OnKeyPressed(const KeyEvent& e) {
+  if (state_ != BS_DISABLED) {
+    // Space sets button state to pushed. Enter clicks the button. This matches
+    // the Windows native behavior of buttons, where Space clicks the button
+    // on KeyRelease and Enter clicks the button on KeyPressed.
+    if (e.GetCharacter() == base::VKEY_SPACE) {
+      SetState(BS_PUSHED);
+      return true;
+    } else if  (e.GetCharacter() == base::VKEY_RETURN) {
+      SetState(BS_NORMAL);
+      NotifyClick(0);
+      return true;
+    }
+  }
+  return false;
+}
+
+bool CustomButton::OnKeyReleased(const KeyEvent& e) {
+  if (state_ != BS_DISABLED) {
+    if (e.GetCharacter() == base::VKEY_SPACE) {
+      SetState(BS_NORMAL);
+      NotifyClick(0);
+      return true;
+    }
+  }
+  return false;
+}
+
+void CustomButton::OnDragDone() {
+  SetState(BS_NORMAL);
+}
+
+void CustomButton::ShowContextMenu(int x, int y, bool is_mouse_gesture) {
+  if (GetContextMenuController()) {
+    // We're about to show the context menu. Showing the context menu likely
+    // means we won't get a mouse exited and reset state. Reset it now to be
+    // sure.
+    if (state_ != BS_DISABLED)
+      SetState(BS_NORMAL);
+    View::ShowContextMenu(x, y, is_mouse_gesture);
+  }
+}
+
+void CustomButton::ViewHierarchyChanged(bool is_add, View *parent,
+                                        View *child) {
+  if (!is_add && state_ != BS_DISABLED)
+    SetState(BS_NORMAL);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CustomButton, AnimationDelegate implementation:
+
+void CustomButton::AnimationProgressed(const Animation* animation) {
+  SchedulePaint();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CustomButton, private:
+
+void CustomButton::SetHighlighted(bool highlighted) {
+  if (highlighted && state_ != BS_DISABLED) {
+    SetState(BS_HOT);
+  } else if (!highlighted && state_ != BS_DISABLED) {
+    SetState(BS_NORMAL);
+  }
+}
+
+bool CustomButton::IsHighlighted() const {
+  return state_ == BS_HOT;
+}
+
+bool CustomButton::IsPushed() const {
+  return state_ == BS_PUSHED;
+}
+
+}  // namespace views
diff --git a/views/controls/button/custom_button.h b/views/controls/button/custom_button.h
new file mode 100644
index 0000000..32ff76b
--- /dev/null
+++ b/views/controls/button/custom_button.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_BUTTON_CUSTOM_BUTTON_H_
+#define VIEWS_CONTROLS_BUTTON_CUSTOM_BUTTON_H_
+
+#include "app/animation.h"
+#include "views/controls/button/button.h"
+
+class ThrobAnimation;
+
+namespace views {
+
+// A button with custom rendering. The common base class of IconButton and
+// TextButton.
+class CustomButton : public Button,
+                     public AnimationDelegate {
+ public:
+  virtual ~CustomButton();
+
+  // Possible states
+  enum ButtonState {
+    BS_NORMAL = 0,
+    BS_HOT,
+    BS_PUSHED,
+    BS_DISABLED,
+    BS_COUNT
+  };
+
+  // Get/sets the current display state of the button.
+  ButtonState state() const { return state_; }
+  void SetState(ButtonState state);
+
+  // Starts throbbing. See HoverAnimation for a description of cycles_til_stop.
+  void StartThrobbing(int cycles_til_stop);
+
+  // Set how long the hover animation will last for.
+  void SetAnimationDuration(int duration);
+
+  // Overridden from View:
+  virtual void SetEnabled(bool enabled);
+  virtual bool IsEnabled() const;
+  virtual bool IsFocusable() const;
+
+  void set_triggerable_event_flags(int triggerable_event_flags) {
+    triggerable_event_flags_ = triggerable_event_flags;
+  }
+
+  int triggerable_event_flags() const {
+    return triggerable_event_flags_;
+  }
+
+ protected:
+  // Construct the Button with a Listener. See comment for Button's ctor.
+  explicit CustomButton(ButtonListener* listener);
+
+  // Returns true if the event is one that can trigger notifying the listener.
+  // This implementation returns true if the left mouse button is down.
+  virtual bool IsTriggerableEvent(const MouseEvent& e);
+
+  // Overridden from View:
+  virtual bool AcceleratorPressed(const Accelerator& accelerator);
+  virtual bool OnMousePressed(const MouseEvent& e);
+  virtual bool OnMouseDragged(const MouseEvent& e);
+  virtual void OnMouseReleased(const MouseEvent& e, bool canceled);
+  virtual void OnMouseEntered(const MouseEvent& e);
+  virtual void OnMouseMoved(const MouseEvent& e);
+  virtual void OnMouseExited(const MouseEvent& e);
+  virtual bool OnKeyPressed(const KeyEvent& e);
+  virtual bool OnKeyReleased(const KeyEvent& e);
+  virtual void OnDragDone();
+  virtual void ShowContextMenu(int x, int y, bool is_mouse_gesture);
+  virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
+
+  // Overridden from AnimationDelegate:
+  virtual void AnimationProgressed(const Animation* animation);
+
+  // The button state (defined in implementation)
+  ButtonState state_;
+
+  // Hover animation.
+  scoped_ptr<ThrobAnimation> hover_animation_;
+
+ private:
+  // Set / test whether the button is highlighted (in the hover state).
+  void SetHighlighted(bool highlighted);
+  bool IsHighlighted() const;
+
+  // Returns whether the button is pushed.
+  bool IsPushed() const;
+
+  // Should we animate when the state changes? Defaults to true, but false while
+  // throbbing.
+  bool animate_on_state_change_;
+
+  // Mouse event flags which can trigger button actions.
+  int triggerable_event_flags_;
+
+  DISALLOW_COPY_AND_ASSIGN(CustomButton);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_BUTTON_CUSTOM_BUTTON_H_
diff --git a/views/controls/button/image_button.cc b/views/controls/button/image_button.cc
new file mode 100644
index 0000000..3c4c7fe
--- /dev/null
+++ b/views/controls/button/image_button.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2006-2008 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 "views/controls/button/image_button.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/throb_animation.h"
+#include "skia/ext/image_operations.h"
+
+namespace views {
+
+static const int kDefaultWidth = 16;   // Default button width if no theme.
+static const int kDefaultHeight = 14;  // Default button height if no theme.
+
+////////////////////////////////////////////////////////////////////////////////
+// ImageButton, public:
+
+ImageButton::ImageButton(ButtonListener* listener)
+    : CustomButton(listener),
+      h_alignment_(ALIGN_LEFT),
+      v_alignment_(ALIGN_TOP) {
+  // By default, we request that the ChromeCanvas passed to our View::Paint()
+  // implementation is flipped horizontally so that the button's bitmaps are
+  // mirrored when the UI directionality is right-to-left.
+  EnableCanvasFlippingForRTLUI(true);
+}
+
+ImageButton::~ImageButton() {
+}
+
+void ImageButton::SetImage(ButtonState aState, SkBitmap* anImage) {
+  images_[aState] = anImage ? *anImage : SkBitmap();
+}
+
+void ImageButton::SetImageAlignment(HorizontalAlignment h_align,
+                                    VerticalAlignment v_align) {
+  h_alignment_ = h_align;
+  v_alignment_ = v_align;
+  SchedulePaint();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ImageButton, View overrides:
+
+gfx::Size ImageButton::GetPreferredSize() {
+  if (!images_[BS_NORMAL].isNull())
+    return gfx::Size(images_[BS_NORMAL].width(), images_[BS_NORMAL].height());
+  return gfx::Size(kDefaultWidth, kDefaultHeight);
+}
+
+void ImageButton::Paint(ChromeCanvas* canvas) {
+  // Call the base class first to paint any background/borders.
+  View::Paint(canvas);
+
+  SkBitmap img = GetImageToPaint();
+
+  if (!img.isNull()) {
+    int x = 0, y = 0;
+
+    if (h_alignment_ == ALIGN_CENTER)
+      x = (width() - img.width()) / 2;
+    else if (h_alignment_ == ALIGN_RIGHT)
+      x = width() - img.width();
+
+    if (v_alignment_ == ALIGN_MIDDLE)
+      y = (height() - img.height()) / 2;
+    else if (v_alignment_ == ALIGN_BOTTOM)
+      y = height() - img.height();
+
+    canvas->DrawBitmapInt(img, x, y);
+  }
+  PaintFocusBorder(canvas);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ImageButton, protected:
+
+SkBitmap ImageButton::GetImageToPaint() {
+  SkBitmap img;
+
+  if (!images_[BS_HOT].isNull() && hover_animation_->IsAnimating()) {
+    img = skia::ImageOperations::CreateBlendedBitmap(images_[BS_NORMAL],
+              images_[BS_HOT], hover_animation_->GetCurrentValue());
+  } else {
+    img = images_[state_];
+  }
+
+  return !img.isNull() ? img : images_[BS_NORMAL];
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ToggleImageButton, public:
+
+ToggleImageButton::ToggleImageButton(ButtonListener* listener)
+    : ImageButton(listener),
+      toggled_(false) {
+}
+
+ToggleImageButton::~ToggleImageButton() {
+}
+
+void ToggleImageButton::SetToggled(bool toggled) {
+  if (toggled == toggled_)
+    return;
+
+  for (int i = 0; i < BS_COUNT; ++i) {
+    SkBitmap temp = images_[i];
+    images_[i] = alternate_images_[i];
+    alternate_images_[i] = temp;
+  }
+  toggled_ = toggled;
+  SchedulePaint();
+}
+
+void ToggleImageButton::SetToggledImage(ButtonState state, SkBitmap* image) {
+  if (toggled_) {
+    images_[state] = image ? *image : SkBitmap();
+    if (state_ == state)
+      SchedulePaint();
+  } else {
+    alternate_images_[state] = image ? *image : SkBitmap();
+  }
+}
+
+void ToggleImageButton::SetToggledTooltipText(const std::wstring& tooltip) {
+  toggled_tooltip_text_.assign(tooltip);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ToggleImageButton, ImageButton overrides:
+
+void ToggleImageButton::SetImage(ButtonState state, SkBitmap* image) {
+  if (toggled_) {
+    alternate_images_[state] = image ? *image : SkBitmap();
+  } else {
+    images_[state] = image ? *image : SkBitmap();
+    if (state_ == state)
+      SchedulePaint();
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ToggleImageButton, View overrides:
+
+bool ToggleImageButton::GetTooltipText(int x, int y, std::wstring* tooltip) {
+  if (!toggled_ || toggled_tooltip_text_.empty())
+    return Button::GetTooltipText(x, y, tooltip);
+
+  *tooltip = toggled_tooltip_text_;
+  return true;
+}
+
+}  // namespace views
diff --git a/views/controls/button/image_button.h b/views/controls/button/image_button.h
new file mode 100644
index 0000000..c687561
--- /dev/null
+++ b/views/controls/button/image_button.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_BUTTON_IMAGE_BUTTON_H_
+#define VIEWS_CONTROLS_BUTTON_IMAGE_BUTTON_H_
+
+#include "skia/include/SkBitmap.h"
+#include "views/controls/button/custom_button.h"
+
+namespace views {
+
+// An image button.
+class ImageButton : public CustomButton {
+ public:
+  explicit ImageButton(ButtonListener* listener);
+  virtual ~ImageButton();
+
+  // Set the image the button should use for the provided state.
+  virtual void SetImage(ButtonState aState, SkBitmap* anImage);
+
+  enum HorizontalAlignment { ALIGN_LEFT = 0,
+                             ALIGN_CENTER,
+                             ALIGN_RIGHT, };
+
+  enum VerticalAlignment { ALIGN_TOP = 0,
+                           ALIGN_MIDDLE,
+                           ALIGN_BOTTOM };
+
+  // Sets how the image is laid out within the button's bounds.
+  void SetImageAlignment(HorizontalAlignment h_align,
+                         VerticalAlignment v_align);
+
+  // Overridden from View:
+  virtual gfx::Size GetPreferredSize();
+  virtual void Paint(ChromeCanvas* canvas);
+
+ protected:
+  // Returns the image to paint. This is invoked from paint and returns a value
+  // from images.
+  virtual SkBitmap GetImageToPaint();
+
+  // The images used to render the different states of this button.
+  SkBitmap images_[BS_COUNT];
+
+ private:
+  // Image alignment.
+  HorizontalAlignment h_alignment_;
+  VerticalAlignment v_alignment_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImageButton);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ToggleImageButton
+//
+// A toggle-able ImageButton.  It swaps out its graphics when toggled.
+//
+////////////////////////////////////////////////////////////////////////////////
+class ToggleImageButton : public ImageButton {
+ public:
+  ToggleImageButton(ButtonListener* listener);
+  virtual ~ToggleImageButton();
+
+  // Change the toggled state.
+  void SetToggled(bool toggled);
+
+  // Like Button::SetImage(), but to set the graphics used for the
+  // "has been toggled" state.  Must be called for each button state
+  // before the button is toggled.
+  void SetToggledImage(ButtonState state, SkBitmap* image);
+
+  // Set the tooltip text displayed when the button is toggled.
+  void SetToggledTooltipText(const std::wstring& tooltip);
+
+  // Overridden from ImageButton:
+  virtual void SetImage(ButtonState aState, SkBitmap* anImage);
+
+  // Overridden from View:
+  virtual bool GetTooltipText(int x, int y, std::wstring* tooltip);
+
+ private:
+  // The parent class's images_ member is used for the current images,
+  // and this array is used to hold the alternative images.
+  // We swap between the two when toggling.
+  SkBitmap alternate_images_[BS_COUNT];
+
+  // True if the button is currently toggled.
+  bool toggled_;
+
+  // The parent class's tooltip_text_ is displayed when not toggled, and
+  // this one is shown when toggled.
+  std::wstring toggled_tooltip_text_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ToggleImageButton);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_BUTTON_IMAGE_BUTTON_H_
diff --git a/views/controls/button/menu_button.cc b/views/controls/button/menu_button.cc
new file mode 100644
index 0000000..888137bd
--- /dev/null
+++ b/views/controls/button/menu_button.cc
@@ -0,0 +1,253 @@
+// Copyright (c) 2006-2008 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 "views/controls/button/menu_button.h"
+
+#include "app/drag_drop_types.h"
+#include "app/gfx/chrome_canvas.h"
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "chrome/common/win_util.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "views/controls/button/button.h"
+#include "views/controls/menu/view_menu_delegate.h"
+#include "views/event.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+
+using base::Time;
+using base::TimeDelta;
+
+namespace views {
+
+// The amount of time, in milliseconds, we wait before allowing another mouse
+// pressed event to show the menu.
+static const int64 kMinimumTimeBetweenButtonClicks = 100;
+
+// The down arrow used to differentiate the menu button from normal
+// text buttons.
+static const SkBitmap* kMenuMarker = NULL;
+
+// How much padding to put on the left and right of the menu marker.
+static const int kMenuMarkerPaddingLeft = 3;
+static const int kMenuMarkerPaddingRight = -1;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// MenuButton - constructors, destructors, initialization
+//
+////////////////////////////////////////////////////////////////////////////////
+
+MenuButton::MenuButton(ButtonListener* listener,
+                       const std::wstring& text,
+                       ViewMenuDelegate* menu_delegate,
+                       bool show_menu_marker)
+    : TextButton(listener, text),
+      menu_visible_(false),
+      menu_closed_time_(),
+      menu_delegate_(menu_delegate),
+      show_menu_marker_(show_menu_marker) {
+  if (kMenuMarker == NULL) {
+    kMenuMarker = ResourceBundle::GetSharedInstance()
+        .GetBitmapNamed(IDR_MENU_DROPARROW);
+  }
+  set_alignment(TextButton::ALIGN_LEFT);
+}
+
+MenuButton::~MenuButton() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// MenuButton - Public APIs
+//
+////////////////////////////////////////////////////////////////////////////////
+
+gfx::Size MenuButton::GetPreferredSize() {
+  gfx::Size prefsize = TextButton::GetPreferredSize();
+  if (show_menu_marker_) {
+    prefsize.Enlarge(kMenuMarker->width() + kMenuMarkerPaddingLeft +
+                         kMenuMarkerPaddingRight,
+                     0);
+  }
+  return prefsize;
+}
+
+void MenuButton::Paint(ChromeCanvas* canvas, bool for_drag) {
+  TextButton::Paint(canvas, for_drag);
+
+  if (show_menu_marker_) {
+    gfx::Insets insets = GetInsets();
+
+    // We can not use the views' mirroring infrastructure for mirroring a
+    // MenuButton control (see TextButton::Paint() for a detailed explanation
+    // regarding why we can not flip the canvas). Therefore, we need to
+    // manually mirror the position of the down arrow.
+    gfx::Rect arrow_bounds(width() - insets.right() -
+                           kMenuMarker->width() - kMenuMarkerPaddingRight,
+                           height() / 2 - kMenuMarker->height() / 2,
+                           kMenuMarker->width(),
+                           kMenuMarker->height());
+    arrow_bounds.set_x(MirroredLeftPointForRect(arrow_bounds));
+    canvas->DrawBitmapInt(*kMenuMarker, arrow_bounds.x(), arrow_bounds.y());
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// MenuButton - Events
+//
+////////////////////////////////////////////////////////////////////////////////
+
+int MenuButton::GetMaximumScreenXCoordinate() {
+  Widget* widget = GetWidget();
+
+  if (!widget) {
+    NOTREACHED();
+    return 0;
+  }
+
+  HWND hwnd = widget->GetNativeView();
+  CRect t;
+  ::GetWindowRect(hwnd, &t);
+
+  gfx::Rect r(t);
+  gfx::Rect monitor_rect = win_util::GetMonitorBoundsForRect(r);
+  return monitor_rect.x() + monitor_rect.width() - 1;
+}
+
+bool MenuButton::Activate() {
+  SetState(BS_PUSHED);
+  // We need to synchronously paint here because subsequently we enter a
+  // menu modal loop which will stop this window from updating and
+  // receiving the paint message that should be spawned by SetState until
+  // after the menu closes.
+  PaintNow();
+  if (menu_delegate_) {
+    gfx::Rect lb = GetLocalBounds(true);
+
+    // The position of the menu depends on whether or not the locale is
+    // right-to-left.
+    gfx::Point menu_position(lb.right(), lb.bottom());
+    if (UILayoutIsRightToLeft())
+      menu_position.set_x(lb.x());
+
+    View::ConvertPointToScreen(this, &menu_position);
+    if (UILayoutIsRightToLeft())
+      menu_position.Offset(2, -4);
+    else
+      menu_position.Offset(-2, -4);
+
+    int max_x_coordinate = GetMaximumScreenXCoordinate();
+    if (max_x_coordinate && max_x_coordinate <= menu_position.x())
+      menu_position.set_x(max_x_coordinate - 1);
+
+    // We're about to show the menu from a mouse press. By showing from the
+    // mouse press event we block RootView in mouse dispatching. This also
+    // appears to cause RootView to get a mouse pressed BEFORE the mouse
+    // release is seen, which means RootView sends us another mouse press no
+    // matter where the user pressed. To force RootView to recalculate the
+    // mouse target during the mouse press we explicitly set the mouse handler
+    // to NULL.
+    GetRootView()->SetMouseHandler(NULL);
+
+    menu_visible_ = true;
+    menu_delegate_->RunMenu(this, menu_position.ToPOINT(),
+                            GetWidget()->GetNativeView());
+    menu_visible_ = false;
+    menu_closed_time_ = Time::Now();
+
+    // Now that the menu has closed, we need to manually reset state to
+    // "normal" since the menu modal loop will have prevented normal
+    // mouse move messages from getting to this View. We set "normal"
+    // and not "hot" because the likelihood is that the mouse is now
+    // somewhere else (user clicked elsewhere on screen to close the menu
+    // or selected an item) and we will inevitably refresh the hot state
+    // in the event the mouse _is_ over the view.
+    SetState(BS_NORMAL);
+
+    // We must return false here so that the RootView does not get stuck
+    // sending all mouse pressed events to us instead of the appropriate
+    // target.
+    return false;
+  }
+  return true;
+}
+
+bool MenuButton::OnMousePressed(const MouseEvent& e) {
+  RequestFocus();
+  if (state() != BS_DISABLED) {
+    // If we're draggable (GetDragOperations returns a non-zero value), then
+    // don't pop on press, instead wait for release.
+    if (e.IsOnlyLeftMouseButton() && HitTest(e.location()) &&
+        GetDragOperations(e.x(), e.y()) == DragDropTypes::DRAG_NONE) {
+      TimeDelta delta = Time::Now() - menu_closed_time_;
+      int64 delta_in_milliseconds = delta.InMilliseconds();
+      if (delta_in_milliseconds > kMinimumTimeBetweenButtonClicks) {
+        return Activate();
+      }
+    }
+  }
+  return true;
+}
+
+void MenuButton::OnMouseReleased(const MouseEvent& e,
+                                 bool canceled) {
+  if (GetDragOperations(e.x(), e.y()) != DragDropTypes::DRAG_NONE &&
+      state() != BS_DISABLED && !canceled && !InDrag() &&
+      e.IsOnlyLeftMouseButton() && HitTest(e.location())) {
+    Activate();
+  } else {
+    TextButton::OnMouseReleased(e, canceled);
+  }
+}
+
+// When the space bar or the enter key is pressed we need to show the menu.
+bool MenuButton::OnKeyReleased(const KeyEvent& e) {
+  if ((e.GetCharacter() == VK_SPACE) || (e.GetCharacter() == VK_RETURN)) {
+    return Activate();
+  }
+  return true;
+}
+
+// The reason we override View::OnMouseExited is because we get this event when
+// we display the menu. If we don't override this method then
+// BaseButton::OnMouseExited will get the event and will set the button's state
+// to BS_NORMAL instead of keeping the state BM_PUSHED. This, in turn, will
+// cause the button to appear depressed while the menu is displayed.
+void MenuButton::OnMouseExited(const MouseEvent& event) {
+  if ((state_ != BS_DISABLED) && (!menu_visible_) && (!InDrag())) {
+    SetState(BS_NORMAL);
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// MenuButton - accessibility
+//
+////////////////////////////////////////////////////////////////////////////////
+
+bool MenuButton::GetAccessibleDefaultAction(std::wstring* action) {
+  DCHECK(action);
+
+  action->assign(l10n_util::GetString(IDS_ACCACTION_PRESS));
+  return true;
+}
+
+bool MenuButton::GetAccessibleRole(AccessibilityTypes::Role* role) {
+  DCHECK(role);
+
+  *role = AccessibilityTypes::ROLE_BUTTONDROPDOWN;
+  return true;
+}
+
+bool MenuButton::GetAccessibleState(AccessibilityTypes::State* state) {
+  DCHECK(state);
+
+  *state = AccessibilityTypes::STATE_HASPOPUP;
+  return true;
+}
+
+}  // namespace views
diff --git a/views/controls/button/menu_button.h b/views/controls/button/menu_button.h
new file mode 100644
index 0000000..cbe9ab8
--- /dev/null
+++ b/views/controls/button/menu_button.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_BUTTON_MENU_BUTTON_H_
+#define VIEWS_CONTROLS_BUTTON_MENU_BUTTON_H_
+
+#include <windows.h>
+
+#include "app/gfx/chrome_font.h"
+#include "base/time.h"
+#include "views/background.h"
+#include "views/controls/button/text_button.h"
+
+namespace views {
+
+class MouseEvent;
+class ViewMenuDelegate;
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// MenuButton
+//
+//  A button that shows a menu when the left mouse button is pushed
+//
+////////////////////////////////////////////////////////////////////////////////
+class MenuButton : public TextButton {
+ public:
+  //
+  // Create a Button
+  MenuButton(ButtonListener* listener,
+             const std::wstring& text,
+             ViewMenuDelegate* menu_delegate,
+             bool show_menu_marker);
+  virtual ~MenuButton();
+
+  void set_menu_delegate(ViewMenuDelegate* delegate) {
+    menu_delegate_ = delegate;
+  }
+
+  // Activate the button (called when the button is pressed).
+  virtual bool Activate();
+
+  // Overridden to take into account the potential use of a drop marker.
+  virtual gfx::Size GetPreferredSize();
+  virtual void Paint(ChromeCanvas* canvas, bool for_drag);
+
+  // These methods are overriden to implement a simple push button
+  // behavior
+  virtual bool OnMousePressed(const MouseEvent& e);
+  void OnMouseReleased(const MouseEvent& e, bool canceled);
+  virtual bool OnKeyReleased(const KeyEvent& e);
+  virtual void OnMouseExited(const MouseEvent& event);
+
+  // Accessibility accessors, overridden from View.
+  virtual bool GetAccessibleDefaultAction(std::wstring* action);
+  virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+  virtual bool GetAccessibleState(AccessibilityTypes::State* state);
+
+ protected:
+  // true if the menu is currently visible.
+  bool menu_visible_;
+
+ private:
+
+  // Compute the maximum X coordinate for the current screen. MenuButtons
+  // use this to make sure a menu is never shown off screen.
+  int GetMaximumScreenXCoordinate();
+
+  DISALLOW_EVIL_CONSTRUCTORS(MenuButton);
+
+  // We use a time object in order to keep track of when the menu was closed.
+  // The time is used for simulating menu behavior for the menu button; that
+  // is, if the menu is shown and the button is pressed, we need to close the
+  // menu. There is no clean way to get the second click event because the
+  // menu is displayed using a modal loop and, unlike regular menus in Windows,
+  // the button is not part of the displayed menu.
+  base::Time menu_closed_time_;
+
+  // The associated menu's resource identifier.
+  ViewMenuDelegate* menu_delegate_;
+
+  // Whether or not we're showing a drop marker.
+  bool show_menu_marker_;
+
+  friend class TextButtonBackground;
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_BUTTON_MENU_BUTTON_H_
diff --git a/views/controls/button/native_button.cc b/views/controls/button/native_button.cc
new file mode 100644
index 0000000..0af6f88
--- /dev/null
+++ b/views/controls/button/native_button.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2009 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 "views/controls/button/native_button.h"
+
+#include "app/l10n_util.h"
+#include "base/logging.h"
+
+namespace views {
+
+static int kButtonBorderHWidth = 8;
+
+// static
+const char NativeButton::kViewClassName[] = "views/NativeButton";
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButton, public:
+
+NativeButton::NativeButton(ButtonListener* listener)
+    : Button(listener),
+      native_wrapper_(NULL),
+      is_default_(false),
+      ignore_minimum_size_(false),
+      minimum_size_(50, 14) {
+  // The min size in DLUs comes from
+  // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwue/html/ch14e.asp
+  InitBorder();
+  SetFocusable(true);
+}
+
+NativeButton::NativeButton(ButtonListener* listener, const std::wstring& label)
+    : Button(listener),
+      native_wrapper_(NULL),
+      is_default_(false),
+      ignore_minimum_size_(false),
+      minimum_size_(50, 14) {
+  SetLabel(label);  // SetLabel takes care of label layout in RTL UI.
+  // The min size in DLUs comes from
+  // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwue/html/ch14e.asp
+  InitBorder();
+  SetFocusable(true);
+}
+
+NativeButton::~NativeButton() {
+}
+
+void NativeButton::SetLabel(const std::wstring& label) {
+  label_ = label;
+
+  // Even though we create a flipped HWND for a native button when the locale
+  // is right-to-left, Windows does not render text for the button using a
+  // right-to-left context (perhaps because the parent HWND is not flipped).
+  // The result is that RTL strings containing punctuation marks are not
+  // displayed properly. For example, the string "...ABC" (where A, B and C are
+  // Hebrew characters) is displayed as "ABC..." which is incorrect.
+  //
+  // In order to overcome this problem, we mark the localized Hebrew strings as
+  // RTL strings explicitly (using the appropriate Unicode formatting) so that
+  // Windows displays the text correctly regardless of the HWND hierarchy.
+  std::wstring localized_label;
+  if (l10n_util::AdjustStringForLocaleDirection(label_, &localized_label))
+    label_ = localized_label;
+
+  if (native_wrapper_)
+    native_wrapper_->UpdateLabel();
+}
+
+void NativeButton::SetIsDefault(bool is_default) {
+  if (is_default == is_default_)
+    return;
+  if (is_default)
+    AddAccelerator(Accelerator(VK_RETURN, false, false, false));
+  else
+    RemoveAccelerator(Accelerator(VK_RETURN, false, false, false));
+  SetAppearsAsDefault(is_default);
+}
+
+void NativeButton::SetAppearsAsDefault(bool appears_as_default) {
+  is_default_ = appears_as_default;
+  if (native_wrapper_)
+    native_wrapper_->UpdateDefault();
+}
+
+void NativeButton::ButtonPressed() {
+  RequestFocus();
+
+  // TODO(beng): obtain mouse event flags for native buttons someday.
+  NotifyClick(mouse_event_flags());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButton, View overrides:
+
+gfx::Size NativeButton::GetPreferredSize() {
+  if (!native_wrapper_)
+    return gfx::Size();
+
+  gfx::Size sz = native_wrapper_->GetView()->GetPreferredSize();
+
+  // Add in the border size. (Do this before clamping the minimum size in case
+  // that clamping causes an increase in size that would include the borders.
+  gfx::Insets border = GetInsets();
+  sz.set_width(sz.width() + border.left() + border.right());
+  sz.set_height(sz.height() + border.top() + border.bottom());
+
+  // Clamp the size returned to at least the minimum size.
+  if (!ignore_minimum_size_) {
+    if (minimum_size_.width()) {
+      int min_width = font_.horizontal_dlus_to_pixels(minimum_size_.width());
+      sz.set_width(std::max(static_cast<int>(sz.width()), min_width));
+    }
+    if (minimum_size_.height()) {
+      int min_height = font_.vertical_dlus_to_pixels(minimum_size_.height());
+      sz.set_height(std::max(static_cast<int>(sz.height()), min_height));
+    }
+  }
+
+  return sz;
+}
+
+void NativeButton::Layout() {
+  if (native_wrapper_) {
+    native_wrapper_->GetView()->SetBounds(0, 0, width(), height());
+    native_wrapper_->GetView()->Layout();
+  }
+}
+
+void NativeButton::SetEnabled(bool flag) {
+  Button::SetEnabled(flag);
+  if (native_wrapper_)
+    native_wrapper_->UpdateEnabled();
+}
+
+void NativeButton::ViewHierarchyChanged(bool is_add, View* parent,
+                                         View* child) {
+  if (is_add && !native_wrapper_ && GetWidget()) {
+    CreateWrapper();
+    AddChildView(native_wrapper_->GetView());
+  }
+}
+
+std::string NativeButton::GetClassName() const {
+  return kViewClassName;
+}
+
+bool NativeButton::AcceleratorPressed(const Accelerator& accelerator) {
+  if (IsEnabled()) {
+    NotifyClick(mouse_event_flags());
+    return true;
+  }
+  return false;
+}
+
+void NativeButton::Focus() {
+  // Forward the focus to the wrapper.
+  if (native_wrapper_)
+    native_wrapper_->SetFocus();
+  else
+    Button::Focus();  // Will focus the RootView window (so we still get
+                      // keyboard messages).
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButton, protected:
+
+void NativeButton::CreateWrapper() {
+  native_wrapper_ = NativeButtonWrapper::CreateNativeButtonWrapper(this);
+  native_wrapper_->UpdateLabel();
+  native_wrapper_->UpdateEnabled();
+}
+
+void NativeButton::InitBorder() {
+  set_border(Border::CreateEmptyBorder(0, kButtonBorderHWidth, 0,
+                                       kButtonBorderHWidth));
+}
+
+}  // namespace views
diff --git a/views/controls/button/native_button.h b/views/controls/button/native_button.h
new file mode 100644
index 0000000..52946d7
--- /dev/null
+++ b/views/controls/button/native_button.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2009 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 VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_H_
+#define VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_H_
+
+#include "app/gfx/chrome_font.h"
+#include "views/controls/button/button.h"
+#include "views/controls/button/native_button_wrapper.h"
+
+class ChromeFont;
+
+namespace views {
+
+class NativeButton : public Button {
+ public:
+  // The button's class name.
+  static const char kViewClassName[];
+
+  explicit NativeButton(ButtonListener* listener);
+  NativeButton(ButtonListener* listener, const std::wstring& label);
+  virtual ~NativeButton();
+
+  // Sets/Gets the text to be used as the button's label.
+  void SetLabel(const std::wstring& label);
+  std::wstring label() const { return label_; }
+
+  // Sets the font to be used when displaying the button's label.
+  void set_font(const ChromeFont& font) { font_ = font; }
+  const ChromeFont& font() const { return font_; }
+
+  // Sets/Gets whether or not the button appears and behaves as the default
+  // button in its current context.
+  void SetIsDefault(bool default_button);
+  bool is_default() const { return is_default_; }
+
+  // Sets whether or not the button appears as the default button. This does
+  // not make it behave as the default (i.e. no enter key accelerator is
+  // registered, use SetIsDefault for that).
+  void SetAppearsAsDefault(bool default_button);
+
+  void set_minimum_size(const gfx::Size& minimum_size) {
+    minimum_size_ = minimum_size;
+  }
+  void set_ignore_minimum_size(bool ignore_minimum_size) {
+    ignore_minimum_size_ = ignore_minimum_size;
+  }
+
+  // Called by the wrapper when the actual wrapped native button was pressed.
+  void ButtonPressed();
+
+  // Overridden from View:
+  virtual gfx::Size GetPreferredSize();
+  virtual void Layout();
+  virtual void SetEnabled(bool flag);
+  virtual void Focus();
+
+ protected:
+  virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child);
+  virtual std::string GetClassName() const;
+  virtual bool AcceleratorPressed(const Accelerator& accelerator);
+
+  // Create the button wrapper. Can be overridden by subclass to create a
+  // wrapper of a particular type. See NativeButtonWrapper interface for types.
+  virtual void CreateWrapper();
+
+  // Sets a border to the button. Override to set a different border or to not
+  // set one (the default is 0,8,0,8 for push buttons).
+  virtual void InitBorder();
+
+  // The object that actually implements the native button.
+  NativeButtonWrapper* native_wrapper_;
+
+ private:
+  // The button label.
+  std::wstring label_;
+
+  // True if the button is the default button in its context.
+  bool is_default_;
+
+  // The font used to render the button label.
+  ChromeFont font_;
+
+  // True if the button should ignore the minimum size for the platform. Default
+  // is false. Set to true to create narrower buttons.
+  bool ignore_minimum_size_;
+
+  // The minimum size of the button from the specified size in native dialog
+  // units. The definition of this unit may vary from platform to platform. If
+  // the width/height is non-zero, the preferred size of the button will not be
+  // less than this value when the dialog units are converted to pixels.
+  gfx::Size minimum_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeButton);
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_H_
diff --git a/views/controls/button/native_button_win.cc b/views/controls/button/native_button_win.cc
new file mode 100644
index 0000000..6748241
--- /dev/null
+++ b/views/controls/button/native_button_win.cc
@@ -0,0 +1,234 @@
+// Copyright (c) 2009 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 "views/controls/button/native_button_win.h"
+
+#include "base/logging.h"
+#include "views/controls/button/checkbox.h"
+#include "views/controls/button/native_button.h"
+#include "views/controls/button/radio_button.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButtonWin, public:
+
+NativeButtonWin::NativeButtonWin(NativeButton* native_button)
+    : NativeControlWin(),
+      native_button_(native_button) {
+  // Associates the actual HWND with the native_button so the native_button is
+  // the one considered as having the focus (not the wrapper) when the HWND is
+  // focused directly (with a click for example).
+  SetAssociatedFocusView(native_button);
+}
+
+NativeButtonWin::~NativeButtonWin() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButtonWin, NativeButtonWrapper implementation:
+
+void NativeButtonWin::UpdateLabel() {
+  SetWindowText(GetHWND(), native_button_->label().c_str());
+}
+
+void NativeButtonWin::UpdateFont() {
+  SendMessage(GetHWND(), WM_SETFONT,
+              reinterpret_cast<WPARAM>(native_button_->font().hfont()),
+              FALSE);
+}
+
+void NativeButtonWin::UpdateEnabled() {
+  SetEnabled(native_button_->IsEnabled());
+}
+
+void NativeButtonWin::UpdateDefault() {
+  if (!IsCheckbox()) {
+    SendMessage(GetHWND(), BM_SETSTYLE,
+                native_button_->is_default() ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON,
+                true);
+  }
+}
+
+View* NativeButtonWin::GetView() {
+  return this;
+}
+
+void NativeButtonWin::SetFocus() {
+  // Focus the associated HWND.
+  Focus();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButtonWin, View overrides:
+
+gfx::Size NativeButtonWin::GetPreferredSize() {
+  SIZE sz = {0};
+  SendMessage(GetHWND(), BCM_GETIDEALSIZE, 0, reinterpret_cast<LPARAM>(&sz));
+
+  return gfx::Size(sz.cx, sz.cy);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButtonWin, NativeControlWin overrides:
+
+bool NativeButtonWin::ProcessMessage(UINT message, WPARAM w_param,
+                                     LPARAM l_param, LRESULT* result) {
+  if (message == WM_COMMAND && HIWORD(w_param) == BN_CLICKED) {
+    native_button_->ButtonPressed();
+    *result = 0;
+    return true;
+  }
+  return NativeControlWin::ProcessMessage(message, w_param, l_param, result);
+}
+
+bool NativeButtonWin::OnKeyDown(int vkey) {
+  bool enter_pressed = vkey == VK_RETURN;
+  if (enter_pressed)
+    native_button_->ButtonPressed();
+  return enter_pressed;
+}
+
+bool NativeButtonWin::NotifyOnKeyDown() const {
+  return true;
+}
+
+void NativeButtonWin::CreateNativeControl() {
+  DWORD flags = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | BS_PUSHBUTTON;
+  if (native_button_->is_default())
+    flags |= BS_DEFPUSHBUTTON;
+  HWND control_hwnd = CreateWindowEx(GetAdditionalExStyle(), L"BUTTON", L"",
+                                     flags, 0, 0, width(), height(),
+                                     GetWidget()->GetNativeView(), NULL, NULL,
+                                     NULL);
+  NativeControlCreated(control_hwnd);
+}
+
+void NativeButtonWin::NativeControlCreated(HWND control_hwnd) {
+  NativeControlWin::NativeControlCreated(control_hwnd);
+
+  UpdateFont();
+  UpdateLabel();
+  UpdateDefault();
+}
+
+// We could obtain this from the theme, but that only works if themes are
+// active.
+static const int kCheckboxSize = 13; // pixels
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeCheckboxWin, public:
+
+NativeCheckboxWin::NativeCheckboxWin(Checkbox* checkbox)
+    : NativeButtonWin(checkbox),
+      checkbox_(checkbox) {
+}
+
+NativeCheckboxWin::~NativeCheckboxWin() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeCheckboxWin, View overrides:
+
+gfx::Size NativeCheckboxWin::GetPreferredSize() {
+  return gfx::Size(kCheckboxSize, kCheckboxSize);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeCheckboxWin, NativeButtonWrapper implementation:
+
+void NativeCheckboxWin::UpdateChecked() {
+  SendMessage(GetHWND(), BM_SETCHECK,
+              checkbox_->checked() ? BST_CHECKED : BST_UNCHECKED, 0);
+}
+
+void NativeCheckboxWin::SetPushed(bool pushed) {
+  SendMessage(GetHWND(), BM_SETSTATE, pushed, 0);
+}
+
+bool NativeCheckboxWin::OnKeyDown(int vkey) {
+  // Override the NativeButtonWin behavior which triggers the button on enter
+  // key presses when focused.
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeCheckboxWin, NativeButtonWin overrides:
+
+bool NativeCheckboxWin::ProcessMessage(UINT message, WPARAM w_param,
+                                       LPARAM l_param, LRESULT* result) {
+  if (message == WM_COMMAND && HIWORD(w_param) == BN_CLICKED) {
+    if (!IsRadioButton() || !checkbox_->checked())
+      checkbox_->SetChecked(!checkbox_->checked());
+    // Fall through to the NativeButtonWin's handler, which will send the
+    // clicked notification to the listener...
+  }
+  return NativeButtonWin::ProcessMessage(message, w_param, l_param, result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeCheckboxWin, protected:
+
+void NativeCheckboxWin::CreateNativeControl() {
+  HWND control_hwnd = CreateWindowEx(
+      WS_EX_TRANSPARENT | GetAdditionalExStyle(), L"BUTTON", L"",
+      WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | BS_CHECKBOX,
+      0, 0, width(), height(), GetWidget()->GetNativeView(), NULL, NULL, NULL);
+  NativeControlCreated(control_hwnd);
+}
+
+void NativeCheckboxWin::NativeControlCreated(HWND control_hwnd) {
+  NativeButtonWin::NativeControlCreated(control_hwnd);
+  UpdateChecked();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeRadioButtonWin, public:
+
+NativeRadioButtonWin::NativeRadioButtonWin(RadioButton* radio_button)
+    : NativeCheckboxWin(radio_button) {
+}
+
+NativeRadioButtonWin::~NativeRadioButtonWin() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeRadioButtonWin, NativeCheckboxWin overrides:
+
+void NativeRadioButtonWin::CreateNativeControl() {
+  HWND control_hwnd = CreateWindowEx(
+      GetAdditionalExStyle(), L"BUTTON",
+      L"", WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | BS_RADIOBUTTON,
+      0, 0, width(), height(), GetWidget()->GetNativeView(), NULL, NULL, NULL);
+  NativeControlCreated(control_hwnd);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeButtonWrapper, public:
+
+// static
+int NativeButtonWrapper::GetFixedWidth() {
+  return kCheckboxSize;
+}
+
+// static
+NativeButtonWrapper* NativeButtonWrapper::CreateNativeButtonWrapper(
+    NativeButton* native_button) {
+  return new NativeButtonWin(native_button);
+}
+
+// static
+NativeButtonWrapper* NativeButtonWrapper::CreateCheckboxWrapper(
+    Checkbox* checkbox) {
+  return new NativeCheckboxWin(checkbox);
+}
+
+// static
+NativeButtonWrapper* NativeButtonWrapper::CreateRadioButtonWrapper(
+    RadioButton* radio_button) {
+  return new NativeRadioButtonWin(radio_button);
+}
+
+}  // namespace views
diff --git a/views/controls/button/native_button_win.h b/views/controls/button/native_button_win.h
new file mode 100644
index 0000000..3f5141a
--- /dev/null
+++ b/views/controls/button/native_button_win.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2009 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 VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WIN_H_
+#define VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WIN_H_
+
+#include "views/controls/native_control_win.h"
+#include "views/controls/button/native_button_wrapper.h"
+
+namespace views {
+
+// A View that hosts a native Windows button.
+class NativeButtonWin : public NativeControlWin,
+                        public NativeButtonWrapper {
+ public:
+  explicit NativeButtonWin(NativeButton* native_button);
+  virtual ~NativeButtonWin();
+
+  // Overridden from NativeButtonWrapper:
+  virtual void UpdateLabel();
+  virtual void UpdateFont();
+  virtual void UpdateEnabled();
+  virtual void UpdateDefault();
+  virtual View* GetView();
+  virtual void SetFocus();
+
+  // Overridden from View:
+  virtual gfx::Size GetPreferredSize();
+
+  // Overridden from NativeControlWin:
+  virtual bool ProcessMessage(UINT message,
+                              WPARAM w_param,
+                              LPARAM l_param,
+                              LRESULT* result);
+  virtual bool OnKeyDown(int vkey);
+
+ protected:
+  virtual bool NotifyOnKeyDown() const;
+  virtual void CreateNativeControl();
+  virtual void NativeControlCreated(HWND control_hwnd);
+
+  // Returns true if this button is actually a checkbox or radio button.
+  virtual bool IsCheckbox() const { return false; }
+
+ private:
+  // The NativeButton we are bound to.
+  NativeButton* native_button_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeButtonWin);
+};
+
+// A View that hosts a native Windows checkbox.
+class NativeCheckboxWin : public NativeButtonWin {
+ public:
+  explicit NativeCheckboxWin(Checkbox* native_button);
+  virtual ~NativeCheckboxWin();
+
+  // Overridden from View:
+  virtual gfx::Size GetPreferredSize();
+
+  // Overridden from NativeButtonWrapper:
+  virtual void UpdateChecked();
+  virtual void SetPushed(bool pushed);
+  virtual bool OnKeyDown(int vkey);
+
+  // Overridden from NativeControlWin:
+  virtual bool ProcessMessage(UINT message,
+                              WPARAM w_param,
+                              LPARAM l_param,
+                              LRESULT* result);
+
+ protected:
+  virtual void CreateNativeControl();
+  virtual void NativeControlCreated(HWND control_hwnd);
+  virtual bool IsCheckbox() const { return true; }
+
+  // Returns true if this button is actually a radio button.
+  virtual bool IsRadioButton() const { return false; }
+
+ private:
+  // The Checkbox we are bound to.
+  Checkbox* checkbox_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeCheckboxWin);
+};
+
+// A View that hosts a native Windows radio button.
+class NativeRadioButtonWin : public NativeCheckboxWin {
+ public:
+  explicit NativeRadioButtonWin(RadioButton* radio_button);
+  virtual ~NativeRadioButtonWin();
+
+ protected:
+  // Overridden from NativeCheckboxWin:
+  virtual void CreateNativeControl();
+  virtual bool IsRadioButton() const { return true; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NativeRadioButtonWin);
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WIN_H_
diff --git a/views/controls/button/native_button_wrapper.h b/views/controls/button/native_button_wrapper.h
new file mode 100644
index 0000000..5535ed4
--- /dev/null
+++ b/views/controls/button/native_button_wrapper.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2009 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 VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WRAPPER_H_
+#define VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WRAPPER_H_
+
+class ChromeFont;
+
+namespace views {
+
+class Checkbox;
+class NativeButton;
+class RadioButton;
+
+// A specialization of NativeControlWrapper that hosts a platform-native button.
+class NativeButtonWrapper {
+ public:
+  // Updates the native button's label from the state stored in its associated
+  // NativeButton.
+  virtual void UpdateLabel() = 0;
+
+  // Updates the native button's label font from the state stored in its
+  // associated NativeButton.
+  virtual void UpdateFont() = 0;
+
+  // Updates the native button's enabled state from the state stored in its
+  // associated NativeButton.
+  virtual void UpdateEnabled() = 0;
+
+  // Updates the native button's default state from the state stored in its
+  // associated NativeButton.
+  virtual void UpdateDefault() = 0;
+
+  // Updates the native button's checked state from the state stored in its
+  // associated NativeCheckbox. Valid only for checkboxes and radio buttons.
+  virtual void UpdateChecked() {}
+
+  // Shows the pushed state for the button if |pushed| is true.
+  virtual void SetPushed(bool pushed) {};
+
+  // Retrieves the views::View that hosts the native control.
+  virtual View* GetView() = 0;
+
+  // Sets the focus to the button.
+  virtual void SetFocus() = 0;
+
+  // Return the width of the button. Used for fixed size buttons (checkboxes and
+  // radio buttons) only.
+  static int GetFixedWidth();
+
+  // Creates an appropriate NativeButtonWrapper for the platform.
+  static NativeButtonWrapper* CreateNativeButtonWrapper(NativeButton* button);
+  static NativeButtonWrapper* CreateCheckboxWrapper(Checkbox* checkbox);
+  static NativeButtonWrapper* CreateRadioButtonWrapper(
+      RadioButton* radio_button);
+
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WRAPPER_H_
diff --git a/views/controls/button/radio_button.cc b/views/controls/button/radio_button.cc
new file mode 100644
index 0000000..3f4820d
--- /dev/null
+++ b/views/controls/button/radio_button.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2009 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 "views/controls/button/radio_button.h"
+
+#include "views/widget/root_view.h"
+
+namespace views {
+
+// static
+const char RadioButton::kViewClassName[] = "views/RadioButton";
+
+////////////////////////////////////////////////////////////////////////////////
+// RadioButton, public:
+
+RadioButton::RadioButton() : Checkbox() {
+}
+
+RadioButton::RadioButton(const std::wstring& label) : Checkbox(label) {
+}
+
+RadioButton::RadioButton(const std::wstring& label, int group_id)
+    : Checkbox(label) {
+  SetGroup(group_id);
+}
+
+RadioButton::~RadioButton() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RadioButton, Checkbox overrides:
+
+void RadioButton::SetChecked(bool checked) {
+  if (checked == RadioButton::checked())
+    return;
+  if (checked) {
+    // We can't just get the root view here because sometimes the radio
+    // button isn't attached to a root view (e.g., if it's part of a tab page
+    // that is currently not active).
+    View* container = GetParent();
+    while (container && container->GetParent())
+      container = container->GetParent();
+    if (container) {
+      std::vector<View*> other;
+      container->GetViewsWithGroup(GetGroup(), &other);
+      std::vector<View*>::iterator i;
+      for (i = other.begin(); i != other.end(); ++i) {
+        if (*i != this) {
+          RadioButton* peer = static_cast<RadioButton*>(*i);
+          peer->SetChecked(false);
+        }
+      }
+    }
+  }
+  Checkbox::SetChecked(checked);
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RadioButton, View overrides:
+
+View* RadioButton::GetSelectedViewForGroup(int group_id) {
+  std::vector<View*> views;
+  GetRootView()->GetViewsWithGroup(group_id, &views);
+  if (views.empty())
+    return NULL;
+
+  for (std::vector<View*>::const_iterator iter = views.begin();
+       iter != views.end(); ++iter) {
+    RadioButton* radio_button = static_cast<RadioButton*>(*iter);
+    if (radio_button->checked())
+      return radio_button;
+  }
+  return NULL;
+}
+
+bool RadioButton::IsGroupFocusTraversable() const {
+  // When focusing a radio button with tab/shift+tab, only the selected button
+  // from the group should be focused.
+  return false;
+}
+
+void RadioButton::OnMouseReleased(const MouseEvent& event, bool canceled) {
+  native_wrapper_->SetPushed(false);
+  // Set the checked state to true only if we are unchecked, since we can't
+  // be toggled on and off like a checkbox.
+  if (!checked() && !canceled && HitTestLabel(event))
+    SetChecked(true);
+
+  ButtonPressed();
+}
+
+std::string RadioButton::GetClassName() const {
+  return kViewClassName;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RadioButton, NativeButton overrides:
+
+void RadioButton::CreateWrapper() {
+  native_wrapper_ = NativeButtonWrapper::CreateRadioButtonWrapper(this);
+  native_wrapper_->UpdateLabel();
+  native_wrapper_->UpdateChecked();
+}
+
+}  // namespace views
diff --git a/views/controls/button/radio_button.h b/views/controls/button/radio_button.h
new file mode 100644
index 0000000..ab7fbe2
--- /dev/null
+++ b/views/controls/button/radio_button.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2009 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 VIEWS_CONTROLS_BUTTON_RADIO_BUTTON_H_
+#define VIEWS_CONTROLS_BUTTON_RADIO_BUTTON_H_
+
+#include "views/controls/button/checkbox.h"
+
+namespace views {
+
+// A Checkbox subclass representing a radio button.
+class RadioButton : public Checkbox {
+ public:
+  // The button's class name.
+  static const char kViewClassName[];
+
+  RadioButton();
+  RadioButton(const std::wstring& label);
+  RadioButton(const std::wstring& label, int group_id);
+  virtual ~RadioButton();
+
+  // Overridden from Checkbox:
+  virtual void SetChecked(bool checked);
+
+  // Overridden from View:
+  virtual View* GetSelectedViewForGroup(int group_id);
+  virtual bool IsGroupFocusTraversable() const;
+  virtual void OnMouseReleased(const MouseEvent& event, bool canceled);
+
+ protected:
+  virtual std::string GetClassName() const;
+
+  // Overridden from NativeButton:
+  virtual void CreateWrapper();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RadioButton);
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_CONTROLS_BUTTON_RADIO_BUTTON_H_
diff --git a/views/controls/button/text_button.cc b/views/controls/button/text_button.cc
new file mode 100644
index 0000000..4f68b90
--- /dev/null
+++ b/views/controls/button/text_button.cc
@@ -0,0 +1,325 @@
+// Copyright (c) 2006-2008 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 "views/controls/button/text_button.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/l10n_util.h"
+#include "app/throb_animation.h"
+#include "app/resource_bundle.h"
+#include "views/controls/button/button.h"
+#include "views/event.h"
+#include "grit/theme_resources.h"
+
+namespace views {
+
+// Padding between the icon and text.
+static const int kIconTextPadding = 5;
+
+// Preferred padding between text and edge
+static const int kPreferredPaddingHorizontal = 6;
+static const int kPreferredPaddingVertical = 5;
+
+static const SkColor kEnabledColor = SkColorSetRGB(6, 45, 117);
+static const SkColor kHighlightColor = SkColorSetARGB(200, 255, 255, 255);
+static const SkColor kDisabledColor = SkColorSetRGB(161, 161, 146);
+
+// How long the hover fade animation should last.
+static const int kHoverAnimationDurationMs = 170;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TextButtonBorder - constructors, destructors, initialization
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TextButtonBorder::TextButtonBorder() {
+  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
+  hot_set_.top_left = rb.GetBitmapNamed(IDR_TEXTBUTTON_TOP_LEFT_H);
+  hot_set_.top = rb.GetBitmapNamed(IDR_TEXTBUTTON_TOP_H);
+  hot_set_.top_right = rb.GetBitmapNamed(IDR_TEXTBUTTON_TOP_RIGHT_H);
+  hot_set_.left = rb.GetBitmapNamed(IDR_TEXTBUTTON_LEFT_H);
+  hot_set_.center = rb.GetBitmapNamed(IDR_TEXTBUTTON_CENTER_H);
+  hot_set_.right = rb.GetBitmapNamed(IDR_TEXTBUTTON_RIGHT_H);
+  hot_set_.bottom_left = rb.GetBitmapNamed(IDR_TEXTBUTTON_BOTTOM_LEFT_H);
+  hot_set_.bottom = rb.GetBitmapNamed(IDR_TEXTBUTTON_BOTTOM_H);
+  hot_set_.bottom_right = rb.GetBitmapNamed(IDR_TEXTBUTTON_BOTTOM_RIGHT_H);
+
+  pushed_set_.top_left = rb.GetBitmapNamed(IDR_TEXTBUTTON_TOP_LEFT_P);
+  pushed_set_.top = rb.GetBitmapNamed(IDR_TEXTBUTTON_TOP_P);
+  pushed_set_.top_right = rb.GetBitmapNamed(IDR_TEXTBUTTON_TOP_RIGHT_P);
+  pushed_set_.left = rb.GetBitmapNamed(IDR_TEXTBUTTON_LEFT_P);
+  pushed_set_.center = rb.GetBitmapNamed(IDR_TEXTBUTTON_CENTER_P);
+  pushed_set_.right = rb.GetBitmapNamed(IDR_TEXTBUTTON_RIGHT_P);
+  pushed_set_.bottom_left = rb.GetBitmapNamed(IDR_TEXTBUTTON_BOTTOM_LEFT_P);
+  pushed_set_.bottom = rb.GetBitmapNamed(IDR_TEXTBUTTON_BOTTOM_P);
+  pushed_set_.bottom_right = rb.GetBitmapNamed(IDR_TEXTBUTTON_BOTTOM_RIGHT_P);
+}
+
+TextButtonBorder::~TextButtonBorder() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TextButtonBackground - painting
+//
+////////////////////////////////////////////////////////////////////////////////
+
+void TextButtonBorder::Paint(const View& view, ChromeCanvas* canvas) const {
+  const TextButton* mb = static_cast<const TextButton*>(&view);
+  int state = mb->state();
+
+  // TextButton takes care of deciding when to call Paint.
+  const MBBImageSet* set = &hot_set_;
+  if (state == TextButton::BS_PUSHED)
+    set = &pushed_set_;
+
+  if (set) {
+    gfx::Rect bounds = view.bounds();
+
+    // Draw the top left image
+    canvas->DrawBitmapInt(*set->top_left, 0, 0);
+
+    // Tile the top image
+    canvas->TileImageInt(
+        *set->top,
+        set->top_left->width(),
+        0,
+        bounds.width() - set->top_right->width() - set->top_left->width(),
+        set->top->height());
+
+    // Draw the top right image
+    canvas->DrawBitmapInt(*set->top_right,
+                          bounds.width() - set->top_right->width(), 0);
+
+    // Tile the left image
+    canvas->TileImageInt(
+        *set->left,
+        0,
+        set->top_left->height(),
+        set->top_left->width(),
+        bounds.height() - set->top->height() - set->bottom_left->height());
+
+    // Tile the center image
+    canvas->TileImageInt(
+        *set->center,
+        set->left->width(),
+        set->top->height(),
+        bounds.width() - set->right->width() - set->left->width(),
+        bounds.height() - set->bottom->height() - set->top->height());
+
+    // Tile the right image
+    canvas->TileImageInt(
+        *set->right,
+        bounds.width() - set->right->width(),
+        set->top_right->height(),
+        bounds.width(),
+        bounds.height() - set->bottom_right->height() -
+            set->top_right->height());
+
+    // Draw the bottom left image
+    canvas->DrawBitmapInt(*set->bottom_left,
+                          0,
+                          bounds.height() - set->bottom_left->height());
+
+    // Tile the bottom image
+    canvas->TileImageInt(
+        *set->bottom,
+        set->bottom_left->width(),
+        bounds.height() - set->bottom->height(),
+        bounds.width() - set->bottom_right->width() -
+            set->bottom_left->width(),
+        set->bottom->height());
+
+    // Draw the bottom right image
+    canvas->DrawBitmapInt(*set->bottom_right,
+                          bounds.width() - set->bottom_right->width(),
+                          bounds.height() -  set->bottom_right->height());
+  } else {
+    // Do nothing
+  }
+}
+
+void TextButtonBorder::GetInsets(gfx::Insets* insets) const {
+  insets->Set(kPreferredPaddingVertical, kPreferredPaddingHorizontal,
+              kPreferredPaddingVertical, kPreferredPaddingHorizontal);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TextButton, public:
+
+TextButton::TextButton(ButtonListener* listener, const std::wstring& text)
+    : CustomButton(listener),
+      alignment_(ALIGN_LEFT),
+      font_(ResourceBundle::GetSharedInstance().GetFont(
+          ResourceBundle::BaseFont)),
+      color_(kEnabledColor),
+      max_width_(0) {
+  SetText(text);
+  set_border(new TextButtonBorder);
+  SetAnimationDuration(kHoverAnimationDurationMs);
+}
+
+TextButton::~TextButton() {
+}
+
+void TextButton::SetText(const std::wstring& text) {
+  text_ = text;
+  // Update our new current and max text size
+  text_size_.SetSize(font_.GetStringWidth(text_), font_.height());
+  max_text_size_.SetSize(std::max(max_text_size_.width(), text_size_.width()),
+                         std::max(max_text_size_.height(),
+                                  text_size_.height()));
+}
+
+void TextButton::SetIcon(const SkBitmap& icon) {
+  icon_ = icon;
+}
+
+void TextButton::ClearMaxTextSize() {
+  max_text_size_ = text_size_;
+}
+
+void TextButton::Paint(ChromeCanvas* canvas, bool for_drag) {
+  if (!for_drag) {
+    PaintBackground(canvas);
+
+    if (hover_animation_->IsAnimating()) {
+      // Draw the hover bitmap into an offscreen buffer, then blend it
+      // back into the current canvas.
+      canvas->saveLayerAlpha(NULL,
+          static_cast<int>(hover_animation_->GetCurrentValue() * 255),
+          SkCanvas::kARGB_NoClipLayer_SaveFlag);
+      canvas->drawARGB(0, 255, 255, 255, SkPorterDuff::kClear_Mode);
+      PaintBorder(canvas);
+      canvas->restore();
+    } else if (state_ == BS_HOT || state_ == BS_PUSHED) {
+      PaintBorder(canvas);
+    }
+
+    PaintFocusBorder(canvas);
+  }
+
+  gfx::Insets insets = GetInsets();
+  int available_width = width() - insets.width();
+  int available_height = height() - insets.height();
+  // Use the actual text (not max) size to properly center the text.
+  int content_width = text_size_.width();
+  if (icon_.width() > 0) {
+    content_width += icon_.width();
+    if (!text_.empty())
+      content_width += kIconTextPadding;
+  }
+  // Place the icon along the left edge.
+  int icon_x;
+  if (alignment_ == ALIGN_LEFT) {
+    icon_x = insets.left();
+  } else if (alignment_ == ALIGN_RIGHT) {
+    icon_x = available_width - content_width;
+  } else {
+    icon_x =
+        std::max(0, (available_width - content_width) / 2) + insets.left();
+  }
+  int text_x = icon_x;
+  if (icon_.width() > 0)
+    text_x += icon_.width() + kIconTextPadding;
+  const int text_width = std::min(text_size_.width(),
+                                  width() - insets.right() - text_x);
+  int text_y = (available_height - text_size_.height()) / 2 + insets.top();
+
+  if (text_width > 0) {
+    // Because the text button can (at times) draw multiple elements on the
+    // canvas, we can not mirror the button by simply flipping the canvas as
+    // doing this will mirror the text itself. Flipping the canvas will also
+    // make the icons look wrong because icons are almost always represented as
+    // direction insentisive bitmaps and such bitmaps should never be flipped
+    // horizontally.
+    //
+    // Due to the above, we must perform the flipping manually for RTL UIs.
+    gfx::Rect text_bounds(text_x, text_y, text_width, text_size_.height());
+    text_bounds.set_x(MirroredLeftPointForRect(text_bounds));
+
+    if (for_drag) {
+#if defined(OS_WIN)
+      // TODO(erg): Either port DrawStringWithHalo to linux or find an
+      // alternative here.
+      canvas->DrawStringWithHalo(text_, font_, color_, kHighlightColor,
+                                 text_bounds.x(),
+                                 text_bounds.y(),
+                                 text_bounds.width(),
+                                 text_bounds.height(),
+                                 l10n_util::DefaultCanvasTextAlignment());
+#endif
+    } else {
+      // Draw bevel highlight
+      canvas->DrawStringInt(text_,
+                            font_,
+                            kHighlightColor,
+                            text_bounds.x() + 1,
+                            text_bounds.y() + 1,
+                            text_bounds.width(),
+                            text_bounds.height());
+
+      canvas->DrawStringInt(text_,
+                            font_,
+                            color_,
+                            text_bounds.x(),
+                            text_bounds.y(),
+                            text_bounds.width(),
+                            text_bounds.height());
+    }
+  }
+
+  if (icon_.width() > 0) {
+    int icon_y = (available_height - icon_.height()) / 2 + insets.top();
+
+    // Mirroring the icon position if necessary.
+    gfx::Rect icon_bounds(icon_x, icon_y, icon_.width(), icon_.height());
+    icon_bounds.set_x(MirroredLeftPointForRect(icon_bounds));
+    canvas->DrawBitmapInt(icon_, icon_bounds.x(), icon_bounds.y());
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TextButton, View overrides:
+
+gfx::Size TextButton::GetPreferredSize() {
+  gfx::Insets insets = GetInsets();
+
+  // Use the max size to set the button boundaries.
+  gfx::Size prefsize(max_text_size_.width() + icon_.width() + insets.width(),
+                     std::max(max_text_size_.height(), icon_.height()) +
+                         insets.height());
+
+  if (icon_.width() > 0 && !text_.empty())
+    prefsize.Enlarge(kIconTextPadding, 0);
+
+  if (max_width_ > 0)
+    prefsize.set_width(std::min(max_width_, prefsize.width()));
+
+  return prefsize;
+}
+
+gfx::Size TextButton::GetMinimumSize() {
+  return max_text_size_;
+}
+
+void TextButton::SetEnabled(bool enabled) {
+  if (enabled == IsEnabled())
+    return;
+  CustomButton::SetEnabled(enabled);
+  color_ = enabled ? kEnabledColor : kDisabledColor;
+  SchedulePaint();
+}
+
+bool TextButton::OnMousePressed(const MouseEvent& e) {
+  return true;
+}
+
+void TextButton::Paint(ChromeCanvas* canvas) {
+  Paint(canvas, false);
+}
+
+}  // namespace views
diff --git a/views/controls/button/text_button.h b/views/controls/button/text_button.h
new file mode 100644
index 0000000..16bac57
--- /dev/null
+++ b/views/controls/button/text_button.h
@@ -0,0 +1,138 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_BUTTON_TEXT_BUTTON_H_
+#define VIEWS_CONTROLS_BUTTON_TEXT_BUTTON_H_
+
+#include "app/gfx/chrome_font.h"
+#include "skia/include/SkBitmap.h"
+#include "views/border.h"
+#include "views/controls/button/custom_button.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TextButtonBorder
+//
+//  A Border subclass that paints a TextButton's background layer -
+//  basically the button frame in the hot/pushed states.
+//
+////////////////////////////////////////////////////////////////////////////////
+class TextButtonBorder : public Border {
+ public:
+  TextButtonBorder();
+  virtual ~TextButtonBorder();
+
+  // Render the background for the provided view
+  virtual void Paint(const View& view, ChromeCanvas* canvas) const;
+
+  // Returns the insets for the border.
+  virtual void GetInsets(gfx::Insets* insets) const;
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(TextButtonBorder);
+
+  // Images
+  struct MBBImageSet {
+    SkBitmap* top_left;
+    SkBitmap* top;
+    SkBitmap* top_right;
+    SkBitmap* left;
+    SkBitmap* center;
+    SkBitmap* right;
+    SkBitmap* bottom_left;
+    SkBitmap* bottom;
+    SkBitmap* bottom_right;
+  };
+  MBBImageSet hot_set_;
+  MBBImageSet pushed_set_;
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TextButton
+//
+//  A button which displays text and/or and icon that can be changed in
+//  response to actions. TextButton reserves space for the largest string
+//  passed to SetText. To reset the cached max size invoke ClearMaxTextSize.
+//
+////////////////////////////////////////////////////////////////////////////////
+class TextButton : public CustomButton {
+ public:
+  TextButton(ButtonListener* listener, const std::wstring& text);
+  virtual ~TextButton();
+
+  // Call SetText once per string in your set of possible values at button
+  // creation time, so that it can contain the largest of them and avoid
+  // resizing the button when the text changes.
+  virtual void SetText(const std::wstring& text);
+  std::wstring text() const { return text_; }
+
+  enum TextAlignment {
+    ALIGN_LEFT,
+    ALIGN_CENTER,
+    ALIGN_RIGHT
+  };
+
+  void set_alignment(TextAlignment alignment) { alignment_ = alignment; }
+
+  // Sets the icon.
+  void SetIcon(const SkBitmap& icon);
+  SkBitmap icon() const { return icon_; }
+
+  // TextButton remembers the maximum display size of the text passed to
+  // SetText. This method resets the cached maximum display size to the
+  // current size.
+  void ClearMaxTextSize();
+
+  void set_max_width(int max_width) { max_width_ = max_width; }
+
+  // Paint the button into the specified canvas. If |for_drag| is true, the
+  // function paints a drag image representation into the canvas.
+  virtual void Paint(ChromeCanvas* canvas, bool for_drag);
+
+  // Overridden from View:
+  virtual gfx::Size GetPreferredSize();
+  virtual gfx::Size GetMinimumSize();
+  virtual void SetEnabled(bool enabled);
+
+ protected:
+  virtual bool OnMousePressed(const MouseEvent& e);
+  virtual void Paint(ChromeCanvas* canvas);
+
+ private:
+  // The text string that is displayed in the button.
+  std::wstring text_;
+
+  // The size of the text string.
+  gfx::Size text_size_;
+
+  // Track the size of the largest text string seen so far, so that
+  // changing text_ will not resize the button boundary.
+  gfx::Size max_text_size_;
+
+  // The alignment of the text string within the button.
+  TextAlignment alignment_;
+
+  // The font used to paint the text.
+  ChromeFont font_;
+
+  // Text color.
+  SkColor color_;
+
+  // An icon displayed with the text.
+  SkBitmap icon_;
+
+  // The width of the button will never be larger than this value. A value <= 0
+  // indicates the width is not constrained.
+  int max_width_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(TextButton);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_BUTTON_TEXT_BUTTON_H_
diff --git a/views/controls/combo_box.cc b/views/controls/combo_box.cc
new file mode 100644
index 0000000..eb079f7
--- /dev/null
+++ b/views/controls/combo_box.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2006-2008 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 "views/controls/combo_box.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/gfx/chrome_font.h"
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/gfx/native_theme.h"
+#include "base/gfx/rect.h"
+
+// Limit how small a combobox can be.
+static const int kMinComboboxWidth = 148;
+
+// Add a couple extra pixels to the widths of comboboxes and combobox
+// dropdowns so that text isn't too crowded.
+static const int kComboboxExtraPaddingX = 6;
+
+namespace views {
+
+ComboBox::ComboBox(Model* model)
+    : model_(model), selected_item_(0), listener_(NULL), content_width_(0) {
+}
+
+ComboBox::~ComboBox() {
+}
+
+void ComboBox::SetListener(Listener* listener) {
+  listener_ = listener;
+}
+
+gfx::Size ComboBox::GetPreferredSize() {
+  HWND hwnd = GetNativeControlHWND();
+  if (!hwnd)
+    return gfx::Size();
+
+  COMBOBOXINFO cbi;
+  memset(reinterpret_cast<unsigned char*>(&cbi), 0, sizeof(cbi));
+  cbi.cbSize = sizeof(cbi);
+  // Note: Don't use CB_GETCOMBOBOXINFO since that crashes on WOW64 systems
+  // when you have a global message hook installed.
+  GetComboBoxInfo(hwnd, &cbi);
+  gfx::Rect rect_item(cbi.rcItem);
+  gfx::Rect rect_button(cbi.rcButton);
+  gfx::Size border = gfx::NativeTheme::instance()->GetThemeBorderSize(
+      gfx::NativeTheme::MENULIST);
+
+  // The padding value of '3' is the xy offset from the corner of the control
+  // to the corner of rcItem.  It does not seem to be queryable from the theme.
+  // It is consistent on all versions of Windows from 2K to Vista, and is
+  // invariant with respect to the combobox border size.  We could conceivably
+  // get this number from rect_item.x, but it seems fragile to depend on
+  // position here, inside of the layout code.
+  const int kItemOffset = 3;
+  int item_to_button_distance = std::max(kItemOffset - border.width(), 0);
+
+  // The cx computation can be read as measuring from left to right.
+  int pref_width = std::max(kItemOffset + content_width_ +
+                                kComboboxExtraPaddingX +
+                                item_to_button_distance + rect_button.width() +
+                                 border.width(), kMinComboboxWidth);
+  // The two arguments to ::max below should be typically be equal.
+  int pref_height = std::max(rect_item.height() + 2 * kItemOffset,
+                             rect_button.height() + 2 * border.height());
+  return gfx::Size(pref_width, pref_height);
+}
+
+// VK_ESCAPE should be handled by this view when the drop down list is active.
+// In other words, the list should be closed instead of the dialog.
+bool ComboBox::OverrideAccelerator(const Accelerator& accelerator) {
+  if (accelerator != Accelerator(VK_ESCAPE, false, false, false))
+    return false;
+
+  HWND hwnd = GetNativeControlHWND();
+  if (!hwnd)
+    return false;
+
+  return ::SendMessage(hwnd, CB_GETDROPPEDSTATE, 0, 0) != 0;
+}
+
+HWND ComboBox::CreateNativeControl(HWND parent_container) {
+  HWND r = ::CreateWindowEx(GetAdditionalExStyle(), L"COMBOBOX", L"",
+                            WS_CHILD | WS_VSCROLL | CBS_DROPDOWNLIST,
+                            0, 0, width(), height(),
+                            parent_container, NULL, NULL, NULL);
+  HFONT font = ResourceBundle::GetSharedInstance().
+      GetFont(ResourceBundle::BaseFont).hfont();
+  SendMessage(r, WM_SETFONT, reinterpret_cast<WPARAM>(font), FALSE);
+  UpdateComboBoxFromModel(r);
+  return r;
+}
+
+LRESULT ComboBox::OnCommand(UINT code, int id, HWND source) {
+  HWND hwnd = GetNativeControlHWND();
+  if (!hwnd)
+    return 0;
+
+  if (code == CBN_SELCHANGE && source == hwnd) {
+    LRESULT r = ::SendMessage(hwnd, CB_GETCURSEL, 0, 0);
+    if (r != CB_ERR) {
+      int prev_selected_item = selected_item_;
+      selected_item_ = static_cast<int>(r);
+      if (listener_)
+        listener_->ItemChanged(this, prev_selected_item, selected_item_);
+    }
+  }
+  return 0;
+}
+
+LRESULT ComboBox::OnNotify(int w_param, LPNMHDR l_param) {
+  return 0;
+}
+
+void ComboBox::UpdateComboBoxFromModel(HWND hwnd) {
+  ::SendMessage(hwnd, CB_RESETCONTENT, 0, 0);
+  ChromeFont font = ResourceBundle::GetSharedInstance().GetFont(
+      ResourceBundle::BaseFont);
+  int max_width = 0;
+  int num_items = model_->GetItemCount(this);
+  for (int i = 0; i < num_items; ++i) {
+    const std::wstring& text = model_->GetItemAt(this, i);
+
+    // Inserting the Unicode formatting characters if necessary so that the
+    // text is displayed correctly in right-to-left UIs.
+    std::wstring localized_text;
+    const wchar_t* text_ptr = text.c_str();
+    if (l10n_util::AdjustStringForLocaleDirection(text, &localized_text))
+      text_ptr = localized_text.c_str();
+
+    ::SendMessage(hwnd, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(text_ptr));
+    max_width = std::max(max_width, font.GetStringWidth(text));
+
+  }
+  content_width_ = max_width;
+
+  if (num_items > 0) {
+    ::SendMessage(hwnd, CB_SETCURSEL, selected_item_, 0);
+
+    // Set the width for the drop down while accounting for the scrollbar and
+    // borders.
+    if (num_items > ComboBox_GetMinVisible(hwnd))
+      max_width += ::GetSystemMetrics(SM_CXVSCROLL);
+    // SM_CXEDGE would not be correct here, since the dropdown is flat, not 3D.
+    int kComboboxDropdownBorderSize = 1;
+    max_width += 2 * kComboboxDropdownBorderSize + kComboboxExtraPaddingX;
+    ::SendMessage(hwnd, CB_SETDROPPEDWIDTH, max_width, 0);
+  }
+}
+
+void ComboBox::ModelChanged() {
+  HWND hwnd = GetNativeControlHWND();
+  if (!hwnd)
+    return;
+  selected_item_ = std::min(0, model_->GetItemCount(this));
+  UpdateComboBoxFromModel(hwnd);
+}
+
+void ComboBox::SetSelectedItem(int index) {
+  selected_item_ = index;
+  HWND hwnd = GetNativeControlHWND();
+  if (!hwnd)
+    return;
+
+  // Note that we use CB_SETCURSEL and not CB_SELECTSTRING because on RTL
+  // locales the strings we get from our ComboBox::Model might be augmented
+  // with Unicode directionality marks before we insert them into the combo box
+  // and therefore we can not assume that the string we get from
+  // ComboBox::Model can be safely searched for and selected (which is what
+  // CB_SELECTSTRING does).
+  ::SendMessage(hwnd, CB_SETCURSEL, selected_item_, 0);
+}
+
+int ComboBox::GetSelectedItem() {
+  return selected_item_;
+}
+
+}  // namespace views
diff --git a/views/controls/combo_box.h b/views/controls/combo_box.h
new file mode 100644
index 0000000..3e8eeae
--- /dev/null
+++ b/views/controls/combo_box.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_COMBO_BOX_H_
+#define VIEWS_CONTROLS_COMBO_BOX_H_
+
+#include "views/controls/native_control.h"
+
+namespace views {
+////////////////////////////////////////////////////////////////////////////////
+//
+// ComboBox is a basic non editable combo box. It is initialized from a simple
+// model.
+//
+////////////////////////////////////////////////////////////////////////////////
+class ComboBox : public NativeControl {
+ public:
+  class Model {
+   public:
+    // Return the number of items in the combo box.
+    virtual int GetItemCount(ComboBox* source) = 0;
+
+    // Return the string that should be used to represent a given item.
+    virtual std::wstring GetItemAt(ComboBox* source, int index) = 0;
+  };
+
+  class Listener {
+   public:
+    // This is invoked once the selected item changed.
+    virtual void ItemChanged(ComboBox* combo_box,
+                             int prev_index,
+                             int new_index) = 0;
+  };
+
+  // |model is not owned by the combo box.
+  explicit ComboBox(Model* model);
+  virtual ~ComboBox();
+
+  // Register |listener| for item change events.
+  void SetListener(Listener* listener);
+
+  // Overridden from View.
+  virtual gfx::Size GetPreferredSize();
+  virtual bool OverrideAccelerator(const Accelerator& accelerator);
+
+  // Overridden from NativeControl
+  virtual HWND CreateNativeControl(HWND parent_container);
+  virtual LRESULT OnCommand(UINT code, int id, HWND source);
+  virtual LRESULT OnNotify(int w_param, LPNMHDR l_param);
+
+  // Inform the combo box that its model changed.
+  void ModelChanged();
+
+  // Set / Get the selected item.
+  void SetSelectedItem(int index);
+  int GetSelectedItem();
+
+ private:
+  // Update a combo box from our model.
+  void UpdateComboBoxFromModel(HWND hwnd);
+
+  // Our model.
+  Model* model_;
+
+  // The current selection.
+  int selected_item_;
+
+  // Item change listener.
+  Listener* listener_;
+
+  // The min width, in pixels, for the text content.
+  int content_width_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ComboBox);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_COMBO_BOX_H_
diff --git a/views/controls/hwnd_view.cc b/views/controls/hwnd_view.cc
new file mode 100644
index 0000000..677e60af
--- /dev/null
+++ b/views/controls/hwnd_view.cc
@@ -0,0 +1,137 @@
+// Copyright (c) 2006-2008 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 "views/controls/hwnd_view.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "base/logging.h"
+#include "views/focus/focus_manager.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+static const char kViewClassName[] = "views/HWNDView";
+
+HWNDView::HWNDView() {
+}
+
+HWNDView::~HWNDView() {
+}
+
+void HWNDView::Attach(HWND hwnd) {
+  DCHECK(native_view() == NULL);
+  DCHECK(hwnd) << "Impossible detatched tab case; See crbug.com/6316";
+
+  set_native_view(hwnd);
+
+  // First hide the new window. We don't want anything to draw (like sub-hwnd
+  // borders), when we change the parent below.
+  ShowWindow(hwnd, SW_HIDE);
+
+  // Need to set the HWND's parent before changing its size to avoid flashing.
+  ::SetParent(hwnd, GetWidget()->GetNativeView());
+  Layout();
+
+  // Register with the focus manager so the associated view is focused when the
+  // native control gets the focus.
+  FocusManager::InstallFocusSubclass(
+      hwnd, associated_focus_view() ? associated_focus_view() : this);
+}
+
+void HWNDView::Detach() {
+  DCHECK(native_view());
+  FocusManager::UninstallFocusSubclass(native_view());
+  set_native_view(NULL);
+  set_installed_clip(false);
+}
+
+void HWNDView::Paint(ChromeCanvas* canvas) {
+  // The area behind our window is black, so during a fast resize (where our
+  // content doesn't draw over the full size of our HWND, and the HWND
+  // background color doesn't show up), we need to cover that blackness with
+  // something so that fast resizes don't result in black flash.
+  //
+  // It would be nice if this used some approximation of the page's
+  // current background color.
+  if (installed_clip())
+    canvas->FillRectInt(SkColorSetRGB(255, 255, 255), 0, 0, width(), height());
+}
+
+std::string HWNDView::GetClassName() const {
+  return kViewClassName;
+}
+
+void HWNDView::ViewHierarchyChanged(bool is_add, View *parent, View *child) {
+  if (!native_view())
+    return;
+
+  Widget* widget = GetWidget();
+  if (is_add && widget) {
+    HWND parent_hwnd = ::GetParent(native_view());
+    HWND widget_hwnd = widget->GetNativeView();
+    if (parent_hwnd != widget_hwnd)
+      ::SetParent(native_view(), widget_hwnd);
+    if (IsVisibleInRootView())
+      ::ShowWindow(native_view(), SW_SHOW);
+    else
+      ::ShowWindow(native_view(), SW_HIDE);
+    Layout();
+  } else if (!is_add) {
+    ::ShowWindow(native_view(), SW_HIDE);
+    ::SetParent(native_view(), NULL);
+  }
+}
+
+void HWNDView::Focus() {
+  ::SetFocus(native_view());
+}
+
+void HWNDView::InstallClip(int x, int y, int w, int h) {
+  HRGN clip_region = CreateRectRgn(x, y, x + w, y + h);
+  // NOTE: SetWindowRgn owns the region (as well as the deleting the
+  // current region), as such we don't delete the old region.
+  SetWindowRgn(native_view(), clip_region, FALSE);
+}
+
+void HWNDView::UninstallClip() {
+  SetWindowRgn(native_view(), 0, FALSE);
+}
+
+void HWNDView::ShowWidget(int x, int y, int w, int h) {
+  UINT swp_flags = SWP_DEFERERASE |
+                   SWP_NOACTIVATE |
+                   SWP_NOCOPYBITS |
+                   SWP_NOOWNERZORDER |
+                   SWP_NOZORDER;
+  // Only send the SHOWWINDOW flag if we're invisible, to avoid flashing.
+  if (!::IsWindowVisible(native_view()))
+    swp_flags = (swp_flags | SWP_SHOWWINDOW) & ~SWP_NOREDRAW;
+
+  if (fast_resize()) {
+    // In a fast resize, we move the window and clip it with SetWindowRgn.
+    CRect rect;
+    GetWindowRect(native_view(), &rect);
+    ::SetWindowPos(native_view(), 0, x, y, rect.Width(), rect.Height(),
+                   swp_flags);
+
+    HRGN clip_region = CreateRectRgn(0, 0, w, h);
+    SetWindowRgn(native_view(), clip_region, FALSE);
+    set_installed_clip(true);
+  } else {
+    ::SetWindowPos(native_view(), 0, x, y, w, h, swp_flags);
+  }
+}
+
+void HWNDView::HideWidget() {
+  if (!::IsWindowVisible(native_view()))
+    return;  // Currently not visible, nothing to do.
+
+  // The window is currently visible, but its clipped by another view. Hide
+  // it.
+  ::SetWindowPos(native_view(), 0, 0, 0, 0, 0,
+                 SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER |
+                 SWP_NOREDRAW | SWP_NOOWNERZORDER);
+}
+
+}  // namespace views
diff --git a/views/controls/hwnd_view.h b/views/controls/hwnd_view.h
new file mode 100644
index 0000000..a8d52b3
--- /dev/null
+++ b/views/controls/hwnd_view.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_HWND_VIEW_H_
+#define VIEWS_CONTROLS_HWND_VIEW_H_
+
+#include <string>
+
+#include "views/controls/native_view_host.h"
+
+namespace views {
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// HWNDView class
+//
+//   The HWNDView class hosts a native window handle (HWND) sizing it
+//   according to the bounds of the view. This is useful whenever you need to
+//   show a UI control that has a HWND (e.g. a native windows Edit control)
+//   within thew View hierarchy and benefit from the sizing/layout.
+//
+/////////////////////////////////////////////////////////////////////////////
+// TODO: Rename this to NativeViewHostWin.
+class HWNDView : public NativeViewHost {
+ public:
+  HWNDView();
+  virtual ~HWNDView();
+
+  // Attach a window handle to this View, making the window it represents
+  // subject to sizing according to this View's parent container's Layout
+  // Manager's sizing heuristics.
+  //
+  // This object should be added to the view hierarchy before calling this
+  // function, which will expect the parent to be valid.
+  void Attach(HWND hwnd);
+
+  // Detach the attached window handle. It will no longer be updated
+  void Detach();
+
+  // TODO(sky): convert this to native_view().
+  HWND GetHWND() const { return native_view(); }
+
+  virtual void Paint(ChromeCanvas* canvas);
+
+  // Overridden from View.
+  virtual std::string GetClassName() const;
+
+ protected:
+  virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
+
+  virtual void Focus();
+
+  // NativeHostView overrides.
+  virtual void InstallClip(int x, int y, int w, int h);
+  virtual void UninstallClip();
+  virtual void ShowWidget(int x, int y, int w, int h);
+  virtual void HideWidget();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HWNDView);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_HWND_VIEW_H_
diff --git a/views/controls/image_view.cc b/views/controls/image_view.cc
new file mode 100644
index 0000000..8f587440
--- /dev/null
+++ b/views/controls/image_view.cc
@@ -0,0 +1,170 @@
+// Copyright (c) 2006-2008 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 "views/controls/image_view.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "base/logging.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;
+  SchedulePaint();
+}
+
+void ImageView::SetImage(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;
+}
+
+bool ImageView::GetImageSize(gfx::Size* image_size) {
+  DCHECK(image_size);
+  if (image_size_set_)
+    *image_size = image_size_;
+  return image_size_set_;
+}
+
+void ImageView::ResetImageSize() {
+  image_size_set_ = false;
+}
+
+gfx::Size ImageView::GetPreferredSize() {
+  if (image_size_set_) {
+    gfx::Size image_size;
+    GetImageSize(&image_size);
+    return image_size;
+  }
+  return gfx::Size(image_.width(), image_.height());
+}
+
+void ImageView::ComputeImageOrigin(int image_width, int image_height,
+                                   int *x, int *y) {
+  // 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 (UILayoutIsRightToLeft()) {
+    if (horiz_alignment_ == TRAILING)
+      actual_horiz_alignment = LEADING;
+    if (horiz_alignment_ == LEADING)
+      actual_horiz_alignment = TRAILING;
+  }
+
+  switch(actual_horiz_alignment) {
+    case LEADING:
+      *x = 0;
+      break;
+    case TRAILING:
+      *x = width() - image_width;
+      break;
+    case CENTER:
+      *x = (width() - image_width) / 2;
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  switch (vert_alignment_) {
+    case LEADING:
+      *y = 0;
+      break;
+    case TRAILING:
+      *y = height() - image_height;
+      break;
+    case CENTER:
+      *y = (height() - image_height) / 2;
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void ImageView::Paint(ChromeCanvas* canvas) {
+  View::Paint(canvas);
+  int image_width = image_.width();
+  int image_height = image_.height();
+
+  if (image_width == 0 || image_height == 0)
+    return;
+
+  int x, y;
+  if (image_size_set_ &&
+      (image_size_.width() != image_width ||
+       image_size_.width() != image_height)) {
+    // Resize case
+    image_.buildMipMap(false);
+    ComputeImageOrigin(image_size_.width(), image_size_.height(), &x, &y);
+    canvas->DrawBitmapInt(image_, 0, 0, image_width, image_height,
+                          x, y, image_size_.width(), image_size_.height(),
+                          true);
+  } else {
+    ComputeImageOrigin(image_width, image_height, &x, &y);
+    canvas->DrawBitmapInt(image_, x, y);
+  }
+}
+
+void ImageView::SetHorizontalAlignment(Alignment ha) {
+  if (ha != horiz_alignment_) {
+    horiz_alignment_ = ha;
+    SchedulePaint();
+  }
+}
+
+ImageView::Alignment ImageView::GetHorizontalAlignment() {
+  return horiz_alignment_;
+}
+
+void ImageView::SetVerticalAlignment(Alignment va) {
+  if (va != vert_alignment_) {
+    vert_alignment_ = va;
+    SchedulePaint();
+  }
+}
+
+ImageView::Alignment ImageView::GetVerticalAlignment() {
+  return vert_alignment_;
+}
+
+void ImageView::SetTooltipText(const std::wstring& tooltip) {
+  tooltip_text_ = tooltip;
+}
+
+std::wstring ImageView::GetTooltipText() {
+  return tooltip_text_;
+}
+
+bool ImageView::GetTooltipText(int x, int y, std::wstring* tooltip) {
+  if (tooltip_text_.empty()) {
+    return false;
+  } else {
+    * tooltip =  GetTooltipText();
+    return true;
+  }
+}
+
+}  // namespace views
diff --git a/views/controls/image_view.h b/views/controls/image_view.h
new file mode 100644
index 0000000..b7ac792
--- /dev/null
+++ b/views/controls/image_view.h
@@ -0,0 +1,107 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_IMAGE_VIEW_H_
+#define VIEWS_CONTROLS_IMAGE_VIEW_H_
+
+#include "skia/include/SkBitmap.h"
+#include "views/view.h"
+
+class ChromeCanvas;
+
+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 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(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);
+
+  // Reset the image size to the current image dimensions.
+  void ResetImageSize();
+
+  // Set / Get the horizontal alignment.
+  void SetHorizontalAlignment(Alignment ha);
+  Alignment GetHorizontalAlignment();
+
+  // Set / Get the vertical alignment.
+  void SetVerticalAlignment(Alignment va);
+  Alignment GetVerticalAlignment();
+
+  // Set / Get the tooltip text.
+  void SetTooltipText(const std::wstring& tooltip);
+  std::wstring GetTooltipText();
+
+  // Return whether the image should be centered inside the view.
+  // Overriden from View
+  virtual gfx::Size GetPreferredSize();
+  virtual void Paint(ChromeCanvas* canvas);
+
+  // Overriden from View.
+  virtual bool GetTooltipText(int x, int y, std::wstring* tooltip);
+
+ private:
+  // Compute the image origin given the desired size and the receiver alignment
+  // properties.
+  void ComputeImageOrigin(int image_width, int image_height, int *x, int *y);
+
+  // 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.
+  std::wstring tooltip_text_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ImageView);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_IMAGE_VIEW_H_
diff --git a/views/controls/label.cc b/views/controls/label.cc
new file mode 100644
index 0000000..1dc0b54
--- /dev/null
+++ b/views/controls/label.cc
@@ -0,0 +1,444 @@
+// Copyright (c) 2006-2008 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 "views/controls/label.h"
+
+#include <math.h>
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/gfx/chrome_font.h"
+#include "app/gfx/insets.h"
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "chrome/common/gfx/text_elider.h"
+#include "views/background.h"
+
+namespace views {
+
+const char Label::kViewClassName[] = "views/Label";
+
+static const SkColor kEnabledColor = SK_ColorBLACK;
+static const SkColor kDisabledColor = SkColorSetRGB(161, 161, 146);
+static const int kFocusBorderPadding = 1;
+
+Label::Label() {
+  Init(L"", GetDefaultFont());
+}
+
+Label::Label(const std::wstring& text) {
+  Init(text, GetDefaultFont());
+}
+
+Label::Label(const std::wstring& text, const ChromeFont& font) {
+  Init(text, font);
+}
+
+void Label::Init(const std::wstring& text, const ChromeFont& font) {
+  contains_mouse_ = false;
+  font_ = font;
+  text_size_valid_ = false;
+  SetText(text);
+  url_set_ = false;
+  color_ = kEnabledColor;
+  horiz_alignment_ = ALIGN_CENTER;
+  is_multi_line_ = false;
+  allow_character_break_ = false;
+  collapse_when_hidden_ = false;
+  rtl_alignment_mode_ = USE_UI_ALIGNMENT;
+  paint_as_focused_ = false;
+  has_focus_border_ = false;
+}
+
+Label::~Label() {
+}
+
+gfx::Size Label::GetPreferredSize() {
+  gfx::Size prefsize;
+
+  // Return a size of (0, 0) if the label is not visible and if the
+  // collapse_when_hidden_ flag is set.
+  // TODO(munjal): This logic probably belongs to the View class. But for now,
+  // put it here since putting it in View class means all inheriting classes
+  // need ot respect the collapse_when_hidden_ flag.
+  if (!IsVisible() && collapse_when_hidden_)
+    return prefsize;
+
+  if (is_multi_line_) {
+    int w = width(), h = 0;
+    ChromeCanvas::SizeStringInt(text_, font_, &w, &h, ComputeMultiLineFlags());
+    prefsize.SetSize(w, h);
+  } else {
+    prefsize = GetTextSize();
+  }
+
+  gfx::Insets insets = GetInsets();
+  prefsize.Enlarge(insets.width(), insets.height());
+  return prefsize;
+}
+
+int Label::ComputeMultiLineFlags() {
+  int flags = ChromeCanvas::MULTI_LINE;
+  if (allow_character_break_)
+    flags |= ChromeCanvas::CHARACTER_BREAK;
+  switch (horiz_alignment_) {
+    case ALIGN_LEFT:
+      flags |= ChromeCanvas::TEXT_ALIGN_LEFT;
+      break;
+    case ALIGN_CENTER:
+      flags |= ChromeCanvas::TEXT_ALIGN_CENTER;
+      break;
+    case ALIGN_RIGHT:
+      flags |= ChromeCanvas::TEXT_ALIGN_RIGHT;
+      break;
+  }
+  return flags;
+}
+
+void Label::CalculateDrawStringParams(
+    std::wstring* paint_text, gfx::Rect* text_bounds, int* flags) {
+  DCHECK(paint_text && text_bounds && flags);
+
+  if (url_set_) {
+    // TODO(jungshik) : Figure out how to get 'intl.accept_languages'
+    // preference and use it when calling ElideUrl.
+    *paint_text = gfx::ElideUrl(url_, font_, width(), std::wstring());
+
+    // An URLs is always treated as an LTR text and therefore we should
+    // explicitly mark it as such if the locale is RTL so that URLs containing
+    // Hebrew or Arabic characters are displayed correctly.
+    //
+    // Note that we don't check the View's UI layout setting in order to
+    // determine whether or not to insert the special Unicode formatting
+    // characters. We use the locale settings because an URL is always treated
+    // as an LTR string, even if its containing view does not use an RTL UI
+    // layout.
+    if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
+      l10n_util::WrapStringWithLTRFormatting(paint_text);
+  } else {
+    *paint_text = text_;
+  }
+
+  if (is_multi_line_) {
+    gfx::Insets insets = GetInsets();
+    text_bounds->SetRect(insets.left(),
+                         insets.top(),
+                         width() - insets.width(),
+                         height() - insets.height());
+    *flags = ComputeMultiLineFlags();
+  } else {
+    *text_bounds = GetTextBounds();
+    *flags = 0;
+  }
+}
+
+void Label::Paint(ChromeCanvas* canvas) {
+  PaintBackground(canvas);
+  std::wstring paint_text;
+  gfx::Rect text_bounds;
+  int flags = 0;
+  CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
+  canvas->DrawStringInt(paint_text,
+                        font_,
+                        color_,
+                        text_bounds.x(),
+                        text_bounds.y(),
+                        text_bounds.width(),
+                        text_bounds.height(),
+                        flags);
+
+  // The focus border always hugs the text, regardless of the label's bounds.
+  if (HasFocus() || paint_as_focused_) {
+    int w = text_bounds.width();
+    int h = 0;
+    // We explicitly OR in MULTI_LINE here since SizeStringInt seems to return
+    // an incorrect height for single line text when the MULTI_LINE flag isn't
+    // specified. o_O...
+    ChromeCanvas::SizeStringInt(paint_text, font_, &w, &h,
+                                flags | ChromeCanvas::MULTI_LINE);
+    gfx::Rect focus_rect = text_bounds;
+    focus_rect.set_width(w);
+    focus_rect.set_height(h);
+    focus_rect.Inset(-kFocusBorderPadding, -kFocusBorderPadding);
+    canvas->DrawFocusRect(MirroredLeftPointForRect(focus_rect), focus_rect.y(),
+                          focus_rect.width(), focus_rect.height());
+  }
+}
+
+void Label::PaintBackground(ChromeCanvas* canvas) {
+  const Background* bg = contains_mouse_ ? GetMouseOverBackground() : NULL;
+  if (!bg)
+    bg = background();
+  if (bg)
+    bg->Paint(canvas, this);
+}
+
+void Label::SetFont(const ChromeFont& font) {
+  font_ = font;
+  text_size_valid_ = false;
+  SchedulePaint();
+}
+
+ChromeFont Label::GetFont() const {
+  return font_;
+}
+
+void Label::SetText(const std::wstring& text) {
+  text_ = text;
+  url_set_ = false;
+  text_size_valid_ = false;
+  SchedulePaint();
+}
+
+void Label::SetURL(const GURL& url) {
+  url_ = url;
+  text_ = UTF8ToWide(url_.spec());
+  url_set_ = true;
+  text_size_valid_ = false;
+  SchedulePaint();
+}
+
+const std::wstring Label::GetText() const {
+  if (url_set_)
+    return UTF8ToWide(url_.spec());
+  else
+    return text_;
+}
+
+const GURL Label::GetURL() const {
+  if (url_set_)
+    return url_;
+  else
+    return GURL(WideToUTF8(text_));
+}
+
+gfx::Size Label::GetTextSize() {
+  if (!text_size_valid_) {
+    text_size_.SetSize(font_.GetStringWidth(text_), font_.height());
+    text_size_valid_ = true;
+  }
+
+  if (text_size_valid_)
+    return text_size_;
+  return gfx::Size();
+}
+
+int Label::GetHeightForWidth(int w) {
+  if (is_multi_line_) {
+    gfx::Insets insets = GetInsets();
+    w = std::max<int>(0, w - insets.width());
+    int h = 0;
+    ChromeCanvas cc(0, 0, true);
+    cc.SizeStringInt(text_, font_, &w, &h, ComputeMultiLineFlags());
+    return h + insets.height();
+  }
+
+  return View::GetHeightForWidth(w);
+}
+
+std::string Label::GetClassName() const {
+  return kViewClassName;
+}
+
+void Label::SetColor(const SkColor& color) {
+  color_ = color;
+}
+
+const SkColor Label::GetColor() const {
+  return color_;
+}
+
+void Label::SetHorizontalAlignment(Alignment a) {
+  // If the View's UI layout is right-to-left and rtl_alignment_mode_ is
+  // USE_UI_ALIGNMENT, we need to flip the alignment so that the alignment
+  // settings take into account the text directionality.
+  if (UILayoutIsRightToLeft() && rtl_alignment_mode_ == USE_UI_ALIGNMENT) {
+    if (a == ALIGN_LEFT)
+      a = ALIGN_RIGHT;
+    else if (a == ALIGN_RIGHT)
+      a = ALIGN_LEFT;
+  }
+  if (horiz_alignment_ != a) {
+    horiz_alignment_ = a;
+    SchedulePaint();
+  }
+}
+
+Label::Alignment Label::GetHorizontalAlignment() const {
+  return horiz_alignment_;
+}
+
+void Label::SetRTLAlignmentMode(RTLAlignmentMode mode) {
+  rtl_alignment_mode_ = mode;
+}
+
+Label::RTLAlignmentMode Label::GetRTLAlignmentMode() const {
+  return rtl_alignment_mode_;
+}
+
+void Label::SetMultiLine(bool f) {
+  if (f != is_multi_line_) {
+    is_multi_line_ = f;
+    SchedulePaint();
+  }
+}
+
+void Label::SetAllowCharacterBreak(bool f) {
+  if (f != allow_character_break_) {
+    allow_character_break_ = f;
+    SchedulePaint();
+  }
+}
+
+bool Label::IsMultiLine() {
+  return is_multi_line_;
+}
+
+void Label::SetTooltipText(const std::wstring& tooltip_text) {
+  tooltip_text_ = tooltip_text;
+}
+
+bool Label::GetTooltipText(int x, int y, std::wstring* tooltip) {
+  DCHECK(tooltip);
+
+  // If a tooltip has been explicitly set, use it.
+  if (!tooltip_text_.empty()) {
+    tooltip->assign(tooltip_text_);
+    return true;
+  }
+
+  // Show the full text if the text does not fit.
+  if (!is_multi_line_ && font_.GetStringWidth(text_) > width()) {
+    *tooltip = text_;
+    return true;
+  }
+  return false;
+}
+
+void Label::OnMouseMoved(const MouseEvent& e) {
+  UpdateContainsMouse(e);
+}
+
+void Label::OnMouseEntered(const MouseEvent& event) {
+  UpdateContainsMouse(event);
+}
+
+void Label::OnMouseExited(const MouseEvent& event) {
+  SetContainsMouse(false);
+}
+
+void Label::SetMouseOverBackground(Background* background) {
+  mouse_over_background_.reset(background);
+}
+
+const Background* Label::GetMouseOverBackground() const {
+  return mouse_over_background_.get();
+}
+
+void Label::SetEnabled(bool enabled) {
+  if (enabled == enabled_)
+    return;
+  View::SetEnabled(enabled);
+  SetColor(enabled ? kEnabledColor : kDisabledColor);
+}
+
+gfx::Insets Label::GetInsets() const {
+  gfx::Insets insets = View::GetInsets();
+  if (IsFocusable() || has_focus_border_)  {
+    insets += gfx::Insets(kFocusBorderPadding, kFocusBorderPadding,
+                          kFocusBorderPadding, kFocusBorderPadding);
+  }
+  return insets;
+}
+
+// static
+ChromeFont Label::GetDefaultFont() {
+  return ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
+}
+
+void Label::UpdateContainsMouse(const MouseEvent& event) {
+  SetContainsMouse(GetTextBounds().Contains(event.x(), event.y()));
+}
+
+void Label::SetContainsMouse(bool contains_mouse) {
+  if (contains_mouse_ == contains_mouse)
+    return;
+  contains_mouse_ = contains_mouse;
+  if (GetMouseOverBackground())
+    SchedulePaint();
+}
+
+gfx::Rect Label::GetTextBounds() {
+  gfx::Size text_size = GetTextSize();
+  gfx::Insets insets = GetInsets();
+  int avail_width = width() - insets.width();
+  // Respect the size set by the owner view
+  text_size.set_width(std::min(avail_width, text_size.width()));
+
+  int text_y = insets.top() +
+      (height() - text_size.height() - insets.height()) / 2;
+  int text_x;
+  switch (horiz_alignment_) {
+    case ALIGN_LEFT:
+      text_x = insets.left();
+      break;
+    case ALIGN_CENTER:
+      // We put any extra margin pixel on the left rather than the right, since
+      // GetTextExtentPoint32() can report a value one too large on the right.
+      text_x = insets.left() + (avail_width + 1 - text_size.width()) / 2;
+      break;
+    case ALIGN_RIGHT:
+      text_x = width() - insets.right() - text_size.width();
+      break;
+    default:
+      NOTREACHED();
+      text_x = 0;
+      break;
+  }
+  return gfx::Rect(text_x, text_y, text_size.width(), text_size.height());
+}
+
+void Label::SizeToFit(int max_width) {
+  DCHECK(is_multi_line_);
+
+  std::vector<std::wstring> lines;
+  SplitString(text_, L'\n', &lines);
+
+  int label_width = 0;
+  for (std::vector<std::wstring>::const_iterator iter = lines.begin();
+       iter != lines.end(); ++iter) {
+    label_width = std::max(label_width, font_.GetStringWidth(*iter));
+  }
+
+  gfx::Insets insets = GetInsets();
+  label_width += insets.width();
+
+  if (max_width > 0)
+    label_width = std::min(label_width, max_width);
+
+  SetBounds(x(), y(), label_width, 0);
+  SizeToPreferredSize();
+}
+
+bool Label::GetAccessibleRole(AccessibilityTypes::Role* role) {
+  DCHECK(role);
+
+  *role = AccessibilityTypes::ROLE_TEXT;
+  return true;
+}
+
+bool Label::GetAccessibleName(std::wstring* name) {
+  *name = GetText();
+  return true;
+}
+
+bool Label::GetAccessibleState(AccessibilityTypes::State* state) {
+  DCHECK(state);
+
+  *state = AccessibilityTypes::STATE_READONLY;
+  return true;
+}
+
+}  // namespace views
diff --git a/views/controls/label.h b/views/controls/label.h
new file mode 100644
index 0000000..fa620e42
--- /dev/null
+++ b/views/controls/label.h
@@ -0,0 +1,250 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_LABEL_H_
+#define VIEWS_CONTROLS_LABEL_H_
+
+#include "app/gfx/chrome_font.h"
+#include "googleurl/src/gurl.h"
+#include "skia/include/SkColor.h"
+#include "testing/gtest/include/gtest/gtest_prod.h"
+#include "views/view.h"
+
+namespace views {
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Label class
+//
+// A label is a view subclass that can display a string.
+//
+/////////////////////////////////////////////////////////////////////////////
+class Label : public View {
+ public:
+  enum Alignment { ALIGN_LEFT = 0,
+                   ALIGN_CENTER,
+                   ALIGN_RIGHT };
+
+  // The following enum is used to indicate whether using the Chrome UI's
+  // alignment as the label's alignment, or autodetecting the label's
+  // alignment.
+  //
+  // If the label text originates from the Chrome UI, we should use the Chrome
+  // UI's alignment as the label's alignment.
+  //
+  // If the text originates from a web page, the text's alignment is determined
+  // based on the first character with strong directionality, disregarding what
+  // directionality the Chrome UI is. And its alignment will not be flipped
+  // around in RTL locales.
+  enum RTLAlignmentMode {
+    USE_UI_ALIGNMENT = 0,
+    AUTO_DETECT_ALIGNMENT
+  };
+
+  // The view class name.
+  static const char kViewClassName[];
+
+  // Create a new label with a default font and empty value
+  Label();
+
+  // Create a new label with a default font
+  explicit Label(const std::wstring& text);
+
+  Label(const std::wstring& text, const ChromeFont& font);
+
+  virtual ~Label();
+
+  // Overridden to compute the size required to display this label
+  virtual gfx::Size GetPreferredSize();
+
+  // Return the height necessary to display this label with the provided width.
+  // This method is used to layout multi-line labels. It is equivalent to
+  // GetPreferredSize().height() if the receiver is not multi-line
+  virtual int GetHeightForWidth(int w);
+
+  // Returns views/Label.
+  virtual std::string GetClassName() const;
+
+  // Overridden to paint
+  virtual void Paint(ChromeCanvas* canvas);
+
+  // If the mouse is over the label, and a mouse over background has been
+  // specified, its used. Otherwise super's implementation is invoked
+  virtual void PaintBackground(ChromeCanvas* canvas);
+
+  // Set the font.
+  void SetFont(const ChromeFont& font);
+
+  // Return the font used by this label
+  ChromeFont GetFont() const;
+
+  // Set the label text.
+  void SetText(const std::wstring& text);
+
+  // Return the label text.
+  const std::wstring GetText() const;
+
+  // Set URL Value - text_ is set to spec().
+  void SetURL(const GURL& url);
+
+  // Return the label URL.
+  const GURL GetURL() const;
+
+  // Set the color
+  virtual void SetColor(const SkColor& color);
+
+  // Return a reference to the currently used color
+  virtual const SkColor GetColor() const;
+
+  // Set horizontal alignment. If the locale is RTL, and the RTL alignment
+  // setting is set as USE_UI_ALIGNMENT, the alignment is flipped around.
+  //
+  // Caveat: for labels originating from a web page, the RTL alignment mode
+  // should be reset to AUTO_DETECT_ALIGNMENT before the horizontal alignment
+  // is set. Otherwise, the label's alignment specified as a parameter will be
+  // flipped in RTL locales. Please see the comments in SetRTLAlignmentMode for
+  // more information.
+  void SetHorizontalAlignment(Alignment a);
+
+  Alignment GetHorizontalAlignment() const;
+
+  // Set the RTL alignment mode. The RTL alignment mode is initialized to
+  // USE_UI_ALIGNMENT when the label is constructed. USE_UI_ALIGNMENT applies
+  // to every label that originates from the Chrome UI. However, if the label
+  // originates from a web page, its alignment should not be flipped around for
+  // RTL locales. For such labels, we need to set the RTL alignment mode to
+  // AUTO_DETECT_ALIGNMENT so that subsequent SetHorizontalAlignment() calls
+  // will not flip the label's alignment around.
+  void SetRTLAlignmentMode(RTLAlignmentMode mode);
+
+  RTLAlignmentMode GetRTLAlignmentMode() const;
+
+  // Set whether the label text can wrap on multiple lines.
+  // Default is false.
+  void SetMultiLine(bool f);
+
+  // Set whether the label text can be split on words.
+  // Default is false. This only works when is_multi_line is true.
+  void SetAllowCharacterBreak(bool f);
+
+  // Return whether the label text can wrap on multiple lines
+  bool IsMultiLine();
+
+  // Sets the tooltip text.  Default behavior for a label (single-line) is to
+  // show the full text if it is wider than its bounds.  Calling this overrides
+  // the default behavior and lets you set a custom tooltip.  To revert to
+  // default behavior, call this with an empty string.
+  void SetTooltipText(const std::wstring& tooltip_text);
+
+  // Gets the tooltip text for labels that are wider than their bounds, except
+  // when the label is multiline, in which case it just returns false (no
+  // tooltip).  If a custom tooltip has been specified with SetTooltipText()
+  // it is returned instead.
+  virtual bool GetTooltipText(int x, int y, std::wstring* tooltip);
+
+  // Mouse enter/exit are overridden to render mouse over background color.
+  // These invoke SetContainsMouse as necessary.
+  virtual void OnMouseMoved(const MouseEvent& e);
+  virtual void OnMouseEntered(const MouseEvent& event);
+  virtual void OnMouseExited(const MouseEvent& event);
+
+  // The background color to use when the mouse is over the label. Label
+  // takes ownership of the Background.
+  void SetMouseOverBackground(Background* background);
+  const Background* GetMouseOverBackground() const;
+
+  // Sets the enabled state. Setting the enabled state resets the color.
+  virtual void SetEnabled(bool enabled);
+
+  // Overridden from View:
+  virtual gfx::Insets GetInsets() const;
+
+  // Resizes the label so its width is set to the width of the longest line and
+  // its height deduced accordingly.
+  // This is only intended for multi-line labels and is useful when the label's
+  // text contains several lines separated with \n.
+  // |max_width| is the maximum width that will be used (longer lines will be
+  // wrapped).  If 0, no maximum width is enforced.
+  void SizeToFit(int max_width);
+
+  // Accessibility accessors, overridden from View.
+  virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+  virtual bool GetAccessibleName(std::wstring* name);
+  virtual bool GetAccessibleState(AccessibilityTypes::State* state);
+
+  // Gets/sets the flag to determine whether the label should be collapsed when
+  // it's hidden (not visible). If this flag is true, the label will return a
+  // preferred size of (0, 0) when it's not visible.
+  void set_collapse_when_hidden(bool value) { collapse_when_hidden_ = value; }
+  bool collapse_when_hidden() const { return collapse_when_hidden_; }
+
+  void set_paint_as_focused(bool paint_as_focused) {
+    paint_as_focused_ = paint_as_focused;
+  }
+  void set_has_focus_border(bool has_focus_border) {
+    has_focus_border_ = has_focus_border;
+  }
+
+ private:
+  // These tests call CalculateDrawStringParams in order to verify the
+  // calculations done for drawing text.
+  FRIEND_TEST(LabelTest, DrawSingleLineString);
+  FRIEND_TEST(LabelTest, DrawMultiLineString);
+
+  static ChromeFont GetDefaultFont();
+
+  // Returns parameters to be used for the DrawString call.
+  void CalculateDrawStringParams(std::wstring* paint_text,
+                                 gfx::Rect* text_bounds,
+                                 int* flags);
+
+  // If the mouse is over the text, SetContainsMouse(true) is invoked, otherwise
+  // SetContainsMouse(false) is invoked.
+  void UpdateContainsMouse(const MouseEvent& event);
+
+  // Updates whether the mouse is contained in the Label. If the new value
+  // differs from the current value, and a mouse over background is specified,
+  // SchedulePaint is invoked.
+  void SetContainsMouse(bool contains_mouse);
+
+  // Returns where the text is drawn, in the receivers coordinate system.
+  gfx::Rect GetTextBounds();
+
+  int ComputeMultiLineFlags();
+  gfx::Size GetTextSize();
+  void Init(const std::wstring& text, const ChromeFont& font);
+  std::wstring text_;
+  GURL url_;
+  ChromeFont font_;
+  SkColor color_;
+  gfx::Size text_size_;
+  bool text_size_valid_;
+  bool is_multi_line_;
+  bool allow_character_break_;
+  bool url_set_;
+  Alignment horiz_alignment_;
+  std::wstring tooltip_text_;
+  // Whether the mouse is over this label.
+  bool contains_mouse_;
+  scoped_ptr<Background> mouse_over_background_;
+  // Whether to collapse the label when it's not visible.
+  bool collapse_when_hidden_;
+  // The following member variable is used to control whether the alignment
+  // needs to be flipped around for RTL locales. Please refer to the definition
+  // of RTLAlignmentMode for more information.
+  RTLAlignmentMode rtl_alignment_mode_;
+  // When embedded in a larger control that is focusable, setting this flag
+  // allows this view to be painted as focused even when it is itself not.
+  bool paint_as_focused_;
+  // When embedded in a larger control that is focusable, setting this flag
+  // allows this view to reserve space for a focus border that it otherwise
+  // might not have because it is not itself focusable.
+  bool has_focus_border_;
+
+  DISALLOW_COPY_AND_ASSIGN(Label);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_LABEL_H_
diff --git a/views/controls/label_unittest.cc b/views/controls/label_unittest.cc
new file mode 100644
index 0000000..1ac74b1
--- /dev/null
+++ b/views/controls/label_unittest.cc
@@ -0,0 +1,441 @@
+// Copyright (c) 2006-2008 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 "app/gfx/chrome_canvas.h"
+#include "app/l10n_util.h"
+#include "base/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "views/border.h"
+#include "views/controls/label.h"
+
+namespace views {
+
+// All text sizing measurements (width and height) should be greater than this.
+const int kMinTextDimension = 4;
+
+TEST(LabelTest, FontProperty) {
+  Label label;
+  std::wstring font_name(L"courier");
+  ChromeFont font = ChromeFont::CreateFont(font_name, 30);
+  label.SetFont(font);
+  ChromeFont font_used = label.GetFont();
+  EXPECT_STREQ(font_name.c_str(), font_used.FontName().c_str());
+  EXPECT_EQ(30, font_used.FontSize());
+}
+
+TEST(LabelTest, TextProperty) {
+  Label label;
+  std::wstring test_text(L"A random string.");
+  label.SetText(test_text);
+  EXPECT_STREQ(test_text.c_str(), label.GetText().c_str());
+}
+
+TEST(LabelTest, UrlProperty) {
+  Label label;
+  std::string my_url("http://www.orkut.com/some/Random/path");
+  GURL url(my_url);
+  label.SetURL(url);
+  EXPECT_STREQ(my_url.c_str(), label.GetURL().spec().c_str());
+  EXPECT_STREQ(UTF8ToWide(my_url).c_str(), label.GetText().c_str());
+}
+
+TEST(LabelTest, ColorProperty) {
+  Label label;
+  SkColor color = SkColorSetARGB(20, 40, 10, 5);
+  label.SetColor(color);
+  EXPECT_EQ(color, label.GetColor());
+}
+
+TEST(LabelTest, AlignmentProperty) {
+  Label label;
+  bool reverse_alignment =
+      l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT;
+
+  label.SetHorizontalAlignment(Label::ALIGN_RIGHT);
+  EXPECT_EQ(
+      reverse_alignment ? Label::ALIGN_LEFT : Label::ALIGN_RIGHT,
+      label.GetHorizontalAlignment());
+  label.SetHorizontalAlignment(Label::ALIGN_LEFT);
+  EXPECT_EQ(
+      reverse_alignment ? Label::ALIGN_RIGHT : Label::ALIGN_LEFT,
+      label.GetHorizontalAlignment());
+  label.SetHorizontalAlignment(Label::ALIGN_CENTER);
+  EXPECT_EQ(Label::ALIGN_CENTER, label.GetHorizontalAlignment());
+
+  // The label's alignment should not be flipped if the RTL alignment mode
+  // is AUTO_DETECT_ALIGNMENT.
+  label.SetRTLAlignmentMode(Label::AUTO_DETECT_ALIGNMENT);
+  label.SetHorizontalAlignment(Label::ALIGN_RIGHT);
+  EXPECT_EQ(Label::ALIGN_RIGHT, label.GetHorizontalAlignment());
+  label.SetHorizontalAlignment(Label::ALIGN_LEFT);
+  EXPECT_EQ(Label::ALIGN_LEFT, label.GetHorizontalAlignment());
+  label.SetHorizontalAlignment(Label::ALIGN_CENTER);
+  EXPECT_EQ(Label::ALIGN_CENTER, label.GetHorizontalAlignment());
+}
+
+TEST(LabelTest, RTLAlignmentModeProperty) {
+  Label label;
+  EXPECT_EQ(Label::USE_UI_ALIGNMENT, label.GetRTLAlignmentMode());
+
+  label.SetRTLAlignmentMode(Label::AUTO_DETECT_ALIGNMENT);
+  EXPECT_EQ(Label::AUTO_DETECT_ALIGNMENT, label.GetRTLAlignmentMode());
+
+  label.SetRTLAlignmentMode(Label::USE_UI_ALIGNMENT);
+  EXPECT_EQ(Label::USE_UI_ALIGNMENT, label.GetRTLAlignmentMode());
+}
+
+TEST(LabelTest, MultiLineProperty) {
+  Label label;
+  EXPECT_FALSE(label.IsMultiLine());
+  label.SetMultiLine(true);
+  EXPECT_TRUE(label.IsMultiLine());
+  label.SetMultiLine(false);
+  EXPECT_FALSE(label.IsMultiLine());
+}
+
+TEST(LabelTest, TooltipProperty) {
+  Label label;
+  std::wstring test_text(L"My cool string.");
+  label.SetText(test_text);
+
+  std::wstring tooltip;
+  EXPECT_TRUE(label.GetTooltipText(0, 0, &tooltip));
+  EXPECT_STREQ(test_text.c_str(), tooltip.c_str());
+
+  std::wstring tooltip_text(L"The tooltip!");
+  label.SetTooltipText(tooltip_text);
+  EXPECT_TRUE(label.GetTooltipText(0, 0, &tooltip));
+  EXPECT_STREQ(tooltip_text.c_str(), tooltip.c_str());
+
+  std::wstring empty_text;
+  label.SetTooltipText(empty_text);
+  EXPECT_TRUE(label.GetTooltipText(0, 0, &tooltip));
+  EXPECT_STREQ(test_text.c_str(), tooltip.c_str());
+
+  // Make the label big enough to hold the text
+  // and expect there to be no tooltip.
+  label.SetBounds(0, 0, 1000, 40);
+  EXPECT_FALSE(label.GetTooltipText(0, 0, &tooltip));
+
+  // Verify that setting the tooltip still shows it.
+  label.SetTooltipText(tooltip_text);
+  EXPECT_TRUE(label.GetTooltipText(0, 0, &tooltip));
+  EXPECT_STREQ(tooltip_text.c_str(), tooltip.c_str());
+  // Clear out the tooltip.
+  label.SetTooltipText(empty_text);
+
+  // Shrink the bounds and the tooltip should come back.
+  label.SetBounds(0, 0, 1, 1);
+  EXPECT_TRUE(label.GetTooltipText(0, 0, &tooltip));
+
+  // Make the label multiline and there is no tooltip again.
+  label.SetMultiLine(true);
+  EXPECT_FALSE(label.GetTooltipText(0, 0, &tooltip));
+
+  // Verify that setting the tooltip still shows it.
+  label.SetTooltipText(tooltip_text);
+  EXPECT_TRUE(label.GetTooltipText(0, 0, &tooltip));
+  EXPECT_STREQ(tooltip_text.c_str(), tooltip.c_str());
+  // Clear out the tooltip.
+  label.SetTooltipText(empty_text);
+}
+
+TEST(LabelTest, Accessibility) {
+  Label label;
+  std::wstring test_text(L"My special text.");
+  label.SetText(test_text);
+
+  AccessibilityTypes::Role role;
+  EXPECT_TRUE(label.GetAccessibleRole(&role));
+  EXPECT_EQ(AccessibilityTypes::ROLE_TEXT, role);
+
+  std::wstring name;
+  EXPECT_TRUE(label.GetAccessibleName(&name));
+  EXPECT_STREQ(test_text.c_str(), name.c_str());
+
+  AccessibilityTypes::State state;
+  EXPECT_TRUE(label.GetAccessibleState(&state));
+  EXPECT_EQ(AccessibilityTypes::STATE_READONLY, state);
+}
+
+TEST(LabelTest, SingleLineSizing) {
+  Label label;
+  std::wstring test_text(L"A not so random string in one line.");
+  label.SetText(test_text);
+
+  // GetPreferredSize
+  gfx::Size required_size = label.GetPreferredSize();
+  EXPECT_GT(required_size.height(), kMinTextDimension);
+  EXPECT_GT(required_size.width(), kMinTextDimension);
+
+  // Test everything with borders.
+  gfx::Insets border(10, 20, 30, 40);
+  label.set_border(Border::CreateEmptyBorder(border.top(),
+                                             border.left(),
+                                             border.bottom(),
+                                             border.right()));
+
+  // GetPreferredSize and borders.
+  label.SetBounds(0, 0, 0, 0);
+  gfx::Size required_size_with_border = label.GetPreferredSize();
+  EXPECT_EQ(required_size_with_border.height(),
+            required_size.height() + border.height());
+  EXPECT_EQ(required_size_with_border.width(),
+            required_size.width() + border.width());
+}
+
+TEST(LabelTest, MultiLineSizing) {
+  Label label;
+  label.SetFocusable(false);
+  std::wstring test_text(L"A random string\nwith multiple lines\nand returns!");
+  label.SetText(test_text);
+  label.SetMultiLine(true);
+
+  // GetPreferredSize
+  gfx::Size required_size = label.GetPreferredSize();
+  EXPECT_GT(required_size.height(), kMinTextDimension);
+  EXPECT_GT(required_size.width(), kMinTextDimension);
+
+  // SizeToFit with unlimited width.
+  label.SizeToFit(0);
+  int required_width = label.GetLocalBounds(true).width();
+  EXPECT_GT(required_width, kMinTextDimension);
+
+  // SizeToFit with limited width.
+  label.SizeToFit(required_width - 1);
+  int constrained_width = label.GetLocalBounds(true).width();
+  EXPECT_LT(constrained_width, required_width);
+  EXPECT_GT(constrained_width, kMinTextDimension);
+
+  // Change the width back to the desire width.
+  label.SizeToFit(required_width);
+  EXPECT_EQ(required_width, label.GetLocalBounds(true).width());
+
+  // General tests for GetHeightForWidth.
+  int required_height = label.GetHeightForWidth(required_width);
+  EXPECT_GT(required_height, kMinTextDimension);
+  int height_for_constrained_width = label.GetHeightForWidth(constrained_width);
+  EXPECT_GT(height_for_constrained_width, required_height);
+  // Using the constrained width or the required_width - 1 should give the
+  // same result for the height because the constrainted width is the tight
+  // width when given "required_width - 1" as the max width.
+  EXPECT_EQ(height_for_constrained_width,
+            label.GetHeightForWidth(required_width - 1));
+
+  // Test everything with borders.
+  gfx::Insets border(10, 20, 30, 40);
+  label.set_border(Border::CreateEmptyBorder(border.top(),
+                                             border.left(),
+                                             border.bottom(),
+                                             border.right()));
+
+  // SizeToFit and borders.
+  label.SizeToFit(0);
+  int required_width_with_border = label.GetLocalBounds(true).width();
+  EXPECT_EQ(required_width_with_border, required_width + border.width());
+
+  // GetHeightForWidth and borders.
+  int required_height_with_border =
+      label.GetHeightForWidth(required_width_with_border);
+  EXPECT_EQ(required_height_with_border, required_height + border.height());
+
+  // Test that the border width is subtracted before doing the height
+  // calculation.  If it is, then the height will grow when width
+  // is shrunk.
+  int height1 = label.GetHeightForWidth(required_width_with_border - 1);
+  EXPECT_GT(height1, required_height_with_border);
+  EXPECT_EQ(height1, height_for_constrained_width + border.height());
+
+  // GetPreferredSize and borders.
+  label.SetBounds(0, 0, 0, 0);
+  gfx::Size required_size_with_border = label.GetPreferredSize();
+  EXPECT_EQ(required_size_with_border.height(),
+            required_size.height() + border.height());
+  EXPECT_EQ(required_size_with_border.width(),
+            required_size.width() + border.width());
+}
+
+TEST(LabelTest, DrawSingleLineString) {
+  Label label;
+  label.SetFocusable(false);
+
+  // Turn off mirroring so that we don't need to figure out if
+  // align right really means align left.
+  label.EnableUIMirroringForRTLLanguages(false);
+
+  std::wstring test_text(L"Here's a string with no returns.");
+  label.SetText(test_text);
+  gfx::Size required_size(label.GetPreferredSize());
+  gfx::Size extra(22, 8);
+  label.SetBounds(0,
+                  0,
+                  required_size.width() + extra.width(),
+                  required_size.height() + extra.height());
+
+  // Do some basic verifications for all three alignments.
+  std::wstring paint_text;
+  gfx::Rect text_bounds;
+  int flags;
+
+  // Centered text.
+  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
+  EXPECT_STREQ(test_text.c_str(), paint_text.c_str());
+  // The text should be centered horizontally and vertically.
+  EXPECT_EQ(extra.width() / 2, text_bounds.x());
+  EXPECT_EQ(extra.height() / 2 , text_bounds.y());
+  EXPECT_EQ(required_size.width(), text_bounds.width());
+  EXPECT_EQ(required_size.height(), text_bounds.height());
+  EXPECT_EQ(0, flags);
+
+  // Left aligned text.
+  label.SetHorizontalAlignment(Label::ALIGN_LEFT);
+  paint_text.clear();
+  text_bounds.SetRect(0, 0, 0, 0);
+  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
+  EXPECT_STREQ(test_text.c_str(), paint_text.c_str());
+  // The text should be left aligned horizontally and centered vertically.
+  EXPECT_EQ(0, text_bounds.x());
+  EXPECT_EQ(extra.height() / 2 , text_bounds.y());
+  EXPECT_EQ(required_size.width(), text_bounds.width());
+  EXPECT_EQ(required_size.height(), text_bounds.height());
+  EXPECT_EQ(0, flags);
+
+  // Right aligned text.
+  label.SetHorizontalAlignment(Label::ALIGN_RIGHT);
+  paint_text.clear();
+  text_bounds.SetRect(0, 0, 0, 0);
+  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
+  EXPECT_STREQ(test_text.c_str(), paint_text.c_str());
+  // The text should be right aligned horizontally and centered vertically.
+  EXPECT_EQ(extra.width(), text_bounds.x());
+  EXPECT_EQ(extra.height() / 2 , text_bounds.y());
+  EXPECT_EQ(required_size.width(), text_bounds.width());
+  EXPECT_EQ(required_size.height(), text_bounds.height());
+  EXPECT_EQ(0, flags);
+
+  // Test single line drawing with a border.
+  gfx::Insets border(39, 34, 8, 96);
+  label.set_border(Border::CreateEmptyBorder(border.top(),
+                                             border.left(),
+                                             border.bottom(),
+                                             border.right()));
+
+  gfx::Size required_size_with_border(label.GetPreferredSize());
+  EXPECT_EQ(required_size.width() + border.width(),
+            required_size_with_border.width());
+  EXPECT_EQ(required_size.height() + border.height(),
+            required_size_with_border.height());
+  label.SetBounds(0,
+                  0,
+                  required_size_with_border.width() + extra.width(),
+                  required_size_with_border.height() + extra.height());
+
+  // Centered text with border.
+  label.SetHorizontalAlignment(Label::ALIGN_CENTER);
+  paint_text.clear();
+  text_bounds.SetRect(0, 0, 0, 0);
+  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
+  EXPECT_STREQ(test_text.c_str(), paint_text.c_str());
+  // The text should be centered horizontally and vertically within the border.
+  EXPECT_EQ(border.left() + extra.width() / 2, text_bounds.x());
+  EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
+  EXPECT_EQ(required_size.width(), text_bounds.width());
+  EXPECT_EQ(required_size.height(), text_bounds.height());
+  EXPECT_EQ(0, flags);
+
+  // Left aligned text with border.
+  label.SetHorizontalAlignment(Label::ALIGN_LEFT);
+  paint_text.clear();
+  text_bounds.SetRect(0, 0, 0, 0);
+  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
+  EXPECT_STREQ(test_text.c_str(), paint_text.c_str());
+  // The text should be left aligned horizontally and centered vertically.
+  EXPECT_EQ(border.left(), text_bounds.x());
+  EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
+  EXPECT_EQ(required_size.width(), text_bounds.width());
+  EXPECT_EQ(required_size.height(), text_bounds.height());
+  EXPECT_EQ(0, flags);
+
+  // Right aligned text.
+  label.SetHorizontalAlignment(Label::ALIGN_RIGHT);
+  paint_text.clear();
+  text_bounds.SetRect(0, 0, 0, 0);
+  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
+  EXPECT_STREQ(test_text.c_str(), paint_text.c_str());
+  // The text should be right aligned horizontally and centered vertically.
+  EXPECT_EQ(border.left() + extra.width(), text_bounds.x());
+  EXPECT_EQ(border.top() + extra.height() / 2 , text_bounds.y());
+  EXPECT_EQ(required_size.width(), text_bounds.width());
+  EXPECT_EQ(required_size.height(), text_bounds.height());
+  EXPECT_EQ(0, flags);
+}
+
+TEST(LabelTest, DrawMultiLineString) {
+  Label label;
+  label.SetFocusable(false);
+
+  // Turn off mirroring so that we don't need to figure out if
+  // align right really means align left.
+  label.EnableUIMirroringForRTLLanguages(false);
+
+  std::wstring test_text(L"Another string\nwith returns\n\n!");
+  label.SetText(test_text);
+  label.SetMultiLine(true);
+  label.SizeToFit(0);
+
+  // Do some basic verifications for all three alignments.
+  std::wstring paint_text;
+  gfx::Rect text_bounds;
+  int flags;
+  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
+  EXPECT_STREQ(test_text.c_str(), paint_text.c_str());
+  EXPECT_EQ(0, text_bounds.x());
+  EXPECT_EQ(0, text_bounds.y());
+  EXPECT_GT(text_bounds.width(), kMinTextDimension);
+  EXPECT_GT(text_bounds.height(), kMinTextDimension);
+  EXPECT_EQ(ChromeCanvas::MULTI_LINE | ChromeCanvas::TEXT_ALIGN_CENTER, flags);
+  gfx::Rect center_bounds(text_bounds);
+
+  label.SetHorizontalAlignment(Label::ALIGN_LEFT);
+  paint_text.clear();
+  text_bounds.SetRect(0, 0, 0, 0);
+  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
+  EXPECT_STREQ(test_text.c_str(), paint_text.c_str());
+  EXPECT_EQ(0, text_bounds.x());
+  EXPECT_EQ(0, text_bounds.y());
+  EXPECT_GT(text_bounds.width(), kMinTextDimension);
+  EXPECT_GT(text_bounds.height(), kMinTextDimension);
+  EXPECT_EQ(ChromeCanvas::MULTI_LINE | ChromeCanvas::TEXT_ALIGN_LEFT, flags);
+
+  label.SetHorizontalAlignment(Label::ALIGN_RIGHT);
+  paint_text.clear();
+  text_bounds.SetRect(0, 0, 0, 0);
+  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
+  EXPECT_STREQ(test_text.c_str(), paint_text.c_str());
+  EXPECT_EQ(0, text_bounds.x());
+  EXPECT_EQ(0, text_bounds.y());
+  EXPECT_GT(text_bounds.width(), kMinTextDimension);
+  EXPECT_GT(text_bounds.height(), kMinTextDimension);
+  EXPECT_EQ(ChromeCanvas::MULTI_LINE | ChromeCanvas::TEXT_ALIGN_RIGHT, flags);
+
+  // Test multiline drawing with a border.
+  gfx::Insets border(19, 92, 23, 2);
+  label.set_border(Border::CreateEmptyBorder(border.top(),
+                                             border.left(),
+                                             border.bottom(),
+                                             border.right()));
+  label.SizeToFit(0);
+  label.SetHorizontalAlignment(Label::ALIGN_CENTER);
+  paint_text.clear();
+  text_bounds.SetRect(0, 0, 0, 0);
+  label.CalculateDrawStringParams(&paint_text, &text_bounds, &flags);
+  EXPECT_STREQ(test_text.c_str(), paint_text.c_str());
+  EXPECT_EQ(center_bounds.x() + border.left(), text_bounds.x());
+  EXPECT_EQ(center_bounds.y() + border.top(), text_bounds.y());
+  EXPECT_EQ(center_bounds.width(), text_bounds.width());
+  EXPECT_EQ(center_bounds.height(), text_bounds.height());
+  EXPECT_EQ(ChromeCanvas::MULTI_LINE | ChromeCanvas::TEXT_ALIGN_CENTER, flags);
+}
+
+}  // namespace views
diff --git a/views/controls/link.cc b/views/controls/link.cc
new file mode 100644
index 0000000..aae254503
--- /dev/null
+++ b/views/controls/link.cc
@@ -0,0 +1,183 @@
+// Copyright (c) 2006-2008 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 "views/controls/link.h"
+
+#include "app/gfx/chrome_font.h"
+#include "views/event.h"
+
+namespace views {
+
+static HCURSOR g_hand_cursor = NULL;
+
+// Default colors used for links.
+static const SkColor kHighlightedColor = SkColorSetRGB(255, 0x00, 0x00);
+static const SkColor kNormalColor = SkColorSetRGB(0, 51, 153);
+static const SkColor kDisabledColor = SkColorSetRGB(0, 0, 0);
+
+const char Link::kViewClassName[] = "views/Link";
+
+Link::Link() : Label(L""),
+               controller_(NULL),
+               highlighted_(false),
+               highlighted_color_(kHighlightedColor),
+               disabled_color_(kDisabledColor),
+               normal_color_(kNormalColor) {
+  Init();
+  SetFocusable(true);
+}
+
+Link::Link(const std::wstring& title) : Label(title),
+                                        controller_(NULL),
+                                        highlighted_(false),
+                                        highlighted_color_(kHighlightedColor),
+                                        disabled_color_(kDisabledColor),
+                                        normal_color_(kNormalColor) {
+  Init();
+  SetFocusable(true);
+}
+
+void Link::Init() {
+  SetColor(normal_color_);
+  ValidateStyle();
+}
+
+Link::~Link() {
+}
+
+void Link::SetController(LinkController* controller) {
+  controller_ = controller;
+}
+
+const LinkController* Link::GetController() {
+  return controller_;
+}
+
+std::string Link::GetClassName() const {
+  return kViewClassName;
+}
+
+void Link::SetHighlightedColor(const SkColor& color) {
+  normal_color_ = color;
+  ValidateStyle();
+}
+
+void Link::SetDisabledColor(const SkColor& color) {
+  disabled_color_ = color;
+  ValidateStyle();
+}
+
+void Link::SetNormalColor(const SkColor& color) {
+  normal_color_ = color;
+  ValidateStyle();
+}
+
+bool Link::OnMousePressed(const MouseEvent& e) {
+  if (!enabled_ || (!e.IsLeftMouseButton() && !e.IsMiddleMouseButton()))
+    return false;
+  SetHighlighted(true);
+  return true;
+}
+
+bool Link::OnMouseDragged(const MouseEvent& e) {
+  SetHighlighted(enabled_ &&
+                 (e.IsLeftMouseButton() || e.IsMiddleMouseButton()) &&
+                 HitTest(e.location()));
+  return true;
+}
+
+void Link::OnMouseReleased(const MouseEvent& e, bool canceled) {
+  // Change the highlight first just in case this instance is deleted
+  // while calling the controller
+  SetHighlighted(false);
+  if (enabled_ && !canceled &&
+      (e.IsLeftMouseButton() || e.IsMiddleMouseButton()) &&
+      HitTest(e.location())) {
+    // Focus the link on click.
+    RequestFocus();
+
+    if (controller_)
+      controller_->LinkActivated(this, e.GetFlags());
+  }
+}
+
+bool Link::OnKeyPressed(const KeyEvent& e) {
+  if ((e.GetCharacter() == VK_SPACE) || (e.GetCharacter() == VK_RETURN)) {
+    SetHighlighted(false);
+
+    // Focus the link on key pressed.
+    RequestFocus();
+
+    if (controller_)
+      controller_->LinkActivated(this, e.GetFlags());
+
+    return true;
+  }
+  return false;
+}
+
+bool Link::OverrideAccelerator(const Accelerator& accelerator) {
+  return (accelerator.GetKeyCode() == VK_SPACE) ||
+         (accelerator.GetKeyCode() == VK_RETURN);
+}
+
+void Link::SetHighlighted(bool f) {
+  if (f != highlighted_) {
+    highlighted_ = f;
+    ValidateStyle();
+    SchedulePaint();
+  }
+}
+
+void Link::ValidateStyle() {
+  ChromeFont font = GetFont();
+
+  if (enabled_) {
+    if ((font.style() & ChromeFont::UNDERLINED) == 0) {
+      Label::SetFont(font.DeriveFont(0, font.style() |
+                                     ChromeFont::UNDERLINED));
+    }
+  } else {
+    if ((font.style() & ChromeFont::UNDERLINED) != 0) {
+      Label::SetFont(font.DeriveFont(0, font.style() &
+                                     ~ChromeFont::UNDERLINED));
+    }
+  }
+
+  if (enabled_) {
+    if (highlighted_) {
+      Label::SetColor(highlighted_color_);
+    } else {
+      Label::SetColor(normal_color_);
+    }
+  } else {
+    Label::SetColor(disabled_color_);
+  }
+}
+
+void Link::SetFont(const ChromeFont& font) {
+  Label::SetFont(font);
+  ValidateStyle();
+}
+
+void Link::SetEnabled(bool f) {
+  if (f != enabled_) {
+    enabled_ = f;
+    ValidateStyle();
+    SchedulePaint();
+  }
+}
+
+HCURSOR Link::GetCursorForPoint(Event::EventType event_type, int x, int y) {
+  if (enabled_) {
+    if (!g_hand_cursor) {
+      g_hand_cursor = LoadCursor(NULL, IDC_HAND);
+    }
+    return g_hand_cursor;
+  } else {
+    return NULL;
+  }
+}
+
+}  // namespace views
diff --git a/views/controls/link.h b/views/controls/link.h
new file mode 100644
index 0000000..6da6aa3
--- /dev/null
+++ b/views/controls/link.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_LINK_H_
+#define VIEWS_CONTROLS_LINK_H_
+
+#include "views/controls/label.h"
+
+namespace views {
+
+class Link;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// LinkController defines the method that should be implemented to
+// receive a notification when a link is clicked
+//
+////////////////////////////////////////////////////////////////////////////////
+class LinkController {
+ public:
+  virtual void LinkActivated(Link* source, int event_flags) = 0;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Link class
+//
+// A Link is a label subclass that looks like an HTML link. It has a
+// controller which is notified when a click occurs.
+//
+////////////////////////////////////////////////////////////////////////////////
+class Link : public Label {
+ public:
+  static const char Link::kViewClassName[];
+
+  Link();
+  Link(const std::wstring& title);
+  virtual ~Link();
+
+  void SetController(LinkController* controller);
+  const LinkController* GetController();
+
+  // Overridden from View:
+  virtual bool OnMousePressed(const MouseEvent& event);
+  virtual bool OnMouseDragged(const MouseEvent& event);
+  virtual void OnMouseReleased(const MouseEvent& event,
+                               bool canceled);
+  virtual bool OnKeyPressed(const KeyEvent& e);
+  virtual bool OverrideAccelerator(const Accelerator& accelerator);
+
+  virtual void SetFont(const ChromeFont& font);
+
+  // Set whether the link is enabled.
+  virtual void SetEnabled(bool f);
+
+  virtual HCURSOR GetCursorForPoint(Event::EventType event_type, int x, int y);
+
+  virtual std::string GetClassName() const;
+
+  void SetHighlightedColor(const SkColor& color);
+  void SetDisabledColor(const SkColor& color);
+  void SetNormalColor(const SkColor& color);
+
+ private:
+
+  // A highlighted link is clicked.
+  void SetHighlighted(bool f);
+
+  // Make sure the label style matched the current state.
+  void ValidateStyle();
+
+  void Init();
+
+  LinkController* controller_;
+
+  // Whether the link is currently highlighted.
+  bool highlighted_;
+
+  // The color when the link is highlighted.
+  SkColor highlighted_color_;
+
+  // The color when the link is disabled.
+  SkColor disabled_color_;
+
+  // The color when the link is neither highlighted nor disabled.
+  SkColor normal_color_;
+
+  DISALLOW_COPY_AND_ASSIGN(Link);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_LINK_H_
diff --git a/views/controls/menu/chrome_menu.cc b/views/controls/menu/chrome_menu.cc
new file mode 100644
index 0000000..a887fd56
--- /dev/null
+++ b/views/controls/menu/chrome_menu.cc
@@ -0,0 +1,2816 @@
+// Copyright (c) 2006-2008 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 "views/controls/menu/chrome_menu.h"
+
+#include <windows.h>
+#include <uxtheme.h>
+#include <Vssym32.h>
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/l10n_util.h"
+#include "app/l10n_util_win.h"
+#include "app/os_exchange_data.h"
+#include "base/base_drag_source.h"
+#include "base/gfx/native_theme.h"
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "base/timer.h"
+#include "base/win_util.h"
+// TODO(beng): (Cleanup) remove this browser dep.
+#include "chrome/browser/drag_utils.h"
+#include "chrome/common/gfx/color_utils.h"
+#include "grit/generated_resources.h"
+#include "skia/ext/skia_utils_win.h"
+#include "views/border.h"
+#include "views/view_constants.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget_win.h"
+
+#undef min
+#undef max
+
+using base::Time;
+using base::TimeDelta;
+
+// Margins between the top of the item and the label.
+static const int kItemTopMargin = 3;
+
+// Margins between the bottom of the item and the label.
+static const int kItemBottomMargin = 4;
+
+// Margins used if the menu doesn't have icons.
+static const int kItemNoIconTopMargin = 1;
+static const int kItemNoIconBottomMargin = 3;
+
+// Margins between the left of the item and the icon.
+static const int kItemLeftMargin = 4;
+
+// Padding between the label and submenu arrow.
+static const int kLabelToArrowPadding = 10;
+
+// Padding between the arrow and the edge.
+static const int kArrowToEdgePadding = 5;
+
+// Padding between the icon and label.
+static const int kIconToLabelPadding = 8;
+
+// Padding between the gutter and label.
+static const int kGutterToLabel = 5;
+
+// Height of the scroll arrow.
+// This goes up to 4 with large fonts, but this is close enough for now.
+static const int kScrollArrowHeight = 3;
+
+// Size of the check. This comes from the OS.
+static int check_width;
+static int check_height;
+
+// Size of the submenu arrow. This comes from the OS.
+static int arrow_width;
+static int arrow_height;
+
+// Width of the gutter. Only used if render_gutter is true.
+static int gutter_width;
+
+// Margins between the right of the item and the label.
+static int item_right_margin;
+
+// X-coordinate of where the label starts.
+static int label_start;
+
+// Height of the separator.
+static int separator_height;
+
+// Padding around the edges of the submenu.
+static const int kSubmenuBorderSize = 3;
+
+// Amount to inset submenus.
+static const int kSubmenuHorizontalInset = 3;
+
+// Delay, in ms, between when menus are selected are moused over and the menu
+// appears.
+static const int kShowDelay = 400;
+
+// Amount of time from when the drop exits the menu and the menu is hidden.
+static const int kCloseOnExitTime = 1200;
+
+// Height of the drop indicator. This should be an event number.
+static const int kDropIndicatorHeight = 2;
+
+// Color of the drop indicator.
+static const SkColor kDropIndicatorColor = SK_ColorBLACK;
+
+// Whether or not the gutter should be rendered. The gutter is specific to
+// Vista.
+static bool render_gutter = false;
+
+// Max width of a menu. There does not appear to be an OS value for this, yet
+// both IE and FF restrict the max width of a menu.
+static const int kMaxMenuWidth = 400;
+
+// Period of the scroll timer (in milliseconds).
+static const int kScrollTimerMS = 30;
+
+// Preferred height of menu items. Reset every time a menu is run.
+static int pref_menu_height;
+
+// Are mnemonics shown? This is updated before the menus are shown.
+static bool show_mnemonics;
+
+using gfx::NativeTheme;
+
+namespace views {
+
+namespace {
+
+// Returns the font menus are to use.
+ChromeFont GetMenuFont() {
+  NONCLIENTMETRICS metrics;
+  win_util::GetNonClientMetrics(&metrics);
+
+  l10n_util::AdjustUIFont(&(metrics.lfMenuFont));
+  HFONT font = CreateFontIndirect(&metrics.lfMenuFont);
+  DLOG_ASSERT(font);
+  return ChromeFont::CreateFont(font);
+}
+
+// Calculates all sizes that we can from the OS.
+//
+// This is invoked prior to Running a menu.
+void UpdateMenuPartSizes(bool has_icons) {
+  HDC dc = GetDC(NULL);
+  RECT bounds = { 0, 0, 200, 200 };
+  SIZE check_size;
+  if (NativeTheme::instance()->GetThemePartSize(
+          NativeTheme::MENU, dc, MENU_POPUPCHECK, MC_CHECKMARKNORMAL, &bounds,
+          TS_TRUE, &check_size) == S_OK) {
+    check_width = check_size.cx;
+    check_height = check_size.cy;
+  } else {
+    check_width = GetSystemMetrics(SM_CXMENUCHECK);
+    check_height = GetSystemMetrics(SM_CYMENUCHECK);
+  }
+
+  SIZE arrow_size;
+  if (NativeTheme::instance()->GetThemePartSize(
+          NativeTheme::MENU, dc, MENU_POPUPSUBMENU, MSM_NORMAL, &bounds,
+          TS_TRUE, &arrow_size) == S_OK) {
+    arrow_width = arrow_size.cx;
+    arrow_height = arrow_size.cy;
+  } else {
+    // Sadly I didn't see a specify metrics for this.
+    arrow_width = GetSystemMetrics(SM_CXMENUCHECK);
+    arrow_height = GetSystemMetrics(SM_CYMENUCHECK);
+  }
+
+  SIZE gutter_size;
+  if (NativeTheme::instance()->GetThemePartSize(
+          NativeTheme::MENU, dc, MENU_POPUPGUTTER, MSM_NORMAL, &bounds,
+          TS_TRUE, &gutter_size) == S_OK) {
+    gutter_width = gutter_size.cx;
+    render_gutter = true;
+  } else {
+    gutter_width = 0;
+    render_gutter = false;
+  }
+
+  SIZE separator_size;
+  if (NativeTheme::instance()->GetThemePartSize(
+          NativeTheme::MENU, dc, MENU_POPUPSEPARATOR, MSM_NORMAL, &bounds,
+          TS_TRUE, &separator_size) == S_OK) {
+    separator_height = separator_size.cy;
+  } else {
+    separator_height = GetSystemMetrics(SM_CYMENU) / 2;
+  }
+
+  item_right_margin = kLabelToArrowPadding + arrow_width + kArrowToEdgePadding;
+
+  if (has_icons) {
+    label_start = kItemLeftMargin + check_width + kIconToLabelPadding;
+  } else {
+    // If there are no icons don't pad by the icon to label padding. This
+    // makes us look close to system menus.
+    label_start = kItemLeftMargin + check_width;
+  }
+  if (render_gutter)
+    label_start += gutter_width + kGutterToLabel;
+
+  ReleaseDC(NULL, dc);
+
+  MenuItemView menu_item(NULL);
+  menu_item.SetTitle(L"blah");  // Text doesn't matter here.
+  pref_menu_height = menu_item.GetPreferredSize().height();
+}
+
+// Convenience for scrolling the view such that the origin is visible.
+static void ScrollToVisible(View* view) {
+  view->ScrollRectToVisible(0, 0, view->width(), view->height());
+}
+
+// MenuScrollTask --------------------------------------------------------------
+
+// MenuScrollTask is used when the SubmenuView does not all fit on screen and
+// the mouse is over the scroll up/down buttons. MenuScrollTask schedules
+// itself with a RepeatingTimer. When Run is invoked MenuScrollTask scrolls
+// appropriately.
+
+class MenuScrollTask {
+ public:
+  MenuScrollTask() : submenu_(NULL) {
+    pixels_per_second_ = pref_menu_height * 20;
+  }
+
+  void Update(const MenuController::MenuPart& part) {
+    if (!part.is_scroll()) {
+      StopScrolling();
+      return;
+    }
+    DCHECK(part.submenu);
+    SubmenuView* new_menu = part.submenu;
+    bool new_is_up = (part.type == MenuController::MenuPart::SCROLL_UP);
+    if (new_menu == submenu_ && is_scrolling_up_ == new_is_up)
+      return;
+
+    start_scroll_time_ = Time::Now();
+    start_y_ = part.submenu->GetVisibleBounds().y();
+    submenu_ = new_menu;
+    is_scrolling_up_ = new_is_up;
+
+    if (!scrolling_timer_.IsRunning()) {
+      scrolling_timer_.Start(TimeDelta::FromMilliseconds(kScrollTimerMS), this,
+                             &MenuScrollTask::Run);
+    }
+  }
+
+  void StopScrolling() {
+    if (scrolling_timer_.IsRunning()) {
+      scrolling_timer_.Stop();
+      submenu_ = NULL;
+    }
+  }
+
+  // The menu being scrolled. Returns null if not scrolling.
+  SubmenuView* submenu() const { return submenu_; }
+
+ private:
+  void Run() {
+    DCHECK(submenu_);
+    gfx::Rect vis_rect = submenu_->GetVisibleBounds();
+    const int delta_y = static_cast<int>(
+        (Time::Now() - start_scroll_time_).InMilliseconds() *
+        pixels_per_second_ / 1000);
+    int target_y = start_y_;
+    if (is_scrolling_up_)
+      target_y = std::max(0, target_y - delta_y);
+    else
+      target_y = std::min(submenu_->height() - vis_rect.height(),
+                          target_y + delta_y);
+    submenu_->ScrollRectToVisible(vis_rect.x(), target_y, vis_rect.width(),
+                                  vis_rect.height());
+  }
+
+  // SubmenuView being scrolled.
+  SubmenuView* submenu_;
+
+  // Direction scrolling.
+  bool is_scrolling_up_;
+
+  // Timer to periodically scroll.
+  base::RepeatingTimer<MenuScrollTask> scrolling_timer_;
+
+  // Time we started scrolling at.
+  Time start_scroll_time_;
+
+  // How many pixels to scroll per second.
+  int pixels_per_second_;
+
+  // Y-coordinate of submenu_view_ when scrolling started.
+  int start_y_;
+
+  DISALLOW_COPY_AND_ASSIGN(MenuScrollTask);
+};
+
+// MenuScrollButton ------------------------------------------------------------
+
+// MenuScrollButton is used for the scroll buttons when not all menu items fit
+// on screen. MenuScrollButton forwards appropriate events to the
+// MenuController.
+
+class MenuScrollButton : public View {
+ public:
+  explicit MenuScrollButton(SubmenuView* host, bool is_up)
+      : host_(host),
+        is_up_(is_up),
+        // Make our height the same as that of other MenuItemViews.
+        pref_height_(pref_menu_height) {
+  }
+
+  virtual gfx::Size GetPreferredSize() {
+    return gfx::Size(kScrollArrowHeight * 2 - 1, pref_height_);
+  }
+
+  virtual bool CanDrop(const OSExchangeData& data) {
+    DCHECK(host_->GetMenuItem()->GetMenuController());
+    return true;  // Always return true so that drop events are targeted to us.
+  }
+
+  virtual void OnDragEntered(const DropTargetEvent& event) {
+    DCHECK(host_->GetMenuItem()->GetMenuController());
+    host_->GetMenuItem()->GetMenuController()->OnDragEnteredScrollButton(
+        host_, is_up_);
+  }
+
+  virtual int OnDragUpdated(const DropTargetEvent& event) {
+    return DragDropTypes::DRAG_NONE;
+  }
+
+  virtual void OnDragExited() {
+    DCHECK(host_->GetMenuItem()->GetMenuController());
+    host_->GetMenuItem()->GetMenuController()->OnDragExitedScrollButton(host_);
+  }
+
+  virtual int OnPerformDrop(const DropTargetEvent& event) {
+    return DragDropTypes::DRAG_NONE;
+  }
+
+  virtual void Paint(ChromeCanvas* canvas) {
+    HDC dc = canvas->beginPlatformPaint();
+
+    // The background.
+    RECT item_bounds = { 0, 0, width(), height() };
+    NativeTheme::instance()->PaintMenuItemBackground(
+        NativeTheme::MENU, dc, MENU_POPUPITEM, MPI_NORMAL, false,
+        &item_bounds);
+
+    // Then the arrow.
+    int x = width() / 2;
+    int y = (height() - kScrollArrowHeight) / 2;
+    int delta_y = 1;
+    if (!is_up_) {
+      delta_y = -1;
+      y += kScrollArrowHeight;
+    }
+    SkColor arrow_color = color_utils::GetSysSkColor(COLOR_MENUTEXT);
+    for (int i = 0; i < kScrollArrowHeight; ++i, --x, y += delta_y)
+      canvas->FillRectInt(arrow_color, x, y, (i * 2) + 1, 1);
+
+    canvas->endPlatformPaint();
+  }
+
+ private:
+  // SubmenuView we were created for.
+  SubmenuView* host_;
+
+  // Direction of the button.
+  bool is_up_;
+
+  // Preferred height.
+  int pref_height_;
+
+  DISALLOW_COPY_AND_ASSIGN(MenuScrollButton);
+};
+
+// MenuScrollView --------------------------------------------------------------
+
+// MenuScrollView is a viewport for the SubmenuView. It's reason to exist is so
+// that ScrollRectToVisible works.
+//
+// NOTE: It is possible to use ScrollView directly (after making it deal with
+// null scrollbars), but clicking on a child of ScrollView forces the window to
+// become active, which we don't want. As we really only need a fraction of
+// what ScrollView does, we use a one off variant.
+
+class MenuScrollView : public View {
+ public:
+  explicit MenuScrollView(View* child) {
+    AddChildView(child);
+  }
+
+  virtual void ScrollRectToVisible(int x, int y, int width, int height) {
+    // NOTE: this assumes we only want to scroll in the y direction.
+
+    View* child = GetContents();
+    // Convert y to view's coordinates.
+    y -= child->y();
+    gfx::Size pref = child->GetPreferredSize();
+    // Constrain y to make sure we don't show past the bottom of the view.
+    y = std::max(0, std::min(pref.height() - this->height(), y));
+    child->SetY(-y);
+  }
+
+  // Returns the contents, which is the SubmenuView.
+  View* GetContents() {
+    return GetChildViewAt(0);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MenuScrollView);
+};
+
+// MenuScrollViewContainer -----------------------------------------------------
+
+// MenuScrollViewContainer contains the SubmenuView (through a MenuScrollView)
+// and two scroll buttons. The scroll buttons are only visible and enabled if
+// the preferred height of the SubmenuView is bigger than our bounds.
+class MenuScrollViewContainer : public View {
+ public:
+  explicit MenuScrollViewContainer(SubmenuView* content_view) {
+    scroll_up_button_ = new MenuScrollButton(content_view, true);
+    scroll_down_button_ = new MenuScrollButton(content_view, false);
+    AddChildView(scroll_up_button_);
+    AddChildView(scroll_down_button_);
+
+    scroll_view_ = new MenuScrollView(content_view);
+    AddChildView(scroll_view_);
+
+    set_border(Border::CreateEmptyBorder(
+        kSubmenuBorderSize, kSubmenuBorderSize,
+        kSubmenuBorderSize, kSubmenuBorderSize));
+  }
+
+  virtual void Paint(ChromeCanvas* canvas) {
+    HDC dc = canvas->beginPlatformPaint();
+    CRect bounds(0, 0, width(), height());
+    NativeTheme::instance()->PaintMenuBackground(
+        NativeTheme::MENU, dc, MENU_POPUPBACKGROUND, 0, &bounds);
+    canvas->endPlatformPaint();
+  }
+
+  View* scroll_down_button() { return scroll_down_button_; }
+
+  View* scroll_up_button() { return scroll_up_button_; }
+
+  virtual void Layout() {
+    gfx::Insets insets = GetInsets();
+    int x = insets.left();
+    int y = insets.top();
+    int width = View::width() - insets.width();
+    int content_height = height() - insets.height();
+    if (!scroll_up_button_->IsVisible()) {
+      scroll_view_->SetBounds(x, y, width, content_height);
+      scroll_view_->Layout();
+      return;
+    }
+
+    gfx::Size pref = scroll_up_button_->GetPreferredSize();
+    scroll_up_button_->SetBounds(x, y, width, pref.height());
+    content_height -= pref.height();
+
+    const int scroll_view_y = y + pref.height();
+
+    pref = scroll_down_button_->GetPreferredSize();
+    scroll_down_button_->SetBounds(x, height() - pref.height() - insets.top(),
+                                   width, pref.height());
+    content_height -= pref.height();
+
+    scroll_view_->SetBounds(x, scroll_view_y, width, content_height);
+    scroll_view_->Layout();
+  }
+
+  virtual void DidChangeBounds(const gfx::Rect& previous,
+                               const gfx::Rect& current) {
+    gfx::Size content_pref = scroll_view_->GetContents()->GetPreferredSize();
+    scroll_up_button_->SetVisible(content_pref.height() > height());
+    scroll_down_button_->SetVisible(content_pref.height() > height());
+  }
+
+  virtual gfx::Size GetPreferredSize() {
+    gfx::Size prefsize = scroll_view_->GetContents()->GetPreferredSize();
+    gfx::Insets insets = GetInsets();
+    prefsize.Enlarge(insets.width(), insets.height());
+    return prefsize;
+  }
+
+ private:
+  // The scroll buttons.
+  View* scroll_up_button_;
+  View* scroll_down_button_;
+
+  // The scroll view.
+  MenuScrollView* scroll_view_;
+
+  DISALLOW_COPY_AND_ASSIGN(MenuScrollViewContainer);
+};
+
+// MenuSeparator ---------------------------------------------------------------
+
+// Renders a separator.
+
+class MenuSeparator : public View {
+ public:
+  MenuSeparator() {
+  }
+
+  void Paint(ChromeCanvas* canvas) {
+    // The gutter is rendered before the background.
+    int start_x = 0;
+    int start_y = height() / 3;
+    HDC dc = canvas->beginPlatformPaint();
+    if (render_gutter) {
+      // If render_gutter is true, we're on Vista and need to render the
+      // gutter, then indent the separator from the gutter.
+      RECT gutter_bounds = { label_start - kGutterToLabel - gutter_width, 0, 0,
+                              height() };
+      gutter_bounds.right = gutter_bounds.left + gutter_width;
+      NativeTheme::instance()->PaintMenuGutter(dc, MENU_POPUPGUTTER, MPI_NORMAL,
+                                               &gutter_bounds);
+      start_x = gutter_bounds.left + gutter_width;
+      start_y = 0;
+    }
+    RECT separator_bounds = { start_x, start_y, width(), height() };
+    NativeTheme::instance()->PaintMenuSeparator(dc, MENU_POPUPSEPARATOR,
+                                                MPI_NORMAL, &separator_bounds);
+    canvas->endPlatformPaint();
+  }
+
+  gfx::Size GetPreferredSize() {
+    return gfx::Size(10,  // Just in case we're the only item in a menu.
+                     separator_height);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MenuSeparator);
+};
+
+// MenuHostRootView ----------------------------------------------------------
+
+// MenuHostRootView is the RootView of the window showing the menu.
+// SubmenuView's scroll view is added as a child of MenuHostRootView.
+// MenuHostRootView forwards relevant events to the MenuController.
+//
+// As all the menu items are owned by the root menu item, care must be taken
+// such that when MenuHostRootView is deleted it doesn't delete the menu items.
+
+class MenuHostRootView : public RootView {
+ public:
+  explicit MenuHostRootView(Widget* widget,
+                            SubmenuView* submenu)
+      : RootView(widget),
+        submenu_(submenu),
+        forward_drag_to_menu_controller_(true),
+        suspend_events_(false) {
+#ifdef DEBUG_MENU
+  DLOG(INFO) << " new MenuHostRootView " << this;
+#endif
+  }
+
+  virtual bool OnMousePressed(const MouseEvent& event) {
+    if (suspend_events_)
+      return true;
+
+    forward_drag_to_menu_controller_ =
+        ((event.x() < 0 || event.y() < 0 || event.x() >= width() ||
+          event.y() >= height()) ||
+         !RootView::OnMousePressed(event));
+    if (forward_drag_to_menu_controller_)
+      GetMenuController()->OnMousePressed(submenu_, event);
+    return true;
+  }
+
+  virtual bool OnMouseDragged(const MouseEvent& event) {
+    if (suspend_events_)
+      return true;
+
+    if (forward_drag_to_menu_controller_) {
+#ifdef DEBUG_MENU
+      DLOG(INFO) << " MenuHostRootView::OnMouseDragged source=" << submenu_;
+#endif
+      GetMenuController()->OnMouseDragged(submenu_, event);
+      return true;
+    }
+    return RootView::OnMouseDragged(event);
+  }
+
+  virtual void OnMouseReleased(const MouseEvent& event, bool canceled) {
+    if (suspend_events_)
+      return;
+
+    RootView::OnMouseReleased(event, canceled);
+    if (forward_drag_to_menu_controller_) {
+      forward_drag_to_menu_controller_ = false;
+      if (canceled) {
+        GetMenuController()->Cancel(true);
+      } else {
+        GetMenuController()->OnMouseReleased(submenu_, event);
+      }
+    }
+  }
+
+  virtual void OnMouseMoved(const MouseEvent& event) {
+    if (suspend_events_)
+      return;
+
+    RootView::OnMouseMoved(event);
+    GetMenuController()->OnMouseMoved(submenu_, event);
+  }
+
+  virtual void ProcessOnMouseExited() {
+    if (suspend_events_)
+      return;
+
+    RootView::ProcessOnMouseExited();
+  }
+
+  virtual bool ProcessMouseWheelEvent(const MouseWheelEvent& e) {
+    // RootView::ProcessMouseWheelEvent forwards to the focused view. We don't
+    // have a focused view, so we need to override this then forward to
+    // the menu.
+    return submenu_->OnMouseWheel(e);
+  }
+
+  void SuspendEvents() {
+    suspend_events_ = true;
+  }
+
+ private:
+  MenuController* GetMenuController() {
+    return submenu_->GetMenuItem()->GetMenuController();
+  }
+
+  // The SubmenuView we contain.
+  SubmenuView* submenu_;
+
+  // Whether mouse dragged/released should be forwarded to the MenuController.
+  bool forward_drag_to_menu_controller_;
+
+  // Whether events are suspended. If true, no events are forwarded to the
+  // MenuController.
+  bool suspend_events_;
+
+  DISALLOW_COPY_AND_ASSIGN(MenuHostRootView);
+};
+
+// MenuHost ------------------------------------------------------------------
+
+// MenuHost is the window responsible for showing a single menu.
+//
+// Similar to MenuHostRootView, care must be taken such that when MenuHost is
+// deleted, it doesn't delete the menu items. MenuHost is closed via a
+// DelayedClosed, which avoids timing issues with deleting the window while
+// capture or events are directed at it.
+
+class MenuHost : public WidgetWin {
+ public:
+  explicit MenuHost(SubmenuView* submenu)
+      : closed_(false),
+        submenu_(submenu),
+        owns_capture_(false) {
+    set_window_style(WS_POPUP);
+    set_initial_class_style(
+        (win_util::GetWinVersion() < win_util::WINVERSION_XP) ?
+        0 : CS_DROPSHADOW);
+    is_mouse_down_ =
+        ((GetKeyState(VK_LBUTTON) & 0x80) ||
+         (GetKeyState(VK_RBUTTON) & 0x80) ||
+         (GetKeyState(VK_MBUTTON) & 0x80) ||
+         (GetKeyState(VK_XBUTTON1) & 0x80) ||
+         (GetKeyState(VK_XBUTTON2) & 0x80));
+    // Mouse clicks shouldn't give us focus.
+    set_window_ex_style(WS_EX_TOPMOST | WS_EX_NOACTIVATE);
+  }
+
+  void Init(HWND parent,
+            const gfx::Rect& bounds,
+            View* contents_view,
+            bool do_capture) {
+    WidgetWin::Init(parent, bounds, true);
+    SetContentsView(contents_view);
+    // We don't want to take focus away from the hosting window.
+    ShowWindow(SW_SHOWNA);
+    owns_capture_ = do_capture;
+    if (do_capture) {
+      SetCapture();
+      has_capture_ = true;
+#ifdef DEBUG_MENU
+      DLOG(INFO) << "Doing capture";
+#endif
+    }
+  }
+
+  virtual void Hide() {
+    if (closed_) {
+      // We're already closed, nothing to do.
+      // This is invoked twice if the first time just hid us, and the second
+      // time deleted Closed (deleted) us.
+      return;
+    }
+    // The menus are freed separately, and possibly before the window is closed,
+    // remove them so that View doesn't try to access deleted objects.
+    static_cast<MenuHostRootView*>(GetRootView())->SuspendEvents();
+    GetRootView()->RemoveAllChildViews(false);
+    closed_ = true;
+    ReleaseCapture();
+    WidgetWin::Hide();
+  }
+
+  virtual void HideWindow() {
+    // Make sure we release capture before hiding.
+    ReleaseCapture();
+    WidgetWin::Hide();
+  }
+
+  virtual void OnCaptureChanged(HWND hwnd) {
+    WidgetWin::OnCaptureChanged(hwnd);
+    owns_capture_ = false;
+#ifdef DEBUG_MENU
+    DLOG(INFO) << "Capture changed";
+#endif
+  }
+
+  void ReleaseCapture() {
+    if (owns_capture_) {
+#ifdef DEBUG_MENU
+      DLOG(INFO) << "released capture";
+#endif
+      owns_capture_ = false;
+      ::ReleaseCapture();
+    }
+  }
+
+ protected:
+  // Overriden to create MenuHostRootView.
+  virtual RootView* CreateRootView() {
+    return new MenuHostRootView(this, submenu_);
+  }
+
+  virtual void OnCancelMode() {
+    if (!closed_) {
+#ifdef DEBUG_MENU
+      DLOG(INFO) << "OnCanceMode, closing menu";
+#endif
+      submenu_->GetMenuItem()->GetMenuController()->Cancel(true);
+    }
+  }
+
+  // Overriden to return false, we do NOT want to release capture on mouse
+  // release.
+  virtual bool ReleaseCaptureOnMouseReleased() {
+    return false;
+  }
+
+ private:
+  // If true, we've been closed.
+  bool closed_;
+
+  // If true, we own the capture and need to release it.
+  bool owns_capture_;
+
+  // The view we contain.
+  SubmenuView* submenu_;
+
+  DISALLOW_COPY_AND_ASSIGN(MenuHost);
+};
+
+// EmptyMenuMenuItem ---------------------------------------------------------
+
+// EmptyMenuMenuItem is used when a menu has no menu items. EmptyMenuMenuItem
+// is itself a MenuItemView, but it uses a different ID so that it isn't
+// identified as a MenuItemView.
+
+class EmptyMenuMenuItem : public MenuItemView {
+ public:
+  // ID used for EmptyMenuMenuItem.
+  static const int kEmptyMenuItemViewID;
+
+  explicit EmptyMenuMenuItem(MenuItemView* parent) :
+      MenuItemView(parent, 0, NORMAL) {
+    SetTitle(l10n_util::GetString(IDS_MENU_EMPTY_SUBMENU));
+    // Set this so that we're not identified as a normal menu item.
+    SetID(kEmptyMenuItemViewID);
+    SetEnabled(false);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EmptyMenuMenuItem);
+};
+
+// static
+const int EmptyMenuMenuItem::kEmptyMenuItemViewID =
+    MenuItemView::kMenuItemViewID + 1;
+
+}  // namespace
+
+// SubmenuView ---------------------------------------------------------------
+
+SubmenuView::SubmenuView(MenuItemView* parent)
+    : parent_menu_item_(parent),
+      host_(NULL),
+      drop_item_(NULL),
+      drop_position_(MenuDelegate::DROP_NONE),
+      scroll_view_container_(NULL) {
+  DCHECK(parent);
+  // We'll delete ourselves, otherwise the ScrollView would delete us on close.
+  SetParentOwned(false);
+}
+
+SubmenuView::~SubmenuView() {
+  // The menu may not have been closed yet (it will be hidden, but not
+  // necessarily closed).
+  Close();
+
+  delete scroll_view_container_;
+}
+
+int SubmenuView::GetMenuItemCount() {
+  int count = 0;
+  for (int i = 0; i < GetChildViewCount(); ++i) {
+    if (GetChildViewAt(i)->GetID() == MenuItemView::kMenuItemViewID)
+      count++;
+  }
+  return count;
+}
+
+MenuItemView* SubmenuView::GetMenuItemAt(int index) {
+  for (int i = 0, count = 0; i < GetChildViewCount(); ++i) {
+    if (GetChildViewAt(i)->GetID() == MenuItemView::kMenuItemViewID &&
+        count++ == index) {
+      return static_cast<MenuItemView*>(GetChildViewAt(i));
+    }
+  }
+  NOTREACHED();
+  return NULL;
+}
+
+void SubmenuView::Layout() {
+  // We're in a ScrollView, and need to set our width/height ourselves.
+  View* parent = GetParent();
+  if (!parent)
+    return;
+  SetBounds(x(), y(), parent->width(), GetPreferredSize().height());
+
+  gfx::Insets insets = GetInsets();
+  int x = insets.left();
+  int y = insets.top();
+  int menu_item_width = width() - insets.width();
+  for (int i = 0; i < GetChildViewCount(); ++i) {
+    View* child = GetChildViewAt(i);
+    gfx::Size child_pref_size = child->GetPreferredSize();
+    child->SetBounds(x, y, menu_item_width, child_pref_size.height());
+    y += child_pref_size.height();
+  }
+}
+
+gfx::Size SubmenuView::GetPreferredSize() {
+  if (GetChildViewCount() == 0)
+    return gfx::Size();
+
+  int max_width = 0;
+  int height = 0;
+  for (int i = 0; i < GetChildViewCount(); ++i) {
+    View* child = GetChildViewAt(i);
+    gfx::Size child_pref_size = child->GetPreferredSize();
+    max_width = std::max(max_width, child_pref_size.width());
+    height += child_pref_size.height();
+  }
+  gfx::Insets insets = GetInsets();
+  return gfx::Size(max_width + insets.width(), height + insets.height());
+}
+
+void SubmenuView::DidChangeBounds(const gfx::Rect& previous,
+                                  const gfx::Rect& current) {
+  SchedulePaint();
+}
+
+void SubmenuView::PaintChildren(ChromeCanvas* canvas) {
+  View::PaintChildren(canvas);
+
+  if (drop_item_ && drop_position_ != MenuDelegate::DROP_ON)
+    PaintDropIndicator(canvas, drop_item_, drop_position_);
+}
+
+bool SubmenuView::CanDrop(const OSExchangeData& data) {
+  DCHECK(GetMenuItem()->GetMenuController());
+  return GetMenuItem()->GetMenuController()->CanDrop(this, data);
+}
+
+void SubmenuView::OnDragEntered(const DropTargetEvent& event) {
+  DCHECK(GetMenuItem()->GetMenuController());
+  GetMenuItem()->GetMenuController()->OnDragEntered(this, event);
+}
+
+int SubmenuView::OnDragUpdated(const DropTargetEvent& event) {
+  DCHECK(GetMenuItem()->GetMenuController());
+  return GetMenuItem()->GetMenuController()->OnDragUpdated(this, event);
+}
+
+void SubmenuView::OnDragExited() {
+  DCHECK(GetMenuItem()->GetMenuController());
+  GetMenuItem()->GetMenuController()->OnDragExited(this);
+}
+
+int SubmenuView::OnPerformDrop(const DropTargetEvent& event) {
+  DCHECK(GetMenuItem()->GetMenuController());
+  return GetMenuItem()->GetMenuController()->OnPerformDrop(this, event);
+}
+
+bool SubmenuView::OnMouseWheel(const MouseWheelEvent& e) {
+  gfx::Rect vis_bounds = GetVisibleBounds();
+  int menu_item_count = GetMenuItemCount();
+  if (vis_bounds.height() == height() || !menu_item_count) {
+    // All menu items are visible, nothing to scroll.
+    return true;
+  }
+
+  // Find the index of the first menu item whose y-coordinate is >= visible
+  // y-coordinate.
+  int first_vis_index = -1;
+  for (int i = 0; i < menu_item_count; ++i) {
+    MenuItemView* menu_item = GetMenuItemAt(i);
+    if (menu_item->y() == vis_bounds.y()) {
+      first_vis_index = i;
+      break;
+    } else if (menu_item->y() > vis_bounds.y()) {
+      first_vis_index = std::max(0, i - 1);
+      break;
+    }
+  }
+  if (first_vis_index == -1)
+    return true;
+
+  // If the first item isn't entirely visible, make it visible, otherwise make
+  // the next/previous one entirely visible.
+  int delta = abs(e.GetOffset() / WHEEL_DELTA);
+  bool scroll_up = (e.GetOffset() > 0);
+  while (delta-- > 0) {
+    int scroll_amount = 0;
+    if (scroll_up) {
+      if (GetMenuItemAt(first_vis_index)->y() == vis_bounds.y()) {
+        if (first_vis_index != 0) {
+          scroll_amount = GetMenuItemAt(first_vis_index - 1)->y() -
+                          vis_bounds.y();
+          first_vis_index--;
+        } else {
+          break;
+        }
+      } else {
+        scroll_amount = GetMenuItemAt(first_vis_index)->y() - vis_bounds.y();
+      }
+    } else {
+      if (first_vis_index + 1 == GetMenuItemCount())
+        break;
+      scroll_amount = GetMenuItemAt(first_vis_index + 1)->y() -
+                      vis_bounds.y();
+      if (GetMenuItemAt(first_vis_index)->y() == vis_bounds.y())
+        first_vis_index++;
+    }
+    ScrollRectToVisible(0, vis_bounds.y() + scroll_amount, vis_bounds.width(),
+                        vis_bounds.height());
+    vis_bounds = GetVisibleBounds();
+  }
+
+  return true;
+}
+
+bool SubmenuView::IsShowing() {
+  return host_ && host_->IsVisible();
+}
+
+void SubmenuView::ShowAt(HWND parent,
+                         const gfx::Rect& bounds,
+                         bool do_capture) {
+  if (host_) {
+    host_->ShowWindow(SW_SHOWNA);
+    return;
+  }
+
+  host_ = new MenuHost(this);
+  // Force construction of the scroll view container.
+  GetScrollViewContainer();
+  // Make sure the first row is visible.
+  ScrollRectToVisible(0, 0, 1, 1);
+  host_->Init(parent, bounds, scroll_view_container_, do_capture);
+}
+
+void SubmenuView::Close() {
+  if (host_) {
+    host_->Close();
+    host_ = NULL;
+  }
+}
+
+void SubmenuView::Hide() {
+  if (host_)
+    host_->HideWindow();
+}
+
+void SubmenuView::ReleaseCapture() {
+  host_->ReleaseCapture();
+}
+
+void SubmenuView::SetDropMenuItem(MenuItemView* item,
+                                  MenuDelegate::DropPosition position) {
+  if (drop_item_ == item && drop_position_ == position)
+    return;
+  SchedulePaintForDropIndicator(drop_item_, drop_position_);
+  drop_item_ = item;
+  drop_position_ = position;
+  SchedulePaintForDropIndicator(drop_item_, drop_position_);
+}
+
+bool SubmenuView::GetShowSelection(MenuItemView* item) {
+  if (drop_item_ == NULL)
+    return true;
+  // Something is being dropped on one of this menus items. Show the
+  // selection if the drop is on the passed in item and the drop position is
+  // ON.
+  return (drop_item_ == item && drop_position_ == MenuDelegate::DROP_ON);
+}
+
+MenuScrollViewContainer* SubmenuView::GetScrollViewContainer() {
+  if (!scroll_view_container_) {
+    scroll_view_container_ = new MenuScrollViewContainer(this);
+    // Otherwise MenuHost would delete us.
+    scroll_view_container_->SetParentOwned(false);
+  }
+  return scroll_view_container_;
+}
+
+void SubmenuView::PaintDropIndicator(ChromeCanvas* canvas,
+                                     MenuItemView* item,
+                                     MenuDelegate::DropPosition position) {
+  if (position == MenuDelegate::DROP_NONE)
+    return;
+
+  gfx::Rect bounds = CalculateDropIndicatorBounds(item, position);
+  canvas->FillRectInt(kDropIndicatorColor, bounds.x(), bounds.y(),
+                      bounds.width(), bounds.height());
+}
+
+void SubmenuView::SchedulePaintForDropIndicator(
+    MenuItemView* item,
+    MenuDelegate::DropPosition position) {
+  if (item == NULL)
+    return;
+
+  if (position == MenuDelegate::DROP_ON) {
+    item->SchedulePaint();
+  } else if (position != MenuDelegate::DROP_NONE) {
+    gfx::Rect bounds = CalculateDropIndicatorBounds(item, position);
+    SchedulePaint(bounds.x(), bounds.y(), bounds.width(), bounds.height());
+  }
+}
+
+gfx::Rect SubmenuView::CalculateDropIndicatorBounds(
+    MenuItemView* item,
+    MenuDelegate::DropPosition position) {
+  DCHECK(position != MenuDelegate::DROP_NONE);
+  gfx::Rect item_bounds = item->bounds();
+  switch (position) {
+    case MenuDelegate::DROP_BEFORE:
+      item_bounds.Offset(0, -kDropIndicatorHeight / 2);
+      item_bounds.set_height(kDropIndicatorHeight);
+      return item_bounds;
+
+    case MenuDelegate::DROP_AFTER:
+      item_bounds.Offset(0, item_bounds.height() - kDropIndicatorHeight / 2);
+      item_bounds.set_height(kDropIndicatorHeight);
+      return item_bounds;
+
+    default:
+      // Don't render anything for on.
+      return gfx::Rect();
+  }
+}
+
+// MenuItemView ---------------------------------------------------------------
+
+//  static
+const int MenuItemView::kMenuItemViewID = 1001;
+
+// static
+bool MenuItemView::allow_task_nesting_during_run_ = false;
+
+MenuItemView::MenuItemView(MenuDelegate* delegate) {
+  // NOTE: don't check the delegate for NULL, UpdateMenuPartSizes supplies a
+  // NULL delegate.
+  Init(NULL, 0, SUBMENU, delegate);
+}
+
+MenuItemView::~MenuItemView() {
+  if (controller_) {
+    // We're currently showing.
+
+    // We can't delete ourselves while we're blocking.
+    DCHECK(!controller_->IsBlockingRun());
+
+    // Invoking Cancel is going to call us back and notify the delegate.
+    // Notifying the delegate from the destructor can be problematic. To avoid
+    // this the delegate is set to NULL.
+    delegate_ = NULL;
+
+    controller_->Cancel(true);
+  }
+  delete submenu_;
+}
+
+void MenuItemView::RunMenuAt(HWND parent,
+                             const gfx::Rect& bounds,
+                             AnchorPosition anchor,
+                             bool has_mnemonics) {
+  PrepareForRun(has_mnemonics);
+
+  int mouse_event_flags;
+
+  MenuController* controller = MenuController::GetActiveInstance();
+  if (controller && !controller->IsBlockingRun()) {
+    // A menu is already showing, but it isn't a blocking menu. Cancel it.
+    // We can get here during drag and drop if the user right clicks on the
+    // menu quickly after the drop.
+    controller->Cancel(true);
+    controller = NULL;
+  }
+  bool owns_controller = false;
+  if (!controller) {
+    // No menus are showing, show one.
+    controller = new MenuController(true);
+    MenuController::SetActiveInstance(controller);
+    owns_controller = true;
+  } else {
+    // A menu is already showing, use the same controller.
+
+    // Don't support blocking from within non-blocking.
+    DCHECK(controller->IsBlockingRun());
+  }
+
+  controller_ = controller;
+
+  // Run the loop.
+  MenuItemView* result =
+      controller->Run(parent, this, bounds, anchor, &mouse_event_flags);
+
+  RemoveEmptyMenus();
+
+  controller_ = NULL;
+
+  if (owns_controller) {
+    // We created the controller and need to delete it.
+    if (MenuController::GetActiveInstance() == controller)
+      MenuController::SetActiveInstance(NULL);
+    delete controller;
+  }
+  // Make sure all the windows we created to show the menus have been
+  // destroyed.
+  DestroyAllMenuHosts();
+  if (result && delegate_)
+    delegate_->ExecuteCommand(result->GetCommand(), mouse_event_flags);
+}
+
+void MenuItemView::RunMenuForDropAt(HWND parent,
+                                    const gfx::Rect& bounds,
+                                    AnchorPosition anchor) {
+  PrepareForRun(false);
+
+  // If there is a menu, hide it so that only one menu is shown during dnd.
+  MenuController* current_controller = MenuController::GetActiveInstance();
+  if (current_controller) {
+    current_controller->Cancel(true);
+  }
+
+  // Always create a new controller for non-blocking.
+  controller_ = new MenuController(false);
+
+  // Set the instance, that way it can be canceled by another menu.
+  MenuController::SetActiveInstance(controller_);
+
+  controller_->Run(parent, this, bounds, anchor, NULL);
+}
+
+void MenuItemView::Cancel() {
+  if (controller_ && !canceled_) {
+    canceled_ = true;
+    controller_->Cancel(true);
+  }
+}
+
+SubmenuView* MenuItemView::CreateSubmenu() {
+  if (!submenu_)
+    submenu_ = new SubmenuView(this);
+  return submenu_;
+}
+
+void MenuItemView::SetSelected(bool selected) {
+  selected_ = selected;
+  SchedulePaint();
+}
+
+void MenuItemView::SetIcon(const SkBitmap& icon, int item_id) {
+  MenuItemView* item = GetDescendantByID(item_id);
+  DCHECK(item);
+  item->SetIcon(icon);
+}
+
+void MenuItemView::SetIcon(const SkBitmap& icon) {
+  icon_ = icon;
+  SchedulePaint();
+}
+
+void MenuItemView::Paint(ChromeCanvas* canvas) {
+  Paint(canvas, false);
+}
+
+gfx::Size MenuItemView::GetPreferredSize() {
+  ChromeFont& font = GetRootMenuItem()->font_;
+  return gfx::Size(
+      font.GetStringWidth(title_) + label_start + item_right_margin,
+      font.height() + GetBottomMargin() + GetTopMargin());
+}
+
+MenuController* MenuItemView::GetMenuController() {
+  return GetRootMenuItem()->controller_;
+}
+
+MenuDelegate* MenuItemView::GetDelegate() {
+  return GetRootMenuItem()->delegate_;
+}
+
+MenuItemView* MenuItemView::GetRootMenuItem() {
+  MenuItemView* item = this;
+  while (item) {
+    MenuItemView* parent = item->GetParentMenuItem();
+    if (!parent)
+      return item;
+    item = parent;
+  }
+  NOTREACHED();
+  return NULL;
+}
+
+wchar_t MenuItemView::GetMnemonic() {
+  if (!has_mnemonics_)
+    return 0;
+
+  const std::wstring& title = GetTitle();
+  size_t index = 0;
+  do {
+    index = title.find('&', index);
+    if (index != std::wstring::npos) {
+      if (index + 1 != title.size() && title[index + 1] != '&')
+        return title[index + 1];
+      index++;
+    }
+  } while (index != std::wstring::npos);
+  return 0;
+}
+
+MenuItemView::MenuItemView(MenuItemView* parent,
+                           int command,
+                           MenuItemView::Type type) {
+  Init(parent, command, type, NULL);
+}
+
+void MenuItemView::Init(MenuItemView* parent,
+                        int command,
+                        MenuItemView::Type type,
+                        MenuDelegate* delegate) {
+  delegate_ = delegate;
+  controller_ = NULL;
+  canceled_ = false;
+  parent_menu_item_ = parent;
+  type_ = type;
+  selected_ = false;
+  command_ = command;
+  submenu_ = NULL;
+  // Assign our ID, this allows SubmenuItemView to find MenuItemViews.
+  SetID(kMenuItemViewID);
+  has_icons_ = false;
+
+  MenuDelegate* root_delegate = GetDelegate();
+  if (root_delegate)
+    SetEnabled(root_delegate->IsCommandEnabled(command));
+}
+
+MenuItemView* MenuItemView::AppendMenuItemInternal(int item_id,
+                                                   const std::wstring& label,
+                                                   const SkBitmap& icon,
+                                                   Type type) {
+  if (!submenu_)
+    CreateSubmenu();
+  if (type == SEPARATOR) {
+    submenu_->AddChildView(new MenuSeparator());
+    return NULL;
+  }
+  MenuItemView* item = new MenuItemView(this, item_id, type);
+  if (label.empty() && GetDelegate())
+    item->SetTitle(GetDelegate()->GetLabel(item_id));
+  else
+    item->SetTitle(label);
+  item->SetIcon(icon);
+  if (type == SUBMENU)
+    item->CreateSubmenu();
+  submenu_->AddChildView(item);
+  return item;
+}
+
+MenuItemView* MenuItemView::GetDescendantByID(int id) {
+  if (GetCommand() == id)
+    return this;
+  if (!HasSubmenu())
+    return NULL;
+  for (int i = 0; i < GetSubmenu()->GetChildViewCount(); ++i) {
+    View* child = GetSubmenu()->GetChildViewAt(i);
+    if (child->GetID() == MenuItemView::kMenuItemViewID) {
+      MenuItemView* result = static_cast<MenuItemView*>(child)->
+          GetDescendantByID(id);
+      if (result)
+        return result;
+    }
+  }
+  return NULL;
+}
+
+void MenuItemView::DropMenuClosed(bool notify_delegate) {
+  DCHECK(controller_);
+  DCHECK(!controller_->IsBlockingRun());
+  if (MenuController::GetActiveInstance() == controller_)
+    MenuController::SetActiveInstance(NULL);
+  delete controller_;
+  controller_ = NULL;
+
+  RemoveEmptyMenus();
+
+  if (notify_delegate && delegate_) {
+    // Our delegate is null when invoked from the destructor.
+    delegate_->DropMenuClosed(this);
+  }
+  // WARNING: its possible the delegate deleted us at this point.
+}
+
+void MenuItemView::PrepareForRun(bool has_mnemonics) {
+  // Currently we only support showing the root.
+  DCHECK(!parent_menu_item_);
+
+  // Don't invoke run from within run on the same menu.
+  DCHECK(!controller_);
+
+  // Force us to have a submenu.
+  CreateSubmenu();
+
+  canceled_ = false;
+
+  has_mnemonics_ = has_mnemonics;
+
+  AddEmptyMenus();
+
+  if (!MenuController::GetActiveInstance()) {
+    // Only update the menu size if there are no menus showing, otherwise
+    // things may shift around.
+    UpdateMenuPartSizes(has_icons_);
+  }
+
+  font_ = GetMenuFont();
+
+  BOOL show_cues;
+  show_mnemonics =
+      (SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &show_cues, 0) &&
+       show_cues == TRUE);
+}
+
+int MenuItemView::GetDrawStringFlags() {
+  int flags = 0;
+  if (UILayoutIsRightToLeft())
+    flags |= ChromeCanvas::TEXT_ALIGN_RIGHT;
+  else
+    flags |= ChromeCanvas::TEXT_ALIGN_LEFT;
+
+  if (has_mnemonics_) {
+    if (show_mnemonics)
+      flags |= ChromeCanvas::SHOW_PREFIX;
+    else
+      flags |= ChromeCanvas::HIDE_PREFIX;
+  }
+  return flags;
+}
+
+void MenuItemView::AddEmptyMenus() {
+  DCHECK(HasSubmenu());
+  if (submenu_->GetChildViewCount() == 0) {
+    submenu_->AddChildView(0, new EmptyMenuMenuItem(this));
+  } else {
+    for (int i = 0, item_count = submenu_->GetMenuItemCount(); i < item_count;
+         ++i) {
+      MenuItemView* child = submenu_->GetMenuItemAt(i);
+      if (child->HasSubmenu())
+        child->AddEmptyMenus();
+    }
+  }
+}
+
+void MenuItemView::RemoveEmptyMenus() {
+  DCHECK(HasSubmenu());
+  // Iterate backwards as we may end up removing views, which alters the child
+  // view count.
+  for (int i = submenu_->GetChildViewCount() - 1; i >= 0; --i) {
+    View* child = submenu_->GetChildViewAt(i);
+    if (child->GetID() == MenuItemView::kMenuItemViewID) {
+      MenuItemView* menu_item = static_cast<MenuItemView*>(child);
+      if (menu_item->HasSubmenu())
+        menu_item->RemoveEmptyMenus();
+    } else if (child->GetID() == EmptyMenuMenuItem::kEmptyMenuItemViewID) {
+      submenu_->RemoveChildView(child);
+    }
+  }
+}
+
+void MenuItemView::AdjustBoundsForRTLUI(RECT* rect) const {
+  gfx::Rect mirrored_rect(*rect);
+  mirrored_rect.set_x(MirroredLeftPointForRect(mirrored_rect));
+  *rect = mirrored_rect.ToRECT();
+}
+
+void MenuItemView::Paint(ChromeCanvas* canvas, bool for_drag) {
+  bool render_selection =
+      (!for_drag && IsSelected() &&
+       parent_menu_item_->GetSubmenu()->GetShowSelection(this));
+  int state = render_selection ? MPI_HOT :
+                                 (IsEnabled() ? MPI_NORMAL : MPI_DISABLED);
+  HDC dc = canvas->beginPlatformPaint();
+
+  // The gutter is rendered before the background.
+  if (render_gutter && !for_drag) {
+    RECT gutter_bounds = { label_start - kGutterToLabel - gutter_width, 0, 0,
+                           height() };
+    gutter_bounds.right = gutter_bounds.left + gutter_width;
+    AdjustBoundsForRTLUI(&gutter_bounds);
+    NativeTheme::instance()->PaintMenuGutter(dc, MENU_POPUPGUTTER, MPI_NORMAL,
+                                             &gutter_bounds);
+  }
+
+  // Render the background.
+  if (!for_drag) {
+    RECT item_bounds = { 0, 0, width(), height() };
+    AdjustBoundsForRTLUI(&item_bounds);
+    NativeTheme::instance()->PaintMenuItemBackground(
+        NativeTheme::MENU, dc, MENU_POPUPITEM, state, render_selection,
+        &item_bounds);
+  }
+
+  int icon_x = kItemLeftMargin;
+  int top_margin = GetTopMargin();
+  int bottom_margin = GetBottomMargin();
+  int icon_y = top_margin + (height() - kItemTopMargin -
+                             bottom_margin - check_height) / 2;
+  int icon_height = check_height;
+  int icon_width = check_width;
+
+  if (type_ == CHECKBOX && GetDelegate()->IsItemChecked(GetCommand())) {
+    // Draw the check background.
+    RECT check_bg_bounds = { 0, 0, icon_x + icon_width, height() };
+    const int bg_state = IsEnabled() ? MCB_NORMAL : MCB_DISABLED;
+    AdjustBoundsForRTLUI(&check_bg_bounds);
+    NativeTheme::instance()->PaintMenuCheckBackground(
+        NativeTheme::MENU, dc, MENU_POPUPCHECKBACKGROUND, bg_state,
+        &check_bg_bounds);
+
+    // And the check.
+    RECT check_bounds = { icon_x, icon_y, icon_x + icon_width,
+                          icon_y + icon_height };
+    const int check_state = IsEnabled() ? MC_CHECKMARKNORMAL :
+                                          MC_CHECKMARKDISABLED;
+    AdjustBoundsForRTLUI(&check_bounds);
+    NativeTheme::instance()->PaintMenuCheck(
+        NativeTheme::MENU, dc, MENU_POPUPCHECK, check_state, &check_bounds,
+        render_selection);
+  }
+
+  // Render the foreground.
+  // Menu color is specific to Vista, fallback to classic colors if can't
+  // get color.
+  int default_sys_color = render_selection ? COLOR_HIGHLIGHTTEXT :
+      (IsEnabled() ? COLOR_MENUTEXT : COLOR_GRAYTEXT);
+  SkColor fg_color = NativeTheme::instance()->GetThemeColorWithDefault(
+      NativeTheme::MENU, MENU_POPUPITEM, state, TMT_TEXTCOLOR,
+      default_sys_color);
+  int width = this->width() - item_right_margin - label_start;
+  ChromeFont& font = GetRootMenuItem()->font_;
+  gfx::Rect text_bounds(label_start, top_margin, width, font.height());
+  text_bounds.set_x(MirroredLeftPointForRect(text_bounds));
+  if (for_drag) {
+    // With different themes, it's difficult to tell what the correct foreground
+    // and background colors are for the text to draw the correct halo. Instead,
+    // just draw black on white, which will look good in most cases.
+    canvas->DrawStringWithHalo(GetTitle(), font, 0x00000000, 0xFFFFFFFF,
+                               text_bounds.x(), text_bounds.y(),
+                               text_bounds.width(), text_bounds.height(),
+                               GetRootMenuItem()->GetDrawStringFlags());
+  } else {
+    canvas->DrawStringInt(GetTitle(), font, fg_color,
+                          text_bounds.x(), text_bounds.y(), text_bounds.width(),
+                          text_bounds.height(),
+                          GetRootMenuItem()->GetDrawStringFlags());
+  }
+
+  if (icon_.width() > 0) {
+    gfx::Rect icon_bounds(kItemLeftMargin,
+                          top_margin + (height() - top_margin -
+                          bottom_margin - icon_.height()) / 2,
+                          icon_.width(),
+                          icon_.height());
+    icon_bounds.set_x(MirroredLeftPointForRect(icon_bounds));
+    canvas->DrawBitmapInt(icon_, icon_bounds.x(), icon_bounds.y());
+  }
+
+  if (HasSubmenu()) {
+    int state_id = IsEnabled() ? MSM_NORMAL : MSM_DISABLED;
+    RECT arrow_bounds = {
+        this->width() - item_right_margin + kLabelToArrowPadding,
+        0,
+        0,
+        height()
+    };
+    arrow_bounds.right = arrow_bounds.left + arrow_width;
+    AdjustBoundsForRTLUI(&arrow_bounds);
+
+    // If our sub menus open from right to left (which is the case when the
+    // locale is RTL) then we should make sure the menu arrow points to the
+    // right direction.
+    NativeTheme::MenuArrowDirection arrow_direction;
+    if (UILayoutIsRightToLeft())
+      arrow_direction = NativeTheme::LEFT_POINTING_ARROW;
+    else
+      arrow_direction = NativeTheme::RIGHT_POINTING_ARROW;
+
+    NativeTheme::instance()->PaintMenuArrow(
+        NativeTheme::MENU, dc, MENU_POPUPSUBMENU, state_id, &arrow_bounds,
+        arrow_direction, render_selection);
+  }
+  canvas->endPlatformPaint();
+}
+
+void MenuItemView::DestroyAllMenuHosts() {
+  if (!HasSubmenu())
+    return;
+
+  submenu_->Close();
+  for (int i = 0, item_count = submenu_->GetMenuItemCount(); i < item_count;
+       ++i) {
+    submenu_->GetMenuItemAt(i)->DestroyAllMenuHosts();
+  }
+}
+
+int MenuItemView::GetTopMargin() {
+  MenuItemView* root = GetRootMenuItem();
+  return root && root->has_icons_ ? kItemTopMargin : kItemNoIconTopMargin;
+}
+
+int MenuItemView::GetBottomMargin() {
+  MenuItemView* root = GetRootMenuItem();
+  return root && root->has_icons_ ?
+      kItemBottomMargin : kItemNoIconBottomMargin;
+}
+
+// MenuController ------------------------------------------------------------
+
+// static
+MenuController* MenuController::active_instance_ = NULL;
+
+// static
+MenuController* MenuController::GetActiveInstance() {
+  return active_instance_;
+}
+
+#ifdef DEBUG_MENU
+static int instance_count = 0;
+static int nested_depth = 0;
+#endif
+
+MenuItemView* MenuController::Run(HWND parent,
+                                  MenuItemView* root,
+                                  const gfx::Rect& bounds,
+                                  MenuItemView::AnchorPosition position,
+                                  int* result_mouse_event_flags) {
+  exit_all_ = false;
+  possible_drag_ = false;
+
+  bool nested_menu = showing_;
+  if (showing_) {
+    // Only support nesting of blocking_run menus, nesting of
+    // blocking/non-blocking shouldn't be needed.
+    DCHECK(blocking_run_);
+
+    // We're already showing, push the current state.
+    menu_stack_.push_back(state_);
+
+    // The context menu should be owned by the same parent.
+    DCHECK(owner_ == parent);
+  } else {
+    showing_ = true;
+  }
+
+  // Reset current state.
+  pending_state_ = State();
+  state_ = State();
+  pending_state_.initial_bounds = bounds;
+  if (bounds.height() > 1) {
+    // Inset the bounds slightly, otherwise drag coordinates don't line up
+    // nicely and menus close prematurely.
+    pending_state_.initial_bounds.Inset(0, 1);
+  }
+  pending_state_.anchor = position;
+  owner_ = parent;
+
+  // Calculate the bounds of the monitor we'll show menus on. Do this once to
+  // avoid repeated system queries for the info.
+  POINT initial_loc = { bounds.x(), bounds.y() };
+  HMONITOR monitor = MonitorFromPoint(initial_loc, MONITOR_DEFAULTTONEAREST);
+  if (monitor) {
+    MONITORINFO mi = {0};
+    mi.cbSize = sizeof(mi);
+    GetMonitorInfo(monitor, &mi);
+    // Menus appear over the taskbar.
+    pending_state_.monitor_bounds = gfx::Rect(mi.rcMonitor);
+  }
+
+  // Set the selection, which opens the initial menu.
+  SetSelection(root, true, true);
+
+  if (!blocking_run_) {
+    // Start the timer to hide the menu. This is needed as we get no
+    // notification when the drag has finished.
+    StartCancelAllTimer();
+    return NULL;
+  }
+
+#ifdef DEBUG_MENU
+  nested_depth++;
+  DLOG(INFO) << " entering nested loop, depth=" << nested_depth;
+#endif
+
+  MessageLoopForUI* loop = MessageLoopForUI::current();
+  if (MenuItemView::allow_task_nesting_during_run_) {
+    bool did_allow_task_nesting = loop->NestableTasksAllowed();
+    loop->SetNestableTasksAllowed(true);
+    loop->Run(this);
+    loop->SetNestableTasksAllowed(did_allow_task_nesting);
+  } else {
+    loop->Run(this);
+  }
+
+#ifdef DEBUG_MENU
+  nested_depth--;
+  DLOG(INFO) << " exiting nested loop,  depth=" << nested_depth;
+#endif
+
+  // Close any open menus.
+  SetSelection(NULL, false, true);
+
+  if (nested_menu) {
+    DCHECK(!menu_stack_.empty());
+    // We're running from within a menu, restore the previous state.
+    // The menus are already showing, so we don't have to show them.
+    state_ = menu_stack_.back();
+    pending_state_ = menu_stack_.back();
+    menu_stack_.pop_back();
+  } else {
+    showing_ = false;
+    did_capture_ = false;
+  }
+
+  MenuItemView* result = result_;
+  // In case we're nested, reset result_.
+  result_ = NULL;
+
+  if (result_mouse_event_flags)
+    *result_mouse_event_flags = result_mouse_event_flags_;
+
+  if (nested_menu && result) {
+    // We're nested and about to return a value. The caller might enter another
+    // blocking loop. We need to make sure all menus are hidden before that
+    // happens otherwise the menus will stay on screen.
+    CloseAllNestedMenus();
+
+    // Set exit_all_ to true, which makes sure all nested loops exit
+    // immediately.
+    exit_all_ = true;
+  }
+
+  return result;
+}
+
+void MenuController::SetSelection(MenuItemView* menu_item,
+                                  bool open_submenu,
+                                  bool update_immediately) {
+  size_t paths_differ_at = 0;
+  std::vector<MenuItemView*> current_path;
+  std::vector<MenuItemView*> new_path;
+  BuildPathsAndCalculateDiff(pending_state_.item, menu_item, &current_path,
+                             &new_path, &paths_differ_at);
+
+  size_t current_size = current_path.size();
+  size_t new_size = new_path.size();
+
+  // Notify the old path it isn't selected.
+  for (size_t i = paths_differ_at; i < current_size; ++i)
+    current_path[i]->SetSelected(false);
+
+  // Notify the new path it is selected.
+  for (size_t i = paths_differ_at; i < new_size; ++i)
+    new_path[i]->SetSelected(true);
+
+  if (menu_item && menu_item->GetDelegate())
+    menu_item->GetDelegate()->SelectionChanged(menu_item);
+
+  pending_state_.item = menu_item;
+  pending_state_.submenu_open = open_submenu;
+
+  // Stop timers.
+  StopShowTimer();
+  StopCancelAllTimer();
+
+  if (update_immediately)
+    CommitPendingSelection();
+  else
+    StartShowTimer();
+}
+
+void MenuController::Cancel(bool all) {
+  if (!showing_) {
+    // This occurs if we're in the process of notifying the delegate for a drop
+    // and the delegate cancels us.
+    return;
+  }
+
+  MenuItemView* selected = state_.item;
+  exit_all_ = all;
+
+  // Hide windows immediately.
+  SetSelection(NULL, false, true);
+
+  if (!blocking_run_) {
+    // If we didn't block the caller we need to notify the menu, which
+    // triggers deleting us.
+    DCHECK(selected);
+    showing_ = false;
+    selected->GetRootMenuItem()->DropMenuClosed(true);
+    // WARNING: the call to MenuClosed deletes us.
+    return;
+  }
+}
+
+void MenuController::OnMousePressed(SubmenuView* source,
+                                    const MouseEvent& event) {
+#ifdef DEBUG_MENU
+  DLOG(INFO) << "OnMousePressed source=" << source;
+#endif
+  if (!blocking_run_)
+    return;
+
+  MenuPart part =
+      GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+  if (part.is_scroll())
+    return;  // Ignore presses on scroll buttons.
+
+  if (part.type == MenuPart::NONE ||
+      (part.type == MenuPart::MENU_ITEM && part.menu &&
+       part.menu->GetRootMenuItem() != state_.item->GetRootMenuItem())) {
+    // Mouse wasn't pressed over any menu, or the active menu, cancel.
+
+    // We're going to close and we own the mouse capture. We need to repost the
+    // mouse down, otherwise the window the user clicked on won't get the
+    // event.
+    RepostEvent(source, event);
+
+    // And close.
+    Cancel(true);
+    return;
+  }
+
+  bool open_submenu = false;
+  if (!part.menu) {
+    part.menu = source->GetMenuItem();
+    open_submenu = true;
+  } else {
+    if (part.menu->GetDelegate()->CanDrag(part.menu)) {
+      possible_drag_ = true;
+      press_x_ = event.x();
+      press_y_ = event.y();
+    }
+    if (part.menu->HasSubmenu())
+      open_submenu = true;
+  }
+  // On a press we immediately commit the selection, that way a submenu
+  // pops up immediately rather than after a delay.
+  SetSelection(part.menu, open_submenu, true);
+}
+
+void MenuController::OnMouseDragged(SubmenuView* source,
+                                    const MouseEvent& event) {
+#ifdef DEBUG_MENU
+  DLOG(INFO) << "OnMouseDragged source=" << source;
+#endif
+  MenuPart part =
+      GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+  UpdateScrolling(part);
+
+  if (!blocking_run_)
+    return;
+
+  if (possible_drag_) {
+    if (View::ExceededDragThreshold(event.x() - press_x_,
+                                    event.y() - press_y_)) {
+      MenuItemView* item = state_.item;
+      DCHECK(item);
+      // Points are in the coordinates of the submenu, need to map to that of
+      // the selected item. Additionally source may not be the parent of
+      // the selected item, so need to map to screen first then to item.
+      gfx::Point press_loc(press_x_, press_y_);
+      View::ConvertPointToScreen(source->GetScrollViewContainer(), &press_loc);
+      View::ConvertPointToView(NULL, item, &press_loc);
+      gfx::Point drag_loc(event.location());
+      View::ConvertPointToScreen(source->GetScrollViewContainer(), &drag_loc);
+      View::ConvertPointToView(NULL, item, &drag_loc);
+      ChromeCanvas canvas(item->width(), item->height(), false);
+      item->Paint(&canvas, true);
+
+      scoped_refptr<OSExchangeData> data(new OSExchangeData);
+      item->GetDelegate()->WriteDragData(item, data.get());
+      drag_utils::SetDragImageOnDataObject(canvas, item->width(),
+                                           item->height(), press_loc.x(),
+                                           press_loc.y(), data);
+
+      scoped_refptr<BaseDragSource> drag_source(new BaseDragSource);
+      int drag_ops = item->GetDelegate()->GetDragOperations(item);
+      DWORD effects;
+      StopScrolling();
+      DoDragDrop(data, drag_source,
+                 DragDropTypes::DragOperationToDropEffect(drag_ops),
+                 &effects);
+      if (GetActiveInstance() == this) {
+        if (showing_) {
+          // We're still showing, close all menus.
+          CloseAllNestedMenus();
+          Cancel(true);
+        }  // else case, drop was on us.
+      }  // else case, someone canceled us, don't do anything
+    }
+    return;
+  }
+  if (part.type == MenuPart::MENU_ITEM) {
+    if (!part.menu)
+      part.menu = source->GetMenuItem();
+    SetSelection(part.menu ? part.menu : state_.item, true, false);
+  }
+}
+
+void MenuController::OnMouseReleased(SubmenuView* source,
+                                     const MouseEvent& event) {
+#ifdef DEBUG_MENU
+  DLOG(INFO) << "OnMouseReleased source=" << source;
+#endif
+  if (!blocking_run_)
+    return;
+
+  DCHECK(state_.item);
+  possible_drag_ = false;
+  DCHECK(blocking_run_);
+  MenuPart part =
+      GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+  if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM &&
+                                     part.menu)) {
+    // Set the selection immediately, making sure the submenu is only open
+    // if it already was.
+    bool open_submenu = (state_.item == pending_state_.item &&
+                         state_.submenu_open);
+    SetSelection(pending_state_.item, open_submenu, true);
+    gfx::Point loc(event.location());
+    View::ConvertPointToScreen(source->GetScrollViewContainer(), &loc);
+
+    // If we open a context menu just return now
+    if (part.menu->GetDelegate()->ShowContextMenu(
+        part.menu, part.menu->GetCommand(), loc.x(), loc.y(), true))
+      return;
+  }
+
+  if (!part.is_scroll() && part.menu && !part.menu->HasSubmenu()) {
+    if (part.menu->GetDelegate()->IsTriggerableEvent(event)) {
+      Accept(part.menu, event.GetFlags());
+      return;
+    }
+  } else if (part.type == MenuPart::MENU_ITEM) {
+    // User either clicked on empty space, or a menu that has children.
+    SetSelection(part.menu ? part.menu : state_.item, true, true);
+  }
+}
+
+void MenuController::OnMouseMoved(SubmenuView* source,
+                                  const MouseEvent& event) {
+#ifdef DEBUG_MENU
+  DLOG(INFO) << "OnMouseMoved source=" << source;
+#endif
+  if (showing_submenu_)
+    return;
+
+  MenuPart part =
+      GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+
+  UpdateScrolling(part);
+
+  if (!blocking_run_)
+    return;
+
+  if (part.type == MenuPart::MENU_ITEM && part.menu) {
+    SetSelection(part.menu, true, false);
+  } else if (!part.is_scroll() && pending_state_.item &&
+             (!pending_state_.item->HasSubmenu() ||
+              !pending_state_.item->GetSubmenu()->IsShowing())) {
+    // On exit if the user hasn't selected an item with a submenu, move the
+    // selection back to the parent menu item.
+    SetSelection(pending_state_.item->GetParentMenuItem(), true, false);
+  }
+}
+
+void MenuController::OnMouseEntered(SubmenuView* source,
+                                    const MouseEvent& event) {
+  // MouseEntered is always followed by a mouse moved, so don't need to
+  // do anything here.
+}
+
+bool MenuController::CanDrop(SubmenuView* source, const OSExchangeData& data) {
+  return source->GetMenuItem()->GetDelegate()->CanDrop(source->GetMenuItem(),
+                                                       data);
+}
+
+void MenuController::OnDragEntered(SubmenuView* source,
+                                   const DropTargetEvent& event) {
+  valid_drop_coordinates_ = false;
+}
+
+int MenuController::OnDragUpdated(SubmenuView* source,
+                                  const DropTargetEvent& event) {
+  StopCancelAllTimer();
+
+  gfx::Point screen_loc(event.location());
+  View::ConvertPointToScreen(source, &screen_loc);
+  if (valid_drop_coordinates_ && screen_loc.x() == drop_x_ &&
+      screen_loc.y() == drop_y_) {
+    return last_drop_operation_;
+  }
+  drop_x_ = screen_loc.x();
+  drop_y_ = screen_loc.y();
+  valid_drop_coordinates_ = true;
+
+  MenuItemView* menu_item = GetMenuItemAt(source, event.x(), event.y());
+  bool over_empty_menu = false;
+  if (!menu_item) {
+    // See if we're over an empty menu.
+    menu_item = GetEmptyMenuItemAt(source, event.x(), event.y());
+    if (menu_item)
+      over_empty_menu = true;
+  }
+  MenuDelegate::DropPosition drop_position = MenuDelegate::DROP_NONE;
+  int drop_operation = DragDropTypes::DRAG_NONE;
+  if (menu_item) {
+    gfx::Point menu_item_loc(event.location());
+    View::ConvertPointToView(source, menu_item, &menu_item_loc);
+    MenuItemView* query_menu_item;
+    if (!over_empty_menu) {
+      int menu_item_height = menu_item->height();
+      if (menu_item->HasSubmenu() &&
+          (menu_item_loc.y() > kDropBetweenPixels &&
+           menu_item_loc.y() < (menu_item_height - kDropBetweenPixels))) {
+        drop_position = MenuDelegate::DROP_ON;
+      } else if (menu_item_loc.y() < menu_item_height / 2) {
+        drop_position = MenuDelegate::DROP_BEFORE;
+      } else {
+        drop_position = MenuDelegate::DROP_AFTER;
+      }
+      query_menu_item = menu_item;
+    } else {
+      query_menu_item = menu_item->GetParentMenuItem();
+      drop_position = MenuDelegate::DROP_ON;
+    }
+    drop_operation = menu_item->GetDelegate()->GetDropOperation(
+        query_menu_item, event, &drop_position);
+
+    if (menu_item->HasSubmenu()) {
+      // The menu has a submenu, schedule the submenu to open.
+      SetSelection(menu_item, true, false);
+    } else {
+      SetSelection(menu_item, false, false);
+    }
+
+    if (drop_position == MenuDelegate::DROP_NONE ||
+        drop_operation == DragDropTypes::DRAG_NONE) {
+      menu_item = NULL;
+    }
+  } else {
+    SetSelection(source->GetMenuItem(), true, false);
+  }
+  SetDropMenuItem(menu_item, drop_position);
+  last_drop_operation_ = drop_operation;
+  return drop_operation;
+}
+
+void MenuController::OnDragExited(SubmenuView* source) {
+  StartCancelAllTimer();
+
+  if (drop_target_) {
+    StopShowTimer();
+    SetDropMenuItem(NULL, MenuDelegate::DROP_NONE);
+  }
+}
+
+int MenuController::OnPerformDrop(SubmenuView* source,
+                                  const DropTargetEvent& event) {
+  DCHECK(drop_target_);
+  // NOTE: the delegate may delete us after invoking OnPerformDrop, as such
+  // we don't call cancel here.
+
+  MenuItemView* item = state_.item;
+  DCHECK(item);
+
+  MenuItemView* drop_target = drop_target_;
+  MenuDelegate::DropPosition drop_position = drop_position_;
+
+  // Close all menus, including any nested menus.
+  SetSelection(NULL, false, true);
+  CloseAllNestedMenus();
+
+  // Set state such that we exit.
+  showing_ = false;
+  exit_all_ = true;
+
+  if (!IsBlockingRun())
+    item->GetRootMenuItem()->DropMenuClosed(false);
+
+  // WARNING: the call to MenuClosed deletes us.
+
+  // If over an empty menu item, drop occurs on the parent.
+  if (drop_target->GetID() == EmptyMenuMenuItem::kEmptyMenuItemViewID)
+    drop_target = drop_target->GetParentMenuItem();
+
+  return drop_target->GetDelegate()->OnPerformDrop(
+      drop_target, drop_position, event);
+}
+
+void MenuController::OnDragEnteredScrollButton(SubmenuView* source,
+                                               bool is_up) {
+  MenuPart part;
+  part.type = is_up ? MenuPart::SCROLL_UP : MenuPart::SCROLL_DOWN;
+  part.submenu = source;
+  UpdateScrolling(part);
+
+  // Do this to force the selection to hide.
+  SetDropMenuItem(source->GetMenuItemAt(0), MenuDelegate::DROP_NONE);
+
+  StopCancelAllTimer();
+}
+
+void MenuController::OnDragExitedScrollButton(SubmenuView* source) {
+  StartCancelAllTimer();
+  SetDropMenuItem(NULL, MenuDelegate::DROP_NONE);
+  StopScrolling();
+}
+
+// static
+void MenuController::SetActiveInstance(MenuController* controller) {
+  active_instance_ = controller;
+}
+
+bool MenuController::Dispatch(const MSG& msg) {
+  DCHECK(blocking_run_);
+
+  if (exit_all_) {
+    // We must translate/dispatch the message here, otherwise we would drop
+    // the message on the floor.
+    TranslateMessage(&msg);
+    DispatchMessage(&msg);
+    return false;
+  }
+
+  // NOTE: we don't get WM_ACTIVATE or anything else interesting in here.
+  switch (msg.message) {
+    case WM_CONTEXTMENU: {
+      MenuItemView* item = pending_state_.item;
+      if (item && item->GetRootMenuItem() != item) {
+        gfx::Point screen_loc(0, item->height());
+        View::ConvertPointToScreen(item, &screen_loc);
+        item->GetDelegate()->ShowContextMenu(
+            item, item->GetCommand(), screen_loc.x(), screen_loc.y(), false);
+      }
+      return true;
+    }
+
+    // NOTE: focus wasn't changed when the menu was shown. As such, don't
+    // dispatch key events otherwise the focused window will get the events.
+    case WM_KEYDOWN:
+      return OnKeyDown(msg);
+
+    case WM_CHAR:
+      return OnChar(msg);
+
+    case WM_KEYUP:
+      return true;
+
+    case WM_SYSKEYUP:
+      // We may have been shown on a system key, as such don't do anything
+      // here. If another system key is pushed we'll get a WM_SYSKEYDOWN and
+      // close the menu.
+      return true;
+
+    case WM_CANCELMODE:
+    case WM_SYSKEYDOWN:
+      // Exit immediately on system keys.
+      Cancel(true);
+      return false;
+
+    default:
+      break;
+  }
+  TranslateMessage(&msg);
+  DispatchMessage(&msg);
+  return !exit_all_;
+}
+
+bool MenuController::OnKeyDown(const MSG& msg) {
+  DCHECK(blocking_run_);
+
+  switch (msg.wParam) {
+    case VK_UP:
+      IncrementSelection(-1);
+      break;
+
+    case VK_DOWN:
+      IncrementSelection(1);
+      break;
+
+    // Handling of VK_RIGHT and VK_LEFT is different depending on the UI
+    // layout.
+    case VK_RIGHT:
+      if (l10n_util::TextDirection() == l10n_util::RIGHT_TO_LEFT)
+        CloseSubmenu();
+      else
+        OpenSubmenuChangeSelectionIfCan();
+      break;
+
+    case VK_LEFT:
+      if (l10n_util::TextDirection() == l10n_util::RIGHT_TO_LEFT)
+        OpenSubmenuChangeSelectionIfCan();
+      else
+        CloseSubmenu();
+      break;
+
+    case VK_RETURN:
+      if (pending_state_.item) {
+        if (pending_state_.item->HasSubmenu()) {
+          OpenSubmenuChangeSelectionIfCan();
+        } else if (pending_state_.item->IsEnabled()) {
+          Accept(pending_state_.item, 0);
+          return false;
+        }
+      }
+      break;
+
+    case VK_ESCAPE:
+      if (!state_.item->GetParentMenuItem() ||
+          (!state_.item->GetParentMenuItem()->GetParentMenuItem() &&
+           (!state_.item->HasSubmenu() ||
+            !state_.item->GetSubmenu()->IsShowing()))) {
+        // User pressed escape and only one menu is shown, cancel it.
+        Cancel(false);
+        return false;
+      } else {
+        CloseSubmenu();
+      }
+      break;
+
+    case VK_APPS:
+      break;
+
+    default:
+      TranslateMessage(&msg);
+      break;
+  }
+  return true;
+}
+
+bool MenuController::OnChar(const MSG& msg) {
+  DCHECK(blocking_run_);
+
+  return !SelectByChar(static_cast<wchar_t>(msg.wParam));
+}
+
+MenuController::MenuController(bool blocking)
+    : blocking_run_(blocking),
+      showing_(false),
+      exit_all_(false),
+      did_capture_(false),
+      result_(NULL),
+      drop_target_(NULL),
+      owner_(NULL),
+      possible_drag_(false),
+      valid_drop_coordinates_(false),
+      showing_submenu_(false),
+      result_mouse_event_flags_(0) {
+#ifdef DEBUG_MENU
+  instance_count++;
+  DLOG(INFO) << "created MC, count=" << instance_count;
+#endif
+}
+
+MenuController::~MenuController() {
+  DCHECK(!showing_);
+  StopShowTimer();
+  StopCancelAllTimer();
+#ifdef DEBUG_MENU
+  instance_count--;
+  DLOG(INFO) << "destroyed MC, count=" << instance_count;
+#endif
+}
+
+void MenuController::Accept(MenuItemView* item, int mouse_event_flags) {
+  DCHECK(IsBlockingRun());
+  result_ = item;
+  exit_all_ = true;
+  result_mouse_event_flags_ = mouse_event_flags;
+}
+
+void MenuController::CloseAllNestedMenus() {
+  for (std::list<State>::iterator i = menu_stack_.begin();
+       i != menu_stack_.end(); ++i) {
+    MenuItemView* item = i->item;
+    MenuItemView* last_item = item;
+    while (item) {
+      CloseMenu(item);
+      last_item = item;
+      item = item->GetParentMenuItem();
+    }
+    i->submenu_open = false;
+    i->item = last_item;
+  }
+}
+
+MenuItemView* MenuController::GetMenuItemAt(View* source, int x, int y) {
+  View* child_under_mouse = source->GetViewForPoint(gfx::Point(x, y));
+  if (child_under_mouse && child_under_mouse->IsEnabled() &&
+      child_under_mouse->GetID() == MenuItemView::kMenuItemViewID) {
+    return static_cast<MenuItemView*>(child_under_mouse);
+  }
+  return NULL;
+}
+
+MenuItemView* MenuController::GetEmptyMenuItemAt(View* source, int x, int y) {
+  View* child_under_mouse = source->GetViewForPoint(gfx::Point(x, y));
+  if (child_under_mouse &&
+      child_under_mouse->GetID() == EmptyMenuMenuItem::kEmptyMenuItemViewID) {
+    return static_cast<MenuItemView*>(child_under_mouse);
+  }
+  return NULL;
+}
+
+bool MenuController::IsScrollButtonAt(SubmenuView* source,
+                                      int x,
+                                      int y,
+                                      MenuPart::Type* part) {
+  MenuScrollViewContainer* scroll_view = source->GetScrollViewContainer();
+  View* child_under_mouse = scroll_view->GetViewForPoint(gfx::Point(x, y));
+  if (child_under_mouse && child_under_mouse->IsEnabled()) {
+    if (child_under_mouse == scroll_view->scroll_up_button()) {
+      *part = MenuPart::SCROLL_UP;
+      return true;
+    }
+    if (child_under_mouse == scroll_view->scroll_down_button()) {
+      *part = MenuPart::SCROLL_DOWN;
+      return true;
+    }
+  }
+  return false;
+}
+
+MenuController::MenuPart MenuController::GetMenuPartByScreenCoordinate(
+    SubmenuView* source,
+    int source_x,
+    int source_y) {
+  MenuPart part;
+
+  gfx::Point screen_loc(source_x, source_y);
+  View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc);
+
+  MenuItemView* item = state_.item;
+  while (item) {
+    if (item->HasSubmenu() && item->GetSubmenu()->IsShowing() &&
+        GetMenuPartByScreenCoordinateImpl(item->GetSubmenu(), screen_loc,
+                                          &part)) {
+      return part;
+    }
+    item = item->GetParentMenuItem();
+  }
+
+  return part;
+}
+
+bool MenuController::GetMenuPartByScreenCoordinateImpl(
+    SubmenuView* menu,
+    const gfx::Point& screen_loc,
+    MenuPart* part) {
+  // Is the mouse over the scroll buttons?
+  gfx::Point scroll_view_loc = screen_loc;
+  View* scroll_view_container = menu->GetScrollViewContainer();
+  View::ConvertPointToView(NULL, scroll_view_container, &scroll_view_loc);
+  if (scroll_view_loc.x() < 0 ||
+      scroll_view_loc.x() >= scroll_view_container->width() ||
+      scroll_view_loc.y() < 0 ||
+      scroll_view_loc.y() >= scroll_view_container->height()) {
+    // Point isn't contained in menu.
+    return false;
+  }
+  if (IsScrollButtonAt(menu, scroll_view_loc.x(), scroll_view_loc.y(),
+                       &(part->type))) {
+    part->submenu = menu;
+    return true;
+  }
+
+  // Not over the scroll button. Check the actual menu.
+  if (DoesSubmenuContainLocation(menu, screen_loc)) {
+    gfx::Point menu_loc = screen_loc;
+    View::ConvertPointToView(NULL, menu, &menu_loc);
+    part->menu = GetMenuItemAt(menu, menu_loc.x(), menu_loc.y());
+    part->type = MenuPart::MENU_ITEM;
+    return true;
+  }
+
+  // While the mouse isn't over a menu item or the scroll buttons of menu, it
+  // is contained by menu and so we return true. If we didn't return true other
+  // menus would be searched, even though they are likely obscured by us.
+  return true;
+}
+
+bool MenuController::DoesSubmenuContainLocation(SubmenuView* submenu,
+                                                const gfx::Point& screen_loc) {
+  gfx::Point view_loc = screen_loc;
+  View::ConvertPointToView(NULL, submenu, &view_loc);
+  gfx::Rect vis_rect = submenu->GetVisibleBounds();
+  return vis_rect.Contains(view_loc.x(), view_loc.y());
+}
+
+void MenuController::CommitPendingSelection() {
+  StopShowTimer();
+
+  size_t paths_differ_at = 0;
+  std::vector<MenuItemView*> current_path;
+  std::vector<MenuItemView*> new_path;
+  BuildPathsAndCalculateDiff(state_.item, pending_state_.item, &current_path,
+                             &new_path, &paths_differ_at);
+
+  // Hide the old menu.
+  for (size_t i = paths_differ_at; i < current_path.size(); ++i) {
+    if (current_path[i]->HasSubmenu()) {
+      current_path[i]->GetSubmenu()->Hide();
+    }
+  }
+
+  // Copy pending to state_, making sure to preserve the direction menus were
+  // opened.
+  std::list<bool> pending_open_direction;
+  state_.open_leading.swap(pending_open_direction);
+  state_ = pending_state_;
+  state_.open_leading.swap(pending_open_direction);
+
+  int menu_depth = MenuDepth(state_.item);
+  if (menu_depth == 0) {
+    state_.open_leading.clear();
+  } else {
+    int cached_size = static_cast<int>(state_.open_leading.size());
+    DCHECK(menu_depth >= 0);
+    while (cached_size-- >= menu_depth)
+      state_.open_leading.pop_back();
+  }
+
+  if (!state_.item) {
+    // Nothing to select.
+    StopScrolling();
+    return;
+  }
+
+  // Open all the submenus preceeding the last menu item (last menu item is
+  // handled next).
+  if (new_path.size() > 1) {
+    for (std::vector<MenuItemView*>::iterator i = new_path.begin();
+         i != new_path.end() - 1; ++i) {
+      OpenMenu(*i);
+    }
+  }
+
+  if (state_.submenu_open) {
+    // The submenu should be open, open the submenu if the item has a submenu.
+    if (state_.item->HasSubmenu()) {
+      OpenMenu(state_.item);
+    } else {
+      state_.submenu_open = false;
+    }
+  } else if (state_.item->HasSubmenu() &&
+             state_.item->GetSubmenu()->IsShowing()) {
+    state_.item->GetSubmenu()->Hide();
+  }
+
+  if (scroll_task_.get() && scroll_task_->submenu()) {
+    // Stop the scrolling if none of the elements of the selection contain
+    // the menu being scrolled.
+    bool found = false;
+    MenuItemView* item = state_.item;
+    while (item && !found) {
+      found = (item->HasSubmenu() && item->GetSubmenu()->IsShowing() &&
+               item->GetSubmenu() == scroll_task_->submenu());
+      item = item->GetParentMenuItem();
+    }
+    if (!found)
+      StopScrolling();
+  }
+}
+
+void MenuController::CloseMenu(MenuItemView* item) {
+  DCHECK(item);
+  if (!item->HasSubmenu())
+    return;
+  item->GetSubmenu()->Hide();
+}
+
+void MenuController::OpenMenu(MenuItemView* item) {
+  DCHECK(item);
+  if (item->GetSubmenu()->IsShowing()) {
+    return;
+  }
+
+  bool prefer_leading =
+      state_.open_leading.empty() ? true : state_.open_leading.back();
+  bool resulting_direction;
+  gfx::Rect bounds =
+      CalculateMenuBounds(item, prefer_leading, &resulting_direction);
+  state_.open_leading.push_back(resulting_direction);
+  bool do_capture = (!did_capture_ && blocking_run_);
+  showing_submenu_ = true;
+  item->GetSubmenu()->ShowAt(owner_, bounds, do_capture);
+  showing_submenu_ = false;
+  did_capture_ = true;
+}
+
+void MenuController::BuildPathsAndCalculateDiff(
+    MenuItemView* old_item,
+    MenuItemView* new_item,
+    std::vector<MenuItemView*>* old_path,
+    std::vector<MenuItemView*>* new_path,
+    size_t* first_diff_at) {
+  DCHECK(old_path && new_path && first_diff_at);
+  BuildMenuItemPath(old_item, old_path);
+  BuildMenuItemPath(new_item, new_path);
+
+  size_t common_size = std::min(old_path->size(), new_path->size());
+
+  // Find the first difference between the two paths, when the loop
+  // returns, diff_i is the first index where the two paths differ.
+  for (size_t i = 0; i < common_size; ++i) {
+    if ((*old_path)[i] != (*new_path)[i]) {
+      *first_diff_at = i;
+      return;
+    }
+  }
+
+  *first_diff_at = common_size;
+}
+
+void MenuController::BuildMenuItemPath(MenuItemView* item,
+                                       std::vector<MenuItemView*>* path) {
+  if (!item)
+    return;
+  BuildMenuItemPath(item->GetParentMenuItem(), path);
+  path->push_back(item);
+}
+
+void MenuController::StartShowTimer() {
+  show_timer_.Start(TimeDelta::FromMilliseconds(kShowDelay), this,
+                    &MenuController::CommitPendingSelection);
+}
+
+void MenuController::StopShowTimer() {
+  show_timer_.Stop();
+}
+
+void MenuController::StartCancelAllTimer() {
+  cancel_all_timer_.Start(TimeDelta::FromMilliseconds(kCloseOnExitTime),
+                          this, &MenuController::CancelAll);
+}
+
+void MenuController::StopCancelAllTimer() {
+  cancel_all_timer_.Stop();
+}
+
+gfx::Rect MenuController::CalculateMenuBounds(MenuItemView* item,
+                                              bool prefer_leading,
+                                              bool* is_leading) {
+  DCHECK(item);
+
+  SubmenuView* submenu = item->GetSubmenu();
+  DCHECK(submenu);
+
+  gfx::Size pref = submenu->GetScrollViewContainer()->GetPreferredSize();
+
+  // Don't let the menu go to wide. This is some where between what IE and FF
+  // do.
+  pref.set_width(std::min(pref.width(), kMaxMenuWidth));
+  if (!state_.monitor_bounds.IsEmpty())
+    pref.set_width(std::min(pref.width(), state_.monitor_bounds.width()));
+
+  // Assume we can honor prefer_leading.
+  *is_leading = prefer_leading;
+
+  int x, y;
+
+  if (!item->GetParentMenuItem()) {
+    // First item, position relative to initial location.
+    x = state_.initial_bounds.x();
+    y = state_.initial_bounds.bottom();
+    if (state_.anchor == MenuItemView::TOPRIGHT)
+      x = x + state_.initial_bounds.width() - pref.width();
+    if (!state_.monitor_bounds.IsEmpty() &&
+        y + pref.height() > state_.monitor_bounds.bottom()) {
+      // The menu doesn't fit on screen. If the first location is above the
+      // half way point, show from the mouse location to bottom of screen.
+      // Otherwise show from the top of the screen to the location of the mouse.
+      // While odd, this behavior matches IE.
+      if (y < (state_.monitor_bounds.y() +
+               state_.monitor_bounds.height() / 2)) {
+        pref.set_height(std::min(pref.height(),
+                                 state_.monitor_bounds.bottom() - y));
+      } else {
+        pref.set_height(std::min(pref.height(),
+            state_.initial_bounds.y() - state_.monitor_bounds.y()));
+        y = state_.initial_bounds.y() - pref.height();
+      }
+    }
+  } else {
+    // Not the first menu; position it relative to the bounds of the menu
+    // item.
+    gfx::Point item_loc;
+    View::ConvertPointToScreen(item, &item_loc);
+
+    // We must make sure we take into account the UI layout. If the layout is
+    // RTL, then a 'leading' menu is positioned to the left of the parent menu
+    // item and not to the right.
+    bool layout_is_rtl = item->UILayoutIsRightToLeft();
+    bool create_on_the_right = (prefer_leading && !layout_is_rtl) ||
+                               (!prefer_leading && layout_is_rtl);
+
+    if (create_on_the_right) {
+      x = item_loc.x() + item->width() - kSubmenuHorizontalInset;
+      if (state_.monitor_bounds.width() != 0 &&
+          x + pref.width() > state_.monitor_bounds.right()) {
+        if (layout_is_rtl)
+          *is_leading = true;
+        else
+          *is_leading = false;
+        x = item_loc.x() - pref.width() + kSubmenuHorizontalInset;
+      }
+    } else {
+      x = item_loc.x() - pref.width() + kSubmenuHorizontalInset;
+      if (state_.monitor_bounds.width() != 0 && x < state_.monitor_bounds.x()) {
+        if (layout_is_rtl)
+          *is_leading = false;
+        else
+          *is_leading = true;
+        x = item_loc.x() + item->width() - kSubmenuHorizontalInset;
+      }
+    }
+    y = item_loc.y() - kSubmenuBorderSize;
+    if (state_.monitor_bounds.width() != 0) {
+      pref.set_height(std::min(pref.height(), state_.monitor_bounds.height()));
+      if (y + pref.height() > state_.monitor_bounds.bottom())
+        y = state_.monitor_bounds.bottom() - pref.height();
+      if (y < state_.monitor_bounds.y())
+        y = state_.monitor_bounds.y();
+    }
+  }
+
+  if (state_.monitor_bounds.width() != 0) {
+    if (x + pref.width() > state_.monitor_bounds.right())
+      x = state_.monitor_bounds.right() - pref.width();
+    if (x < state_.monitor_bounds.x())
+      x = state_.monitor_bounds.x();
+  }
+  return gfx::Rect(x, y, pref.width(), pref.height());
+}
+
+// static
+int MenuController::MenuDepth(MenuItemView* item) {
+  if (!item)
+    return 0;
+  return MenuDepth(item->GetParentMenuItem()) + 1;
+}
+
+void MenuController::IncrementSelection(int delta) {
+  MenuItemView* item = pending_state_.item;
+  DCHECK(item);
+  if (pending_state_.submenu_open && item->HasSubmenu() &&
+      item->GetSubmenu()->IsShowing()) {
+    // A menu is selected and open, but none of its children are selected,
+    // select the first menu item.
+    if (item->GetSubmenu()->GetMenuItemCount()) {
+      SetSelection(item->GetSubmenu()->GetMenuItemAt(0), false, false);
+      ScrollToVisible(item->GetSubmenu()->GetMenuItemAt(0));
+      return;  // return so else case can fall through.
+    }
+  }
+  if (item->GetParentMenuItem()) {
+    MenuItemView* parent = item->GetParentMenuItem();
+    int parent_count = parent->GetSubmenu()->GetMenuItemCount();
+    if (parent_count > 1) {
+      for (int i = 0; i < parent_count; ++i) {
+        if (parent->GetSubmenu()->GetMenuItemAt(i) == item) {
+          int next_index = (i + delta + parent_count) % parent_count;
+          ScrollToVisible(parent->GetSubmenu()->GetMenuItemAt(next_index));
+          SetSelection(parent->GetSubmenu()->GetMenuItemAt(next_index), false,
+                       false);
+          break;
+        }
+      }
+    }
+  }
+}
+
+void MenuController::OpenSubmenuChangeSelectionIfCan() {
+  MenuItemView* item = pending_state_.item;
+  if (item->HasSubmenu()) {
+    if (item->GetSubmenu()->GetMenuItemCount() > 0) {
+      SetSelection(item->GetSubmenu()->GetMenuItemAt(0), false, true);
+    } else {
+      // No menu items, just show the sub-menu.
+      SetSelection(item, true, true);
+    }
+  }
+}
+
+void MenuController::CloseSubmenu() {
+  MenuItemView* item = state_.item;
+  DCHECK(item);
+  if (!item->GetParentMenuItem())
+    return;
+  if (item->HasSubmenu() && item->GetSubmenu()->IsShowing()) {
+    SetSelection(item, false, true);
+  } else if (item->GetParentMenuItem()->GetParentMenuItem()) {
+    SetSelection(item->GetParentMenuItem(), false, true);
+  }
+}
+
+bool MenuController::IsMenuWindow(MenuItemView* item, HWND window) {
+  if (!item)
+    return false;
+  return ((item->HasSubmenu() && item->GetSubmenu()->IsShowing() &&
+           item->GetSubmenu()->GetWidget()->GetNativeView() == window) ||
+           IsMenuWindow(item->GetParentMenuItem(), window));
+}
+
+bool MenuController::SelectByChar(wchar_t character) {
+  wchar_t char_array[1] = { character };
+  wchar_t key = l10n_util::ToLower(char_array)[0];
+  MenuItemView* item = pending_state_.item;
+  if (!item->HasSubmenu() || !item->GetSubmenu()->IsShowing())
+    item = item->GetParentMenuItem();
+  DCHECK(item);
+  DCHECK(item->HasSubmenu());
+  SubmenuView* submenu = item->GetSubmenu();
+  DCHECK(submenu);
+  int menu_item_count = submenu->GetMenuItemCount();
+  if (!menu_item_count)
+    return false;
+  for (int i = 0; i < menu_item_count; ++i) {
+    MenuItemView* child = submenu->GetMenuItemAt(i);
+    if (child->GetMnemonic() == key && child->IsEnabled()) {
+      Accept(child, 0);
+      return true;
+    }
+  }
+
+  // No matching mnemonic, search through items that don't have mnemonic
+  // based on first character of the title.
+  int first_match = -1;
+  bool has_multiple = false;
+  int next_match = -1;
+  int index_of_item = -1;
+  for (int i = 0; i < menu_item_count; ++i) {
+    MenuItemView* child = submenu->GetMenuItemAt(i);
+    if (!child->GetMnemonic() && child->IsEnabled()) {
+      std::wstring lower_title = l10n_util::ToLower(child->GetTitle());
+      if (child == pending_state_.item)
+        index_of_item = i;
+      if (lower_title.length() && lower_title[0] == key) {
+        if (first_match == -1)
+          first_match = i;
+        else
+          has_multiple = true;
+        if (next_match == -1 && index_of_item != -1 && i > index_of_item)
+          next_match = i;
+      }
+    }
+  }
+  if (first_match != -1) {
+    if (!has_multiple) {
+      if (submenu->GetMenuItemAt(first_match)->HasSubmenu()) {
+        SetSelection(submenu->GetMenuItemAt(first_match), true, false);
+      } else {
+        Accept(submenu->GetMenuItemAt(first_match), 0);
+        return true;
+      }
+    } else if (index_of_item == -1 || next_match == -1) {
+      SetSelection(submenu->GetMenuItemAt(first_match), false, false);
+    } else {
+      SetSelection(submenu->GetMenuItemAt(next_match), false, false);
+    }
+  }
+  return false;
+}
+
+void MenuController::RepostEvent(SubmenuView* source,
+                                 const MouseEvent& event) {
+  gfx::Point screen_loc(event.location());
+  View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc);
+  HWND window = WindowFromPoint(screen_loc.ToPOINT());
+  if (window) {
+#ifdef DEBUG_MENU
+    DLOG(INFO) << "RepostEvent on press";
+#endif
+
+    // Release the capture.
+    SubmenuView* submenu = state_.item->GetRootMenuItem()->GetSubmenu();
+    submenu->ReleaseCapture();
+
+    if (submenu->host() && submenu->host()->GetNativeView() &&
+        GetWindowThreadProcessId(submenu->host()->GetNativeView(), NULL) !=
+        GetWindowThreadProcessId(window, NULL)) {
+      // Even though we have mouse capture, windows generates a mouse event
+      // if the other window is in a separate thread. Don't generate an event in
+      // this case else the target window can get double events leading to bad
+      // behavior.
+      return;
+    }
+
+    // Convert the coordinates to the target window.
+    RECT window_bounds;
+    GetWindowRect(window, &window_bounds);
+    int window_x = screen_loc.x() - window_bounds.left;
+    int window_y = screen_loc.y() - window_bounds.top;
+
+    // Determine whether the click was in the client area or not.
+    // NOTE: WM_NCHITTEST coordinates are relative to the screen.
+    LRESULT nc_hit_result = SendMessage(window, WM_NCHITTEST, 0,
+                                        MAKELPARAM(screen_loc.x(),
+                                                   screen_loc.y()));
+    const bool in_client_area = (nc_hit_result == HTCLIENT);
+
+    // TODO(sky): this isn't right. The event to generate should correspond
+    // with the event we just got. MouseEvent only tells us what is down,
+    // which may differ. Need to add ability to get changed button from
+    // MouseEvent.
+    int event_type;
+    if (event.IsLeftMouseButton())
+      event_type = in_client_area ? WM_LBUTTONDOWN : WM_NCLBUTTONDOWN;
+    else if (event.IsMiddleMouseButton())
+      event_type = in_client_area ? WM_MBUTTONDOWN : WM_NCMBUTTONDOWN;
+    else if (event.IsRightMouseButton())
+      event_type = in_client_area ? WM_RBUTTONDOWN : WM_NCRBUTTONDOWN;
+    else
+      event_type = 0;  // Unknown mouse press.
+
+    if (event_type) {
+      if (in_client_area) {
+        PostMessage(window, event_type, event.GetWindowsFlags(),
+                    MAKELPARAM(window_x, window_y));
+      } else {
+        PostMessage(window, event_type, nc_hit_result,
+                    MAKELPARAM(screen_loc.x(), screen_loc.y()));
+      }
+    }
+  }
+}
+
+void MenuController::SetDropMenuItem(
+    MenuItemView* new_target,
+    MenuDelegate::DropPosition new_position) {
+  if (new_target == drop_target_ && new_position == drop_position_)
+    return;
+
+  if (drop_target_) {
+    drop_target_->GetParentMenuItem()->GetSubmenu()->SetDropMenuItem(
+        NULL, MenuDelegate::DROP_NONE);
+  }
+  drop_target_ = new_target;
+  drop_position_ = new_position;
+  if (drop_target_) {
+    drop_target_->GetParentMenuItem()->GetSubmenu()->SetDropMenuItem(
+        drop_target_, drop_position_);
+  }
+}
+
+void MenuController::UpdateScrolling(const MenuPart& part) {
+  if (!part.is_scroll() && !scroll_task_.get())
+    return;
+
+  if (!scroll_task_.get())
+    scroll_task_.reset(new MenuScrollTask());
+  scroll_task_->Update(part);
+}
+
+void MenuController::StopScrolling() {
+  scroll_task_.reset(NULL);
+}
+
+}  // namespace views
diff --git a/views/controls/menu/chrome_menu.h b/views/controls/menu/chrome_menu.h
new file mode 100644
index 0000000..02caaed4
--- /dev/null
+++ b/views/controls/menu/chrome_menu.h
@@ -0,0 +1,948 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_MENU_CHROME_MENU_H_
+#define VIEWS_CONTROLS_MENU_CHROME_MENU_H_
+
+#include <list>
+#include <vector>
+
+#include "app/drag_drop_types.h"
+#include "app/gfx/chrome_font.h"
+#include "base/gfx/point.h"
+#include "base/gfx/rect.h"
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "skia/include/SkBitmap.h"
+#include "views/controls/menu/controller.h"
+#include "views/view.h"
+
+namespace views {
+
+class WidgetWin;
+class MenuController;
+class MenuItemView;
+class SubmenuView;
+
+namespace {
+class MenuHost;
+class MenuHostRootView;
+class MenuScrollTask;
+class MenuScrollViewContainer;
+}
+
+// MenuDelegate --------------------------------------------------------------
+
+// Delegate for the menu.
+
+class MenuDelegate : Controller {
+ public:
+  // Used during drag and drop to indicate where the drop indicator should
+  // be rendered.
+  enum DropPosition {
+    // Indicates a drop is not allowed here.
+    DROP_NONE,
+
+    // Indicates the drop should occur before the item.
+    DROP_BEFORE,
+
+    // Indicates the drop should occur after the item.
+    DROP_AFTER,
+
+    // Indicates the drop should occur on the item.
+    DROP_ON
+  };
+
+  // Whether or not an item should be shown as checked.
+  // TODO(sky): need checked support.
+  virtual bool IsItemChecked(int id) const {
+    return false;
+  }
+
+  // The string shown for the menu item. This is only invoked when an item is
+  // added with an empty label.
+  virtual std::wstring GetLabel(int id) const {
+    return std::wstring();
+  }
+
+  // Shows the context menu with the specified id. This is invoked when the
+  // user does the appropriate gesture to show a context menu. The id
+  // identifies the id of the menu to show the context menu for.
+  // is_mouse_gesture is true if this is the result of a mouse gesture.
+  // If this is not the result of a mouse gesture x/y is the recommended
+  // location to display the content menu at. In either case, x/y is in
+  // screen coordinates.
+  // Returns true if a context menu was displayed, otherwise false
+  virtual bool ShowContextMenu(MenuItemView* source,
+                               int id,
+                               int x,
+                               int y,
+                               bool is_mouse_gesture) {
+    return false;
+  }
+
+  // Controller
+  virtual bool SupportsCommand(int id) const {
+    return true;
+  }
+  virtual bool IsCommandEnabled(int id) const {
+    return true;
+  }
+  virtual bool GetContextualLabel(int id, std::wstring* out) const {
+    return false;
+  }
+  virtual void ExecuteCommand(int id) {
+  }
+
+  // Executes the specified command. mouse_event_flags give the flags of the
+  // mouse event that triggered this to be invoked (views::MouseEvent
+  // flags). mouse_event_flags is 0 if this is triggered by a user gesture
+  // other than a mouse event.
+  virtual void ExecuteCommand(int id, int mouse_event_flags) {
+    ExecuteCommand(id);
+  }
+
+  // Returns true if the specified mouse event is one the user can use
+  // to trigger, or accept, the mouse. Defaults to left or right mouse buttons.
+  virtual bool IsTriggerableEvent(const MouseEvent& e) {
+    return e.IsLeftMouseButton() || e.IsRightMouseButton();
+  }
+
+  // Invoked to determine if drops can be accepted for a submenu. This is
+  // ONLY invoked for menus that have submenus and indicates whether or not
+  // a drop can occur on any of the child items of the item. For example,
+  // consider the following menu structure:
+  //
+  // A
+  //   B
+  //   C
+  //
+  // Where A has a submenu with children B and C. This is ONLY invoked for
+  // A, not B and C.
+  //
+  // To restrict which children can be dropped on override GetDropOperation.
+  virtual bool CanDrop(MenuItemView* menu, const OSExchangeData& data) {
+    return false;
+  }
+
+  // Returns the drop operation for the specified target menu item. This is
+  // only invoked if CanDrop returned true for the parent menu. position
+  // is set based on the location of the mouse, reset to specify a different
+  // position.
+  //
+  // If a drop should not be allowed, returned DragDropTypes::DRAG_NONE.
+  virtual int GetDropOperation(MenuItemView* item,
+                               const DropTargetEvent& event,
+                               DropPosition* position) {
+    NOTREACHED() << "If you override CanDrop, you need to override this too";
+    return DragDropTypes::DRAG_NONE;
+  }
+
+  // Invoked to perform the drop operation. This is ONLY invoked if
+  // canDrop returned true for the parent menu item, and GetDropOperation
+  // returned an operation other than DragDropTypes::DRAG_NONE.
+  //
+  // menu indicates the menu the drop occurred on.
+  virtual int OnPerformDrop(MenuItemView* menu,
+                            DropPosition position,
+                            const DropTargetEvent& event) {
+    NOTREACHED() << "If you override CanDrop, you need to override this too";
+    return DragDropTypes::DRAG_NONE;
+  }
+
+  // Invoked to determine if it is possible for the user to drag the specified
+  // menu item.
+  virtual bool CanDrag(MenuItemView* menu) {
+    return false;
+  }
+
+  // Invoked to write the data for a drag operation to data. sender is the
+  // MenuItemView being dragged.
+  virtual void WriteDragData(MenuItemView* sender, OSExchangeData* data) {
+    NOTREACHED() << "If you override CanDrag, you must override this too.";
+  }
+
+  // Invoked to determine the drag operations for a drag session of sender.
+  // See DragDropTypes for possible values.
+  virtual int GetDragOperations(MenuItemView* sender) {
+    NOTREACHED() << "If you override CanDrag, you must override this too.";
+    return 0;
+  }
+
+  // Notification the menu has closed. This is only sent when running the
+  // menu for a drop.
+  virtual void DropMenuClosed(MenuItemView* menu) {
+  }
+
+  // Notification that the user has highlighted the specified item.
+  virtual void SelectionChanged(MenuItemView* menu) {
+  }
+};
+
+// MenuItemView --------------------------------------------------------------
+
+// MenuItemView represents a single menu item with a label and optional icon.
+// Each MenuItemView may also contain a submenu, which in turn may contain
+// any number of child MenuItemViews.
+//
+// To use a menu create an initial MenuItemView using the constructor that
+// takes a MenuDelegate, then create any number of child menu items by way
+// of the various AddXXX methods.
+//
+// MenuItemView is itself a View, which means you can add Views to each
+// MenuItemView. This normally NOT want you want, rather add other child Views
+// to the submenu of the MenuItemView.
+//
+// There are two ways to show a MenuItemView:
+// 1. Use RunMenuAt. This blocks the caller, executing the selected command
+//    on success.
+// 2. Use RunMenuForDropAt. This is intended for use during a drop session
+//    and does NOT block the caller. Instead the delegate is notified when the
+//    menu closes via the DropMenuClosed method.
+
+class MenuItemView : public View {
+  friend class MenuController;
+
+ public:
+  // ID used to identify menu items.
+  static const int kMenuItemViewID;
+
+  // If true SetNestableTasksAllowed(true) is invoked before MessageLoop::Run
+  // is invoked. This is only useful for testing and defaults to false.
+  static bool allow_task_nesting_during_run_;
+
+  // Different types of menu items.
+  enum Type {
+    NORMAL,
+    SUBMENU,
+    CHECKBOX,
+    RADIO,
+    SEPARATOR
+  };
+
+  // Where the menu should be anchored to.
+  enum AnchorPosition {
+    TOPLEFT,
+    TOPRIGHT
+  };
+
+  // Constructor for use with the top level menu item. This menu is never
+  // shown to the user, rather its use as the parent for all menu items.
+  explicit MenuItemView(MenuDelegate* delegate);
+
+  virtual ~MenuItemView();
+
+  // Run methods. See description above class for details. Both Run methods take
+  // a rectangle, which is used to position the menu. |has_mnemonics| indicates
+  // whether the items have mnemonics. Mnemonics are identified by way of the
+  // character following the '&'.
+  void RunMenuAt(HWND parent,
+                 const gfx::Rect& bounds,
+                 AnchorPosition anchor,
+                 bool has_mnemonics);
+  void RunMenuForDropAt(HWND parent,
+                        const gfx::Rect& bounds,
+                        AnchorPosition anchor);
+
+  // Hides and cancels the menu. This does nothing if the menu is not open.
+  void Cancel();
+
+  // Adds an item to this menu.
+  // item_id    The id of the item, used to identify it in delegate callbacks
+  //            or (if delegate is NULL) to identify the command associated
+  //            with this item with the controller specified in the ctor. Note
+  //            that this value should not be 0 as this has a special meaning
+  //            ("NULL command, no item selected")
+  // label      The text label shown.
+  // type       The type of item.
+  void AppendMenuItem(int item_id,
+                      const std::wstring& label,
+                      Type type) {
+    AppendMenuItemInternal(item_id, label, SkBitmap(), type);
+  }
+
+  // Append a submenu to this menu.
+  // The returned pointer is owned by this menu.
+  MenuItemView* AppendSubMenu(int item_id,
+                              const std::wstring& label) {
+    return AppendMenuItemInternal(item_id, label, SkBitmap(), SUBMENU);
+  }
+
+  // Append a submenu with an icon to this menu.
+  // The returned pointer is owned by this menu.
+  MenuItemView* AppendSubMenuWithIcon(int item_id,
+                                      const std::wstring& label,
+                                      const SkBitmap& icon) {
+    return AppendMenuItemInternal(item_id, label, icon, SUBMENU);
+  }
+
+  // This is a convenience for standard text label menu items where the label
+  // is provided with this call.
+  void AppendMenuItemWithLabel(int item_id,
+                               const std::wstring& label) {
+    AppendMenuItem(item_id, label, NORMAL);
+  }
+
+  // This is a convenience for text label menu items where the label is
+  // provided by the delegate.
+  void AppendDelegateMenuItem(int item_id) {
+    AppendMenuItem(item_id, std::wstring(), NORMAL);
+  }
+
+  // Adds a separator to this menu
+  void AppendSeparator() {
+    AppendMenuItemInternal(0, std::wstring(), SkBitmap(), SEPARATOR);
+  }
+
+  // Appends a menu item with an icon. This is for the menu item which
+  // needs an icon. Calling this function forces the Menu class to draw
+  // the menu, instead of relying on Windows.
+  void AppendMenuItemWithIcon(int item_id,
+                              const std::wstring& label,
+                              const SkBitmap& icon) {
+    AppendMenuItemInternal(item_id, label, icon, NORMAL);
+  }
+
+  // Returns the view that contains child menu items. If the submenu has
+  // not been creates, this creates it.
+  virtual SubmenuView* CreateSubmenu();
+
+  // Returns true if this menu item has a submenu.
+  virtual bool HasSubmenu() const { return (submenu_ != NULL); }
+
+  // Returns the view containing child menu items.
+  virtual SubmenuView* GetSubmenu() const { return submenu_; }
+
+  // Returns the parent menu item.
+  MenuItemView* GetParentMenuItem() const { return parent_menu_item_; }
+
+  // Sets the font.
+  void SetFont(const ChromeFont& font) { font_ = font; }
+
+  // Sets the title
+  void SetTitle(const std::wstring& title) {
+    title_ = title;
+  }
+
+  // Returns the title.
+  const std::wstring& GetTitle() const { return title_; }
+
+  // Sets whether this item is selected. This is invoked as the user moves
+  // the mouse around the menu while open.
+  void SetSelected(bool selected);
+
+  // Returns true if the item is selected.
+  bool IsSelected() const { return selected_; }
+
+  // Sets the icon for the descendant identified by item_id.
+  void SetIcon(const SkBitmap& icon, int item_id);
+
+  // Sets the icon of this menu item.
+  void SetIcon(const SkBitmap& icon);
+
+  // Returns the icon.
+  const SkBitmap& GetIcon() const { return icon_; }
+
+  // Sets the command id of this menu item.
+  void SetCommand(int command) { command_ = command; }
+
+  // Returns the command id of this item.
+  int GetCommand() const { return command_; }
+
+  // Paints the menu item.
+  virtual void Paint(ChromeCanvas* canvas);
+
+  // Returns the preferred size of this item.
+  virtual gfx::Size GetPreferredSize();
+
+  // Returns the object responsible for controlling showing the menu.
+  MenuController* GetMenuController();
+
+  // Returns the delegate. This returns the delegate of the root menu item.
+  MenuDelegate* GetDelegate();
+
+  // Returns the root parent, or this if this has no parent.
+  MenuItemView* GetRootMenuItem();
+
+  // Returns the mnemonic for this MenuItemView, or 0 if this MenuItemView
+  // doesn't have a mnemonic.
+  wchar_t GetMnemonic();
+
+  // Do we have icons? This only has effect on the top menu. Turning this on
+  // makes the menus slightly wider and taller.
+  void set_has_icons(bool has_icons) {
+    has_icons_ = has_icons;
+  }
+
+ protected:
+  // Creates a MenuItemView. This is used by the various AddXXX methods.
+  MenuItemView(MenuItemView* parent, int command, Type type);
+
+ private:
+  // Called by the two constructors to initialize this menu item.
+  void Init(MenuItemView* parent,
+            int command,
+            MenuItemView::Type type,
+            MenuDelegate* delegate);
+
+  // All the AddXXX methods funnel into this.
+  MenuItemView* AppendMenuItemInternal(int item_id,
+                                       const std::wstring& label,
+                                       const SkBitmap& icon,
+                                       Type type);
+
+  // Returns the descendant with the specified command.
+  MenuItemView* GetDescendantByID(int id);
+
+  // Invoked by the MenuController when the menu closes as the result of
+  // drag and drop run.
+  void DropMenuClosed(bool notify_delegate);
+
+  // The RunXXX methods call into this to set up the necessary state before
+  // running.
+  void PrepareForRun(bool has_mnemonics);
+
+  // Returns the flags passed to DrawStringInt.
+  int GetDrawStringFlags();
+
+  // If this menu item has no children a child is added showing it has no
+  // children. Otherwise AddEmtpyMenuIfNecessary is recursively invoked on
+  // child menu items that have children.
+  void AddEmptyMenus();
+
+  // Undoes the work of AddEmptyMenus.
+  void RemoveEmptyMenus();
+
+  // Given bounds within our View, this helper routine mirrors the bounds if
+  // necessary.
+  void AdjustBoundsForRTLUI(RECT* rect) const;
+
+  // Actual paint implementation. If for_drag is true, portions of the menu
+  // are not rendered.
+  void Paint(ChromeCanvas* canvas, bool for_drag);
+
+  // Destroys the window used to display this menu and recursively destroys
+  // the windows used to display all descendants.
+  void DestroyAllMenuHosts();
+
+  // Returns the various margins.
+  int GetTopMargin();
+  int GetBottomMargin();
+
+  // The delegate. This is only valid for the root menu item. You shouldn't
+  // use this directly, instead use GetDelegate() which walks the tree as
+  // as necessary.
+  MenuDelegate* delegate_;
+
+  // Returns the controller for the run operation, or NULL if the menu isn't
+  // showing.
+  MenuController* controller_;
+
+  // Used to detect when Cancel was invoked.
+  bool canceled_;
+
+  // Our parent.
+  MenuItemView* parent_menu_item_;
+
+  // Type of menu. NOTE: MenuItemView doesn't itself represent SEPARATOR,
+  // that is handled by an entirely different view class.
+  Type type_;
+
+  // Whether we're selected.
+  bool selected_;
+
+  // Command id.
+  int command_;
+
+  // Submenu, created via CreateSubmenu.
+  SubmenuView* submenu_;
+
+  // Font.
+  ChromeFont font_;
+
+  // Title.
+  std::wstring title_;
+
+  // Icon.
+  SkBitmap icon_;
+
+  // Does the title have a mnemonic?
+  bool has_mnemonics_;
+
+  bool has_icons_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(MenuItemView);
+};
+
+// SubmenuView ----------------------------------------------------------------
+
+// SubmenuView is the parent of all menu items.
+//
+// SubmenuView has the following responsibilities:
+// . It positions and sizes all child views (any type of View may be added,
+//   not just MenuItemViews).
+// . Forwards the appropriate events to the MenuController. This allows the
+//   MenuController to update the selection as the user moves the mouse around.
+// . Renders the drop indicator during a drop operation.
+// . Shows and hides the window (a WidgetWin) when the menu is shown on
+//   screen.
+//
+// SubmenuView is itself contained in a MenuScrollViewContainer.
+// MenuScrollViewContainer handles showing as much of the SubmenuView as the
+// screen allows. If the SubmenuView is taller than the screen, scroll buttons
+// are provided that allow the user to see all the menu items.
+class SubmenuView : public View {
+ public:
+  // Creates a SubmenuView for the specified menu item.
+  explicit SubmenuView(MenuItemView* parent);
+  ~SubmenuView();
+
+  // Returns the number of child views that are MenuItemViews.
+  // MenuItemViews are identified by ID.
+  int GetMenuItemCount();
+
+  // Returns the MenuItemView at the specified index.
+  MenuItemView* GetMenuItemAt(int index);
+
+  // Positions and sizes the child views. This tiles the views vertically,
+  // giving each child the available width.
+  virtual void Layout();
+  virtual gfx::Size GetPreferredSize();
+
+  // View method. Overriden to schedule a paint. We do this so that when
+  // scrolling occurs, everything is repainted correctly.
+  virtual void DidChangeBounds(const gfx::Rect& previous,
+                               const gfx::Rect& current);
+
+  // Painting.
+  void PaintChildren(ChromeCanvas* canvas);
+
+  // Drag and drop methods. These are forwarded to the MenuController.
+  virtual bool CanDrop(const OSExchangeData& data);
+  virtual void OnDragEntered(const DropTargetEvent& event);
+  virtual int OnDragUpdated(const DropTargetEvent& event);
+  virtual void OnDragExited();
+  virtual int OnPerformDrop(const DropTargetEvent& event);
+
+  // Scrolls on menu item boundaries.
+  virtual bool OnMouseWheel(const MouseWheelEvent& e);
+
+  // Returns true if the menu is showing.
+  bool IsShowing();
+
+  // Shows the menu at the specified location. Coordinates are in screen
+  // coordinates. max_width gives the max width the view should be.
+  void ShowAt(HWND parent, const gfx::Rect& bounds, bool do_capture);
+
+  // Closes the menu, destroying the host.
+  void Close();
+
+  // Hides the hosting window.
+  //
+  // The hosting window is hidden first, then deleted (Close) when the menu is
+  // done running. This is done to avoid deletion ordering dependencies. In
+  // particular, during drag and drop (and when a modal dialog is shown as
+  // a result of choosing a context menu) it is possible that an event is
+  // being processed by the host, so that host is on the stack when we need to
+  // close the window. If we closed the window immediately (and deleted it),
+  // when control returned back to host we would crash as host was deleted.
+  void Hide();
+
+  // If mouse capture was grabbed, it is released. Does nothing if mouse was
+  // not captured.
+  void ReleaseCapture();
+
+  // Returns the parent menu item we're showing children for.
+  MenuItemView* GetMenuItem() const { return parent_menu_item_; }
+
+  // Overriden to return true. This prevents tab from doing anything.
+  virtual bool CanProcessTabKeyEvents() { return true; }
+
+  // Set the drop item and position.
+  void SetDropMenuItem(MenuItemView* item,
+                       MenuDelegate::DropPosition position);
+
+  // Returns whether the selection should be shown for the specified item.
+  // The selection is NOT shown during drag and drop when the drop is over
+  // the menu.
+  bool GetShowSelection(MenuItemView* item);
+
+  // Returns the container for the SubmenuView.
+  MenuScrollViewContainer* GetScrollViewContainer();
+
+  // Returns the host of the menu. Returns NULL if not showing.
+  MenuHost* host() const { return host_; }
+
+ private:
+  // Paints the drop indicator. This is only invoked if item is non-NULL and
+  // position is not DROP_NONE.
+  void PaintDropIndicator(ChromeCanvas* canvas,
+                          MenuItemView* item,
+                          MenuDelegate::DropPosition position);
+
+  void SchedulePaintForDropIndicator(MenuItemView* item,
+                                     MenuDelegate::DropPosition position);
+
+  // Calculates the location of th edrop indicator.
+  gfx::Rect CalculateDropIndicatorBounds(MenuItemView* item,
+                                         MenuDelegate::DropPosition position);
+
+  // Parent menu item.
+  MenuItemView* parent_menu_item_;
+
+  // WidgetWin subclass used to show the children.
+  MenuHost* host_;
+
+  // If non-null, indicates a drop is in progress and drop_item is the item
+  // the drop is over.
+  MenuItemView* drop_item_;
+
+  // Position of the drop.
+  MenuDelegate::DropPosition drop_position_;
+
+  // Ancestor of the SubmenuView, lazily created.
+  MenuScrollViewContainer* scroll_view_container_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(SubmenuView);
+};
+
+// MenuController -------------------------------------------------------------
+
+// MenuController manages showing, selecting and drag/drop for menus.
+// All relevant events are forwarded to the MenuController from SubmenuView
+// and MenuHost.
+
+class MenuController : public MessageLoopForUI::Dispatcher {
+ public:
+  friend class MenuHostRootView;
+  friend class MenuItemView;
+  friend class MenuScrollTask;
+
+  // If a menu is currently active, this returns the controller for it.
+  static MenuController* GetActiveInstance();
+
+  // Runs the menu at the specified location. If the menu was configured to
+  // block, the selected item is returned. If the menu does not block this
+  // returns NULL immediately.
+  MenuItemView* Run(HWND parent,
+                    MenuItemView* root,
+                    const gfx::Rect& bounds,
+                    MenuItemView::AnchorPosition position,
+                    int* mouse_event_flags);
+
+  // Whether or not Run blocks.
+  bool IsBlockingRun() const { return blocking_run_; }
+
+  // Sets the selection to menu_item, a value of NULL unselects everything.
+  // If open_submenu is true and menu_item has a submenu, the submenu is shown.
+  // If update_immediately is true, submenus are opened immediately, otherwise
+  // submenus are only opened after a timer fires.
+  //
+  // Internally this updates pending_state_ immediatley, and if
+  // update_immediately is true, CommitPendingSelection is invoked to
+  // show/hide submenus and update state_.
+  void SetSelection(MenuItemView* menu_item,
+                    bool open_submenu,
+                    bool update_immediately);
+
+  // Cancels the current Run. If all is true, any nested loops are canceled
+  // as well. This immediately hides all menus.
+  void Cancel(bool all);
+
+  // An alternative to Cancel(true) that can be used with a OneShotTimer.
+  void CancelAll() { return Cancel(true); }
+
+  // Various events, forwarded from the submenu.
+  //
+  // NOTE: the coordinates of the events are in that of the
+  // MenuScrollViewContainer.
+  void OnMousePressed(SubmenuView* source, const MouseEvent& event);
+  void OnMouseDragged(SubmenuView* source, const MouseEvent& event);
+  void OnMouseReleased(SubmenuView* source, const MouseEvent& event);
+  void OnMouseMoved(SubmenuView* source, const MouseEvent& event);
+  void OnMouseEntered(SubmenuView* source, const MouseEvent& event);
+  bool CanDrop(SubmenuView* source, const OSExchangeData& data);
+  void OnDragEntered(SubmenuView* source, const DropTargetEvent& event);
+  int OnDragUpdated(SubmenuView* source, const DropTargetEvent& event);
+  void OnDragExited(SubmenuView* source);
+  int OnPerformDrop(SubmenuView* source, const DropTargetEvent& event);
+
+  // Invoked from the scroll buttons of the MenuScrollViewContainer.
+  void OnDragEnteredScrollButton(SubmenuView* source, bool is_up);
+  void OnDragExitedScrollButton(SubmenuView* source);
+
+ private:
+  // Tracks selection information.
+  struct State {
+    State() : item(NULL), submenu_open(false) {}
+
+    // The selected menu item.
+    MenuItemView* item;
+
+    // If item has a submenu this indicates if the submenu is showing.
+    bool submenu_open;
+
+    // Bounds passed to the run menu. Used for positioning the first menu.
+    gfx::Rect initial_bounds;
+
+    // Position of the initial menu.
+    MenuItemView::AnchorPosition anchor;
+
+    // The direction child menus have opened in.
+    std::list<bool> open_leading;
+
+    // Bounds for the monitor we're showing on.
+    gfx::Rect monitor_bounds;
+  };
+
+  // Used by GetMenuPartByScreenCoordinate to indicate the menu part at a
+  // particular location.
+  struct MenuPart {
+    // Type of part.
+    enum Type {
+      NONE,
+      MENU_ITEM,
+      SCROLL_UP,
+      SCROLL_DOWN
+    };
+
+    MenuPart() : type(NONE), menu(NULL), submenu(NULL) {}
+
+    // Convenience for testing type == SCROLL_DOWN or type == SCROLL_UP.
+    bool is_scroll() const { return type == SCROLL_DOWN || type == SCROLL_UP; }
+
+    // Type of part.
+    Type type;
+
+    // If type is MENU_ITEM, this is the menu item the mouse is over, otherwise
+    // this is NULL.
+    // NOTE: if type is MENU_ITEM and the mouse is not over a valid menu item
+    //       but is over a menu (for example, the mouse is over a separator or
+    //       empty menu), this is NULL.
+    MenuItemView* menu;
+
+    // If type is SCROLL_*, this is the submenu the mouse is over.
+    SubmenuView* submenu;
+  };
+
+  // Sets the active MenuController.
+  static void SetActiveInstance(MenuController* controller);
+
+  // Dispatcher method. This returns true if the menu was canceled, or
+  // if the message is such that the menu should be closed.
+  virtual bool Dispatch(const MSG& msg);
+
+  // Key processing. The return value of these is returned from Dispatch.
+  // In other words, if these return false (which they do if escape was
+  // pressed, or a matching mnemonic was found) the message loop returns.
+  bool OnKeyDown(const MSG& msg);
+  bool OnChar(const MSG& msg);
+
+  // Creates a MenuController. If blocking is true, Run blocks the caller
+  explicit MenuController(bool blocking);
+
+  ~MenuController();
+
+  // Invoked when the user accepts the selected item. This is only used
+  // when blocking. This schedules the loop to quit.
+  void Accept(MenuItemView* item, int mouse_event_flags);
+
+  // Closes all menus, including any menus of nested invocations of Run.
+  void CloseAllNestedMenus();
+
+  // Gets the enabled menu item at the specified location.
+  // If over_any_menu is non-null it is set to indicate whether the location
+  // is over any menu. It is possible for this to return NULL, but
+  // over_any_menu to be true. For example, the user clicked on a separator.
+  MenuItemView* GetMenuItemAt(View* menu, int x, int y);
+
+  // If there is an empty menu item at the specified location, it is returned.
+  MenuItemView* GetEmptyMenuItemAt(View* source, int x, int y);
+
+  // Returns true if the coordinate is over the scroll buttons of the
+  // SubmenuView's MenuScrollViewContainer. If true is returned, part is set to
+  // indicate which scroll button the coordinate is.
+  bool IsScrollButtonAt(SubmenuView* source,
+                        int x,
+                        int y,
+                        MenuPart::Type* part);
+
+  // Returns the target for the mouse event.
+  MenuPart GetMenuPartByScreenCoordinate(SubmenuView* source,
+                                         int source_x,
+                                         int source_y);
+
+  // Implementation of GetMenuPartByScreenCoordinate for a single menu. Returns
+  // true if the supplied SubmenuView contains the location in terms of the
+  // screen. If it does, part is set appropriately and true is returned.
+  bool GetMenuPartByScreenCoordinateImpl(SubmenuView* menu,
+                                         const gfx::Point& screen_loc,
+                                         MenuPart* part);
+
+  // Returns true if the SubmenuView contains the specified location. This does
+  // NOT included the scroll buttons, only the submenu view.
+  bool DoesSubmenuContainLocation(SubmenuView* submenu,
+                                  const gfx::Point& screen_loc);
+
+  // Opens/Closes the necessary menus such that state_ matches that of
+  // pending_state_. This is invoked if submenus are not opened immediately,
+  // but after a delay.
+  void CommitPendingSelection();
+
+  // If item has a submenu, it is closed. This does NOT update the selection
+  // in anyway.
+  void CloseMenu(MenuItemView* item);
+
+  // If item has a submenu, it is opened. This does NOT update the selection
+  // in anyway.
+  void OpenMenu(MenuItemView* item);
+
+  // Builds the paths of the two menu items into the two paths, and
+  // sets first_diff_at to the location of the first difference between the
+  // two paths.
+  void BuildPathsAndCalculateDiff(MenuItemView* old_item,
+                                  MenuItemView* new_item,
+                                  std::vector<MenuItemView*>* old_path,
+                                  std::vector<MenuItemView*>* new_path,
+                                  size_t* first_diff_at);
+
+  // Builds the path for the specified item.
+  void BuildMenuItemPath(MenuItemView* item, std::vector<MenuItemView*>* path);
+
+  // Starts/stops the timer that commits the pending state to state
+  // (opens/closes submenus).
+  void StartShowTimer();
+  void StopShowTimer();
+
+  // Starts/stops the timer cancel the menu. This is used during drag and
+  // drop when the drop enters/exits the menu.
+  void StartCancelAllTimer();
+  void StopCancelAllTimer();
+
+  // Calculates the bounds of the menu to show. is_leading is set to match the
+  // direction the menu opened in.
+  gfx::Rect CalculateMenuBounds(MenuItemView* item,
+                                bool prefer_leading,
+                                bool* is_leading);
+
+  // Returns the depth of the menu.
+  static int MenuDepth(MenuItemView* item);
+
+  // Selects the next/previous menu item.
+  void IncrementSelection(int delta);
+
+  // If the selected item has a submenu and it isn't currently open, the
+  // the selection is changed such that the menu opens immediately.
+  void OpenSubmenuChangeSelectionIfCan();
+
+  // If possible, closes the submenu.
+  void CloseSubmenu();
+
+  // Returns true if window is the window used to show item, or any of
+  // items ancestors.
+  bool IsMenuWindow(MenuItemView* item, HWND window);
+
+  // Selects by mnemonic, and if that doesn't work tries the first character of
+  // the title. Returns true if a match was selected and the menu should exit.
+  bool SelectByChar(wchar_t key);
+
+  // If there is a window at the location of the event, a new mouse event is
+  // generated and posted to it.
+  void RepostEvent(SubmenuView* source, const MouseEvent& event);
+
+  // Sets the drop target to new_item.
+  void SetDropMenuItem(MenuItemView* new_item,
+                       MenuDelegate::DropPosition position);
+
+  // Starts/stops scrolling as appropriate. part gives the part the mouse is
+  // over.
+  void UpdateScrolling(const MenuPart& part);
+
+  // Stops scrolling.
+  void StopScrolling();
+
+  // The active instance.
+  static MenuController* active_instance_;
+
+  // If true, Run blocks. If false, Run doesn't block and this is used for
+  // drag and drop. Note that the semantics for drag and drop are slightly
+  // different: cancel timer is kicked off any time the drag moves outside the
+  // menu, mouse events do nothing...
+  bool blocking_run_;
+
+  // If true, we're showing.
+  bool showing_;
+
+  // If true, all nested run loops should be exited.
+  bool exit_all_;
+
+  // Whether we did a capture. We do a capture only if we're blocking and
+  // the mouse was down when Run.
+  bool did_capture_;
+
+  // As the user drags the mouse around pending_state_ changes immediately.
+  // When the user stops moving/dragging the mouse (or clicks the mouse)
+  // pending_state_ is committed to state_, potentially resulting in
+  // opening or closing submenus. This gives a slight delayed effect to
+  // submenus as the user moves the mouse around. This is done so that as the
+  // user moves the mouse all submenus don't immediately pop.
+  State pending_state_;
+  State state_;
+
+  // If the user accepted the selection, this is the result.
+  MenuItemView* result_;
+
+  // The mouse event flags when the user clicked on a menu. Is 0 if the
+  // user did not use the mousee to select the menu.
+  int result_mouse_event_flags_;
+
+  // If not empty, it means we're nested. When Run is invoked from within
+  // Run, the current state (state_) is pushed onto menu_stack_. This allows
+  // MenuController to restore the state when the nested run returns.
+  std::list<State> menu_stack_;
+
+  // As the mouse moves around submenus are not opened immediately. Instead
+  // they open after this timer fires.
+  base::OneShotTimer<MenuController> show_timer_;
+
+  // Used to invoke CancelAll(). This is used during drag and drop to hide the
+  // menu after the mouse moves out of the of the menu. This is necessitated by
+  // the lack of an ability to detect when the drag has completed from the drop
+  // side.
+  base::OneShotTimer<MenuController> cancel_all_timer_;
+
+  // Drop target.
+  MenuItemView* drop_target_;
+  MenuDelegate::DropPosition drop_position_;
+
+  // Owner of child windows.
+  HWND owner_;
+
+  // Indicates a possible drag operation.
+  bool possible_drag_;
+
+  // Location the mouse was pressed at. Used to detect d&d.
+  int press_x_;
+  int press_y_;
+
+  // We get a slew of drag updated messages as the mouse is over us. To avoid
+  // continually processing whether we can drop, we cache the coordinates.
+  bool valid_drop_coordinates_;
+  int drop_x_;
+  int drop_y_;
+  int last_drop_operation_;
+
+  // If true, we're in the middle of invoking ShowAt on a submenu.
+  bool showing_submenu_;
+
+  // Task for scrolling the menu. If non-null indicates a scroll is currently
+  // underway.
+  scoped_ptr<MenuScrollTask> scroll_task_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(MenuController);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_MENU_CHROME_MENU_H_
diff --git a/views/controls/menu/controller.h b/views/controls/menu/controller.h
new file mode 100644
index 0000000..6a693cc0
--- /dev/null
+++ b/views/controls/menu/controller.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_MENU_CONTROLLER_H_
+#define VIEWS_CONTROLS_MENU_CONTROLLER_H_
+
+#include <string>
+
+// TODO(beng): remove this interface and fold it into MenuDelegate.
+
+class Controller {
+ public:
+  virtual ~Controller() { }
+
+  // Whether or not a command is supported by this controller.
+  virtual bool SupportsCommand(int id) const = 0;
+
+  // Whether or not a command is enabled.
+  virtual bool IsCommandEnabled(int id) const = 0;
+
+  // Assign the provided string with a contextual label. Returns true if a
+  // contextual label exists and false otherwise. This method can be used when
+  // implementing a menu or button that needs to have a different label
+  // depending on the context. If this method returns false, the default
+  // label used when creating the button or menu is used.
+  virtual bool GetContextualLabel(int id, std::wstring* out) const = 0;
+
+  // Executes a command.
+  virtual void ExecuteCommand(int id) = 0;
+};
+
+#endif // VIEWS_CONTROLS_MENU_CONTROLLER_H_
diff --git a/views/controls/menu/menu.cc b/views/controls/menu/menu.cc
new file mode 100644
index 0000000..1597da58
--- /dev/null
+++ b/views/controls/menu/menu.cc
@@ -0,0 +1,626 @@
+// Copyright (c) 2006-2008 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 "views/controls/menu/menu.h"
+
+#include <atlbase.h>
+#include <atlapp.h>
+#include <atlwin.h>
+#include <atlcrack.h>
+#include <atlframe.h>
+#include <atlmisc.h>
+#include <string>
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/gfx/chrome_font.h"
+#include "app/l10n_util.h"
+#include "app/l10n_util_win.h"
+#include "base/gfx/rect.h"
+#include "base/logging.h"
+#include "base/stl_util-inl.h"
+#include "base/string_util.h"
+#include "views/accelerator.h"
+
+const SkBitmap* Menu::Delegate::kEmptyIcon = 0;
+
+// The width of an icon, including the pixels between the icon and
+// the item label.
+static const int kIconWidth = 23;
+// Margins between the top of the item and the label.
+static const int kItemTopMargin = 3;
+// Margins between the bottom of the item and the label.
+static const int kItemBottomMargin = 4;
+// Margins between the left of the item and the icon.
+static const int kItemLeftMargin = 4;
+// Margins between the right of the item and the label.
+static const int kItemRightMargin = 10;
+// The width for displaying the sub-menu arrow.
+static const int kArrowWidth = 10;
+
+// Current active MenuHostWindow. If NULL, no menu is active.
+static MenuHostWindow* active_host_window = NULL;
+
+// The data of menu items needed to display.
+struct Menu::ItemData {
+  std::wstring label;
+  SkBitmap icon;
+  bool submenu;
+};
+
+namespace {
+
+static int ChromeGetMenuItemID(HMENU hMenu, int pos) {
+  // The built-in Windows ::GetMenuItemID doesn't work for submenus,
+  // so here's our own implementation.
+  MENUITEMINFO mii = {0};
+  mii.cbSize = sizeof(mii);
+  mii.fMask = MIIM_ID;
+  GetMenuItemInfo(hMenu, pos, TRUE, &mii);
+  return mii.wID;
+}
+
+// MenuHostWindow -------------------------------------------------------------
+
+// MenuHostWindow is the HWND the HMENU is parented to. MenuHostWindow is used
+// to intercept right clicks on the HMENU and notify the delegate as well as
+// for drawing icons.
+//
+class MenuHostWindow : public CWindowImpl<MenuHostWindow, CWindow,
+                                          CWinTraits<WS_CHILD>> {
+ public:
+  MenuHostWindow(Menu* menu, HWND parent_window) : menu_(menu) {
+    int extended_style = 0;
+    // If the menu needs to be created with a right-to-left UI layout, we must
+    // set the appropriate RTL flags (such as WS_EX_LAYOUTRTL) property for the
+    // underlying HWND.
+    if (menu_->delegate_->IsRightToLeftUILayout())
+      extended_style |= l10n_util::GetExtendedStyles();
+    Create(parent_window, gfx::Rect().ToRECT(), 0, 0, extended_style);
+  }
+
+  ~MenuHostWindow() {
+    DestroyWindow();
+  }
+
+  DECLARE_FRAME_WND_CLASS(L"MenuHostWindow", NULL);
+  BEGIN_MSG_MAP(MenuHostWindow);
+    MSG_WM_RBUTTONUP(OnRButtonUp)
+    MSG_WM_MEASUREITEM(OnMeasureItem)
+    MSG_WM_DRAWITEM(OnDrawItem)
+  END_MSG_MAP();
+
+ private:
+  // NOTE: I really REALLY tried to use WM_MENURBUTTONUP, but I ran into
+  // two problems in using it:
+  // 1. It doesn't contain the coordinates of the mouse.
+  // 2. It isn't invoked for menuitems representing a submenu that have children
+  //   menu items (not empty).
+
+  void OnRButtonUp(UINT w_param, const CPoint& loc) {
+    int id;
+    if (menu_->delegate_ && FindMenuIDByLocation(menu_, loc, &id))
+      menu_->delegate_->ShowContextMenu(menu_, id, loc.x, loc.y, true);
+  }
+
+  void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* lpmis) {
+    Menu::ItemData* data = reinterpret_cast<Menu::ItemData*>(lpmis->itemData);
+    if (data != NULL) {
+      ChromeFont font;
+      lpmis->itemWidth = font.GetStringWidth(data->label) + kIconWidth +
+          kItemLeftMargin + kItemRightMargin -
+          GetSystemMetrics(SM_CXMENUCHECK);
+      if (data->submenu)
+        lpmis->itemWidth += kArrowWidth;
+      // If the label contains an accelerator, make room for tab.
+      if (data->label.find(L'\t') != std::wstring::npos)
+        lpmis->itemWidth += font.GetStringWidth(L" ");
+      lpmis->itemHeight = font.height() + kItemBottomMargin + kItemTopMargin;
+    } else {
+      // Measure separator size.
+      lpmis->itemHeight = GetSystemMetrics(SM_CYMENU) / 2;
+      lpmis->itemWidth = 0;
+    }
+  }
+
+  void OnDrawItem(UINT wParam, DRAWITEMSTRUCT* lpdis) {
+    HDC hDC = lpdis->hDC;
+    COLORREF prev_bg_color, prev_text_color;
+
+    // Set background color and text color
+    if (lpdis->itemState & ODS_SELECTED) {
+      prev_bg_color = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
+      prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+    } else {
+      prev_bg_color = SetBkColor(hDC, GetSysColor(COLOR_MENU));
+      if (lpdis->itemState & ODS_DISABLED)
+        prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT));
+      else
+        prev_text_color = SetTextColor(hDC, GetSysColor(COLOR_MENUTEXT));
+    }
+
+    if (lpdis->itemData) {
+      Menu::ItemData* data =
+          reinterpret_cast<Menu::ItemData*>(lpdis->itemData);
+
+      // Draw the background.
+      HBRUSH hbr = CreateSolidBrush(GetBkColor(hDC));
+      FillRect(hDC, &lpdis->rcItem, hbr);
+      DeleteObject(hbr);
+
+      // Draw the label.
+      RECT rect = lpdis->rcItem;
+      rect.top += kItemTopMargin;
+      // Should we add kIconWidth only when icon.width() != 0 ?
+      rect.left += kItemLeftMargin + kIconWidth;
+      rect.right -= kItemRightMargin;
+      UINT format = DT_TOP | DT_SINGLELINE;
+      // Check whether the mnemonics should be underlined.
+      BOOL underline_mnemonics;
+      SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0);
+      if (!underline_mnemonics)
+        format |= DT_HIDEPREFIX;
+      ChromeFont font;
+      HGDIOBJ old_font = static_cast<HFONT>(SelectObject(hDC, font.hfont()));
+      int fontsize = font.FontSize();
+
+      // If an accelerator is specified (with a tab delimiting the rest of the
+      // label from the accelerator), we have to justify the fist part on the
+      // left and the accelerator on the right.
+      // TODO(jungshik): This will break in RTL UI. Currently, he/ar use the
+      //                 window system UI font and will not hit here.
+      std::wstring label = data->label;
+      std::wstring accel;
+      std::wstring::size_type tab_pos = label.find(L'\t');
+      if (tab_pos != std::wstring::npos) {
+        accel = label.substr(tab_pos);
+        label = label.substr(0, tab_pos);
+      }
+      DrawTextEx(hDC, const_cast<wchar_t*>(label.data()),
+                 static_cast<int>(label.size()), &rect, format | DT_LEFT, NULL);
+      if (!accel.empty())
+        DrawTextEx(hDC, const_cast<wchar_t*>(accel.data()),
+                   static_cast<int>(accel.size()), &rect,
+                   format | DT_RIGHT, NULL);
+      SelectObject(hDC, old_font);
+
+      // Draw the icon after the label, otherwise it would be covered
+      // by the label.
+      if (data->icon.width() != 0 && data->icon.height() != 0) {
+        ChromeCanvas canvas(data->icon.width(), data->icon.height(), false);
+        canvas.drawColor(SK_ColorBLACK, SkPorterDuff::kClear_Mode);
+        canvas.DrawBitmapInt(data->icon, 0, 0);
+        canvas.getTopPlatformDevice().drawToHDC(hDC, lpdis->rcItem.left +
+            kItemLeftMargin, lpdis->rcItem.top + (lpdis->rcItem.bottom -
+                lpdis->rcItem.top - data->icon.height()) / 2, NULL);
+      }
+
+    } else {
+      // Draw the separator
+      lpdis->rcItem.top += (lpdis->rcItem.bottom - lpdis->rcItem.top) / 3;
+      DrawEdge(hDC, &lpdis->rcItem, EDGE_ETCHED, BF_TOP);
+    }
+
+    SetBkColor(hDC, prev_bg_color);
+    SetTextColor(hDC, prev_text_color);
+  }
+
+  bool FindMenuIDByLocation(Menu* menu, const CPoint& loc, int* id) {
+    int index = MenuItemFromPoint(NULL, menu->menu_, loc);
+    if (index != -1) {
+      *id = ChromeGetMenuItemID(menu->menu_, index);
+      return true;
+    } else {
+      for (std::vector<Menu*>::iterator i = menu->submenus_.begin();
+           i != menu->submenus_.end(); ++i) {
+        if (FindMenuIDByLocation(*i, loc, id))
+          return true;
+      }
+    }
+    return false;
+  }
+
+  // The menu that created us.
+  Menu* menu_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(MenuHostWindow);
+};
+
+}  // namespace
+
+bool Menu::Delegate::IsRightToLeftUILayout() const {
+  return l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT;
+}
+
+const SkBitmap& Menu::Delegate::GetEmptyIcon() const {
+  if (kEmptyIcon == NULL)
+    kEmptyIcon = new SkBitmap();
+  return *kEmptyIcon;
+}
+
+Menu::Menu(Delegate* delegate, AnchorPoint anchor, HWND owner)
+    : delegate_(delegate),
+      menu_(CreatePopupMenu()),
+      anchor_(anchor),
+      owner_(owner),
+      is_menu_visible_(false),
+      owner_draw_(l10n_util::NeedOverrideDefaultUIFont(NULL, NULL)) {
+  DCHECK(delegate_);
+}
+
+Menu::Menu(Menu* parent)
+    : delegate_(parent->delegate_),
+      menu_(CreatePopupMenu()),
+      anchor_(parent->anchor_),
+      owner_(parent->owner_),
+      is_menu_visible_(false),
+      owner_draw_(parent->owner_draw_) {
+}
+
+Menu::Menu(HMENU hmenu)
+    : delegate_(NULL),
+      menu_(hmenu),
+      anchor_(TOPLEFT),
+      owner_(NULL),
+      is_menu_visible_(false),
+      owner_draw_(false) {
+  DCHECK(menu_);
+}
+
+Menu::~Menu() {
+  STLDeleteContainerPointers(submenus_.begin(), submenus_.end());
+  STLDeleteContainerPointers(item_data_.begin(), item_data_.end());
+  DestroyMenu(menu_);
+}
+
+UINT Menu::GetStateFlagsForItemID(int item_id) const {
+  // Use the delegate to get enabled and checked state.
+  UINT flags =
+    delegate_->IsCommandEnabled(item_id) ? MFS_ENABLED : MFS_DISABLED;
+
+  if (delegate_->IsItemChecked(item_id))
+    flags |= MFS_CHECKED;
+
+  if (delegate_->IsItemDefault(item_id))
+    flags |= MFS_DEFAULT;
+
+  return flags;
+}
+
+void Menu::AddMenuItemInternal(int index,
+                               int item_id,
+                               const std::wstring& label,
+                               const SkBitmap& icon,
+                               HMENU submenu,
+                               MenuItemType type) {
+  DCHECK(type != SEPARATOR) << "Call AddSeparator instead!";
+
+  if (label.empty() && !delegate_) {
+    // No label and no delegate; don't add an empty menu.
+    // It appears under some circumstance we're getting an empty label
+    // (l10n_util::GetString(IDS_TASK_MANAGER) returns ""). This shouldn't
+    // happen, but I'm working over the crash here.
+    NOTREACHED();
+    return;
+  }
+
+  MENUITEMINFO mii;
+  mii.cbSize = sizeof(mii);
+  mii.fMask = MIIM_FTYPE | MIIM_ID;
+  if (submenu) {
+    mii.fMask |= MIIM_SUBMENU;
+    mii.hSubMenu = submenu;
+  }
+
+  // Set the type and ID.
+  if (!owner_draw_) {
+    mii.fType = MFT_STRING;
+    mii.fMask |= MIIM_STRING;
+  } else {
+    mii.fType = MFT_OWNERDRAW;
+  }
+
+  if (type == RADIO)
+    mii.fType |= MFT_RADIOCHECK;
+
+  mii.wID = item_id;
+
+  // Set the item data.
+  Menu::ItemData* data = new ItemData;
+  item_data_.push_back(data);
+  data->submenu = submenu != NULL;
+
+  std::wstring actual_label(label.empty() ?
+      delegate_->GetLabel(item_id) : label);
+
+  // Find out if there is a shortcut we need to append to the label.
+  views::Accelerator accelerator(0, false, false, false);
+  if (delegate_ && delegate_->GetAcceleratorInfo(item_id, &accelerator)) {
+    actual_label += L'\t';
+    actual_label += accelerator.GetShortcutText();
+  }
+  labels_.push_back(actual_label);
+
+  if (owner_draw_) {
+    if (icon.width() != 0 && icon.height() != 0)
+      data->icon = icon;
+    else
+      data->icon = delegate_->GetIcon(item_id);
+  } else {
+    mii.dwTypeData = const_cast<wchar_t*>(labels_.back().c_str());
+  }
+
+  InsertMenuItem(menu_, index, TRUE, &mii);
+}
+
+void Menu::AppendMenuItem(int item_id,
+                          const std::wstring& label,
+                          MenuItemType type) {
+  AddMenuItem(-1, item_id, label, type);
+}
+
+void Menu::AddMenuItem(int index,
+                       int item_id,
+                       const std::wstring& label,
+                       MenuItemType type) {
+  if (type == SEPARATOR)
+    AddSeparator(index);
+  else
+    AddMenuItemInternal(index, item_id, label, SkBitmap(), NULL, type);
+}
+
+Menu* Menu::AppendSubMenu(int item_id, const std::wstring& label) {
+  return AddSubMenu(-1, item_id, label);
+}
+
+Menu* Menu::AddSubMenu(int index, int item_id, const std::wstring& label) {
+  return AddSubMenuWithIcon(index, item_id, label, SkBitmap());
+}
+
+Menu* Menu::AppendSubMenuWithIcon(int item_id,
+                                  const std::wstring& label,
+                                  const SkBitmap& icon) {
+  return AddSubMenuWithIcon(-1, item_id, label, icon);
+}
+
+Menu* Menu::AddSubMenuWithIcon(int index,
+                               int item_id,
+                               const std::wstring& label,
+                               const SkBitmap& icon) {
+  if (!owner_draw_ && icon.width() != 0 && icon.height() != 0)
+    owner_draw_ = true;
+
+  Menu* submenu = new Menu(this);
+  submenus_.push_back(submenu);
+  AddMenuItemInternal(index, item_id, label, icon, submenu->menu_, NORMAL);
+  return submenu;
+}
+
+void Menu::AppendMenuItemWithLabel(int item_id, const std::wstring& label) {
+  AddMenuItemWithLabel(-1, item_id, label);
+}
+
+void Menu::AddMenuItemWithLabel(int index, int item_id,
+                                const std::wstring& label) {
+  AddMenuItem(index, item_id, label, Menu::NORMAL);
+}
+
+void Menu::AppendDelegateMenuItem(int item_id) {
+  AddDelegateMenuItem(-1, item_id);
+}
+
+void Menu::AddDelegateMenuItem(int index, int item_id) {
+  AddMenuItem(index, item_id, std::wstring(), Menu::NORMAL);
+}
+
+void Menu::AppendSeparator() {
+  AddSeparator(-1);
+}
+
+void Menu::AddSeparator(int index) {
+  MENUITEMINFO mii;
+  mii.cbSize = sizeof(mii);
+  mii.fMask = MIIM_FTYPE;
+  mii.fType = MFT_SEPARATOR;
+  InsertMenuItem(menu_, index, TRUE, &mii);
+}
+
+void Menu::AppendMenuItemWithIcon(int item_id,
+                                  const std::wstring& label,
+                                  const SkBitmap& icon) {
+  AddMenuItemWithIcon(-1, item_id, label, icon);
+}
+
+void Menu::AddMenuItemWithIcon(int index,
+                               int item_id,
+                               const std::wstring& label,
+                               const SkBitmap& icon) {
+  if (!owner_draw_)
+    owner_draw_ = true;
+  AddMenuItemInternal(index, item_id, label, icon, NULL, Menu::NORMAL);
+}
+
+void Menu::EnableMenuItemByID(int item_id, bool enabled) {
+  UINT enable_flags = enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED;
+  EnableMenuItem(menu_, item_id, MF_BYCOMMAND | enable_flags);
+}
+
+void Menu::EnableMenuItemAt(int index, bool enabled) {
+  UINT enable_flags = enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED;
+  EnableMenuItem(menu_, index, MF_BYPOSITION | enable_flags);
+}
+
+void Menu::SetMenuLabel(int item_id, const std::wstring& label) {
+  MENUITEMINFO mii = {0};
+  mii.cbSize = sizeof(mii);
+  mii.fMask = MIIM_STRING;
+  mii.dwTypeData = const_cast<wchar_t*>(label.c_str());
+  mii.cch = static_cast<UINT>(label.size());
+  SetMenuItemInfo(menu_, item_id, false, &mii);
+}
+
+DWORD Menu::GetTPMAlignFlags() const {
+  // The manner in which we handle the menu alignment depends on whether or not
+  // the menu is displayed within a mirrored view. If the UI is mirrored, the
+  // alignment needs to be fliped so that instead of aligning the menu to the
+  // right of the point, we align it to the left and vice versa.
+  DWORD align_flags = TPM_TOPALIGN;
+  switch (anchor_) {
+    case TOPLEFT:
+      if (delegate_->IsRightToLeftUILayout()) {
+        align_flags |= TPM_RIGHTALIGN;
+      } else {
+        align_flags |= TPM_LEFTALIGN;
+      }
+      break;
+
+    case TOPRIGHT:
+      if (delegate_->IsRightToLeftUILayout()) {
+        align_flags |= TPM_LEFTALIGN;
+      } else {
+        align_flags |= TPM_RIGHTALIGN;
+      }
+      break;
+
+    default:
+      NOTREACHED();
+      return 0;
+  }
+  return align_flags;
+}
+
+bool Menu::SetIcon(const SkBitmap& icon, int item_id) {
+  if (!owner_draw_)
+    owner_draw_ = true;
+
+  const int num_items = GetMenuItemCount(menu_);
+  int sep_count = 0;
+  for (int i = 0; i < num_items; ++i) {
+    if (!(GetMenuState(menu_, i, MF_BYPOSITION) & MF_SEPARATOR)) {
+      if (ChromeGetMenuItemID(menu_, i) == item_id) {
+        item_data_[i - sep_count]->icon = icon;
+        // When the menu is running, we use SetMenuItemInfo to let Windows
+        // update the item information so that the icon being displayed
+        // could change immediately.
+        if (active_host_window) {
+          MENUITEMINFO mii;
+          mii.cbSize = sizeof(mii);
+          mii.fMask = MIIM_FTYPE | MIIM_DATA;
+          mii.fType = MFT_OWNERDRAW;
+          mii.dwItemData =
+              reinterpret_cast<ULONG_PTR>(item_data_[i - sep_count]);
+          SetMenuItemInfo(menu_, item_id, false, &mii);
+        }
+        return true;
+      }
+    } else {
+      ++sep_count;
+    }
+  }
+
+  // Continue searching for the item in submenus.
+  for (size_t i = 0; i < submenus_.size(); ++i) {
+    if (submenus_[i]->SetIcon(icon, item_id))
+      return true;
+  }
+
+  return false;
+}
+
+void Menu::SetMenuInfo() {
+  const int num_items = GetMenuItemCount(menu_);
+  int sep_count = 0;
+  for (int i = 0; i < num_items; ++i) {
+    MENUITEMINFO mii_info;
+    mii_info.cbSize = sizeof(mii_info);
+    // Get the menu's original type.
+    mii_info.fMask = MIIM_FTYPE;
+    GetMenuItemInfo(menu_, i, MF_BYPOSITION, &mii_info);
+    // Set item states.
+    if (!(mii_info.fType & MF_SEPARATOR)) {
+      const int id = ChromeGetMenuItemID(menu_, i);
+
+      MENUITEMINFO mii;
+      mii.cbSize = sizeof(mii);
+      mii.fMask = MIIM_STATE | MIIM_FTYPE | MIIM_DATA | MIIM_STRING;
+      // We also need MFT_STRING for owner drawn items in order to let Windows
+      // handle the accelerators for us.
+      mii.fType = MFT_STRING;
+      if (owner_draw_)
+        mii.fType |= MFT_OWNERDRAW;
+      // If the menu originally has radiocheck type, we should follow it.
+      if (mii_info.fType & MFT_RADIOCHECK)
+        mii.fType |= MFT_RADIOCHECK;
+      mii.fState = GetStateFlagsForItemID(id);
+
+      // Validate the label. If there is a contextual label, use it, otherwise
+      // default to the static label
+      std::wstring label;
+      if (!delegate_->GetContextualLabel(id, &label))
+        label = labels_[i - sep_count];
+
+      if (owner_draw_) {
+        item_data_[i - sep_count]->label = label;
+        mii.dwItemData = reinterpret_cast<ULONG_PTR>(item_data_[i - sep_count]);
+      }
+      mii.dwTypeData = const_cast<wchar_t*>(label.c_str());
+      mii.cch = static_cast<UINT>(label.size());
+      SetMenuItemInfo(menu_, i, true, &mii);
+    } else {
+      // Set data for owner drawn separators. Set dwItemData NULL to indicate
+      // a separator.
+      if (owner_draw_) {
+        MENUITEMINFO mii;
+        mii.cbSize = sizeof(mii);
+        mii.fMask = MIIM_FTYPE;
+        mii.fType = MFT_SEPARATOR | MFT_OWNERDRAW;
+        mii.dwItemData = NULL;
+        SetMenuItemInfo(menu_, i, true, &mii);
+      }
+      ++sep_count;
+    }
+  }
+
+  for (size_t i = 0; i < submenus_.size(); ++i)
+    submenus_[i]->SetMenuInfo();
+}
+
+void Menu::RunMenuAt(int x, int y) {
+  SetMenuInfo();
+
+  delegate_->MenuWillShow();
+
+  // NOTE: we don't use TPM_RIGHTBUTTON here as it breaks selecting by way of
+  // press, drag, release. See bugs 718 and 8560.
+  UINT flags =
+      GetTPMAlignFlags() | TPM_LEFTBUTTON | TPM_RETURNCMD | TPM_RECURSE;
+  is_menu_visible_ = true;
+  DCHECK(owner_);
+  // In order for context menus on menus to work, the context menu needs to
+  // share the same window as the first menu is parented to.
+  bool created_host = false;
+  if (!active_host_window) {
+    created_host = true;
+    active_host_window = new MenuHostWindow(this, owner_);
+  }
+  UINT selected_id =
+      TrackPopupMenuEx(menu_, flags, x, y, active_host_window->m_hWnd, NULL);
+  if (created_host) {
+    delete active_host_window;
+    active_host_window = NULL;
+  }
+  is_menu_visible_ = false;
+
+  // Execute the chosen command
+  if (selected_id != 0)
+    delegate_->ExecuteCommand(selected_id);
+}
+
+void Menu::Cancel() {
+  DCHECK(is_menu_visible_);
+  EndMenu();
+}
+
+int Menu::ItemCount() {
+  return GetMenuItemCount(menu_);
+}
diff --git a/views/controls/menu/menu.h b/views/controls/menu/menu.h
new file mode 100644
index 0000000..0be9126
--- /dev/null
+++ b/views/controls/menu/menu.h
@@ -0,0 +1,355 @@
+// Copyright (c) 2006-2008 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 CONTROLS_MENU_VIEWS_MENU_H_
+#define CONTROLS_MENU_VIEWS_MENU_H_
+
+#include <windows.h>
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "views/controls/menu/controller.h"
+
+class SkBitmap;
+
+namespace {
+class MenuHostWindow;
+}
+
+namespace views {
+class Accelerator;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Menu class
+//
+//   A wrapper around a Win32 HMENU handle that provides convenient APIs for
+//   menu construction, display and subsequent command execution.
+//
+///////////////////////////////////////////////////////////////////////////////
+class Menu {
+  friend class MenuHostWindow;
+
+ public:
+  /////////////////////////////////////////////////////////////////////////////
+  //
+  // Delegate Interface
+  //
+  //  Classes implement this interface to tell the menu system more about each
+  //  item as it is created.
+  //
+  /////////////////////////////////////////////////////////////////////////////
+  class Delegate : public Controller {
+   public:
+    virtual ~Delegate() { }
+
+    // Whether or not an item should be shown as checked.
+    virtual bool IsItemChecked(int id) const {
+      return false;
+    }
+
+    // Whether or not an item should be shown as the default (using bold).
+    // There can only be one default menu item.
+    virtual bool IsItemDefault(int id) const {
+      return false;
+    }
+
+    // The string shown for the menu item.
+    virtual std::wstring GetLabel(int id) const {
+      return std::wstring();
+    }
+
+    // The delegate needs to implement this function if it wants to display
+    // the shortcut text next to each menu item. If there is an accelerator
+    // for a given item id, the implementor must return it.
+    virtual bool GetAcceleratorInfo(int id, views::Accelerator* accel) {
+      return false;
+    }
+
+    // The icon shown for the menu item.
+    virtual const SkBitmap& GetIcon(int id) const {
+      return GetEmptyIcon();
+    }
+
+    // The number of items to show in the menu
+    virtual int GetItemCount() const {
+      return 0;
+    }
+
+    // Whether or not an item is a separator.
+    virtual bool IsItemSeparator(int id) const {
+      return false;
+    }
+
+    // Shows the context menu with the specified id. This is invoked when the
+    // user does the appropriate gesture to show a context menu. The id
+    // identifies the id of the menu to show the context menu for.
+    // is_mouse_gesture is true if this is the result of a mouse gesture.
+    // If this is not the result of a mouse gesture x/y is the recommended
+    // location to display the content menu at. In either case, x/y is in
+    // screen coordinates.
+    virtual void ShowContextMenu(Menu* source,
+                                 int id,
+                                 int x,
+                                 int y,
+                                 bool is_mouse_gesture) {
+    }
+
+    // Whether an item has an icon.
+    virtual bool HasIcon(int id) const {
+      return false;
+    }
+
+    // Notification that the menu is about to be popped up.
+    virtual void MenuWillShow() {
+    }
+
+    // Whether to create a right-to-left menu. The default implementation
+    // returns true if the locale's language is a right-to-left language (such
+    // as Hebrew) and false otherwise. This is generally the right behavior
+    // since there is no reason to show left-to-right menus for right-to-left
+    // locales. However, subclasses can override this behavior so that the menu
+    // is a right-to-left menu only if the view's layout is right-to-left
+    // (since the view can use a different layout than the locale's language
+    // layout).
+    virtual bool IsRightToLeftUILayout() const;
+
+    // Controller
+    virtual bool SupportsCommand(int id) const {
+      return true;
+    }
+    virtual bool IsCommandEnabled(int id) const {
+      return true;
+    }
+    virtual bool GetContextualLabel(int id, std::wstring* out) const {
+      return false;
+    }
+    virtual void ExecuteCommand(int id) {
+    }
+
+   protected:
+    // Returns an empty icon. Will initialize kEmptyIcon if it hasn't been
+    // initialized.
+    const SkBitmap& GetEmptyIcon() const;
+
+   private:
+    // Will be initialized to an icon of 0 width and 0 height when first using.
+    // An empty icon means we don't need to draw it.
+    static const SkBitmap* kEmptyIcon;
+  };
+
+  // This class is a helper that simply wraps a controller and forwards all
+  // state and execution actions to it.  Use this when you're not defining your
+  // own custom delegate, but just hooking a context menu to some existing
+  // controller elsewhere.
+  class BaseControllerDelegate : public Delegate {
+   public:
+    explicit BaseControllerDelegate(Controller* wrapped)
+      : controller_(wrapped) {
+    }
+
+    // Overridden from Menu::Delegate
+    virtual bool SupportsCommand(int id) const {
+      return controller_->SupportsCommand(id);
+    }
+    virtual bool IsCommandEnabled(int id) const {
+      return controller_->IsCommandEnabled(id);
+    }
+    virtual void ExecuteCommand(int id) {
+      controller_->ExecuteCommand(id);
+    }
+    virtual bool GetContextualLabel(int id, std::wstring* out) const {
+      return controller_->GetContextualLabel(id, out);
+    }
+
+   private:
+    // The internal controller that we wrap to forward state and execution
+    // actions to.
+    Controller* controller_;
+
+    DISALLOW_COPY_AND_ASSIGN(BaseControllerDelegate);
+  };
+
+  // How this popup should align itself relative to the point it is run at.
+  enum AnchorPoint {
+    TOPLEFT,
+    TOPRIGHT
+  };
+
+  // Different types of menu items
+  enum MenuItemType {
+    NORMAL,
+    CHECKBOX,
+    RADIO,
+    SEPARATOR
+  };
+
+  // Construct a Menu using the specified controller to determine command
+  // state.
+  // delegate     A Menu::Delegate implementation that provides more
+  //              information about the Menu presentation.
+  // anchor       An alignment hint for the popup menu.
+  // owner        The window that the menu is being brought up relative
+  //              to. Not actually used for anything but must not be
+  //              NULL.
+  Menu(Delegate* delegate, AnchorPoint anchor, HWND owner);
+  // Alternatively, a Menu object can be constructed wrapping an existing
+  // HMENU. This can be used to use the convenience methods to insert
+  // menu items and manage label string ownership. However this kind of
+  // Menu object cannot use the delegate.
+  explicit Menu(HMENU hmenu);
+  virtual ~Menu();
+
+  void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+
+  // Adds an item to this menu.
+  // item_id    The id of the item, used to identify it in delegate callbacks
+  //            or (if delegate is NULL) to identify the command associated
+  //            with this item with the controller specified in the ctor. Note
+  //            that this value should not be 0 as this has a special meaning
+  //            ("NULL command, no item selected")
+  // label      The text label shown.
+  // type       The type of item.
+  void AppendMenuItem(int item_id,
+                      const std::wstring& label,
+                      MenuItemType type);
+  void AddMenuItem(int index,
+                   int item_id,
+                   const std::wstring& label,
+                   MenuItemType type);
+
+  // Append a submenu to this menu.
+  // The returned pointer is owned by this menu.
+  Menu* AppendSubMenu(int item_id,
+                      const std::wstring& label);
+  Menu* AddSubMenu(int index, int item_id, const std::wstring& label);
+
+  // Append a submenu with an icon to this menu
+  // The returned pointer is owned by this menu.
+  // Unless the icon is empty, calling this function forces the Menu class
+  // to draw the menu, instead of relying on Windows.
+  Menu* AppendSubMenuWithIcon(int item_id,
+                              const std::wstring& label,
+                              const SkBitmap& icon);
+  Menu* AddSubMenuWithIcon(int index,
+                           int item_id,
+                           const std::wstring& label,
+                           const SkBitmap& icon);
+
+  // This is a convenience for standard text label menu items where the label
+  // is provided with this call.
+  void AppendMenuItemWithLabel(int item_id, const std::wstring& label);
+  void AddMenuItemWithLabel(int index, int item_id, const std::wstring& label);
+
+  // This is a convenience for text label menu items where the label is
+  // provided by the delegate.
+  void AppendDelegateMenuItem(int item_id);
+  void AddDelegateMenuItem(int index, int item_id);
+
+  // Adds a separator to this menu
+  void AppendSeparator();
+  void AddSeparator(int index);
+
+  // Appends a menu item with an icon. This is for the menu item which
+  // needs an icon. Calling this function forces the Menu class to draw
+  // the menu, instead of relying on Windows.
+  void AppendMenuItemWithIcon(int item_id,
+                              const std::wstring& label,
+                              const SkBitmap& icon);
+  void AddMenuItemWithIcon(int index,
+                           int item_id,
+                           const std::wstring& label,
+                           const SkBitmap& icon);
+
+  // Enables or disables the item with the specified id.
+  void EnableMenuItemByID(int item_id, bool enabled);
+  void EnableMenuItemAt(int index, bool enabled);
+
+  // Sets menu label at specified index.
+  void SetMenuLabel(int item_id, const std::wstring& label);
+
+  // Sets an icon for an item with a given item_id. Calling this function
+  // also forces the Menu class to draw the menu, instead of relying on Windows.
+  // Returns false if the item with |item_id| is not found.
+  bool SetIcon(const SkBitmap& icon, int item_id);
+
+  // Shows the menu, blocks until the user dismisses the menu or selects an
+  // item, and executes the command for the selected item (if any).
+  // Warning: Blocking call. Will implicitly run a message loop.
+  void RunMenuAt(int x, int y);
+
+  // Cancels the menu.
+  virtual void Cancel();
+
+  // Returns the number of menu items.
+  int ItemCount();
+
+ protected:
+  // The delegate that is being used to get information about the presentation.
+  Delegate* delegate_;
+
+ private:
+  // The data of menu items needed to display.
+  struct ItemData;
+
+  explicit Menu(Menu* parent);
+
+  void AddMenuItemInternal(int index,
+                           int item_id,
+                           const std::wstring& label,
+                           const SkBitmap& icon,
+                           HMENU submenu,
+                           MenuItemType type);
+
+  // Sets menu information before displaying, including sub-menus.
+  void SetMenuInfo();
+
+  // Get all the state flags for the |fState| field of MENUITEMINFO for the
+  // item with the specified id. |delegate| is consulted if non-NULL about
+  // the state of the item in preference to |controller_|.
+  UINT GetStateFlagsForItemID(int item_id) const;
+
+  // Gets the Win32 TPM alignment flags for the specified AnchorPoint.
+  DWORD GetTPMAlignFlags() const;
+
+  // The Win32 Menu Handle we wrap
+  HMENU menu_;
+
+  // The window that would receive WM_COMMAND messages when the user selects
+  // an item from the menu.
+  HWND owner_;
+
+  // This list is used to store the default labels for the menu items.
+  // We may use contextual labels when RunMenu is called, so we must save
+  // a copy of default ones here.
+  std::vector<std::wstring> labels_;
+
+  // A flag to indicate whether this menu will be drawn by the Menu class.
+  // If it's true, all the menu items will be owner drawn. Otherwise,
+  // all the drawing will be done by Windows.
+  bool owner_draw_;
+
+  // How this popup menu should be aligned relative to the point it is run at.
+  AnchorPoint anchor_;
+
+  // This list is to store the string labels and icons to display. It's used
+  // when owner_draw_ is true. We give MENUITEMINFO pointers to these
+  // structures to specify what we'd like to draw. If owner_draw_ is false,
+  // we only give MENUITEMINFO pointers to the labels_.
+  // The label member of the ItemData structure comes from either labels_ or
+  // the GetContextualLabel.
+  std::vector<ItemData*> item_data_;
+
+  // Our sub-menus, if any.
+  std::vector<Menu*> submenus_;
+
+  // Whether the menu is visible.
+  bool is_menu_visible_;
+
+  DISALLOW_COPY_AND_ASSIGN(Menu);
+};
+
+#endif  // CONTROLS_MENU_VIEWS_MENU_H_
diff --git a/views/controls/menu/view_menu_delegate.h b/views/controls/menu/view_menu_delegate.h
new file mode 100644
index 0000000..bb72ed3
--- /dev/null
+++ b/views/controls/menu/view_menu_delegate.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_MENU_VIEW_MENU_DELEGATE_H_
+#define VIEWS_CONTROLS_MENU_VIEW_MENU_DELEGATE_H_
+
+#include "base/gfx/native_widget_types.h"
+
+namespace views {
+
+class View;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ViewMenuDelegate
+//
+// An interface that allows a component to tell a View about a menu that it
+// has constructed that the view can show (e.g. for MenuButton views, or as a
+// context menu.)
+//
+////////////////////////////////////////////////////////////////////////////////
+class ViewMenuDelegate {
+ public:
+  // Create and show a menu at the specified position. Source is the view the
+  // ViewMenuDelegate was set on.
+  virtual void RunMenu(View* source,
+                       const CPoint& pt,
+                       gfx::NativeView hwnd) = 0;
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_MENU_VIEW_MENU_DELEGATE_H_
diff --git a/views/controls/message_box_view.cc b/views/controls/message_box_view.cc
new file mode 100644
index 0000000..d9c45c2
--- /dev/null
+++ b/views/controls/message_box_view.cc
@@ -0,0 +1,209 @@
+// Copyright (c) 2006-2008 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 "views/controls/message_box_view.h"
+
+#include "app/l10n_util.h"
+#include "app/message_box_flags.h"
+#include "base/clipboard.h"
+#include "base/message_loop.h"
+#include "base/scoped_clipboard_writer.h"
+#include "base/string_util.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/views/standard_layout.h"
+#include "views/controls/button/checkbox.h"
+#include "views/window/client_view.h"
+#include "grit/generated_resources.h"
+
+static const int kDefaultMessageWidth = 320;
+
+///////////////////////////////////////////////////////////////////////////////
+// MessageBoxView, public:
+
+MessageBoxView::MessageBoxView(int dialog_flags,
+                               const std::wstring& message,
+                               const std::wstring& default_prompt,
+                               int message_width)
+    : message_label_(new views::Label(message)),
+      prompt_field_(NULL),
+      icon_(NULL),
+      checkbox_(NULL),
+      message_width_(message_width),
+      focus_grabber_factory_(this) {
+  Init(dialog_flags, default_prompt);
+}
+
+MessageBoxView::MessageBoxView(int dialog_flags,
+                               const std::wstring& message,
+                               const std::wstring& default_prompt)
+    : message_label_(new views::Label(message)),
+      prompt_field_(NULL),
+      icon_(NULL),
+      checkbox_(NULL),
+      message_width_(kDefaultMessageWidth),
+      focus_grabber_factory_(this) {
+  Init(dialog_flags, default_prompt);
+}
+
+std::wstring MessageBoxView::GetInputText() {
+  if (prompt_field_)
+    return prompt_field_->GetText();
+  return EmptyWString();
+}
+
+bool MessageBoxView::IsCheckBoxSelected() {
+  return checkbox_ ? checkbox_->checked() : false;
+}
+
+void MessageBoxView::SetIcon(const SkBitmap& icon) {
+  if (!icon_)
+    icon_ = new views::ImageView();
+  icon_->SetImage(icon);
+  icon_->SetBounds(0, 0, icon.width(), icon.height());
+  ResetLayoutManager();
+}
+
+void MessageBoxView::SetCheckBoxLabel(const std::wstring& label) {
+  if (!checkbox_)
+    checkbox_ = new views::Checkbox(label);
+  else
+    checkbox_->SetLabel(label);
+  ResetLayoutManager();
+}
+
+void MessageBoxView::SetCheckBoxSelected(bool selected) {
+  if (!checkbox_)
+    return;
+  checkbox_->SetChecked(selected);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MessageBoxView, views::View overrides:
+
+void MessageBoxView::ViewHierarchyChanged(bool is_add,
+                                          views::View* parent,
+                                          views::View* child) {
+  if (child == this && is_add) {
+    if (prompt_field_)
+      prompt_field_->SelectAll();
+  }
+}
+
+bool MessageBoxView::AcceleratorPressed(
+    const views::Accelerator& accelerator) {
+  // We only accepts Ctrl-C.
+  DCHECK(accelerator.GetKeyCode() == 'C' && accelerator.IsCtrlDown());
+
+  Clipboard* clipboard = g_browser_process->clipboard();
+  if (!clipboard)
+    return false;
+
+  ScopedClipboardWriter scw(clipboard);
+  scw.WriteText(message_label_->GetText());
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MessageBoxView, private:
+
+void MessageBoxView::Init(int dialog_flags,
+                          const std::wstring& default_prompt) {
+  message_label_->SetMultiLine(true);
+  message_label_->SetAllowCharacterBreak(true);
+  if (dialog_flags & MessageBoxFlags::kAutoDetectAlignment) {
+    // Determine the alignment and directionality based on the first character
+    // with strong directionality.
+    l10n_util::TextDirection direction =
+        l10n_util::GetFirstStrongCharacterDirection(message_label_->GetText());
+    views::Label::Alignment alignment;
+    if (direction == l10n_util::RIGHT_TO_LEFT)
+      alignment = views::Label::ALIGN_RIGHT;
+    else
+      alignment = views::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_->SetRTLAlignmentMode(views::Label::AUTO_DETECT_ALIGNMENT);
+    message_label_->SetHorizontalAlignment(alignment);
+  } else {
+    message_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+  }
+
+  if (dialog_flags & MessageBoxFlags::kFlagHasPromptField) {
+    prompt_field_ = new views::TextField;
+    prompt_field_->SetText(default_prompt);
+  }
+
+  ResetLayoutManager();
+}
+
+void MessageBoxView::ResetLayoutManager() {
+  using views::GridLayout;
+  using views::ColumnSet;
+
+  // Initialize the Grid Layout Manager used for this dialog box.
+  GridLayout* layout = CreatePanelGridLayout(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);
+}
diff --git a/views/controls/message_box_view.h b/views/controls/message_box_view.h
new file mode 100644
index 0000000..6356d84
--- /dev/null
+++ b/views/controls/message_box_view.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_MESSAGE_BOX_VIEW_VIEW_H_
+#define VIEWS_CONTROLS_MESSAGE_BOX_VIEW_VIEW_H_
+
+#include <string>
+
+#include "base/task.h"
+#include "views/controls/image_view.h"
+#include "views/controls/label.h"
+#include "views/controls/text_field.h"
+#include "views/view.h"
+
+namespace views {
+class Checkbox;
+}
+
+// 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 MessageBoxView : public views::View {
+ public:
+  MessageBoxView(int dialog_flags,
+                 const std::wstring& message,
+                 const std::wstring& default_prompt,
+                 int message_width);
+
+  MessageBoxView(int dialog_flags,
+                 const std::wstring& message,
+                 const std::wstring& default_prompt);
+
+  // Returns the text box.
+  views::TextField* text_box() { return prompt_field_; }
+
+  // Returns user entered data in the prompt field.
+  std::wstring 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 std::wstring& label);
+
+  // Sets the state of the check-box.
+  void SetCheckBoxSelected(bool selected);
+
+ protected:
+  // Layout and Painting functions.
+  virtual void ViewHierarchyChanged(bool is_add,
+                                    views::View* parent,
+                                    views::View* child);
+
+  // Handles Ctrl-C and writes the message in the system clipboard.
+  virtual bool AcceleratorPressed(const views::Accelerator& accelerator);
+
+ 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 std::wstring& 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.
+  views::Label* message_label_;
+
+  // Input text field for the message box.
+  views::TextField* prompt_field_;
+
+  // Icon displayed in the upper left corner of the message box.
+  views::ImageView* icon_;
+
+  // Checkbox for the message box.
+  views::Checkbox* checkbox_;
+
+  // Maximum width of the message label.
+  int message_width_;
+
+  ScopedRunnableMethodFactory<MessageBoxView> focus_grabber_factory_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(MessageBoxView);
+};
+
+#endif  // VIEWS_CONTROLS_MESSAGE_BOX_VIEW_VIEW_H_
diff --git a/views/controls/native_control.cc b/views/controls/native_control.cc
new file mode 100644
index 0000000..ce37193e
--- /dev/null
+++ b/views/controls/native_control.cc
@@ -0,0 +1,385 @@
+// Copyright (c) 2006-2008 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 "views/controls/native_control.h"
+
+#include <atlbase.h>
+#include <atlapp.h>
+#include <atlcrack.h>
+#include <atlframe.h>
+
+#include "app/l10n_util_win.h"
+#include "base/logging.h"
+#include "base/win_util.h"
+#include "views/background.h"
+#include "views/border.h"
+#include "views/controls/hwnd_view.h"
+#include "views/focus/focus_manager.h"
+#include "views/widget/widget.h"
+#include "base/gfx/native_theme.h"
+
+namespace views {
+
+// Maps to the original WNDPROC for the controller window before we subclassed
+// it.
+static const wchar_t* const kHandlerKey =
+    L"__CONTROL_ORIGINAL_MESSAGE_HANDLER__";
+
+// Maps to the NativeControl.
+static const wchar_t* const kNativeControlKey = L"__NATIVE_CONTROL__";
+
+class NativeControlContainer : public CWindowImpl<NativeControlContainer,
+                               CWindow,
+                               CWinTraits<WS_CHILD | WS_CLIPSIBLINGS |
+                                          WS_CLIPCHILDREN>> {
+ public:
+
+  explicit NativeControlContainer(NativeControl* parent) : parent_(parent),
+                                                           control_(NULL) {
+    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:
+
+  LRESULT OnCreate(LPCREATESTRUCT create_struct) {
+    TRACK_HWND_CREATION(m_hWnd);
+
+    control_ = parent_->CreateNativeControl(m_hWnd);
+    TRACK_HWND_CREATION(control_);
+
+    FocusManager::InstallFocusSubclass(control_, parent_);
+
+    // We subclass the control hwnd so we get the WM_KEYDOWN messages.
+    WNDPROC original_handler =
+        win_util::SetWindowProc(control_,
+                                &NativeControl::NativeControlWndProc);
+    SetProp(control_, kHandlerKey, original_handler);
+    SetProp(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();
+    TRACK_HWND_DESTRUCTION(m_hWnd);
+  }
+
+  void OnContextMenu(HWND window, const CPoint& 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->GetParent();
+    }
+
+    // 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_;
+  DISALLOW_EVIL_CONSTRUCTORS(NativeControlContainer);
+};
+
+NativeControl::NativeControl() : hwnd_view_(NULL),
+                                 container_(NULL),
+                                 fixed_width_(-1),
+                                 horizontal_alignment_(CENTER),
+                                 fixed_height_(-1),
+                                 vertical_alignment_(CENTER) {
+  enabled_ = true;
+  focusable_ = true;
+}
+
+NativeControl::~NativeControl() {
+  if (container_) {
+    container_->ResetParent();
+    ::DestroyWindow(*container_);
+  }
+}
+
+void NativeControl::ValidateNativeControl() {
+  if (hwnd_view_ == NULL) {
+    hwnd_view_ = new HWNDView();
+    AddChildView(hwnd_view_);
+  }
+
+  if (!container_ && IsVisible()) {
+    container_ = new NativeControlContainer(this);
+    hwnd_view_->Attach(*container_);
+    if (!enabled_)
+      EnableWindow(GetNativeControlHWND(), enabled_);
+
+    // 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 && GetWidget()) {
+    ValidateNativeControl();
+    Layout();
+  }
+}
+
+void NativeControl::Layout() {
+  if (!container_ && GetWidget())
+    ValidateNativeControl();
+
+  if (hwnd_view_) {
+    gfx::Rect lb = GetLocalBounds(false);
+
+    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 CPoint& location) {
+  if (!GetContextMenuController())
+    return;
+
+  int x = location.x;
+  int y = location.y;
+  bool is_mouse = true;
+  if (x == -1 && y == -1) {
+    gfx::Point point = GetKeyboardContextMenuLocation();
+    x = point.x();
+    y = point.y();
+    is_mouse = false;
+  }
+  ShowContextMenu(x, y, is_mouse);
+}
+
+void NativeControl::Focus() {
+  if (container_) {
+    DCHECK(container_->GetControl());
+    ::SetFocus(container_->GetControl());
+  }
+}
+
+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::SetEnabled(bool enabled) {
+  if (enabled_ != enabled) {
+    View::SetEnabled(enabled);
+    if (GetNativeControlHWND()) {
+      EnableWindow(GetNativeControlHWND(), enabled_);
+    }
+  }
+}
+
+void NativeControl::Paint(ChromeCanvas* canvas) {
+}
+
+void NativeControl::VisibilityChanged(View* starting_from, bool is_visible) {
+  SetVisible(is_visible);
+}
+
+void NativeControl::SetFixedWidth(int width, Alignment alignment) {
+  DCHECK(width > 0);
+  fixed_width_ = width;
+  horizontal_alignment_ = alignment;
+}
+
+void NativeControl::SetFixedHeight(int height, Alignment alignment) {
+  DCHECK(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 (UILayoutIsRightToLeft())
+    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 (UILayoutIsRightToLeft())
+    ex_style |= l10n_util::GetExtendedTooltipStyles();
+
+  return ex_style;
+}
+
+// static
+LRESULT CALLBACK NativeControl::NativeControlWndProc(HWND window, UINT message,
+                                                     WPARAM w_param,
+                                                     LPARAM l_param) {
+  HANDLE original_handler = GetProp(window, kHandlerKey);
+  DCHECK(original_handler);
+  NativeControl* native_control =
+      static_cast<NativeControl*>(GetProp(window, kNativeControlKey));
+  DCHECK(native_control);
+
+  if (message == WM_KEYDOWN && native_control->NotifyOnKeyDown()) {
+    if (native_control->OnKeyDown(static_cast<int>(w_param)))
+      return 0;
+  } else if (message == WM_DESTROY) {
+    win_util::SetWindowProc(window,
+                            reinterpret_cast<WNDPROC>(original_handler));
+    RemoveProp(window, kHandlerKey);
+    RemoveProp(window, kNativeControlKey);
+    TRACK_HWND_DESTRUCTION(window);
+  }
+
+  return CallWindowProc(reinterpret_cast<WNDPROC>(original_handler), window,
+                        message, w_param, l_param);
+}
+
+}  // namespace views
diff --git a/views/controls/native_control.h b/views/controls/native_control.h
new file mode 100644
index 0000000..0573168
--- /dev/null
+++ b/views/controls/native_control.h
@@ -0,0 +1,132 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_NATIVE_CONTROL_H_
+#define VIEWS_CONTROLS_NATIVE_CONTROL_H_
+
+#include <windows.h>
+
+#include "views/view.h"
+
+namespace views {
+
+class HWNDView;
+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 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 SetEnabled(bool enabled);
+
+  // Overridden to do nothing.
+  virtual void Paint(ChromeCanvas* 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 CPoint& location);
+
+  // Overridden so to set the native focus to the native control.
+  virtual void Focus();
+
+  // 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);
+
+  // Derived classes interested in receiving key down notification should
+  // override this method and return true.  In which case OnKeyDown is called
+  // when a key down message is sent to the control.
+  // Note that this method is called at the time of the control creation: the
+  // behavior will not change if the returned value changes after the control
+  // has been created.
+  virtual bool NotifyOnKeyDown() const { return false; }
+
+  // Invoked when a key is pressed on the control (if NotifyOnKeyDown returns
+  // true).  Should return true if the key message was processed, false
+  // otherwise.
+  virtual bool OnKeyDown(int 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().
+  HWNDView* 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  // VIEWS_CONTROLS_NATIVE_CONTROL_H_
diff --git a/views/controls/native_control_win.cc b/views/controls/native_control_win.cc
new file mode 100644
index 0000000..0c1baf8
--- /dev/null
+++ b/views/controls/native_control_win.cc
@@ -0,0 +1,201 @@
+// Copyright (c) 2009 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 "views/controls/native_control_win.h"
+
+#include "app/l10n_util_win.h"
+#include "base/logging.h"
+#include "base/win_util.h"
+
+namespace views {
+
+// static
+const wchar_t* NativeControlWin::kNativeControlWinKey =
+    L"__NATIVE_CONTROL_WIN__";
+
+static const wchar_t* kNativeControlOriginalWndProcKey =
+    L"__NATIVE_CONTROL_ORIGINAL_WNDPROC__";
+
+// static
+WNDPROC NativeControlWin::original_wndproc_ = NULL;
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlWin, public:
+
+NativeControlWin::NativeControlWin() : HWNDView() {
+}
+
+NativeControlWin::~NativeControlWin() {
+  HWND hwnd = GetHWND();
+  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(LOWORD(l_param), HIWORD(l_param)));
+      *result = 0;
+      return true;
+    case WM_CTLCOLORBTN:
+    case WM_CTLCOLORSTATIC:
+      *result = GetControlColor(message, reinterpret_cast<HDC>(w_param),
+                                GetHWND());
+      return true;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlWin, View overrides:
+
+void NativeControlWin::SetEnabled(bool enabled) {
+  if (IsEnabled() != enabled) {
+    View::SetEnabled(enabled);
+    if (GetHWND())
+      EnableWindow(GetHWND(), IsEnabled());
+  }
+}
+
+void NativeControlWin::ViewHierarchyChanged(bool is_add, View* parent,
+                                            View* 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() && !GetHWND())
+    CreateNativeControl();
+
+  // Call the base class to hide the view if we're being removed.
+  HWNDView::ViewHierarchyChanged(is_add, parent, child);
+}
+
+void NativeControlWin::VisibilityChanged(View* starting_from, bool is_visible) {
+  if (!is_visible) {
+    // We destroy the child control HWND when we become invisible because of the
+    // performance cost of maintaining many HWNDs.
+    HWND hwnd = GetHWND();
+    Detach();
+    DestroyWindow(hwnd);
+  } else if (!GetHWND()) {
+    CreateNativeControl();
+  }
+}
+
+void NativeControlWin::Focus() {
+  DCHECK(GetHWND());
+  SetFocus(GetHWND());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeControlWin, protected:
+
+void NativeControlWin::ShowContextMenu(const gfx::Point& location) {
+  if (!GetContextMenuController())
+    return;
+
+  int x = location.x();
+  int y = location.y();
+  bool is_mouse = true;
+  if (x == -1 && y == -1) {
+    gfx::Point point = GetKeyboardContextMenuLocation();
+    x = point.x();
+    y = point.y();
+    is_mouse = false;
+  }
+  View::ShowContextMenu(x, y, is_mouse);
+}
+
+void NativeControlWin::NativeControlCreated(HWND native_control) {
+  TRACK_HWND_CREATION(native_control);
+
+  // Associate this object with the control's HWND so that WidgetWin can find
+  // this object when it receives messages from it.
+  SetProp(native_control, kNativeControlWinKey, this);
+
+  // Subclass the window so we can monitor for key presses.
+  original_wndproc_ =
+      win_util::SetWindowProc(native_control,
+                              &NativeControlWin::NativeControlWndProc);
+  SetProp(native_control, kNativeControlOriginalWndProcKey, original_wndproc_);
+
+  Attach(native_control);
+  // GetHWND() is now valid.
+
+  // Update the newly created HWND with any resident enabled state.
+  EnableWindow(GetHWND(), IsEnabled());
+
+  // This message ensures that the focus border is shown.
+  SendMessage(GetHWND(), 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 (UILayoutIsRightToLeft())
+    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 (UILayoutIsRightToLeft())
+    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->GetParent();
+  }
+
+  // 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 =
+      static_cast<NativeControlWin*>(GetProp(window, kNativeControlWinKey));
+  DCHECK(native_control);
+
+  if (message == WM_KEYDOWN && native_control->NotifyOnKeyDown()) {
+    if (native_control->OnKeyDown(static_cast<int>(w_param)))
+      return 0;
+  } else if (message == WM_DESTROY) {
+    win_util::SetWindowProc(window, native_control->original_wndproc_);
+    RemoveProp(window, kNativeControlWinKey);
+    TRACK_HWND_DESTRUCTION(window);
+  }
+
+  return CallWindowProc(native_control->original_wndproc_, window, message,
+                        w_param, l_param);
+}
+
+}  // namespace views
diff --git a/views/controls/native_control_win.h b/views/controls/native_control_win.h
new file mode 100644
index 0000000..6f9923f
--- /dev/null
+++ b/views/controls/native_control_win.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2009 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 VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
+#define VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
+
+#include "views/controls/hwnd_view.h"
+
+namespace views {
+
+// A View that hosts a native Windows control.
+class NativeControlWin : public HWNDView {
+ public:
+  static const wchar_t* kNativeControlWinKey;
+
+  NativeControlWin();
+  virtual ~NativeControlWin();
+
+  // Called by the containing WidgetWin when a message is received from the HWND
+  // created by an object derived from NativeControlWin. Derived classes MUST
+  // call _this_ version of the function if they override it and do not handle
+  // all of the messages listed in widget_win.cc ProcessNativeControlWinMessage.
+  // Returns true if the message was handled, with a valid result in |result|.
+  // Returns false if the message was not handled.
+  virtual bool ProcessMessage(UINT message,
+                                 WPARAM w_param,
+                                 LPARAM l_param,
+                                 LRESULT* result);
+
+  // 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 View:
+  virtual void SetEnabled(bool enabled);
+
+ protected:
+  virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
+  virtual void VisibilityChanged(View* starting_from, bool is_visible);
+  virtual void Focus();
+
+  // Called by the containing WidgetWin when a WM_CONTEXTMENU message is
+  // received from the HWND created by an object derived from NativeControlWin.
+  virtual void ShowContextMenu(const gfx::Point& location);
+
+  // Derived classes interested in receiving key down notification should
+  // override this method and return true.  In which case OnKeyDown is called
+  // when a key down message is sent to the control.
+  // Note that this method is called at the time of the control creation: the
+  // behavior will not change if the returned value changes after the control
+  // has been created.
+  virtual bool NotifyOnKeyDown() const { return false; }
+
+  // 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 HWNDView 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:
+  // Called by the containing WidgetWin when a message of type WM_CTLCOLORBTN or
+  // WM_CTLCOLORSTATIC is sent from the HWND created by an object dreived 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.
+  static WNDPROC original_wndproc_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeControlWin);
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_CONTROLS_NATIVE_CONTROL_WIN_H_
diff --git a/views/controls/native_view_host.cc b/views/controls/native_view_host.cc
new file mode 100644
index 0000000..3fc5fba
--- /dev/null
+++ b/views/controls/native_view_host.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2009 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 "views/controls/native_view_host.h"
+
+#include "views/widget/widget.h"
+#include "base/logging.h"
+
+namespace views {
+
+NativeViewHost::NativeViewHost()
+    : native_view_(NULL),
+      installed_clip_(false),
+      fast_resize_(false),
+      focus_view_(NULL) {
+  // The native widget is placed relative to the root. As such, we need to
+  // know when the position of any ancestor changes, or our visibility relative
+  // to other views changed as it'll effect our position relative to the root.
+  SetNotifyWhenVisibleBoundsInRootChanges(true);
+}
+
+NativeViewHost::~NativeViewHost() {
+}
+
+gfx::Size NativeViewHost::GetPreferredSize() {
+  return preferred_size_;
+}
+
+void NativeViewHost::Layout() {
+  if (!native_view_)
+    return;
+
+  // Since widgets know nothing about the View hierarchy (they are direct
+  // children of the Widget that hosts our View hierarchy) they need to be
+  // positioned in the coordinate system of the Widget, not the current
+  // view.
+  gfx::Point top_left;
+  ConvertPointToWidget(this, &top_left);
+
+  gfx::Rect vis_bounds = GetVisibleBounds();
+  bool visible = !vis_bounds.IsEmpty();
+
+  if (visible && !fast_resize_) {
+    if (vis_bounds.size() != size()) {
+      // Only a portion of the Widget is really visible.
+      int x = vis_bounds.x();
+      int y = vis_bounds.y();
+      InstallClip(x, y, vis_bounds.width(), vis_bounds.height());
+      installed_clip_ = true;
+    } else if (installed_clip_) {
+      // The whole widget is visible but we installed a clip on the widget,
+      // uninstall it.
+      UninstallClip();
+      installed_clip_ = false;
+    }
+  }
+
+  if (visible) {
+    ShowWidget(top_left.x(), top_left.y(), width(), height());
+  } else {
+    HideWidget();
+  }
+}
+
+void NativeViewHost::VisibilityChanged(View* starting_from, bool is_visible) {
+  Layout();
+}
+
+void NativeViewHost::VisibleBoundsInRootChanged() {
+  Layout();
+}
+
+}  // namespace views
diff --git a/views/controls/native_view_host.h b/views/controls/native_view_host.h
new file mode 100644
index 0000000..99b85b6
--- /dev/null
+++ b/views/controls/native_view_host.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2009 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 VIEWS_CONTROLS_NATIVE_VIEW_HOST_H_
+#define VIEWS_CONTROLS_NATIVE_VIEW_HOST_H_
+
+#include <string>
+
+#include "views/view.h"
+
+#include "base/gfx/native_widget_types.h"
+
+namespace views {
+
+// Base class for embedding native widgets in a view.
+class NativeViewHost : public View {
+ public:
+  NativeViewHost();
+  virtual ~NativeViewHost();
+
+  void set_preferred_size(const gfx::Size& size) { preferred_size_ = size; }
+
+  // Returns the preferred size set via set_preferred_size.
+  virtual gfx::Size GetPreferredSize();
+
+  // Overriden to invoke Layout.
+  virtual void VisibilityChanged(View* starting_from, bool is_visible);
+
+  // Invokes any of InstallClip, UninstallClip, ShowWidget or HideWidget
+  // depending upon what portion of the widget is view in the parent.
+  virtual void Layout();
+
+  // A NativeViewHost has an associated focus View so that the focus of the
+  // native control and of the View are kept in sync. In simple cases where the
+  // NativeViewHost directly wraps a native window as is, the associated view
+  // is this View. In other cases where the NativeViewHost is part of another
+  // view (such as TextField), the actual View is not the NativeViewHost and
+  // this method must be called to set that.
+  // This method must be called before Attach().
+  void SetAssociatedFocusView(View* view) { focus_view_ = view; }
+  View* associated_focus_view() { return focus_view_; }
+
+  void set_fast_resize(bool fast_resize) { fast_resize_ = fast_resize; }
+  bool fast_resize() const { return fast_resize_; }
+
+  // The embedded native view.
+  gfx::NativeView native_view() const { return native_view_; }
+
+ protected:
+  // Notification that our visible bounds relative to the root has changed.
+  // Invokes Layout to make sure the widget is positioned correctly.
+  virtual void VisibleBoundsInRootChanged();
+
+  // Sets the native view. Subclasses will typically invoke Layout after setting
+  // the widget.
+  void set_native_view(gfx::NativeView widget) { native_view_ = widget; }
+
+  // Installs a clip on the native widget.
+  virtual void InstallClip(int x, int y, int w, int h) = 0;
+
+  // Removes the clip installed on the native widget by way of InstallClip.
+  virtual void UninstallClip() = 0;
+
+  // Shows the widget at the specified position (relative to the parent widget).
+  virtual void ShowWidget(int x, int y, int w, int h) = 0;
+
+  // Hides the widget. NOTE: this may be invoked when the widget is already
+  // hidden.
+  virtual void HideWidget() = 0;
+
+  void set_installed_clip(bool installed_clip) {
+    installed_clip_ = installed_clip;
+  }
+  bool installed_clip() const { return installed_clip_; }
+
+ private:
+  gfx::NativeView native_view_;
+
+  // The preferred size of this View
+  gfx::Size preferred_size_;
+
+  // Have we installed a region on the HWND used to clip to only the visible
+  // portion of the HWND?
+  bool installed_clip_;
+
+  // Fast resizing will move the hwnd and clip its window region, this will
+  // result in white areas and will not resize the content (so scrollbars
+  // will be all wrong and content will flow offscreen). Only use this
+  // when you're doing extremely quick, high-framerate vertical resizes
+  // and don't care about accuracy. Make sure you do a real resize at the
+  // end. USE WITH CAUTION.
+  bool fast_resize_;
+
+  // The view that should be given focus when this NativeViewHost is focused.
+  View* focus_view_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeViewHost);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_NATIVE_VIEW_HOST_H_
diff --git a/views/controls/scroll_view.cc b/views/controls/scroll_view.cc
new file mode 100644
index 0000000..680b623
--- /dev/null
+++ b/views/controls/scroll_view.cc
@@ -0,0 +1,517 @@
+// Copyright (c) 2006-2008 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 "views/controls/scroll_view.h"
+
+#include "app/resource_bundle.h"
+#include "base/logging.h"
+#include "grit/theme_resources.h"
+#include "views/controls/scrollbar/native_scroll_bar.h"
+#include "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 void ScrollRectToVisible(int x, int y, int width, int height) {
+    if (!GetChildViewCount() || !GetParent())
+      return;
+
+    View* contents = GetChildViewAt(0);
+    x -= contents->x();
+    y -= contents->y();
+    static_cast<ScrollView*>(GetParent())->ScrollContentsRegionToBeVisible(
+        x, y, width, height);
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(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_->GetParent()) {
+    delete horiz_sb_;
+  }
+
+  if (!vert_sb_->GetParent()) {
+    delete vert_sb_;
+  }
+
+  if (resize_corner_ && !resize_corner_->GetParent()) {
+    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_->SetController(this);
+  vert_sb_->SetVisible(false);
+  vert_sb_->SetController(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(true);
+  // 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_->SetBounds(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(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_->SetBounds(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(int x,
+                                                 int y,
+                                                 int width,
+                                                 int height) {
+  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_*].
+  x = std::max(0, std::min(contents_max_x, x));
+  y = std::max(0, std::min(contents_max_y, 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(width, viewport_->width()));
+  const int max_y = std::min(contents_max_y,
+                             y + std::min(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_->SchedulePaint(contents_->GetLocalBounds(true), true);
+    }
+  } 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_->SchedulePaint(contents_->GetLocalBounds(true), true);
+    }
+  }
+}
+
+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;
+}
+
+void ScrollView::ViewHierarchyChanged(bool is_add, View *parent, View *child) {
+  if (is_add) {
+    RootView* rv = GetRootView();
+    if (rv) {
+      rv->SetDefaultKeyboardHandler(this);
+      rv->SetFocusOnMousePressed(true);
+    }
+  }
+}
+
+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()->GetParent()->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(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/views/controls/scroll_view.h b/views/controls/scroll_view.h
new file mode 100644
index 0000000..5a578cd1
--- /dev/null
+++ b/views/controls/scroll_view.h
@@ -0,0 +1,207 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_SCROLL_VIEW_H_
+#define VIEWS_CONTROLS_SCROLL_VIEW_H_
+
+#include "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 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();
+
+  // 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(int x, int y, int width, int height);
+
+  // 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);
+
+  // 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);
+
+  // Overridden to setup keyboard ui when the view hierarchy changes
+  virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
+
+  // Keyboard events
+  virtual bool OnKeyPressed(const KeyEvent& event);
+  virtual bool OnMouseWheel(const MouseWheelEvent& e);
+
+  virtual std::string GetClassName() const;
+
+  // 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_EVIL_CONSTRUCTORS(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_EVIL_CONSTRUCTORS(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);
+
+ private:
+  int top_margin_;
+  int row_height_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(FixedRowHeightScrollHelper);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_SCROLL_VIEW_H_
diff --git a/views/controls/scrollbar/bitmap_scroll_bar.cc b/views/controls/scrollbar/bitmap_scroll_bar.cc
new file mode 100644
index 0000000..4a93782
--- /dev/null
+++ b/views/controls/scrollbar/bitmap_scroll_bar.cc
@@ -0,0 +1,703 @@
+// Copyright (c) 2006-2008 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 "views/controls/scrollbar/bitmap_scroll_bar.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/l10n_util.h"
+#include "base/message_loop.h"
+#include "grit/generated_resources.h"
+#include "skia/include/SkBitmap.h"
+#include "views/controls/menu/menu.h"
+#include "views/controls/scroll_view.h"
+#include "views/widget/widget.h"
+
+#undef min
+#undef max
+
+namespace views {
+
+namespace {
+
+// The distance the mouse can be dragged outside the bounds of the thumb during
+// dragging before the scrollbar will snap back to its regular position.
+static const int kScrollThumbDragOutSnap = 100;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// AutorepeatButton
+//
+//  A button that activates on mouse pressed rather than released, and that
+//  continues to fire the clicked action as the mouse button remains pressed
+//  down on the button.
+//
+///////////////////////////////////////////////////////////////////////////////
+class AutorepeatButton : public ImageButton {
+ public:
+  AutorepeatButton(ButtonListener* listener)
+      : ImageButton(listener),
+        repeater_(NewCallback<AutorepeatButton>(this,
+            &AutorepeatButton::NotifyClick)) {
+  }
+  virtual ~AutorepeatButton() {}
+
+ protected:
+  virtual bool OnMousePressed(const MouseEvent& event) {
+    Button::NotifyClick(event.GetFlags());
+    repeater_.Start();
+    return true;
+  }
+
+  virtual void OnMouseReleased(const MouseEvent& event, bool canceled) {
+    repeater_.Stop();
+    View::OnMouseReleased(event, canceled);
+  }
+
+ private:
+  void NotifyClick() {
+    Button::NotifyClick(0);
+  }
+
+  // The repeat controller that we use to repeatedly click the button when the
+  // mouse button is down.
+  RepeatController repeater_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(AutorepeatButton);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// BitmapScrollBarThumb
+//
+//  A view that acts as the thumb in the scroll bar track that the user can
+//  drag to scroll the associated contents view within the viewport.
+//
+///////////////////////////////////////////////////////////////////////////////
+class BitmapScrollBarThumb : public View {
+ public:
+  explicit BitmapScrollBarThumb(BitmapScrollBar* scroll_bar)
+      : scroll_bar_(scroll_bar),
+        drag_start_position_(-1),
+        mouse_offset_(-1),
+        state_(CustomButton::BS_NORMAL) {
+  }
+  virtual ~BitmapScrollBarThumb() { }
+
+  // Sets the size (width or height) of the thumb to the specified value.
+  void SetSize(int size) {
+    // Make sure the thumb is never sized smaller than its minimum possible
+    // display size.
+    gfx::Size prefsize = GetPreferredSize();
+    size = std::max(size,
+                    static_cast<int>(scroll_bar_->IsHorizontal() ?
+                        prefsize.width() : prefsize.height()));
+    gfx::Rect thumb_bounds = bounds();
+    if (scroll_bar_->IsHorizontal()) {
+      thumb_bounds.set_width(size);
+    } else {
+      thumb_bounds.set_height(size);
+    }
+    SetBounds(thumb_bounds);
+  }
+
+  // Retrieves the size (width or height) of the thumb.
+  int GetSize() const {
+    if (scroll_bar_->IsHorizontal())
+      return width();
+    return height();
+  }
+
+  // Sets the position of the thumb on the x or y axis.
+  void SetPosition(int position) {
+    gfx::Rect thumb_bounds = bounds();
+    gfx::Rect track_bounds = scroll_bar_->GetTrackBounds();
+    if (scroll_bar_->IsHorizontal()) {
+      thumb_bounds.set_x(track_bounds.x() + position);
+    } else {
+      thumb_bounds.set_x(track_bounds.y() + position);
+    }
+    SetBounds(thumb_bounds);
+  }
+
+  // Gets the position of the thumb on the x or y axis.
+  int GetPosition() const {
+    gfx::Rect track_bounds = scroll_bar_->GetTrackBounds();
+    if (scroll_bar_->IsHorizontal())
+      return x() - track_bounds.x();
+    return y() - track_bounds.y();
+  }
+
+  // View overrides:
+  virtual gfx::Size GetPreferredSize() {
+    return gfx::Size(background_bitmap()->width(),
+                     start_cap_bitmap()->height() +
+                         end_cap_bitmap()->height() +
+                         grippy_bitmap()->height());
+  }
+
+ protected:
+  // View overrides:
+  virtual void Paint(ChromeCanvas* canvas) {
+    canvas->DrawBitmapInt(*start_cap_bitmap(), 0, 0);
+    int top_cap_height = start_cap_bitmap()->height();
+    int bottom_cap_height = end_cap_bitmap()->height();
+    int thumb_body_height = height() - top_cap_height - bottom_cap_height;
+    canvas->TileImageInt(*background_bitmap(), 0, top_cap_height,
+                         background_bitmap()->width(), thumb_body_height);
+    canvas->DrawBitmapInt(*end_cap_bitmap(), 0,
+                          height() - bottom_cap_height);
+
+    // Paint the grippy over the track.
+    int grippy_x = (width() - grippy_bitmap()->width()) / 2;
+    int grippy_y = (thumb_body_height - grippy_bitmap()->height()) / 2;
+    canvas->DrawBitmapInt(*grippy_bitmap(), grippy_x, grippy_y);
+  }
+
+  virtual void OnMouseEntered(const MouseEvent& event) {
+    SetState(CustomButton::BS_HOT);
+  }
+
+  virtual void OnMouseExited(const MouseEvent& event) {
+    SetState(CustomButton::BS_NORMAL);
+  }
+
+  virtual bool OnMousePressed(const MouseEvent& event) {
+    mouse_offset_ = scroll_bar_->IsHorizontal() ? event.x() : event.y();
+    drag_start_position_ = GetPosition();
+    SetState(CustomButton::BS_PUSHED);
+    return true;
+  }
+
+  virtual bool OnMouseDragged(const MouseEvent& event) {
+    // If the user moves the mouse more than |kScrollThumbDragOutSnap| outside
+    // the bounds of the thumb, the scrollbar will snap the scroll back to the
+    // point it was at before the drag began.
+    if (scroll_bar_->IsHorizontal()) {
+      if ((event.y() < y() - kScrollThumbDragOutSnap) ||
+          (event.y() > (y() + height() + kScrollThumbDragOutSnap))) {
+        scroll_bar_->ScrollToThumbPosition(drag_start_position_, false);
+        return true;
+      }
+    } else {
+      if ((event.x() < x() - kScrollThumbDragOutSnap) ||
+          (event.x() > (x() + width() + kScrollThumbDragOutSnap))) {
+        scroll_bar_->ScrollToThumbPosition(drag_start_position_, false);
+        return true;
+      }
+    }
+    if (scroll_bar_->IsHorizontal()) {
+      int thumb_x = event.x() - mouse_offset_;
+      scroll_bar_->ScrollToThumbPosition(x() + thumb_x, false);
+    } else {
+      int thumb_y = event.y() - mouse_offset_;
+      scroll_bar_->ScrollToThumbPosition(y() + thumb_y, false);
+    }
+    return true;
+  }
+
+  virtual void OnMouseReleased(const MouseEvent& event,
+                               bool canceled) {
+    SetState(CustomButton::BS_HOT);
+    View::OnMouseReleased(event, canceled);
+  }
+
+ private:
+  // Returns the bitmap rendered at the start of the thumb.
+  SkBitmap* start_cap_bitmap() const {
+    return scroll_bar_->images_[BitmapScrollBar::THUMB_START_CAP][state_];
+  }
+
+  // Returns the bitmap rendered at the end of the thumb.
+  SkBitmap* end_cap_bitmap() const {
+    return scroll_bar_->images_[BitmapScrollBar::THUMB_END_CAP][state_];
+  }
+
+  // Returns the bitmap that is tiled in the background of the thumb between
+  // the start and the end caps.
+  SkBitmap* background_bitmap() const {
+    return scroll_bar_->images_[BitmapScrollBar::THUMB_MIDDLE][state_];
+  }
+
+  // Returns the bitmap that is rendered in the middle of the thumb
+  // transparently over the background bitmap.
+  SkBitmap* grippy_bitmap() const {
+    return scroll_bar_->images_[BitmapScrollBar::THUMB_GRIPPY]
+        [CustomButton::BS_NORMAL];
+  }
+
+  // Update our state and schedule a repaint when the mouse moves over us.
+  void SetState(CustomButton::ButtonState state) {
+    state_ = state;
+    SchedulePaint();
+  }
+
+  // The BitmapScrollBar that owns us.
+  BitmapScrollBar* scroll_bar_;
+
+  int drag_start_position_;
+
+  // The position of the mouse on the scroll axis relative to the top of this
+  // View when the drag started.
+  int mouse_offset_;
+
+  // The current state of the thumb button.
+  CustomButton::ButtonState state_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(BitmapScrollBarThumb);
+};
+
+} // anonymous namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// BitmapScrollBar, public:
+
+BitmapScrollBar::BitmapScrollBar(bool horizontal, bool show_scroll_buttons)
+    : contents_size_(0),
+      contents_scroll_offset_(0),
+      prev_button_(new AutorepeatButton(this)),
+      next_button_(new AutorepeatButton(this)),
+      thumb_(new BitmapScrollBarThumb(this)),
+      thumb_track_state_(CustomButton::BS_NORMAL),
+      last_scroll_amount_(SCROLL_NONE),
+      repeater_(NewCallback<BitmapScrollBar>(this,
+          &BitmapScrollBar::TrackClicked)),
+      context_menu_mouse_position_(0),
+      show_scroll_buttons_(show_scroll_buttons),
+      ScrollBar(horizontal) {
+  if (!show_scroll_buttons_) {
+    prev_button_->SetVisible(false);
+    next_button_->SetVisible(false);
+  }
+
+  AddChildView(prev_button_);
+  AddChildView(next_button_);
+  AddChildView(thumb_);
+
+  SetContextMenuController(this);
+  prev_button_->SetContextMenuController(this);
+  next_button_->SetContextMenuController(this);
+  thumb_->SetContextMenuController(this);
+}
+
+gfx::Rect BitmapScrollBar::GetTrackBounds() const {
+  gfx::Size prefsize = prev_button_->GetPreferredSize();
+  if (IsHorizontal()) {
+    if (!show_scroll_buttons_)
+      prefsize.set_width(0);
+    int new_width =
+        std::max(0, static_cast<int>(width() - (prefsize.width() * 2)));
+    gfx::Rect track_bounds(prefsize.width(), 0, new_width, prefsize.height());
+    return track_bounds;
+  }
+  if (!show_scroll_buttons_)
+    prefsize.set_height(0);
+  gfx::Rect track_bounds(0, prefsize.height(), prefsize.width(),
+                         std::max(0, height() - (prefsize.height() * 2)));
+  return track_bounds;
+}
+
+void BitmapScrollBar::SetImage(ScrollBarPart part,
+                               CustomButton::ButtonState state,
+                               SkBitmap* bitmap) {
+  DCHECK(part < PART_COUNT);
+  DCHECK(state < CustomButton::BS_COUNT);
+  switch (part) {
+    case PREV_BUTTON:
+      prev_button_->SetImage(state, bitmap);
+      break;
+    case NEXT_BUTTON:
+      next_button_->SetImage(state, bitmap);
+      break;
+    case THUMB_START_CAP:
+    case THUMB_MIDDLE:
+    case THUMB_END_CAP:
+    case THUMB_GRIPPY:
+    case THUMB_TRACK:
+      images_[part][state] = bitmap;
+      break;
+  }
+}
+
+void BitmapScrollBar::ScrollByAmount(ScrollAmount amount) {
+  ScrollBarController* controller = GetController();
+  int offset = contents_scroll_offset_;
+  switch (amount) {
+    case SCROLL_START:
+      offset = GetMinPosition();
+      break;
+    case SCROLL_END:
+      offset = GetMaxPosition();
+      break;
+    case SCROLL_PREV_LINE:
+      offset -= controller->GetScrollIncrement(this, false, false);
+      offset = std::max(GetMinPosition(), offset);
+      break;
+    case SCROLL_NEXT_LINE:
+      offset += controller->GetScrollIncrement(this, false, true);
+      offset = std::min(GetMaxPosition(), offset);
+      break;
+    case SCROLL_PREV_PAGE:
+      offset -= controller->GetScrollIncrement(this, true, false);
+      offset = std::max(GetMinPosition(), offset);
+      break;
+    case SCROLL_NEXT_PAGE:
+      offset += controller->GetScrollIncrement(this, true, true);
+      offset = std::min(GetMaxPosition(), offset);
+      break;
+  }
+  contents_scroll_offset_ = offset;
+  ScrollContentsToOffset();
+}
+
+void BitmapScrollBar::ScrollToThumbPosition(int thumb_position,
+                                            bool scroll_to_middle) {
+  contents_scroll_offset_ =
+      CalculateContentsOffset(thumb_position, scroll_to_middle);
+  if (contents_scroll_offset_ < GetMinPosition()) {
+    contents_scroll_offset_ = GetMinPosition();
+  } else if (contents_scroll_offset_ > GetMaxPosition()) {
+    contents_scroll_offset_ = GetMaxPosition();
+  }
+  ScrollContentsToOffset();
+  SchedulePaint();
+}
+
+void BitmapScrollBar::ScrollByContentsOffset(int contents_offset) {
+  contents_scroll_offset_ -= contents_offset;
+  if (contents_scroll_offset_ < GetMinPosition()) {
+    contents_scroll_offset_ = GetMinPosition();
+  } else if (contents_scroll_offset_ > GetMaxPosition()) {
+    contents_scroll_offset_ = GetMaxPosition();
+  }
+  ScrollContentsToOffset();
+}
+
+void BitmapScrollBar::TrackClicked() {
+  if (last_scroll_amount_ != SCROLL_NONE)
+    ScrollByAmount(last_scroll_amount_);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BitmapScrollBar, View implementation:
+
+gfx::Size BitmapScrollBar::GetPreferredSize() {
+  // In this case, we're returning the desired width of the scrollbar and its
+  // minimum allowable height.
+  gfx::Size button_prefsize = prev_button_->GetPreferredSize();
+  return gfx::Size(button_prefsize.width(), button_prefsize.height() * 2);
+}
+
+void BitmapScrollBar::Paint(ChromeCanvas* canvas) {
+  // Paint the track.
+  gfx::Rect track_bounds = GetTrackBounds();
+  canvas->TileImageInt(*images_[THUMB_TRACK][thumb_track_state_],
+                       track_bounds.x(), track_bounds.y(),
+                       track_bounds.width(), track_bounds.height());
+}
+
+void BitmapScrollBar::Layout() {
+  // Size and place the two scroll buttons.
+  if (show_scroll_buttons_) {
+    gfx::Size prefsize = prev_button_->GetPreferredSize();
+    prev_button_->SetBounds(0, 0, prefsize.width(), prefsize.height());
+    prefsize = next_button_->GetPreferredSize();
+    if (IsHorizontal()) {
+      next_button_->SetBounds(width() - prefsize.width(), 0, prefsize.width(),
+                              prefsize.height());
+    } else {
+      next_button_->SetBounds(0, height() - prefsize.height(), prefsize.width(),
+                              prefsize.height());
+    }
+  } else {
+    prev_button_->SetBounds(0, 0, 0, 0);
+    next_button_->SetBounds(0, 0, 0, 0);
+  }
+
+  // Size and place the thumb
+  gfx::Size thumb_prefsize = thumb_->GetPreferredSize();
+  gfx::Rect track_bounds = GetTrackBounds();
+
+  // Preserve the height/width of the thumb (depending on orientation) as set
+  // by the last call to |Update|, but coerce the width/height to be the
+  // appropriate value for the bitmaps provided.
+  if (IsHorizontal()) {
+    thumb_->SetBounds(thumb_->x(), thumb_->y(), thumb_->width(),
+                      thumb_prefsize.height());
+  } else {
+    thumb_->SetBounds(thumb_->x(), thumb_->y(), thumb_prefsize.width(),
+                      thumb_->height());
+  }
+
+  // Hide the thumb if the track isn't tall enough to display even a tiny
+  // thumb. The user can only use the mousewheel, scroll buttons or keyboard
+  // in this scenario.
+  if ((IsHorizontal() && (track_bounds.width() < thumb_prefsize.width()) ||
+      (!IsHorizontal() && (track_bounds.height() < thumb_prefsize.height())))) {
+    thumb_->SetVisible(false);
+  } else if (!thumb_->IsVisible()) {
+    thumb_->SetVisible(true);
+  }
+}
+
+bool BitmapScrollBar::OnMousePressed(const MouseEvent& event) {
+  if (event.IsOnlyLeftMouseButton()) {
+    SetThumbTrackState(CustomButton::BS_PUSHED);
+    gfx::Rect thumb_bounds = thumb_->bounds();
+    if (IsHorizontal()) {
+      if (event.x() < thumb_bounds.x()) {
+        last_scroll_amount_ = SCROLL_PREV_PAGE;
+      } else if (event.x() > thumb_bounds.right()) {
+        last_scroll_amount_ = SCROLL_NEXT_PAGE;
+      }
+    } else {
+      if (event.y() < thumb_bounds.y()) {
+        last_scroll_amount_ = SCROLL_PREV_PAGE;
+      } else if (event.y() > thumb_bounds.bottom()) {
+        last_scroll_amount_ = SCROLL_NEXT_PAGE;
+      }
+    }
+    TrackClicked();
+    repeater_.Start();
+  }
+  return true;
+}
+
+void BitmapScrollBar::OnMouseReleased(const MouseEvent& event, bool canceled) {
+  SetThumbTrackState(CustomButton::BS_NORMAL);
+  repeater_.Stop();
+  View::OnMouseReleased(event, canceled);
+}
+
+bool BitmapScrollBar::OnMouseWheel(const MouseWheelEvent& event) {
+  ScrollByContentsOffset(event.GetOffset());
+  return true;
+}
+
+bool BitmapScrollBar::OnKeyPressed(const KeyEvent& event) {
+  ScrollAmount amount = SCROLL_NONE;
+  switch(event.GetCharacter()) {
+    case VK_UP:
+      if (!IsHorizontal())
+        amount = SCROLL_PREV_LINE;
+      break;
+    case VK_DOWN:
+      if (!IsHorizontal())
+        amount = SCROLL_NEXT_LINE;
+      break;
+    case VK_LEFT:
+      if (IsHorizontal())
+        amount = SCROLL_PREV_LINE;
+      break;
+    case VK_RIGHT:
+      if (IsHorizontal())
+        amount = SCROLL_NEXT_LINE;
+      break;
+    case VK_PRIOR:
+      amount = SCROLL_PREV_PAGE;
+      break;
+    case VK_NEXT:
+      amount = SCROLL_NEXT_PAGE;
+      break;
+    case VK_HOME:
+      amount = SCROLL_START;
+      break;
+    case VK_END:
+      amount = SCROLL_END;
+      break;
+  }
+  if (amount != SCROLL_NONE) {
+    ScrollByAmount(amount);
+    return true;
+  }
+  return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BitmapScrollBar, ContextMenuController implementation:
+
+enum ScrollBarContextMenuCommands {
+  ScrollBarContextMenuCommand_ScrollHere = 1,
+  ScrollBarContextMenuCommand_ScrollStart,
+  ScrollBarContextMenuCommand_ScrollEnd,
+  ScrollBarContextMenuCommand_ScrollPageUp,
+  ScrollBarContextMenuCommand_ScrollPageDown,
+  ScrollBarContextMenuCommand_ScrollPrev,
+  ScrollBarContextMenuCommand_ScrollNext
+};
+
+void BitmapScrollBar::ShowContextMenu(View* source,
+                                      int x,
+                                      int y,
+                                      bool is_mouse_gesture) {
+  Widget* widget = GetWidget();
+  gfx::Rect widget_bounds;
+  widget->GetBounds(&widget_bounds, true);
+  gfx::Point temp_pt(x - widget_bounds.x(), y - widget_bounds.y());
+  View::ConvertPointFromWidget(this, &temp_pt);
+  context_menu_mouse_position_ = IsHorizontal() ? temp_pt.x() : temp_pt.y();
+
+  Menu menu(this, Menu::TOPLEFT, GetWidget()->GetNativeView());
+  menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollHere);
+  menu.AppendSeparator();
+  menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollStart);
+  menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollEnd);
+  menu.AppendSeparator();
+  menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageUp);
+  menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPageDown);
+  menu.AppendSeparator();
+  menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollPrev);
+  menu.AppendDelegateMenuItem(ScrollBarContextMenuCommand_ScrollNext);
+  menu.RunMenuAt(x, y);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BitmapScrollBar, Menu::Delegate implementation:
+
+std::wstring BitmapScrollBar::GetLabel(int id) const {
+  switch (id) {
+    case ScrollBarContextMenuCommand_ScrollHere:
+      return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLHERE);
+    case ScrollBarContextMenuCommand_ScrollStart:
+      if (IsHorizontal())
+        return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLLEFTEDGE);
+      return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLHOME);
+    case ScrollBarContextMenuCommand_ScrollEnd:
+      if (IsHorizontal())
+        return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLRIGHTEDGE);
+      return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLEND);
+    case ScrollBarContextMenuCommand_ScrollPageUp:
+      if (IsHorizontal())
+        return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLPAGEUP);
+      return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLPAGEUP);
+    case ScrollBarContextMenuCommand_ScrollPageDown:
+      if (IsHorizontal())
+        return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLPAGEDOWN);
+      return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLPAGEDOWN);
+    case ScrollBarContextMenuCommand_ScrollPrev:
+      if (IsHorizontal())
+        return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLLEFT);
+      return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLUP);
+    case ScrollBarContextMenuCommand_ScrollNext:
+      if (IsHorizontal())
+        return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLRIGHT);
+      return l10n_util::GetString(IDS_SCROLLBAR_CXMENU_SCROLLDOWN);
+  }
+  NOTREACHED() << "Invalid BitmapScrollBar Context Menu command!";
+  return L"";
+}
+
+bool BitmapScrollBar::IsCommandEnabled(int id) const {
+  switch (id) {
+    case ScrollBarContextMenuCommand_ScrollPageUp:
+    case ScrollBarContextMenuCommand_ScrollPageDown:
+      return !IsHorizontal();
+  }
+  return true;
+}
+
+void BitmapScrollBar::ExecuteCommand(int id) {
+  switch (id) {
+    case ScrollBarContextMenuCommand_ScrollHere:
+      ScrollToThumbPosition(context_menu_mouse_position_, true);
+      break;
+    case ScrollBarContextMenuCommand_ScrollStart:
+      ScrollByAmount(SCROLL_START);
+      break;
+    case ScrollBarContextMenuCommand_ScrollEnd:
+      ScrollByAmount(SCROLL_END);
+      break;
+    case ScrollBarContextMenuCommand_ScrollPageUp:
+      ScrollByAmount(SCROLL_PREV_PAGE);
+      break;
+    case ScrollBarContextMenuCommand_ScrollPageDown:
+      ScrollByAmount(SCROLL_NEXT_PAGE);
+      break;
+    case ScrollBarContextMenuCommand_ScrollPrev:
+      ScrollByAmount(SCROLL_PREV_LINE);
+      break;
+    case ScrollBarContextMenuCommand_ScrollNext:
+      ScrollByAmount(SCROLL_NEXT_LINE);
+      break;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BitmapScrollBar, ButtonListener implementation:
+
+void BitmapScrollBar::ButtonPressed(Button* sender) {
+  if (sender == prev_button_) {
+    ScrollByAmount(SCROLL_PREV_LINE);
+  } else if (sender == next_button_) {
+    ScrollByAmount(SCROLL_NEXT_LINE);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BitmapScrollBar, ScrollBar implementation:
+
+void BitmapScrollBar::Update(int viewport_size, int content_size,
+                             int contents_scroll_offset) {
+  ScrollBar::Update(viewport_size, content_size, contents_scroll_offset);
+
+  // Make sure contents_size is always > 0 to avoid divide by zero errors in
+  // calculations throughout this code.
+  contents_size_ = std::max(1, content_size);
+
+  if (content_size < 0)
+    content_size = 0;
+  if (contents_scroll_offset < 0)
+    contents_scroll_offset = 0;
+  if (contents_scroll_offset > content_size)
+    contents_scroll_offset = content_size;
+
+  // Thumb Height and Thumb Pos.
+  // The height of the thumb is the ratio of the Viewport height to the
+  // content size multiplied by the height of the thumb track.
+  double ratio = static_cast<double>(viewport_size) / contents_size_;
+  int thumb_size = static_cast<int>(ratio * GetTrackSize());
+  thumb_->SetSize(thumb_size);
+
+  int thumb_position = CalculateThumbPosition(contents_scroll_offset);
+  thumb_->SetPosition(thumb_position);
+}
+
+int BitmapScrollBar::GetLayoutSize() const {
+  gfx::Size prefsize = prev_button_->GetPreferredSize();
+  return IsHorizontal() ? prefsize.height() : prefsize.width();
+}
+
+int BitmapScrollBar::GetPosition() const {
+  return thumb_->GetPosition();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// BitmapScrollBar, private:
+
+void BitmapScrollBar::ScrollContentsToOffset() {
+  GetController()->ScrollToPosition(this, contents_scroll_offset_);
+  thumb_->SetPosition(CalculateThumbPosition(contents_scroll_offset_));
+}
+
+int BitmapScrollBar::GetTrackSize() const {
+  gfx::Rect track_bounds = GetTrackBounds();
+  return IsHorizontal() ? track_bounds.width() : track_bounds.height();
+}
+
+int BitmapScrollBar::CalculateThumbPosition(int contents_scroll_offset) const {
+  return (contents_scroll_offset * GetTrackSize()) / contents_size_;
+}
+
+int BitmapScrollBar::CalculateContentsOffset(int thumb_position,
+                                             bool scroll_to_middle) const {
+  if (scroll_to_middle)
+    thumb_position = thumb_position - (thumb_->GetSize() / 2);
+  return (thumb_position * contents_size_) / GetTrackSize();
+}
+
+void BitmapScrollBar::SetThumbTrackState(CustomButton::ButtonState state) {
+  thumb_track_state_ = state;
+  SchedulePaint();
+}
+
+}  // namespace views
diff --git a/views/controls/scrollbar/bitmap_scroll_bar.h b/views/controls/scrollbar/bitmap_scroll_bar.h
new file mode 100644
index 0000000..45e3535
--- /dev/null
+++ b/views/controls/scrollbar/bitmap_scroll_bar.h
@@ -0,0 +1,192 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_SCROLLBAR_BITMAP_SCROLL_BAR_H_
+#define VIEWS_CONTROLS_SCROLLBAR_BITMAP_SCROLL_BAR_H_
+
+#include "views/controls/button/image_button.h"
+#include "views/controls/menu/menu.h"
+#include "views/controls/scrollbar/scroll_bar.h"
+#include "views/repeat_controller.h"
+
+namespace views {
+
+namespace {
+class BitmapScrollBarThumb;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// BitmapScrollBar
+//
+//  A ScrollBar subclass that implements a scroll bar rendered using bitmaps
+//  that the user provides. There are bitmaps for the up and down buttons, as
+//  well as for the thumb and track. This is intended for creating UIs that
+//  have customized, non-native appearances, like floating HUDs etc.
+//
+//  Maybe TODO(beng): (Cleanup) If we need to, we may want to factor rendering
+//                    out of this altogether and have the user supply
+//                    Background impls for each component, and just use those
+//                    to render, so that for example we get native theme
+//                    rendering.
+//
+///////////////////////////////////////////////////////////////////////////////
+class BitmapScrollBar : public ScrollBar,
+                        public ButtonListener,
+                        public ContextMenuController,
+                        public Menu::Delegate {
+ public:
+  BitmapScrollBar(bool horizontal, bool show_scroll_buttons);
+  virtual ~BitmapScrollBar() { }
+
+  // Get the bounds of the "track" area that the thumb is free to slide within.
+  gfx::Rect GetTrackBounds() const;
+
+  // A list of parts that the user may supply bitmaps for.
+  enum ScrollBarPart {
+    // The button used to represent scrolling up/left by 1 line.
+    PREV_BUTTON = 0,
+    // The button used to represent scrolling down/right by 1 line.
+    // IMPORTANT: The code assumes the prev and next
+    // buttons have equal width and equal height.
+    NEXT_BUTTON,
+    // The top/left segment of the thumb on the scrollbar.
+    THUMB_START_CAP,
+    // The tiled background image of the thumb.
+    THUMB_MIDDLE,
+    // The bottom/right segment of the thumb on the scrollbar.
+    THUMB_END_CAP,
+    // The grippy that is rendered in the center of the thumb.
+    THUMB_GRIPPY,
+    // The tiled background image of the thumb track.
+    THUMB_TRACK,
+    PART_COUNT
+  };
+
+  // Sets the bitmap to be rendered for the specified part and state.
+  void SetImage(ScrollBarPart part,
+                CustomButton::ButtonState state,
+                SkBitmap* bitmap);
+
+  // An enumeration of different amounts of incremental scroll, representing
+  // events sent from different parts of the UI/keyboard.
+  enum ScrollAmount {
+    SCROLL_NONE = 0,
+    SCROLL_START,
+    SCROLL_END,
+    SCROLL_PREV_LINE,
+    SCROLL_NEXT_LINE,
+    SCROLL_PREV_PAGE,
+    SCROLL_NEXT_PAGE,
+  };
+
+  // Scroll the contents by the specified type (see ScrollAmount above).
+  void ScrollByAmount(ScrollAmount amount);
+
+  // Scroll the contents to the appropriate position given the supplied
+  // position of the thumb (thumb track coordinates). If |scroll_to_middle| is
+  // true, then the conversion assumes |thumb_position| is in the middle of the
+  // thumb rather than the top.
+  void ScrollToThumbPosition(int thumb_position, bool scroll_to_middle);
+
+  // Scroll the contents by the specified offset (contents coordinates).
+  void ScrollByContentsOffset(int contents_offset);
+
+  // View overrides:
+  virtual gfx::Size GetPreferredSize();
+  virtual void Paint(ChromeCanvas* canvas);
+  virtual void Layout();
+  virtual bool OnMousePressed(const MouseEvent& event);
+  virtual void OnMouseReleased(const MouseEvent& event, bool canceled);
+  virtual bool OnMouseWheel(const MouseWheelEvent& event);
+  virtual bool OnKeyPressed(const KeyEvent& event);
+
+  // BaseButton::ButtonListener overrides:
+  virtual void ButtonPressed(Button* sender);
+
+  // ScrollBar overrides:
+  virtual void Update(int viewport_size,
+                      int content_size,
+                      int contents_scroll_offset);
+  virtual int GetLayoutSize() const;
+  virtual int GetPosition() const;
+
+  // ContextMenuController overrides.
+  virtual void ShowContextMenu(View* source,
+                               int x,
+                               int y,
+                               bool is_mouse_gesture);
+
+  // Menu::Delegate overrides:
+  virtual std::wstring GetLabel(int id) const;
+  virtual bool IsCommandEnabled(int id) const;
+  virtual void ExecuteCommand(int id);
+
+ private:
+  // Called when the mouse is pressed down in the track area.
+  void TrackClicked();
+
+  // Responsible for scrolling the contents and also updating the UI to the
+  // current value of the Scroll Offset.
+  void ScrollContentsToOffset();
+
+  // Returns the size (width or height) of the track area of the ScrollBar.
+  int GetTrackSize() const;
+
+  // Calculate the position of the thumb within the track based on the
+  // specified scroll offset of the contents.
+  int CalculateThumbPosition(int contents_scroll_offset) const;
+
+  // Calculates the current value of the contents offset (contents coordinates)
+  // based on the current thumb position (thumb track coordinates). See
+  // |ScrollToThumbPosition| for an explanation of |scroll_to_middle|.
+  int CalculateContentsOffset(int thumb_position,
+                              bool scroll_to_middle) const;
+
+  // Called when the state of the thumb track changes (e.g. by the user
+  // pressing the mouse button down in it).
+  void SetThumbTrackState(CustomButton::ButtonState state);
+
+  // The thumb needs to be able to access the part images.
+  friend BitmapScrollBarThumb;
+  SkBitmap* images_[PART_COUNT][CustomButton::BS_COUNT];
+
+  // The size of the scrolled contents, in pixels.
+  int contents_size_;
+
+  // The current amount the contents is offset by in the viewport.
+  int contents_scroll_offset_;
+
+  // Up/Down/Left/Right buttons and the Thumb.
+  ImageButton* prev_button_;
+  ImageButton* next_button_;
+  BitmapScrollBarThumb* thumb_;
+
+  // The state of the scrollbar track. Typically, the track will highlight when
+  // the user presses the mouse on them (during page scrolling).
+  CustomButton::ButtonState thumb_track_state_;
+
+  // The last amount of incremental scroll that this scrollbar performed. This
+  // is accessed by the callbacks for the auto-repeat up/down buttons to know
+  // what direction to repeatedly scroll in.
+  ScrollAmount last_scroll_amount_;
+
+  // An instance of a RepeatController which scrolls the scrollbar continuously
+  // as the user presses the mouse button down on the up/down buttons or the
+  // track.
+  RepeatController repeater_;
+
+  // The position of the mouse within the scroll bar when the context menu
+  // was invoked.
+  int context_menu_mouse_position_;
+
+  // True if the scroll buttons at each end of the scroll bar should be shown.
+  bool show_scroll_buttons_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(BitmapScrollBar);
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_CONTROLS_SCROLLBAR_BITMAP_SCROLL_BAR_H_
diff --git a/views/controls/scrollbar/native_scroll_bar.cc b/views/controls/scrollbar/native_scroll_bar.cc
new file mode 100644
index 0000000..52ddd91
--- /dev/null
+++ b/views/controls/scrollbar/native_scroll_bar.cc
@@ -0,0 +1,357 @@
+// Copyright (c) 2006-2008 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 "views/controls/scrollbar/native_scroll_bar.h"
+
+#include <atlbase.h>
+#include <atlapp.h>
+#include <atlwin.h>
+#include <atlcrack.h>
+#include <atlframe.h>
+#include <atlmisc.h>
+#include <string>
+
+#include "base/message_loop.h"
+#include "views/controls/hwnd_view.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ScrollBarContainer
+//
+// Since windows scrollbar only send notifications to their parent hwnd, we
+// use instance of this class to wrap native scrollbars.
+//
+/////////////////////////////////////////////////////////////////////////////
+class ScrollBarContainer : public CWindowImpl<ScrollBarContainer,
+                           CWindow,
+                           CWinTraits<WS_CHILD>> {
+ public:
+  ScrollBarContainer(ScrollBar* parent) : parent_(parent),
+                                          scrollbar_(NULL) {
+    Create(parent->GetWidget()->GetNativeView());
+    ::ShowWindow(m_hWnd, SW_SHOW);
+  }
+
+  virtual ~ScrollBarContainer() {
+  }
+
+  DECLARE_FRAME_WND_CLASS(L"ChromeViewsScrollBarContainer", NULL);
+  BEGIN_MSG_MAP(ScrollBarContainer);
+    MSG_WM_CREATE(OnCreate);
+    MSG_WM_ERASEBKGND(OnEraseBkgnd);
+    MSG_WM_PAINT(OnPaint);
+    MSG_WM_SIZE(OnSize);
+    MSG_WM_HSCROLL(OnHorizScroll);
+    MSG_WM_VSCROLL(OnVertScroll);
+  END_MSG_MAP();
+
+  HWND GetScrollBarHWND() {
+    return scrollbar_;
+  }
+
+  // Invoked when the scrollwheel is used
+  void ScrollWithOffset(int o) {
+    SCROLLINFO si;
+    si.cbSize = sizeof(si);
+    si.fMask = SIF_POS;
+    ::GetScrollInfo(scrollbar_, SB_CTL, &si);
+    int pos = si.nPos - o;
+
+    if (pos < parent_->GetMinPosition())
+      pos = parent_->GetMinPosition();
+    else if (pos > parent_->GetMaxPosition())
+      pos = parent_->GetMaxPosition();
+
+    ScrollBarController* sbc = parent_->GetController();
+    sbc->ScrollToPosition(parent_, pos);
+
+    si.nPos = pos;
+    si.fMask = SIF_POS;
+    ::SetScrollInfo(scrollbar_, SB_CTL, &si, TRUE);
+  }
+
+ private:
+
+  LRESULT OnCreate(LPCREATESTRUCT create_struct) {
+    scrollbar_ = CreateWindow(L"SCROLLBAR",
+                              L"",
+                              WS_CHILD | (parent_->IsHorizontal() ?
+                                          SBS_HORZ : SBS_VERT),
+                              0,
+                              0,
+                              parent_->width(),
+                              parent_->height(),
+                              m_hWnd,
+                              NULL,
+                              NULL,
+                              NULL);
+    ::ShowWindow(scrollbar_, 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) {
+    ::SetWindowPos(scrollbar_,
+                   0,
+                   0,
+                   0,
+                   sz.cx,
+                   sz.cy,
+                   SWP_DEFERERASE |
+                   SWP_NOACTIVATE |
+                   SWP_NOCOPYBITS |
+                   SWP_NOOWNERZORDER |
+                   SWP_NOSENDCHANGING |
+                   SWP_NOZORDER);
+  }
+
+  void OnScroll(int code, HWND source, bool is_horizontal) {
+    int pos;
+
+    if (code == SB_ENDSCROLL) {
+      return;
+    }
+
+    // If we receive an event from the scrollbar, make the view
+    // component focused so we actually get mousewheel events.
+    if (source != NULL) {
+      Widget* widget = parent_->GetWidget();
+      if (widget && widget->GetNativeView() != GetFocus()) {
+        parent_->RequestFocus();
+      }
+    }
+
+    SCROLLINFO si;
+    si.cbSize = sizeof(si);
+    si.fMask = SIF_POS | SIF_TRACKPOS;
+    ::GetScrollInfo(scrollbar_, SB_CTL, &si);
+    pos = si.nPos;
+
+    ScrollBarController* sbc = parent_->GetController();
+
+    switch (code) {
+      case SB_BOTTOM: // case SB_RIGHT:
+        pos = parent_->GetMaxPosition();
+        break;
+      case SB_TOP:  // case SB_LEFT:
+        pos = parent_->GetMinPosition();
+        break;
+      case SB_LINEDOWN:  //  case SB_LINERIGHT:
+        pos += sbc->GetScrollIncrement(parent_, false, true);
+        pos = std::min(parent_->GetMaxPosition(), pos);
+        break;
+      case SB_LINEUP:  //  case SB_LINELEFT:
+        pos -= sbc->GetScrollIncrement(parent_, false, false);
+        pos = std::max(parent_->GetMinPosition(), pos);
+        break;
+      case SB_PAGEDOWN:  //  case SB_PAGERIGHT:
+        pos += sbc->GetScrollIncrement(parent_, true, true);
+        pos = std::min(parent_->GetMaxPosition(), pos);
+        break;
+      case SB_PAGEUP:  // case SB_PAGELEFT:
+        pos -= sbc->GetScrollIncrement(parent_, true, false);
+        pos = std::max(parent_->GetMinPosition(), pos);
+        break;
+      case SB_THUMBPOSITION:
+      case SB_THUMBTRACK:
+        pos = si.nTrackPos;
+        if (pos < parent_->GetMinPosition())
+          pos = parent_->GetMinPosition();
+        else if (pos > parent_->GetMaxPosition())
+          pos = parent_->GetMaxPosition();
+        break;
+      default:
+        break;
+    }
+
+    sbc->ScrollToPosition(parent_, pos);
+
+    si.nPos = pos;
+    si.fMask = SIF_POS;
+    ::SetScrollInfo(scrollbar_, SB_CTL, &si, TRUE);
+
+    // Note: the system scrollbar modal loop doesn't give a chance
+    // to our message_loop so we need to call DidProcessMessage()
+    // manually.
+    //
+    // Sadly, we don't know what message has been processed. We may
+    // want to remove the message from DidProcessMessage()
+    MSG dummy;
+    dummy.hwnd = NULL;
+    dummy.message = 0;
+    MessageLoopForUI::current()->DidProcessMessage(dummy);
+  }
+
+  // note: always ignore 2nd param as it is 16 bits
+  void OnHorizScroll(int n_sb_code, int ignore, HWND source) {
+    OnScroll(n_sb_code, source, true);
+  }
+
+  // note: always ignore 2nd param as it is 16 bits
+  void OnVertScroll(int n_sb_code, int ignore, HWND source) {
+    OnScroll(n_sb_code, source, false);
+  }
+
+
+
+  ScrollBar* parent_;
+  HWND scrollbar_;
+};
+
+NativeScrollBar::NativeScrollBar(bool is_horiz)
+  : sb_view_(NULL),
+    sb_container_(NULL),
+    ScrollBar(is_horiz) {
+}
+
+NativeScrollBar::~NativeScrollBar() {
+  if (sb_container_) {
+    // We always destroy the scrollbar container explicitly to cover all
+    // cases including when the container is no longer connected to a
+    // widget tree.
+    ::DestroyWindow(*sb_container_);
+    delete sb_container_;
+  }
+}
+
+void NativeScrollBar::ViewHierarchyChanged(bool is_add, View *parent,
+                                           View *child) {
+  Widget* widget;
+  if (is_add && (widget = GetWidget()) && !sb_view_) {
+    sb_view_ = new HWNDView();
+    AddChildView(sb_view_);
+    sb_container_ = new ScrollBarContainer(this);
+    sb_view_->Attach(*sb_container_);
+    Layout();
+  }
+}
+
+void NativeScrollBar::Layout() {
+  if (sb_view_)
+    sb_view_->SetBounds(GetLocalBounds(true));
+}
+
+gfx::Size NativeScrollBar::GetPreferredSize() {
+  if (IsHorizontal())
+    return gfx::Size(0, GetLayoutSize());
+  return gfx::Size(GetLayoutSize(), 0);
+}
+
+void NativeScrollBar::Update(int viewport_size,
+                             int content_size,
+                             int current_pos) {
+  ScrollBar::Update(viewport_size, content_size, current_pos);
+  if (!sb_container_)
+    return;
+
+  if (content_size < 0)
+    content_size = 0;
+
+  if (current_pos < 0)
+    current_pos = 0;
+
+  if (current_pos > content_size)
+    current_pos = content_size;
+
+  SCROLLINFO si;
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_DISABLENOSCROLL | SIF_POS | SIF_RANGE | SIF_PAGE;
+  si.nMin = 0;
+  si.nMax = content_size;
+  si.nPos = current_pos;
+  si.nPage = viewport_size;
+  ::SetScrollInfo(sb_container_->GetScrollBarHWND(),
+                  SB_CTL,
+                  &si,
+                  TRUE);
+}
+
+int NativeScrollBar::GetLayoutSize() const {
+  return ::GetSystemMetrics(IsHorizontal() ? SM_CYHSCROLL : SM_CYVSCROLL);
+}
+
+int NativeScrollBar::GetPosition() const {
+  SCROLLINFO si;
+  si.cbSize = sizeof(si);
+  si.fMask = SIF_POS;
+  GetScrollInfo(sb_container_->GetScrollBarHWND(), SB_CTL, &si);
+  return si.nPos;
+}
+
+bool NativeScrollBar::OnMouseWheel(const MouseWheelEvent& e) {
+  if (!sb_container_) {
+    return false;
+  }
+
+  sb_container_->ScrollWithOffset(e.GetOffset());
+  return true;
+}
+
+bool NativeScrollBar::OnKeyPressed(const KeyEvent& event) {
+  if (!sb_container_) {
+    return false;
+  }
+  int code = -1;
+  switch(event.GetCharacter()) {
+    case VK_UP:
+      if (!IsHorizontal())
+        code = SB_LINEUP;
+      break;
+    case VK_PRIOR:
+      code = SB_PAGEUP;
+      break;
+    case VK_NEXT:
+      code = SB_PAGEDOWN;
+      break;
+    case VK_DOWN:
+      if (!IsHorizontal())
+        code = SB_LINEDOWN;
+      break;
+    case VK_HOME:
+      code = SB_TOP;
+      break;
+    case VK_END:
+      code = SB_BOTTOM;
+      break;
+    case VK_LEFT:
+      if (IsHorizontal())
+        code = SB_LINELEFT;
+      break;
+    case VK_RIGHT:
+      if (IsHorizontal())
+        code = SB_LINERIGHT;
+      break;
+  }
+  if (code != -1) {
+    ::SendMessage(*sb_container_,
+                  IsHorizontal() ? WM_HSCROLL : WM_VSCROLL,
+                  MAKELONG(static_cast<WORD>(code), 0), 0L);
+    return true;
+  }
+  return false;
+}
+
+//static
+int NativeScrollBar::GetHorizontalScrollBarHeight() {
+  return ::GetSystemMetrics(SM_CYHSCROLL);
+}
+
+//static
+int NativeScrollBar::GetVerticalScrollBarWidth() {
+  return ::GetSystemMetrics(SM_CXVSCROLL);
+}
+
+}  // namespace views
diff --git a/views/controls/scrollbar/native_scroll_bar.h b/views/controls/scrollbar/native_scroll_bar.h
new file mode 100644
index 0000000..2747bce
--- /dev/null
+++ b/views/controls/scrollbar/native_scroll_bar.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_SCROLLBAR_NATIVE_SCROLLBAR_H_
+#define VIEWS_CONTROLS_SCROLLBAR_NATIVE_SCROLLBAR_H_
+
+#include "build/build_config.h"
+
+#include "views/controls/scrollbar/scroll_bar.h"
+
+namespace views {
+
+class HWNDView;
+class ScrollBarContainer;
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// NativeScrollBar
+//
+// A View subclass that wraps a Native Windows scrollbar control.
+//
+// A scrollbar is either horizontal or vertical.
+//
+/////////////////////////////////////////////////////////////////////////////
+class NativeScrollBar : public ScrollBar {
+ public:
+
+  // Create new scrollbar, either horizontal or vertical
+  explicit NativeScrollBar(bool is_horiz);
+  virtual ~NativeScrollBar();
+
+  // Overridden for layout purpose
+  virtual void Layout();
+  virtual gfx::Size GetPreferredSize();
+
+  // Overridden for keyboard UI purpose
+  virtual bool OnKeyPressed(const KeyEvent& event);
+  virtual bool OnMouseWheel(const MouseWheelEvent& e);
+
+  virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
+
+  // Overridden from ScrollBar
+  virtual void Update(int viewport_size, int content_size, int current_pos);
+  virtual int GetLayoutSize() const;
+  virtual int GetPosition() const;
+
+  // Return the system sizes
+  static int GetHorizontalScrollBarHeight();
+  static int GetVerticalScrollBarWidth();
+
+ private:
+#if defined(OS_WIN)
+  // The sb_view_ takes care of keeping sb_container in sync with the
+  // view hierarchy
+  HWNDView* sb_view_;
+#endif  // defined(OS_WIN)
+
+  // sb_container_ is a custom hwnd that we use to wrap the real
+  // windows scrollbar. We need to do this to get the scroll events
+  // without having to do anything special in the high level hwnd.
+  ScrollBarContainer* sb_container_;
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_CONTROLS_SCROLLBAR_NATIVE_SCROLLBAR_H_
diff --git a/views/controls/scrollbar/scroll_bar.cc b/views/controls/scrollbar/scroll_bar.cc
new file mode 100644
index 0000000..a475c44
--- /dev/null
+++ b/views/controls/scrollbar/scroll_bar.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2006-2008 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 "views/controls/scrollbar/scroll_bar.h"
+
+namespace views {
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ScrollBar implementation
+//
+/////////////////////////////////////////////////////////////////////////////
+
+ScrollBar::ScrollBar(bool is_horiz) : is_horiz_(is_horiz),
+                                      controller_(NULL),
+                                      max_pos_(0) {
+}
+
+ScrollBar::~ScrollBar() {
+}
+
+bool ScrollBar::IsHorizontal() const {
+  return is_horiz_;
+}
+
+void ScrollBar::SetController(ScrollBarController* controller) {
+  controller_ = controller;
+}
+
+ScrollBarController* ScrollBar::GetController() const {
+  return controller_;
+}
+
+void ScrollBar::Update(int viewport_size, int content_size, int current_pos) {
+  max_pos_ = std::max(0, content_size - viewport_size);
+}
+
+int ScrollBar::GetMaxPosition() const {
+  return max_pos_;
+}
+
+int ScrollBar::GetMinPosition() const {
+  return 0;
+}
+
+}  // namespace views
diff --git a/views/controls/scrollbar/scroll_bar.h b/views/controls/scrollbar/scroll_bar.h
new file mode 100644
index 0000000..36a9d2e
--- /dev/null
+++ b/views/controls/scrollbar/scroll_bar.h
@@ -0,0 +1,102 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_SCROLLBAR_SCROLLBAR_H_
+#define VIEWS_CONTROLS_SCROLLBAR_SCROLLBAR_H_
+
+#include "views/view.h"
+#include "views/event.h"
+
+namespace views {
+
+class ScrollBar;
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ScrollBarController
+//
+// ScrollBarController defines the method that should be implemented to
+// receive notification from a scrollbar
+//
+/////////////////////////////////////////////////////////////////////////////
+class ScrollBarController {
+ public:
+
+  // Invoked by the scrollbar when the scrolling position changes
+  // This method typically implements the actual scrolling.
+  //
+  // The provided position is expressed in pixels. It is the new X or Y
+  // position which is in the GetMinPosition() / GetMaxPosition range.
+  virtual void ScrollToPosition(ScrollBar* source, int position) = 0;
+
+  // Returns the amount to scroll. The amount to scroll may be requested in
+  // two different amounts. If is_page is true the 'page scroll' amount is
+  // requested. The page scroll amount typically corresponds to the
+  // visual size of the view. If is_page is false, the 'line scroll' amount
+  // is being requested. The line scroll amount typically corresponds to the
+  // size of one row/column.
+  //
+  // The return value should always be positive. A value <= 0 results in
+  // scrolling by a fixed amount.
+  virtual int GetScrollIncrement(ScrollBar* source,
+                                 bool is_page,
+                                 bool is_positive) = 0;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ScrollBar
+//
+// A View subclass to wrap to implement a ScrollBar. Our current windows
+// version simply wraps a native windows scrollbar.
+//
+// A scrollbar is either horizontal or vertical
+//
+/////////////////////////////////////////////////////////////////////////////
+class ScrollBar : public View {
+ public:
+  virtual ~ScrollBar();
+
+  // Return whether this scrollbar is horizontal
+  bool IsHorizontal() const;
+
+  // Set / Get the controller
+  void SetController(ScrollBarController* controller);
+  ScrollBarController* GetController() const;
+
+  // Update the scrollbar appearance given a viewport size, content size and
+  // current position
+  virtual void Update(int viewport_size, int content_size, int current_pos);
+
+  // Return the max and min positions
+  int GetMaxPosition() const;
+  int GetMinPosition() const;
+
+  // Returns the position of the scrollbar.
+  virtual int GetPosition() const = 0;
+
+  // Get the width or height of this scrollbar, for use in layout calculations.
+  // For a vertical scrollbar, this is the width of the scrollbar, likewise it
+  // is the height for a horizontal scrollbar.
+  virtual int GetLayoutSize() const = 0;
+
+ protected:
+  // Create new scrollbar, either horizontal or vertical. These are protected
+  // since you need to be creating either a NativeScrollBar or a
+  // BitmapScrollBar.
+  ScrollBar(bool is_horiz);
+
+ private:
+  const bool is_horiz_;
+
+  // Current controller
+  ScrollBarController* controller_;
+
+  // properties
+  int max_pos_;
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_CONTROLS_SCROLLBAR_SCROLLBAR_H_
diff --git a/views/controls/separator.cc b/views/controls/separator.cc
new file mode 100644
index 0000000..f331ce8
--- /dev/null
+++ b/views/controls/separator.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2006-2008 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 "views/controls/separator.h"
+
+#include "views/controls/hwnd_view.h"
+
+namespace views {
+
+static const int kSeparatorSize = 2;
+
+Separator::Separator() {
+  SetFocusable(false);
+}
+
+Separator::~Separator() {
+}
+
+HWND Separator::CreateNativeControl(HWND parent_container) {
+  SetFixedHeight(kSeparatorSize, CENTER);
+
+  return ::CreateWindowEx(GetAdditionalExStyle(), L"STATIC", L"",
+                          WS_CHILD | SS_ETCHEDHORZ | SS_SUNKEN,
+                          0, 0, width(), height(),
+                          parent_container, NULL, NULL, NULL);
+}
+
+LRESULT Separator::OnNotify(int w_param, LPNMHDR l_param) {
+  return 0;
+}
+
+gfx::Size Separator::GetPreferredSize() {
+  return gfx::Size(width(), fixed_height_);
+}
+
+}  // namespace views
diff --git a/views/controls/separator.h b/views/controls/separator.h
new file mode 100644
index 0000000..866beda
--- /dev/null
+++ b/views/controls/separator.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_SEPARATOR_H_
+#define VIEWS_CONTROLS_SEPARATOR_H_
+
+#include "views/controls/native_control.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 Separator : public NativeControl {
+ public:
+  Separator();
+  virtual ~Separator();
+
+  // NativeControl overrides:
+  virtual HWND CreateNativeControl(HWND parent_container);
+  virtual LRESULT OnNotify(int w_param, LPNMHDR l_param);
+
+  // View overrides:
+  virtual gfx::Size GetPreferredSize();
+
+ private:
+
+  DISALLOW_EVIL_CONSTRUCTORS(Separator);
+};
+
+}  // namespace views
+
+#endif  // #define VIEWS_CONTROLS_SEPARATOR_H_
diff --git a/views/controls/single_split_view.cc b/views/controls/single_split_view.cc
new file mode 100644
index 0000000..4558ffd
--- /dev/null
+++ b/views/controls/single_split_view.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2006-2008 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 "views/controls/single_split_view.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "skia/ext/skia_utils_win.h"
+#include "views/background.h"
+
+namespace views {
+
+// Size of the divider in pixels.
+static const int kDividerSize = 4;
+
+SingleSplitView::SingleSplitView(View* leading, View* trailing)
+    : divider_x_(-1) {
+  AddChildView(leading);
+  AddChildView(trailing);
+  set_background(
+      views::Background::CreateSolidBackground(
+          skia::COLORREFToSkColor(GetSysColor(COLOR_3DFACE))));
+}
+
+void SingleSplitView::Layout() {
+  if (GetChildViewCount() != 2)
+    return;
+
+  View* leading = GetChildViewAt(0);
+  View* trailing = GetChildViewAt(1);
+  if (divider_x_ < 0)
+    divider_x_ = (width() - kDividerSize) / 2;
+  else
+    divider_x_ = std::min(divider_x_, width() - kDividerSize);
+  leading->SetBounds(0, 0, divider_x_, height());
+  trailing->SetBounds(divider_x_ + kDividerSize, 0,
+                      width() - divider_x_ - kDividerSize, height());
+
+  SchedulePaint();
+
+  // Invoke super's implementation so that the children are layed out.
+  View::Layout();
+}
+
+gfx::Size SingleSplitView::GetPreferredSize() {
+  int width = 0;
+  int height = 0;
+  for (int i = 0; i < 2 && i < GetChildViewCount(); ++i) {
+    View* view = GetChildViewAt(i);
+    gfx::Size pref = view->GetPreferredSize();
+    width += pref.width();
+    height = std::max(height, pref.height());
+  }
+  width += kDividerSize;
+  return gfx::Size(width, height);
+}
+
+HCURSOR SingleSplitView::GetCursorForPoint(Event::EventType event_type,
+                                           int x,
+                                           int y) {
+  if (IsPointInDivider(x)) {
+    static HCURSOR resize_cursor = LoadCursor(NULL, IDC_SIZEWE);
+    return resize_cursor;
+  }
+  return NULL;
+}
+
+bool SingleSplitView::OnMousePressed(const MouseEvent& event) {
+  if (!IsPointInDivider(event.x()))
+    return false;
+  drag_info_.initial_mouse_x = event.x();
+  drag_info_.initial_divider_x = divider_x_;
+  return true;
+}
+
+bool SingleSplitView::OnMouseDragged(const MouseEvent& event) {
+  if (GetChildViewCount() < 2)
+    return false;
+
+  int delta_x = event.x() - drag_info_.initial_mouse_x;
+  if (UILayoutIsRightToLeft())
+    delta_x *= -1;
+  // Honor the minimum size when resizing.
+  int new_width = std::max(GetChildViewAt(0)->GetMinimumSize().width(),
+                           drag_info_.initial_divider_x + delta_x);
+
+  // And don't let the view get bigger than our width.
+  new_width = std::min(width() - kDividerSize, new_width);
+
+  if (new_width != divider_x_) {
+    set_divider_x(new_width);
+    Layout();
+  }
+  return true;
+}
+
+void SingleSplitView::OnMouseReleased(const MouseEvent& event, bool canceled) {
+  if (GetChildViewCount() < 2)
+    return;
+
+  if (canceled && drag_info_.initial_divider_x != divider_x_) {
+    set_divider_x(drag_info_.initial_divider_x);
+    Layout();
+  }
+}
+
+bool SingleSplitView::IsPointInDivider(int x) {
+  if (GetChildViewCount() < 2)
+    return false;
+
+  int divider_relative_x =
+      x - GetChildViewAt(UILayoutIsRightToLeft() ? 1 : 0)->width();
+  return (divider_relative_x >= 0 && divider_relative_x < kDividerSize);
+}
+
+}  // namespace views
diff --git a/views/controls/single_split_view.h b/views/controls/single_split_view.h
new file mode 100644
index 0000000..a531800
--- /dev/null
+++ b/views/controls/single_split_view.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_H_
+#define VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_H_
+
+#include "views/view.h"
+
+namespace views {
+
+// SingleSplitView lays out two views horizontally. A splitter exists between
+// the two views that the user can drag around to resize the views.
+class SingleSplitView : public views::View {
+ public:
+  SingleSplitView(View* leading, View* trailing);
+
+  virtual void Layout();
+
+  // SingleSplitView's preferred size is the sum of the preferred widths
+  // and the max of the heights.
+  virtual gfx::Size GetPreferredSize();
+
+  // Overriden to return a resize cursor when over the divider.
+  virtual HCURSOR GetCursorForPoint(Event::EventType event_type, int x, int y);
+
+  void set_divider_x(int divider_x) { divider_x_ = divider_x; }
+  int divider_x() { return divider_x_; }
+
+ protected:
+  virtual bool OnMousePressed(const MouseEvent& event);
+  virtual bool OnMouseDragged(const MouseEvent& event);
+  virtual void OnMouseReleased(const MouseEvent& event, bool canceled);
+
+ private:
+  // Returns true if |x| is over the divider.
+  bool IsPointInDivider(int x);
+
+  // Used to track drag info.
+  struct DragInfo {
+    // The initial coordinate of the mouse when the user started the drag.
+    int initial_mouse_x;
+    // The initial position of the divider when the user started the drag.
+    int initial_divider_x;
+  };
+
+  DragInfo drag_info_;
+
+  // Position of the divider.
+  int divider_x_;
+
+  DISALLOW_COPY_AND_ASSIGN(SingleSplitView);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_H_
diff --git a/views/controls/tabbed_pane.cc b/views/controls/tabbed_pane.cc
new file mode 100644
index 0000000..401cb795
--- /dev/null
+++ b/views/controls/tabbed_pane.cc
@@ -0,0 +1,264 @@
+// Copyright (c) 2006-2008 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 "views/controls/tabbed_pane.h"
+
+#include <vssym32.h>
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/gfx/chrome_font.h"
+#include "app/l10n_util_win.h"
+#include "app/resource_bundle.h"
+#include "base/gfx/native_theme.h"
+#include "base/logging.h"
+#include "base/stl_util-inl.h"
+#include "skia/ext/skia_utils_win.h"
+#include "skia/include/SkColor.h"
+#include "views/background.h"
+#include "views/fill_layout.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget_win.h"
+
+namespace views {
+
+// A background object that paints the tab panel background which may be
+// rendered by the system visual styles system.
+class TabBackground : public Background {
+ public:
+  explicit TabBackground() {
+    // TMT_FILLCOLORHINT returns a color value that supposedly
+    // approximates the texture drawn by PaintTabPanelBackground.
+    SkColor tab_page_color =
+        gfx::NativeTheme::instance()->GetThemeColorWithDefault(
+            gfx::NativeTheme::TAB, TABP_BODY, 0, TMT_FILLCOLORHINT,
+            COLOR_3DFACE);
+    SetNativeControlColor(tab_page_color);
+  }
+  virtual ~TabBackground() {}
+
+  virtual void Paint(ChromeCanvas* canvas, View* view) const {
+    HDC dc = canvas->beginPlatformPaint();
+    RECT r = {0, 0, view->width(), view->height()};
+    gfx::NativeTheme::instance()->PaintTabPanelBackground(dc, &r);
+    canvas->endPlatformPaint();
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(TabBackground);
+};
+
+TabbedPane::TabbedPane() : content_window_(NULL), listener_(NULL) {
+}
+
+TabbedPane::~TabbedPane() {
+  // We own the tab views, let's delete them.
+  STLDeleteContainerPointers(tab_views_.begin(), tab_views_.end());
+}
+
+void TabbedPane::SetListener(Listener* listener) {
+  listener_ = listener;
+}
+
+void TabbedPane::AddTab(const std::wstring& title, View* contents) {
+  AddTabAtIndex(static_cast<int>(tab_views_.size()), title, contents, true);
+}
+
+void TabbedPane::AddTabAtIndex(int index,
+                               const std::wstring& title,
+                               View* contents,
+                               bool select_if_first_tab) {
+  DCHECK(index <= static_cast<int>(tab_views_.size()));
+  contents->SetParentOwned(false);
+  tab_views_.insert(tab_views_.begin() + index, contents);
+
+  TCITEM tcitem;
+  tcitem.mask = TCIF_TEXT;
+
+  // If the locale is RTL, we set the TCIF_RTLREADING so that BiDi text is
+  // rendered properly on the tabs.
+  if (UILayoutIsRightToLeft()) {
+    tcitem.mask |= TCIF_RTLREADING;
+  }
+
+  tcitem.pszText = const_cast<wchar_t*>(title.c_str());
+  int result = TabCtrl_InsertItem(tab_control_, index, &tcitem);
+  DCHECK(result != -1);
+
+  if (!contents->background()) {
+    contents->set_background(new TabBackground);
+  }
+
+  if (tab_views_.size() == 1 && select_if_first_tab) {
+    // If this is the only tab displayed, make sure the contents is set.
+    content_window_->GetRootView()->AddChildView(contents);
+  }
+
+  // The newly added tab may have made the contents window smaller.
+  ResizeContents(tab_control_);
+}
+
+View* TabbedPane::RemoveTabAtIndex(int index) {
+  int tab_count = static_cast<int>(tab_views_.size());
+  DCHECK(index >= 0 && index < tab_count);
+
+  if (index < (tab_count - 1)) {
+    // Select the next tab.
+    SelectTabAt(index + 1);
+  } else {
+    // We are the last tab, select the previous one.
+    if (index > 0) {
+      SelectTabAt(index - 1);
+    } else {
+      // That was the last tab. Remove the contents.
+      content_window_->GetRootView()->RemoveAllChildViews(false);
+    }
+  }
+  TabCtrl_DeleteItem(tab_control_, index);
+
+  // The removed tab may have made the contents window bigger.
+  ResizeContents(tab_control_);
+
+  std::vector<View*>::iterator iter = tab_views_.begin() + index;
+  View* removed_tab = *iter;
+  tab_views_.erase(iter);
+
+  return removed_tab;
+}
+
+void TabbedPane::SelectTabAt(int index) {
+  DCHECK((index >= 0) && (index < static_cast<int>(tab_views_.size())));
+  TabCtrl_SetCurSel(tab_control_, index);
+  DoSelectTabAt(index);
+}
+
+void TabbedPane::SelectTabForContents(const View* contents) {
+  SelectTabAt(GetIndexForContents(contents));
+}
+
+int TabbedPane::GetTabCount() {
+  return TabCtrl_GetItemCount(tab_control_);
+}
+
+HWND TabbedPane::CreateNativeControl(HWND parent_container) {
+  // Create the tab control.
+  //
+  // Note that we don't follow the common convention for NativeControl
+  // subclasses and we don't pass the value returned from
+  // NativeControl::GetAdditionalExStyle() as the dwExStyle parameter. Here is
+  // why: on RTL locales, if we pass NativeControl::GetAdditionalExStyle() when
+  // we basically tell Windows to create our HWND with the WS_EX_LAYOUTRTL. If
+  // we do that, then the HWND we create for |content_window_| below will
+  // inherit the WS_EX_LAYOUTRTL property and this will result in the contents
+  // being flipped, which is not what we want (because we handle mirroring in
+  // views without the use of Windows' support for mirroring). Therefore,
+  // we initially create our HWND without the aforementioned property and we
+  // explicitly set this property our child is created. This way, on RTL
+  // locales, our tabs will be nicely rendered from right to left (by virtue of
+  // Windows doing the right thing with the TabbedPane HWND) and each tab
+  // contents will use an RTL layout correctly (by virtue of the mirroring
+  // infrastructure in views doing the right thing with each View we put
+  // in the tab).
+  tab_control_ = ::CreateWindowEx(0,
+                                  WC_TABCONTROL,
+                                  L"",
+                                  WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
+                                  0, 0, width(), height(),
+                                  parent_container, NULL, NULL, NULL);
+
+  HFONT font = ResourceBundle::GetSharedInstance().
+      GetFont(ResourceBundle::BaseFont).hfont();
+  SendMessage(tab_control_, WM_SETFONT, reinterpret_cast<WPARAM>(font), FALSE);
+
+  // Create the view container which is a child of the TabControl.
+  content_window_ = new WidgetWin();
+  content_window_->Init(tab_control_, gfx::Rect(), false);
+
+  // Explicitly setting the WS_EX_LAYOUTRTL property for the HWND (see above
+  // for a thorough explanation regarding why we waited until |content_window_|
+  // if created before we set this property for the tabbed pane's HWND).
+  if (UILayoutIsRightToLeft()) {
+    l10n_util::HWNDSetRTLLayout(tab_control_);
+  }
+
+  RootView* root_view = content_window_->GetRootView();
+  root_view->SetLayoutManager(new FillLayout());
+  DWORD sys_color = ::GetSysColor(COLOR_3DHILIGHT);
+  SkColor color = SkColorSetRGB(GetRValue(sys_color), GetGValue(sys_color),
+                                GetBValue(sys_color));
+  root_view->set_background(Background::CreateSolidBackground(color));
+
+  content_window_->SetFocusTraversableParentView(this);
+  ResizeContents(tab_control_);
+  return tab_control_;
+}
+
+LRESULT TabbedPane::OnNotify(int w_param, LPNMHDR l_param) {
+  if (static_cast<LPNMHDR>(l_param)->code == TCN_SELCHANGE) {
+    int selected_tab = TabCtrl_GetCurSel(tab_control_);
+    DCHECK(selected_tab != -1);
+    DoSelectTabAt(selected_tab);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+void TabbedPane::DoSelectTabAt(int index) {
+  RootView* content_root = content_window_->GetRootView();
+
+  // Clear the focus if the focused view was on the tab.
+  FocusManager* focus_manager = GetFocusManager();
+  DCHECK(focus_manager);
+  View* focused_view = focus_manager->GetFocusedView();
+  if (focused_view && content_root->IsParentOf(focused_view))
+    focus_manager->ClearFocus();
+
+  content_root->RemoveAllChildViews(false);
+  content_root->AddChildView(tab_views_[index]);
+  content_root->Layout();
+  if (listener_)
+    listener_->TabSelectedAt(index);
+}
+
+int TabbedPane::GetIndexForContents(const View* contents) const {
+  std::vector<View*>::const_iterator i =
+      std::find(tab_views_.begin(), tab_views_.end(), contents);
+  DCHECK(i != tab_views_.end());
+  return static_cast<int>(i - tab_views_.begin());
+}
+
+void TabbedPane::Layout() {
+  NativeControl::Layout();
+  ResizeContents(GetNativeControlHWND());
+}
+
+RootView* TabbedPane::GetContentsRootView() {
+  return content_window_->GetRootView();
+}
+
+FocusTraversable* TabbedPane::GetFocusTraversable() {
+  return content_window_;
+}
+
+void TabbedPane::ViewHierarchyChanged(bool is_add, View *parent, View *child) {
+  NativeControl::ViewHierarchyChanged(is_add, parent, child);
+
+  if (is_add && (child == this) && content_window_) {
+    // We have been added to a view hierarchy, update the FocusTraversable
+    // parent.
+    content_window_->SetFocusTraversableParent(GetRootView());
+  }
+}
+
+void TabbedPane::ResizeContents(HWND tab_control) {
+  DCHECK(tab_control);
+  CRect content_bounds;
+  if (!GetClientRect(tab_control, &content_bounds))
+    return;
+  TabCtrl_AdjustRect(tab_control, FALSE, &content_bounds);
+  content_window_->MoveWindow(content_bounds.left, content_bounds.top,
+                              content_bounds.Width(), content_bounds.Height(),
+                              TRUE);
+}
+
+}  // namespace views
diff --git a/views/controls/tabbed_pane.h b/views/controls/tabbed_pane.h
new file mode 100644
index 0000000..528a2d5c
--- /dev/null
+++ b/views/controls/tabbed_pane.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_TABBED_PANE_H_
+#define VIEWS_CONTROLS_TABBED_PANE_H_
+
+#include "views/controls/native_control.h"
+
+namespace views {
+
+// The TabbedPane class is a view that shows tabs.  When the user clicks on a
+// tab, the associated view is displayed.
+// TODO (jcampan): implement GetPreferredSize().
+class WidgetWin;
+
+class TabbedPane : public NativeControl {
+ public:
+  TabbedPane();
+  virtual ~TabbedPane();
+
+  // An interface an object can implement to be notified about events within
+  // the TabbedPane.
+  class Listener {
+   public:
+    // Called when the tab at the specified |index| is selected by the user.
+    virtual void TabSelectedAt(int index) = 0;
+  };
+  void SetListener(Listener* listener);
+
+  // Adds a new tab at the end of this TabbedPane with the specified |title|.
+  // |contents| is the view displayed when the tab is selected and is owned by
+  // the TabbedPane.
+  void AddTab(const std::wstring& title, View* contents);
+
+  // Adds a new tab at the specified |index| with the specified |title|.
+  // |contents| is the view displayed when the tab is selected and is owned by
+  // the TabbedPane. If |select_if_first_tab| is true and the tabbed pane is
+  // currently empty, the new tab is selected. If you pass in false for
+  // |select_if_first_tab| you need to explicitly invoke SelectTabAt, otherwise
+  // the tabbed pane will not have a valid selection.
+  void AddTabAtIndex(int index,
+                     const std::wstring& title,
+                     View* contents,
+                     bool select_if_first_tab);
+
+  // Removes the tab at the specified |index| and returns the associated content
+  // view.  The caller becomes the owner of the returned view.
+  View* RemoveTabAtIndex(int index);
+
+  // Selects the tab at the specified |index|, which must be valid.
+  void SelectTabAt(int index);
+
+  // Selects the tab containing the specified |contents|, which must be valid.
+  void SelectTabForContents(const View* contents);
+
+  // Returns the number of tabs.
+  int GetTabCount();
+
+  virtual HWND CreateNativeControl(HWND parent_container);
+  virtual LRESULT OnNotify(int w_param, LPNMHDR l_param);
+
+  virtual void Layout();
+
+  virtual RootView* GetContentsRootView();
+  virtual FocusTraversable* GetFocusTraversable();
+  virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
+
+ private:
+  // Changes the contents view to the view associated with the tab at |index|.
+  void DoSelectTabAt(int index);
+
+  // Returns the index of the tab containing the specified |contents|.
+  int GetIndexForContents(const View* contents) const;
+
+  void ResizeContents(HWND tab_control);
+
+  HWND tab_control_;
+
+  // The views associated with the different tabs.
+  std::vector<View*> tab_views_;
+
+  // The window displayed in the tab.
+  WidgetWin* content_window_;
+
+  // The listener we notify about tab selection changes.
+  Listener* listener_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(TabbedPane);
+};
+
+}  // namespace views
+
+#endif  // #define VIEWS_CONTROLS_TABBED_PANE_H_
diff --git a/views/controls/table/group_table_view.cc b/views/controls/table/group_table_view.cc
new file mode 100644
index 0000000..5e6a155
--- /dev/null
+++ b/views/controls/table/group_table_view.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2006-2008 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 "views/controls/table/group_table_view.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "base/message_loop.h"
+#include "base/task.h"
+
+namespace views {
+
+static const COLORREF kSeparatorLineColor = RGB(208, 208, 208);
+static const int kSeparatorLineThickness = 1;
+
+const char GroupTableView::kViewClassName[] = "views/GroupTableView";
+
+GroupTableView::GroupTableView(GroupTableModel* model,
+                               const std::vector<TableColumn>& columns,
+                               TableTypes table_type,
+                               bool single_selection,
+                               bool resizable_columns,
+                               bool autosize_columns)
+    : TableView(model, columns, table_type, false, resizable_columns,
+                autosize_columns),
+    model_(model),
+    sync_selection_factory_(this) {
+}
+
+GroupTableView::~GroupTableView() {
+}
+
+void GroupTableView::SyncSelection() {
+  int index = 0;
+  int row_count = model_->RowCount();
+  GroupRange group_range;
+  while (index < row_count) {
+    model_->GetGroupRangeForItem(index, &group_range);
+    if (group_range.length == 1) {
+      // No synching required for single items.
+      index++;
+    }  else {
+      // We need to select the group if at least one item is selected.
+      bool should_select = false;
+      for (int i = group_range.start;
+           i < group_range.start + group_range.length; ++i) {
+        if (IsItemSelected(i)) {
+          should_select = true;
+          break;
+        }
+      }
+      if (should_select) {
+        for (int i = group_range.start;
+             i < group_range.start + group_range.length; ++i) {
+          SetSelectedState(i, true);
+        }
+      }
+      index += group_range.length;
+    }
+  }
+}
+
+void GroupTableView::OnKeyDown(unsigned short virtual_keycode) {
+  // In a list view, multiple items can be selected but only one item has the
+  // focus. This creates a problem when the arrow keys are used for navigating
+  // between items in the list view. An example will make this more clear:
+  //
+  // Suppose we have 5 items in the list view, and three of these items are
+  // part of one group:
+  //
+  // Index0: ItemA (No Group)
+  // Index1: ItemB (GroupX)
+  // Index2: ItemC (GroupX)
+  // Index3: ItemD (GroupX)
+  // Index4: ItemE (No Group)
+  //
+  // When GroupX is selected (say, by clicking on ItemD with the mouse),
+  // GroupTableView::SyncSelection() will make sure ItemB, ItemC and ItemD are
+  // selected. Also, the item with the focus will be ItemD (simply because
+  // this is the item the user happened to click on). If then the UP arrow is
+  // pressed once, the focus will be switched to ItemC and not to ItemA and the
+  // end result is that we are stuck in GroupX even though the intention was to
+  // switch to ItemA.
+  //
+  // For that exact reason, we need to set the focus appropriately when we
+  // detect that one of the arrow keys is pressed. Thus, when it comes time
+  // for the list view control to actually switch the focus, the right item
+  // will be selected.
+  if ((virtual_keycode != VK_UP) && (virtual_keycode != VK_DOWN)) {
+    TableView::OnKeyDown(virtual_keycode);
+    return;
+  }
+
+  // We start by finding the index of the item with the focus. If no item
+  // currently has the focus, then this routine doesn't do anything.
+  int focused_index;
+  int row_count = model_->RowCount();
+  for (focused_index = 0; focused_index < row_count; focused_index++) {
+    if (ItemHasTheFocus(focused_index)) {
+      break;
+    }
+  }
+
+  if (focused_index == row_count) {
+    return;
+  }
+  DCHECK_LT(focused_index, row_count);
+
+  // Nothing to do if the item which has the focus is not part of a group.
+  GroupRange group_range;
+  model_->GetGroupRangeForItem(focused_index, &group_range);
+  if (group_range.length == 1) {
+    return;
+  }
+
+  // If the user pressed the UP key, then the focus should be set to the
+  // topmost element in the group. If the user pressed the DOWN key, the focus
+  // should be set to the bottommost element.
+  if (virtual_keycode == VK_UP) {
+    SetFocusOnItem(group_range.start);
+  } else {
+    DCHECK_EQ(virtual_keycode, VK_DOWN);
+    SetFocusOnItem(group_range.start + group_range.length - 1);
+  }
+}
+
+void GroupTableView::PrepareForSort() {
+  GroupRange range;
+  int row_count = RowCount();
+  model_index_to_range_start_map_.clear();
+  for (int model_row = 0; model_row < row_count;) {
+    model_->GetGroupRangeForItem(model_row, &range);
+    for (int range_counter = 0; range_counter < range.length; range_counter++)
+      model_index_to_range_start_map_[range_counter + model_row] = model_row;
+    model_row += range.length;
+  }
+}
+
+int GroupTableView::CompareRows(int model_row1, int model_row2) {
+  int range1 = model_index_to_range_start_map_[model_row1];
+  int range2 = model_index_to_range_start_map_[model_row2];
+  if (range1 == range2) {
+    // The two rows are in the same group, sort so that items in the same group
+    // always appear in the same order.
+    return model_row1 - model_row2;
+  }
+  // Sort by the first entry of each of the groups.
+  return TableView::CompareRows(range1, range2);
+}
+
+void GroupTableView::OnSelectedStateChanged() {
+  // The goal is to make sure all items for a same group are in a consistent
+  // state in term of selection. When a user clicks an item, several selection
+  // messages are sent, possibly including unselecting all currently selected
+  // items. For that reason, we post a task to be performed later, after all
+  // selection messages have been processed. In the meantime we just ignore all
+  // selection notifications.
+  if (sync_selection_factory_.empty()) {
+    MessageLoop::current()->PostTask(FROM_HERE,
+        sync_selection_factory_.NewRunnableMethod(
+            &GroupTableView::SyncSelection));
+  }
+  TableView::OnSelectedStateChanged();
+}
+
+// Draws the line separator betweens the groups.
+void GroupTableView::PostPaint(int model_row, int column, bool selected,
+                               const CRect& bounds, HDC hdc) {
+  GroupRange group_range;
+  model_->GetGroupRangeForItem(model_row, &group_range);
+
+  // We always paint a vertical line at the end of the last cell.
+  HPEN hPen = CreatePen(PS_SOLID, kSeparatorLineThickness, kSeparatorLineColor);
+  HPEN hPenOld = (HPEN) SelectObject(hdc, hPen);
+  int x = static_cast<int>(bounds.right - kSeparatorLineThickness);
+  MoveToEx(hdc, x, bounds.top, NULL);
+  LineTo(hdc, x, bounds.bottom);
+
+  // We paint a separator line after the last item of a group.
+  if (model_row == (group_range.start + group_range.length - 1)) {
+    int y = static_cast<int>(bounds.bottom - kSeparatorLineThickness);
+    MoveToEx(hdc, 0, y, NULL);
+    LineTo(hdc, bounds.Width(), y);
+  }
+  SelectObject(hdc, hPenOld);
+  DeleteObject(hPen);
+}
+
+std::string GroupTableView::GetClassName() const {
+  return kViewClassName;
+}
+
+}  // namespace views
diff --git a/views/controls/table/group_table_view.h b/views/controls/table/group_table_view.h
new file mode 100644
index 0000000..d128759
--- /dev/null
+++ b/views/controls/table/group_table_view.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_TABLE_GROUP_TABLE_VIEW_H_
+#define VIEWS_CONTROLS_TABLE_GROUP_TABLE_VIEW_H_
+
+#include "base/task.h"
+#include "views/controls/table/table_view.h"
+
+// The GroupTableView adds grouping to the TableView class.
+// It allows to have groups of rows that act as a single row from the selection
+// perspective. Groups are visually separated by a horizontal line.
+
+namespace views {
+
+struct GroupRange {
+  int start;
+  int length;
+};
+
+// The model driving the GroupTableView.
+class GroupTableModel : public TableModel {
+ public:
+  // Populates the passed range with the first row/last row (included)
+  // that this item belongs to.
+  virtual void GetGroupRangeForItem(int item, GroupRange* range) = 0;
+};
+
+class GroupTableView : public TableView {
+ public:
+   // The view class name.
+   static const char kViewClassName[];
+
+  GroupTableView(GroupTableModel* model,
+                 const std::vector<TableColumn>& columns,
+                 TableTypes table_type, bool single_selection,
+                 bool resizable_columns, bool autosize_columns);
+  virtual ~GroupTableView();
+
+  virtual std::string GetClassName() const;
+
+ protected:
+  // Notification from the ListView that the selected state of an item has
+  // changed.
+  void OnSelectedStateChanged();
+
+  // Extra-painting required to draw the separator line between groups.
+  virtual bool ImplementPostPaint() { return true; }
+  virtual void PostPaint(int model_row, int column, bool selected,
+                         const CRect& bounds, HDC device_context);
+
+  // In order to make keyboard navigation possible (using the Up and Down
+  // keys), we must take action when an arrow key is pressed. The reason we
+  // need to process this message has to do with the manner in which the focus
+  // needs to be set on a group item when a group is selected.
+  virtual void OnKeyDown(unsigned short virtual_keycode);
+
+  // Overriden to make sure rows in the same group stay grouped together.
+  virtual int CompareRows(int model_row1, int model_row2);
+
+  // Updates model_index_to_range_start_map_ from the model.
+  virtual void PrepareForSort();
+
+ private:
+  // Make the selection of group consistent.
+  void SyncSelection();
+
+  GroupTableModel* model_;
+
+  // A factory to make the selection consistent among groups.
+  ScopedRunnableMethodFactory<GroupTableView> sync_selection_factory_;
+
+  // Maps from model row to start of group.
+  std::map<int,int> model_index_to_range_start_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(GroupTableView);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_TABLE_GROUP_TABLE_VIEW_H_
diff --git a/views/controls/table/table_view.cc b/views/controls/table/table_view.cc
new file mode 100644
index 0000000..f8c7303
--- /dev/null
+++ b/views/controls/table/table_view.cc
@@ -0,0 +1,1570 @@
+// Copyright (c) 2006-2008 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 "views/controls/table/table_view.h"
+
+#include <algorithm>
+#include <windowsx.h>
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/gfx/favicon_size.h"
+#include "app/gfx/icon_util.h"
+#include "app/l10n_util_win.h"
+#include "app/resource_bundle.h"
+#include "base/string_util.h"
+#include "base/win_util.h"
+#include "skia/ext/skia_utils_win.h"
+#include "skia/include/SkBitmap.h"
+#include "skia/include/SkColorFilter.h"
+#include "views/controls/hwnd_view.h"
+
+namespace views {
+
+// Added to column width to prevent truncation.
+const int kListViewTextPadding = 15;
+// Additional column width necessary if column has icons.
+const int kListViewIconWidthAndPadding = 18;
+
+// TableModel -----------------------------------------------------------------
+
+// static
+const int TableView::kImageSize = 18;
+
+// Used for sorting.
+static Collator* collator = NULL;
+
+SkBitmap TableModel::GetIcon(int row) {
+  return SkBitmap();
+}
+
+int TableModel::CompareValues(int row1, int row2, int column_id) {
+  DCHECK(row1 >= 0 && row1 < RowCount() &&
+         row2 >= 0 && row2 < RowCount());
+  std::wstring value1 = GetText(row1, column_id);
+  std::wstring value2 = GetText(row2, column_id);
+  Collator* collator = GetCollator();
+
+  if (collator) {
+    UErrorCode compare_status = U_ZERO_ERROR;
+    UCollationResult compare_result = collator->compare(
+        static_cast<const UChar*>(value1.c_str()),
+        static_cast<int>(value1.length()),
+        static_cast<const UChar*>(value2.c_str()),
+        static_cast<int>(value2.length()),
+        compare_status);
+    DCHECK(U_SUCCESS(compare_status));
+    return compare_result;
+  }
+  NOTREACHED();
+  return 0;
+}
+
+Collator* TableModel::GetCollator() {
+  if (!collator) {
+    UErrorCode create_status = U_ZERO_ERROR;
+    collator = Collator::createInstance(create_status);
+    if (!U_SUCCESS(create_status)) {
+      collator = NULL;
+      NOTREACHED();
+    }
+  }
+  return collator;
+}
+
+// TableView ------------------------------------------------------------------
+
+TableView::TableView(TableModel* model,
+                     const std::vector<TableColumn>& columns,
+                     TableTypes table_type,
+                     bool single_selection,
+                     bool resizable_columns,
+                     bool autosize_columns)
+    : model_(model),
+      table_view_observer_(NULL),
+      visible_columns_(),
+      all_columns_(),
+      column_count_(static_cast<int>(columns.size())),
+      table_type_(table_type),
+      single_selection_(single_selection),
+      ignore_listview_change_(false),
+      custom_colors_enabled_(false),
+      sized_columns_(false),
+      autosize_columns_(autosize_columns),
+      resizable_columns_(resizable_columns),
+      list_view_(NULL),
+      header_original_handler_(NULL),
+      original_handler_(NULL),
+      table_view_wrapper_(this),
+      custom_cell_font_(NULL),
+      content_offset_(0) {
+  for (std::vector<TableColumn>::const_iterator i = columns.begin();
+      i != columns.end(); ++i) {
+    AddColumn(*i);
+    visible_columns_.push_back(i->id);
+  }
+}
+
+TableView::~TableView() {
+  if (list_view_) {
+    if (model_)
+      model_->SetObserver(NULL);
+  }
+  if (custom_cell_font_)
+    DeleteObject(custom_cell_font_);
+}
+
+void TableView::SetModel(TableModel* model) {
+  if (model == model_)
+    return;
+
+  if (list_view_ && model_)
+    model_->SetObserver(NULL);
+  model_ = model;
+  if (list_view_ && model_)
+    model_->SetObserver(this);
+  if (list_view_)
+    OnModelChanged();
+}
+
+void TableView::SetSortDescriptors(const SortDescriptors& sort_descriptors) {
+  if (!sort_descriptors_.empty()) {
+    ResetColumnSortImage(sort_descriptors_[0].column_id,
+                         NO_SORT);
+  }
+  sort_descriptors_ = sort_descriptors;
+  if (!sort_descriptors_.empty()) {
+    ResetColumnSortImage(
+        sort_descriptors_[0].column_id,
+        sort_descriptors_[0].ascending ? ASCENDING_SORT : DESCENDING_SORT);
+  }
+  if (!list_view_)
+    return;
+
+  // For some reason we have to turn off/on redraw, otherwise the display
+  // isn't updated when done.
+  SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(FALSE), 0);
+
+  UpdateItemsLParams(0, 0);
+
+  SortItemsAndUpdateMapping();
+
+  SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(TRUE), 0);
+}
+
+void TableView::DidChangeBounds(const gfx::Rect& previous,
+                                const gfx::Rect& current) {
+  if (!list_view_)
+    return;
+  SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(FALSE), 0);
+  Layout();
+  if ((!sized_columns_ || autosize_columns_) && width() > 0) {
+    sized_columns_ = true;
+    ResetColumnSizes();
+  }
+  UpdateContentOffset();
+  SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(TRUE), 0);
+}
+
+int TableView::RowCount() {
+  if (!list_view_)
+    return 0;
+  return ListView_GetItemCount(list_view_);
+}
+
+int TableView::SelectedRowCount() {
+  if (!list_view_)
+    return 0;
+  return ListView_GetSelectedCount(list_view_);
+}
+
+void TableView::Select(int model_row) {
+  if (!list_view_)
+    return;
+
+  DCHECK(model_row >= 0 && model_row < RowCount());
+  SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(FALSE), 0);
+  ignore_listview_change_ = true;
+
+  // Unselect everything.
+  ListView_SetItemState(list_view_, -1, 0, LVIS_SELECTED);
+
+  // Select the specified item.
+  int view_row = model_to_view(model_row);
+  ListView_SetItemState(list_view_, view_row, LVIS_SELECTED | LVIS_FOCUSED,
+                        LVIS_SELECTED | LVIS_FOCUSED);
+
+  // Make it visible.
+  ListView_EnsureVisible(list_view_, view_row, FALSE);
+  ignore_listview_change_ = false;
+  SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(TRUE), 0);
+  if (table_view_observer_)
+    table_view_observer_->OnSelectionChanged();
+}
+
+void TableView::SetSelectedState(int model_row, bool state) {
+  if (!list_view_)
+    return;
+
+  DCHECK(model_row >= 0 && model_row < RowCount());
+
+  ignore_listview_change_ = true;
+
+  // Select the specified item.
+  ListView_SetItemState(list_view_, model_to_view(model_row),
+                        state ? LVIS_SELECTED : 0,  LVIS_SELECTED);
+
+  ignore_listview_change_ = false;
+}
+
+void TableView::SetFocusOnItem(int model_row) {
+  if (!list_view_)
+    return;
+
+  DCHECK(model_row >= 0 && model_row < RowCount());
+
+  ignore_listview_change_ = true;
+
+  // Set the focus to the given item.
+  ListView_SetItemState(list_view_, model_to_view(model_row), LVIS_FOCUSED,
+                        LVIS_FOCUSED);
+
+  ignore_listview_change_ = false;
+}
+
+int TableView::FirstSelectedRow() {
+  if (!list_view_)
+    return -1;
+
+  int view_row = ListView_GetNextItem(list_view_, -1, LVNI_ALL | LVIS_SELECTED);
+  return view_row == -1 ? -1 : view_to_model(view_row);
+}
+
+bool TableView::IsItemSelected(int model_row) {
+  if (!list_view_)
+    return false;
+
+  DCHECK(model_row >= 0 && model_row < RowCount());
+  return (ListView_GetItemState(list_view_, model_to_view(model_row),
+                                LVIS_SELECTED) == LVIS_SELECTED);
+}
+
+bool TableView::ItemHasTheFocus(int model_row) {
+  if (!list_view_)
+    return false;
+
+  DCHECK(model_row >= 0 && model_row < RowCount());
+  return (ListView_GetItemState(list_view_, model_to_view(model_row),
+                                LVIS_FOCUSED) == LVIS_FOCUSED);
+}
+
+TableView::iterator TableView::SelectionBegin() {
+  return TableView::iterator(this, LastSelectedViewIndex());
+}
+
+TableView::iterator TableView::SelectionEnd() {
+  return TableView::iterator(this, -1);
+}
+
+void TableView::OnItemsChanged(int start, int length) {
+  if (!list_view_)
+    return;
+
+  if (length == -1) {
+    DCHECK(start >= 0);
+    length = model_->RowCount() - start;
+  }
+  int row_count = RowCount();
+  DCHECK(start >= 0 && length > 0 && start + length <= row_count);
+  SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(FALSE), 0);
+  if (table_type_ == ICON_AND_TEXT) {
+    // The redraw event does not include the icon in the clip rect, preventing
+    // our icon from being repainted. So far the only way I could find around
+    // this is to change the image for the item. Even if the image does not
+    // exist, it causes the clip rect to include the icon's bounds so we can
+    // paint it in the post paint event.
+    LVITEM lv_item;
+    memset(&lv_item, 0, sizeof(LVITEM));
+    lv_item.mask = LVIF_IMAGE;
+    for (int i = start; i < start + length; ++i) {
+      // Retrieve the current icon index.
+      lv_item.iItem = model_to_view(i);
+      BOOL r = ListView_GetItem(list_view_, &lv_item);
+      DCHECK(r);
+      // Set the current icon index to the other image.
+      lv_item.iImage = (lv_item.iImage + 1) % 2;
+      DCHECK((lv_item.iImage == 0) || (lv_item.iImage == 1));
+      r = ListView_SetItem(list_view_, &lv_item);
+      DCHECK(r);
+    }
+  }
+  UpdateListViewCache(start, length, false);
+  SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(TRUE), 0);
+}
+
+void TableView::OnModelChanged() {
+  if (!list_view_)
+    return;
+
+  int current_row_count = ListView_GetItemCount(list_view_);
+  if (current_row_count > 0)
+    OnItemsRemoved(0, current_row_count);
+  if (model_ && model_->RowCount())
+    OnItemsAdded(0, model_->RowCount());
+}
+
+void TableView::OnItemsAdded(int start, int length) {
+  if (!list_view_)
+    return;
+
+  DCHECK(start >= 0 && length > 0 && start <= RowCount());
+  SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(FALSE), 0);
+  UpdateListViewCache(start, length, true);
+  SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(TRUE), 0);
+}
+
+void TableView::OnItemsRemoved(int start, int length) {
+  if (!list_view_)
+    return;
+
+  if (start < 0 || length < 0 || start + length > RowCount()) {
+    NOTREACHED();
+    return;
+  }
+
+  SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(FALSE), 0);
+
+  bool had_selection = (SelectedRowCount() > 0);
+  int old_row_count = RowCount();
+  if (start == 0 && length == RowCount()) {
+    // Everything was removed.
+    ListView_DeleteAllItems(list_view_);
+    view_to_model_.reset(NULL);
+    model_to_view_.reset(NULL);
+  } else {
+    // Only a portion of the data was removed.
+    if (is_sorted()) {
+      int new_row_count = model_->RowCount();
+      std::vector<int> view_items_to_remove;
+      view_items_to_remove.reserve(length);
+      // Iterate through the elements, updating the view_to_model_ mapping
+      // as well as collecting the rows that need to be deleted.
+      for (int i = 0, removed_count = 0; i < old_row_count; ++i) {
+        int model_index = view_to_model(i);
+        if (model_index >= start) {
+          if (model_index < start + length) {
+            // This item was removed.
+            view_items_to_remove.push_back(i);
+            model_index = -1;
+          } else {
+            model_index -= length;
+          }
+        }
+        if (model_index >= 0) {
+          view_to_model_[i - static_cast<int>(view_items_to_remove.size())] =
+              model_index;
+        }
+      }
+
+      // Update the model_to_view mapping from the updated view_to_model
+      // mapping.
+      for (int i = 0; i < new_row_count; ++i)
+        model_to_view_[view_to_model_[i]] = i;
+
+      // And finally delete the items. We do this backwards as the items were
+      // added ordered smallest to largest.
+      for (int i = length - 1; i >= 0; --i)
+        ListView_DeleteItem(list_view_, view_items_to_remove[i]);
+    } else {
+      for (int i = 0; i < length; ++i)
+        ListView_DeleteItem(list_view_, start);
+    }
+  }
+
+  SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(TRUE), 0);
+
+  // If the row count goes to zero and we had a selection LVN_ITEMCHANGED isn't
+  // invoked, so we handle it here.
+  //
+  // When the model is set to NULL all the rows are removed. We don't notify
+  // the delegate in this case as setting the model to NULL is usually done as
+  // the last step before being deleted and callers shouldn't have to deal with
+  // getting a selection change when the model is being reset.
+  if (model_ && table_view_observer_ && had_selection && RowCount() == 0)
+    table_view_observer_->OnSelectionChanged();
+}
+
+void TableView::AddColumn(const TableColumn& col) {
+  DCHECK(all_columns_.count(col.id) == 0);
+  all_columns_[col.id] = col;
+}
+
+void TableView::SetColumns(const std::vector<TableColumn>& columns) {
+  // Remove the currently visible columns.
+  while (!visible_columns_.empty())
+    SetColumnVisibility(visible_columns_.front(), false);
+
+  all_columns_.clear();
+  for (std::vector<TableColumn>::const_iterator i = columns.begin();
+       i != columns.end(); ++i) {
+    AddColumn(*i);
+  }
+
+  // Remove any sort descriptors that are no longer valid.
+  SortDescriptors sort = sort_descriptors();
+  for (SortDescriptors::iterator i = sort.begin(); i != sort.end();) {
+    if (all_columns_.count(i->column_id) == 0)
+      i = sort.erase(i);
+    else
+      ++i;
+  }
+  sort_descriptors_ = sort;
+}
+
+void TableView::OnColumnsChanged() {
+  column_count_ = static_cast<int>(visible_columns_.size());
+  ResetColumnSizes();
+}
+
+void TableView::SetColumnVisibility(int id, bool is_visible) {
+  bool changed = false;
+  for (std::vector<int>::iterator i = visible_columns_.begin();
+       i != visible_columns_.end(); ++i) {
+    if (*i == id) {
+      if (is_visible) {
+        // It's already visible, bail out early.
+        return;
+      } else {
+        int index = static_cast<int>(i - visible_columns_.begin());
+        // This could be called before the native list view has been created
+        // (in CreateNativeControl, called when the view is added to a
+        // Widget). In that case since the column is not in
+        // visible_columns_ it will not be added later on when it is created.
+        if (list_view_)
+          SendMessage(list_view_, LVM_DELETECOLUMN, index, 0);
+        visible_columns_.erase(i);
+        changed = true;
+        break;
+      }
+    }
+  }
+  if (is_visible) {
+    visible_columns_.push_back(id);
+    TableColumn& column = all_columns_[id];
+    InsertColumn(column, column_count_);
+    if (column.min_visible_width == 0) {
+      // ListView_GetStringWidth must be padded or else truncation will occur.
+      column.min_visible_width = ListView_GetStringWidth(list_view_,
+                                                         column.title.c_str()) +
+                                 kListViewTextPadding;
+    }
+    changed = true;
+  }
+  if (changed)
+    OnColumnsChanged();
+}
+
+void TableView::SetVisibleColumns(const std::vector<int>& columns) {
+  size_t old_count = visible_columns_.size();
+  size_t new_count = columns.size();
+  // remove the old columns
+  if (list_view_) {
+    for (std::vector<int>::reverse_iterator i = visible_columns_.rbegin();
+         i != visible_columns_.rend(); ++i) {
+      int index = static_cast<int>(i - visible_columns_.rend());
+      SendMessage(list_view_, LVM_DELETECOLUMN, index, 0);
+    }
+  }
+  visible_columns_ = columns;
+  // Insert the new columns.
+  if (list_view_) {
+    for (std::vector<int>::iterator i = visible_columns_.begin();
+         i != visible_columns_.end(); ++i) {
+      int index = static_cast<int>(i - visible_columns_.end());
+      InsertColumn(all_columns_[*i], index);
+    }
+  }
+  OnColumnsChanged();
+}
+
+bool TableView::IsColumnVisible(int id) const {
+  for (std::vector<int>::const_iterator i = visible_columns_.begin();
+       i != visible_columns_.end(); ++i)
+    if (*i == id) {
+      return true;
+    }
+  return false;
+}
+
+const TableColumn& TableView::GetColumnAtPosition(int pos) {
+  return all_columns_[visible_columns_[pos]];
+}
+
+bool TableView::HasColumn(int id) {
+  return all_columns_.count(id) > 0;
+}
+
+gfx::Point TableView::GetKeyboardContextMenuLocation() {
+  int first_selected = FirstSelectedRow();
+  int y = height() / 2;
+  if (first_selected != -1) {
+    RECT cell_bounds;
+    RECT client_rect;
+    if (ListView_GetItemRect(GetNativeControlHWND(), first_selected,
+                             &cell_bounds, LVIR_BOUNDS) &&
+        GetClientRect(GetNativeControlHWND(), &client_rect) &&
+        cell_bounds.bottom >= 0 && cell_bounds.bottom < client_rect.bottom) {
+      y = cell_bounds.bottom;
+    }
+  }
+  gfx::Point screen_loc(0, y);
+  if (UILayoutIsRightToLeft())
+    screen_loc.set_x(width());
+  ConvertPointToScreen(this, &screen_loc);
+  return screen_loc;
+}
+
+void TableView::SetCustomColorsEnabled(bool custom_colors_enabled) {
+  custom_colors_enabled_ = custom_colors_enabled;
+}
+
+bool TableView::GetCellColors(int model_row,
+                              int column,
+                              ItemColor* foreground,
+                              ItemColor* background,
+                              LOGFONT* logfont) {
+  return false;
+}
+
+static int GetViewIndexFromMouseEvent(HWND window, LPARAM l_param) {
+  int x = GET_X_LPARAM(l_param);
+  int y = GET_Y_LPARAM(l_param);
+  LVHITTESTINFO hit_info = {0};
+  hit_info.pt.x = x;
+  hit_info.pt.y = y;
+  return ListView_HitTest(window, &hit_info);
+}
+
+// static
+LRESULT CALLBACK TableView::TableWndProc(HWND window,
+                                         UINT message,
+                                         WPARAM w_param,
+                                         LPARAM l_param) {
+  TableView* table_view = reinterpret_cast<TableViewWrapper*>(
+      GetWindowLongPtr(window, GWLP_USERDATA))->table_view;
+
+  // Is the mouse down on the table?
+  static bool in_mouse_down = false;
+  // Should we select on mouse up?
+  static bool select_on_mouse_up = false;
+
+  // If the mouse is down, this is the location of the mouse down message.
+  static int mouse_down_x, mouse_down_y;
+
+  switch (message) {
+    case WM_CONTEXTMENU: {
+      // This addresses two problems seen with context menus in right to left
+      // locales:
+      // 1. The mouse coordinates in the l_param were occasionally wrong in
+      //    weird ways. This is most often seen when right clicking on the
+      //    list-view twice in a row.
+      // 2. Right clicking on the icon would show the scrollbar menu.
+      //
+      // As a work around this uses the position of the cursor and ignores
+      // the position supplied in the l_param.
+      if (table_view->UILayoutIsRightToLeft() &&
+          (GET_X_LPARAM(l_param) != -1 || GET_Y_LPARAM(l_param) != -1)) {
+        CPoint screen_point;
+        GetCursorPos(&screen_point);
+        CPoint table_point = screen_point;
+        CRect client_rect;
+        if (ScreenToClient(window, &table_point) &&
+            GetClientRect(window, &client_rect) &&
+            client_rect.PtInRect(table_point)) {
+          // The point is over the client area of the table, handle it ourself.
+          // But first select the row if it isn't already selected.
+          LVHITTESTINFO hit_info = {0};
+          hit_info.pt.x = table_point.x;
+          hit_info.pt.y = table_point.y;
+          int view_index = ListView_HitTest(window, &hit_info);
+          if (view_index != -1) {
+            int model_index = table_view->view_to_model(view_index);
+            if (!table_view->IsItemSelected(model_index))
+              table_view->Select(model_index);
+          }
+          table_view->OnContextMenu(screen_point);
+          return 0;  // So that default processing doesn't occur.
+        }
+      }
+      // else case: default handling is fine, so break and let the default
+      // handler service the request (which will likely calls us back with
+      // OnContextMenu).
+      break;
+    }
+
+    case WM_CANCELMODE: {
+      if (in_mouse_down) {
+        in_mouse_down = false;
+        return 0;
+      }
+      break;
+    }
+
+    case WM_ERASEBKGND:
+      // We make WM_ERASEBKGND do nothing (returning 1 indicates we handled
+      // the request). We do this so that the table view doesn't flicker during
+      // resizing.
+      return 1;
+
+    case WM_PAINT: {
+      LRESULT result = CallWindowProc(table_view->original_handler_, window,
+                                      message, w_param, l_param);
+      table_view->PostPaint();
+      return result;
+    }
+
+    case WM_KEYDOWN: {
+      if (!table_view->single_selection_ && w_param == 'A' &&
+          GetKeyState(VK_CONTROL) < 0 && table_view->RowCount() > 0) {
+        // Select everything.
+        ListView_SetItemState(window, -1, LVIS_SELECTED, LVIS_SELECTED);
+        // And make the first row focused.
+        ListView_SetItemState(window, 0, LVIS_FOCUSED, LVIS_FOCUSED);
+        return 0;
+      } else if (w_param == VK_DELETE && table_view->table_view_observer_) {
+        table_view->table_view_observer_->OnTableViewDelete(table_view);
+        return 0;
+      }
+      // else case: fall through to default processing.
+      break;
+    }
+
+    case WM_LBUTTONDBLCLK: {
+      if (w_param == MK_LBUTTON)
+        table_view->OnDoubleClick();
+      return 0;
+    }
+
+    case WM_LBUTTONUP: {
+      if (in_mouse_down) {
+        in_mouse_down = false;
+        ReleaseCapture();
+        SetFocus(window);
+        if (select_on_mouse_up) {
+          int view_index = GetViewIndexFromMouseEvent(window, l_param);
+          if (view_index != -1)
+            table_view->Select(table_view->view_to_model(view_index));
+        }
+        return 0;
+      }
+      break;
+    }
+
+    case WM_LBUTTONDOWN: {
+      // ListView treats clicking on an area outside the text of a column as
+      // drag to select. This is confusing when the selection is shown across
+      // the whole row. For this reason we override the default handling for
+      // mouse down/move/up and treat the whole row as draggable. That is, no
+      // matter where you click in the row we'll attempt to start dragging.
+      //
+      // Only do custom mouse handling if no other mouse buttons are down.
+      if ((w_param | (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ==
+          (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) {
+        if (in_mouse_down)
+          return 0;
+
+        int view_index = GetViewIndexFromMouseEvent(window, l_param);
+        if (view_index != -1) {
+          table_view->ignore_listview_change_ = true;
+          in_mouse_down = true;
+          select_on_mouse_up = false;
+          mouse_down_x = GET_X_LPARAM(l_param);
+          mouse_down_y = GET_Y_LPARAM(l_param);
+          int model_index = table_view->view_to_model(view_index);
+          bool select = true;
+          if (w_param & MK_CONTROL) {
+            select = false;
+            if (!table_view->IsItemSelected(model_index)) {
+              if (table_view->single_selection_) {
+                // Single selection mode and the row isn't selected, select
+                // only it.
+                table_view->Select(model_index);
+              } else {
+                // Not single selection, add this row to the selection.
+                table_view->SetSelectedState(model_index, true);
+              }
+            } else {
+              // Remove this row from the selection.
+              table_view->SetSelectedState(model_index, false);
+            }
+            ListView_SetSelectionMark(window, view_index);
+          } else if (!table_view->single_selection_ && w_param & MK_SHIFT) {
+            int mark_view_index = ListView_GetSelectionMark(window);
+            if (mark_view_index != -1) {
+              // Unselect everything.
+              ListView_SetItemState(window, -1, 0, LVIS_SELECTED);
+              select = false;
+
+              // Select from mark to mouse down location.
+              for (int i = std::min(view_index, mark_view_index),
+                   max_i = std::max(view_index, mark_view_index); i <= max_i;
+                   ++i) {
+                table_view->SetSelectedState(table_view->view_to_model(i),
+                                             true);
+              }
+            }
+          }
+          // Make the row the user clicked on the focused row.
+          ListView_SetItemState(window, view_index, LVIS_FOCUSED,
+                                LVIS_FOCUSED);
+          if (select) {
+            if (!table_view->IsItemSelected(model_index)) {
+              // Clear all.
+              ListView_SetItemState(window, -1, 0, LVIS_SELECTED);
+              // And select the row the user clicked on.
+              table_view->SetSelectedState(model_index, true);
+            } else {
+              // The item is already selected, don't clear the state right away
+              // in case the user drags. Instead wait for mouse up, then only
+              // select the row the user clicked on.
+              select_on_mouse_up = true;
+            }
+            ListView_SetSelectionMark(window, view_index);
+          }
+          table_view->ignore_listview_change_ = false;
+          table_view->OnSelectedStateChanged();
+          SetCapture(window);
+          return 0;
+        }
+        // else case, continue on to default handler
+      }
+      break;
+    }
+
+    case WM_MOUSEMOVE: {
+      if (in_mouse_down) {
+        int x = GET_X_LPARAM(l_param);
+        int y = GET_Y_LPARAM(l_param);
+        if (View::ExceededDragThreshold(x - mouse_down_x, y - mouse_down_y)) {
+          // We're about to start drag and drop, which results in no mouse up.
+          // Release capture and reset state.
+          ReleaseCapture();
+          in_mouse_down = false;
+
+          NMLISTVIEW details;
+          memset(&details, 0, sizeof(details));
+          details.hdr.code = LVN_BEGINDRAG;
+          SendMessage(::GetParent(window), WM_NOTIFY, 0,
+                      reinterpret_cast<LPARAM>(&details));
+        }
+        return 0;
+      }
+      break;
+    }
+
+    default:
+      break;
+  }
+  DCHECK(table_view->original_handler_);
+  return CallWindowProc(table_view->original_handler_, window, message, w_param,
+                        l_param);
+}
+
+LRESULT CALLBACK TableView::TableHeaderWndProc(HWND window, UINT message,
+                                               WPARAM w_param, LPARAM l_param) {
+  TableView* table_view = reinterpret_cast<TableViewWrapper*>(
+      GetWindowLongPtr(window, GWLP_USERDATA))->table_view;
+
+  switch (message) {
+    case WM_SETCURSOR:
+      if (!table_view->resizable_columns_)
+        // Prevents the cursor from changing to the resize cursor.
+        return TRUE;
+      break;
+    case WM_LBUTTONDBLCLK:
+      if (!table_view->resizable_columns_)
+        // Prevents the double-click on the column separator from auto-resizing
+        // the column.
+        return TRUE;
+      break;
+    default:
+      break;
+  }
+  DCHECK(table_view->header_original_handler_);
+  return CallWindowProc(table_view->header_original_handler_,
+                        window, message, w_param, l_param);
+}
+
+HWND TableView::CreateNativeControl(HWND parent_container) {
+  int style = WS_CHILD | LVS_REPORT | LVS_SHOWSELALWAYS;
+  if (single_selection_)
+    style |= LVS_SINGLESEL;
+  // If there's only one column and the title string is empty, don't show a
+  // header.
+  if (all_columns_.size() == 1) {
+    std::map<int, TableColumn>::const_iterator first =
+        all_columns_.begin();
+    if (first->second.title.empty())
+      style |= LVS_NOCOLUMNHEADER;
+  }
+  list_view_ = ::CreateWindowEx(WS_EX_CLIENTEDGE | GetAdditionalRTLStyle(),
+                                WC_LISTVIEW,
+                                L"",
+                                style,
+                                0, 0, width(), height(),
+                                parent_container, NULL, NULL, NULL);
+
+  // Make the selection extend across the row.
+  // Reduce overdraw/flicker artifacts by double buffering.
+  DWORD list_view_style = LVS_EX_FULLROWSELECT;
+  if (win_util::GetWinVersion() > win_util::WINVERSION_2000) {
+    list_view_style |= LVS_EX_DOUBLEBUFFER;
+  }
+  if (table_type_ == CHECK_BOX_AND_TEXT)
+    list_view_style |= LVS_EX_CHECKBOXES;
+  ListView_SetExtendedListViewStyleEx(list_view_, 0, list_view_style);
+  l10n_util::AdjustUIFontForWindow(list_view_);
+
+  // Add the columns.
+  for (std::vector<int>::iterator i = visible_columns_.begin();
+       i != visible_columns_.end(); ++i) {
+    InsertColumn(all_columns_[*i],
+                 static_cast<int>(i - visible_columns_.begin()));
+  }
+
+  if (model_)
+    model_->SetObserver(this);
+
+  // Add the groups.
+  if (model_ && model_->HasGroups() &&
+      win_util::GetWinVersion() > win_util::WINVERSION_2000) {
+    ListView_EnableGroupView(list_view_, true);
+
+    TableModel::Groups groups = model_->GetGroups();
+    LVGROUP group = { 0 };
+    group.cbSize = sizeof(LVGROUP);
+    group.mask = LVGF_HEADER | LVGF_ALIGN | LVGF_GROUPID;
+    group.uAlign = LVGA_HEADER_LEFT;
+    for (size_t i = 0; i < groups.size(); ++i) {
+      group.pszHeader = const_cast<wchar_t*>(groups[i].title.c_str());
+      group.iGroupId = groups[i].id;
+      ListView_InsertGroup(list_view_, static_cast<int>(i), &group);
+    }
+  }
+
+  // Set the # of rows.
+  if (model_)
+    UpdateListViewCache(0, model_->RowCount(), true);
+
+  if (table_type_ == ICON_AND_TEXT) {
+    HIMAGELIST image_list =
+        ImageList_Create(kImageSize, kImageSize, ILC_COLOR32, 2, 2);
+    // We create 2 phony images because we are going to switch images at every
+    // refresh in order to force a refresh of the icon area (somehow the clip
+    // rect does not include the icon).
+    ChromeCanvas canvas(kImageSize, kImageSize, false);
+    // Make the background completely transparent.
+    canvas.drawColor(SK_ColorBLACK, SkPorterDuff::kClear_Mode);
+    HICON empty_icon =
+        IconUtil::CreateHICONFromSkBitmap(canvas.ExtractBitmap());
+    ImageList_AddIcon(image_list, empty_icon);
+    ImageList_AddIcon(image_list, empty_icon);
+    DeleteObject(empty_icon);
+    ListView_SetImageList(list_view_, image_list, LVSIL_SMALL);
+  }
+
+  if (!resizable_columns_) {
+    // To disable the resizing of columns we'll filter the events happening on
+    // the header. We also need to intercept the HDM_LAYOUT to size the header
+    // for the Chrome headers.
+    HWND header = ListView_GetHeader(list_view_);
+    DCHECK(header);
+    SetWindowLongPtr(header, GWLP_USERDATA,
+        reinterpret_cast<LONG_PTR>(&table_view_wrapper_));
+    header_original_handler_ = win_util::SetWindowProc(header,
+        &TableView::TableHeaderWndProc);
+  }
+
+  SetWindowLongPtr(list_view_, GWLP_USERDATA,
+      reinterpret_cast<LONG_PTR>(&table_view_wrapper_));
+  original_handler_ =
+      win_util::SetWindowProc(list_view_, &TableView::TableWndProc);
+
+  // Bug 964884: detach the IME attached to this window.
+  // We should attach IMEs only when we need to input CJK strings.
+  ::ImmAssociateContextEx(list_view_, NULL, 0);
+
+  UpdateContentOffset();
+
+  return list_view_;
+}
+
+void TableView::ToggleSortOrder(int column_id) {
+  SortDescriptors sort = sort_descriptors();
+  if (!sort.empty() && sort[0].column_id == column_id) {
+    sort[0].ascending = !sort[0].ascending;
+  } else {
+    SortDescriptor descriptor(column_id, true);
+    sort.insert(sort.begin(), descriptor);
+    if (sort.size() > 2) {
+      // Only persist two sort descriptors.
+      sort.resize(2);
+    }
+  }
+  SetSortDescriptors(sort);
+}
+
+void TableView::UpdateItemsLParams(int start, int length) {
+  LVITEM item;
+  memset(&item, 0, sizeof(LVITEM));
+  item.mask = LVIF_PARAM;
+  int row_count = RowCount();
+  for (int i = 0; i < row_count; ++i) {
+    item.iItem = i;
+    int model_index = view_to_model(i);
+    if (length > 0 && model_index >= start)
+      model_index += length;
+    item.lParam = static_cast<LPARAM>(model_index);
+    ListView_SetItem(list_view_, &item);
+  }
+}
+
+void TableView::SortItemsAndUpdateMapping() {
+  if (!is_sorted()) {
+    ListView_SortItems(list_view_, &TableView::NaturalSortFunc, this);
+    view_to_model_.reset(NULL);
+    model_to_view_.reset(NULL);
+    return;
+  }
+
+  PrepareForSort();
+
+  // Sort the items.
+  ListView_SortItems(list_view_, &TableView::SortFunc, this);
+
+  // Cleanup the collator.
+  if (collator) {
+    delete collator;
+    collator = NULL;
+  }
+
+  // Update internal mapping to match how items were actually sorted.
+  int row_count = RowCount();
+  model_to_view_.reset(new int[row_count]);
+  view_to_model_.reset(new int[row_count]);
+  LVITEM item;
+  memset(&item, 0, sizeof(LVITEM));
+  item.mask = LVIF_PARAM;
+  for (int i = 0; i < row_count; ++i) {
+    item.iItem = i;
+    ListView_GetItem(list_view_, &item);
+    int model_index = static_cast<int>(item.lParam);
+    view_to_model_[i] = model_index;
+    model_to_view_[model_index] = i;
+  }
+}
+
+// static
+int CALLBACK TableView::SortFunc(LPARAM model_index_1_p,
+                                 LPARAM model_index_2_p,
+                                 LPARAM table_view_param) {
+  int model_index_1 = static_cast<int>(model_index_1_p);
+  int model_index_2 = static_cast<int>(model_index_2_p);
+  TableView* table_view = reinterpret_cast<TableView*>(table_view_param);
+  return table_view->CompareRows(model_index_1, model_index_2);
+}
+
+// static
+int CALLBACK TableView::NaturalSortFunc(LPARAM model_index_1_p,
+                                        LPARAM model_index_2_p,
+                                        LPARAM table_view_param) {
+  return model_index_1_p - model_index_2_p;
+}
+
+void TableView::ResetColumnSortImage(int column_id, SortDirection direction) {
+  if (!list_view_ || column_id == -1)
+    return;
+
+  std::vector<int>::const_iterator i =
+      std::find(visible_columns_.begin(), visible_columns_.end(), column_id);
+  if (i == visible_columns_.end())
+    return;
+
+  HWND header = ListView_GetHeader(list_view_);
+  if (!header)
+    return;
+
+  int column_index = static_cast<int>(i - visible_columns_.begin());
+  HDITEM header_item;
+  memset(&header_item, 0, sizeof(header_item));
+  header_item.mask = HDI_FORMAT;
+  Header_GetItem(header, column_index, &header_item);
+  header_item.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
+  if (direction == ASCENDING_SORT)
+    header_item.fmt |= HDF_SORTUP;
+  else if (direction == DESCENDING_SORT)
+    header_item.fmt |= HDF_SORTDOWN;
+  Header_SetItem(header, column_index, &header_item);
+}
+
+void TableView::InsertColumn(const TableColumn& tc, int index) {
+  if (!list_view_)
+    return;
+
+  LVCOLUMN column = { 0 };
+  column.mask = LVCF_TEXT|LVCF_FMT;
+  column.pszText = const_cast<LPWSTR>(tc.title.c_str());
+  switch (tc.alignment) {
+      case TableColumn::LEFT:
+        column.fmt = LVCFMT_LEFT;
+        break;
+      case TableColumn::RIGHT:
+        column.fmt = LVCFMT_RIGHT;
+        break;
+      case TableColumn::CENTER:
+        column.fmt = LVCFMT_CENTER;
+        break;
+      default:
+        NOTREACHED();
+  }
+  if (tc.width != -1) {
+    column.mask |= LVCF_WIDTH;
+    column.cx = tc.width;
+  }
+  column.mask |= LVCF_SUBITEM;
+  // Sub-items are 1s indexed.
+  column.iSubItem = index + 1;
+  SendMessage(list_view_, LVM_INSERTCOLUMN, index,
+              reinterpret_cast<LPARAM>(&column));
+  if (is_sorted() && sort_descriptors_[0].column_id == tc.id) {
+    ResetColumnSortImage(
+        tc.id,
+        sort_descriptors_[0].ascending ? ASCENDING_SORT : DESCENDING_SORT);
+  }
+}
+
+LRESULT TableView::OnNotify(int w_param, LPNMHDR hdr) {
+  if (!model_)
+    return 0;
+
+  switch (hdr->code) {
+    case NM_CUSTOMDRAW: {
+      // Draw notification. dwDragState indicates the current stage of drawing.
+      return OnCustomDraw(reinterpret_cast<NMLVCUSTOMDRAW*>(hdr));
+    }
+
+    case LVN_ITEMCHANGED: {
+      // Notification that the state of an item has changed. The state
+      // includes such things as whether the item is selected or checked.
+      NMLISTVIEW* state_change = reinterpret_cast<NMLISTVIEW*>(hdr);
+      if ((state_change->uChanged & LVIF_STATE) != 0) {
+        if ((state_change->uOldState & LVIS_SELECTED) !=
+            (state_change->uNewState & LVIS_SELECTED)) {
+          // Selected state of the item changed.
+          OnSelectedStateChanged();
+        }
+        if ((state_change->uOldState & LVIS_STATEIMAGEMASK) !=
+            (state_change->uNewState & LVIS_STATEIMAGEMASK)) {
+          // Checked state of the item changed.
+          bool is_checked =
+            ((state_change->uNewState & LVIS_STATEIMAGEMASK) ==
+             INDEXTOSTATEIMAGEMASK(2));
+          OnCheckedStateChanged(view_to_model(state_change->iItem),
+                                is_checked);
+        }
+      }
+      break;
+    }
+
+    case HDN_BEGINTRACKW:
+    case HDN_BEGINTRACKA:
+      // Prevent clicks so columns cannot be resized.
+      if (!resizable_columns_)
+        return TRUE;
+      break;
+
+    case NM_DBLCLK:
+      OnDoubleClick();
+      break;
+
+    // If we see a key down message, we need to invoke the OnKeyDown handler
+    // in order to give our class (or any subclass) and opportunity to perform
+    // a key down triggered action, if such action is necessary.
+    case LVN_KEYDOWN: {
+      NMLVKEYDOWN* key_down_message = reinterpret_cast<NMLVKEYDOWN*>(hdr);
+      OnKeyDown(key_down_message->wVKey);
+      break;
+    }
+
+    case LVN_COLUMNCLICK: {
+      const TableColumn& column = GetColumnAtPosition(
+          reinterpret_cast<NMLISTVIEW*>(hdr)->iSubItem);
+      if (column.sortable)
+        ToggleSortOrder(column.id);
+      break;
+    }
+
+    case LVN_MARQUEEBEGIN:  // We don't want the marque selection.
+      return 1;
+
+    default:
+      break;
+  }
+  return 0;
+}
+
+void TableView::OnDestroy() {
+  if (table_type_ == ICON_AND_TEXT) {
+    HIMAGELIST image_list =
+        ListView_GetImageList(GetNativeControlHWND(), LVSIL_SMALL);
+    DCHECK(image_list);
+    if (image_list)
+      ImageList_Destroy(image_list);
+  }
+}
+
+// Returns result, unless ascending is false in which case -result is returned.
+static int SwapCompareResult(int result, bool ascending) {
+  return ascending ? result : -result;
+}
+
+int TableView::CompareRows(int model_row1, int model_row2) {
+  if (model_->HasGroups()) {
+    // By default ListView sorts the elements regardless of groups. In such
+    // a situation the groups display only the items they contain. This results
+    // in the visual order differing from the item indices. I could not find
+    // a way to iterate over the visual order in this situation. As a workaround
+    // this forces the items to be sorted by groups as well, which means the
+    // visual order matches the item indices.
+    int g1 = model_->GetGroupID(model_row1);
+    int g2 = model_->GetGroupID(model_row2);
+    if (g1 != g2)
+      return g1 - g2;
+  }
+  int sort_result = model_->CompareValues(
+      model_row1, model_row2, sort_descriptors_[0].column_id);
+  if (sort_result == 0 && sort_descriptors_.size() > 1 &&
+      sort_descriptors_[1].column_id != -1) {
+    // Try the secondary sort.
+    return SwapCompareResult(
+        model_->CompareValues(model_row1, model_row2,
+                              sort_descriptors_[1].column_id),
+        sort_descriptors_[1].ascending);
+  }
+  return SwapCompareResult(sort_result, sort_descriptors_[0].ascending);
+}
+
+int TableView::GetColumnWidth(int column_id) {
+  if (!list_view_)
+    return -1;
+
+  std::vector<int>::const_iterator i =
+      std::find(visible_columns_.begin(), visible_columns_.end(), column_id);
+  if (i == visible_columns_.end())
+    return -1;
+
+  return ListView_GetColumnWidth(
+      list_view_, static_cast<int>(i - visible_columns_.begin()));
+}
+
+LRESULT TableView::OnCustomDraw(NMLVCUSTOMDRAW* draw_info) {
+  switch (draw_info->nmcd.dwDrawStage) {
+    case CDDS_PREPAINT: {
+      return CDRF_NOTIFYITEMDRAW;
+    }
+    case CDDS_ITEMPREPAINT: {
+      // The list-view is about to paint an item, tell it we want to
+      // notified when it paints every subitem.
+      LRESULT r = CDRF_NOTIFYSUBITEMDRAW;
+      if (table_type_ == ICON_AND_TEXT)
+        r |= CDRF_NOTIFYPOSTPAINT;
+      return r;
+    }
+    case (CDDS_ITEMPREPAINT | CDDS_SUBITEM): {
+      // The list-view is painting a subitem. See if the colors should be
+      // changed from the default.
+      if (custom_colors_enabled_) {
+        // At this time, draw_info->clrText and draw_info->clrTextBk are not
+        // set.  So we pass in an ItemColor to GetCellColors.  If
+        // ItemColor.color_is_set is true, then we use the provided color.
+        ItemColor foreground = {0};
+        ItemColor background = {0};
+
+        LOGFONT logfont;
+        GetObject(GetWindowFont(list_view_), sizeof(logfont), &logfont);
+
+        if (GetCellColors(view_to_model(
+                              static_cast<int>(draw_info->nmcd.dwItemSpec)),
+                          draw_info->iSubItem,
+                          &foreground,
+                          &background,
+                          &logfont)) {
+          // TODO(tc): Creating/deleting a font for every cell seems like a
+          // waste if the font hasn't changed.  Maybe we should use a struct
+          // with a bool like we do with colors?
+          if (custom_cell_font_)
+            DeleteObject(custom_cell_font_);
+          l10n_util::AdjustUIFont(&logfont);
+          custom_cell_font_ = CreateFontIndirect(&logfont);
+          SelectObject(draw_info->nmcd.hdc, custom_cell_font_);
+          draw_info->clrText = foreground.color_is_set
+                               ? skia::SkColorToCOLORREF(foreground.color)
+                               : CLR_DEFAULT;
+          draw_info->clrTextBk = background.color_is_set
+                                 ? skia::SkColorToCOLORREF(background.color)
+                                 : CLR_DEFAULT;
+          return CDRF_NEWFONT;
+        }
+      }
+      return CDRF_DODEFAULT;
+    }
+    case CDDS_ITEMPOSTPAINT: {
+      DCHECK((table_type_ == ICON_AND_TEXT) || (ImplementPostPaint()));
+      int view_index = static_cast<int>(draw_info->nmcd.dwItemSpec);
+      // We get notifications for empty items, just ignore them.
+      if (view_index >= model_->RowCount())
+        return CDRF_DODEFAULT;
+      int model_index = view_to_model(view_index);
+      LRESULT r = CDRF_DODEFAULT;
+      // First let's take care of painting the right icon.
+      if (table_type_ == ICON_AND_TEXT) {
+        SkBitmap image = model_->GetIcon(model_index);
+        if (!image.isNull()) {
+          // Get the rect that holds the icon.
+          CRect icon_rect, client_rect;
+          if (ListView_GetItemRect(list_view_, view_index, &icon_rect,
+                                   LVIR_ICON) &&
+              GetClientRect(list_view_, &client_rect)) {
+            CRect intersection;
+            // Client rect includes the header but we need to make sure we don't
+            // paint into it.
+            client_rect.top += content_offset_;
+            // Make sure the region need to paint is visible.
+            if (intersection.IntersectRect(&icon_rect, &client_rect)) {
+              ChromeCanvas canvas(icon_rect.Width(), icon_rect.Height(), false);
+
+              // It seems the state in nmcd.uItemState is not correct.
+              // We'll retrieve it explicitly.
+              int selected = ListView_GetItemState(
+                  list_view_, view_index, LVIS_SELECTED | LVIS_DROPHILITED);
+              bool drop_highlight = ((selected & LVIS_DROPHILITED) != 0);
+              int bg_color_index;
+              if (!IsEnabled())
+                bg_color_index = COLOR_3DFACE;
+              else if (drop_highlight)
+                bg_color_index = COLOR_HIGHLIGHT;
+              else if (selected)
+                bg_color_index = HasFocus() ? COLOR_HIGHLIGHT : COLOR_3DFACE;
+              else
+                bg_color_index = COLOR_WINDOW;
+              // NOTE: This may be invoked without the ListView filling in the
+              // background (or rather windows paints background, then invokes
+              // this twice). As such, we always fill in the background.
+              canvas.drawColor(
+                  skia::COLORREFToSkColor(GetSysColor(bg_color_index)),
+                  SkPorterDuff::kSrc_Mode);
+              // + 1 for padding (we declared the image as 18x18 in the list-
+              // view when they are 16x16 so we get an extra pixel of padding).
+              canvas.DrawBitmapInt(image, 0, 0,
+                                   image.width(), image.height(),
+                                   1, 1, kFavIconSize, kFavIconSize, true);
+
+              // Only paint the visible region of the icon.
+              RECT to_draw = { intersection.left - icon_rect.left,
+                               intersection.top - icon_rect.top,
+                               0, 0 };
+              to_draw.right = to_draw.left +
+                              (intersection.right - intersection.left);
+              to_draw.bottom = to_draw.top +
+                              (intersection.bottom - intersection.top);
+              canvas.getTopPlatformDevice().drawToHDC(draw_info->nmcd.hdc,
+                                                      intersection.left,
+                                                      intersection.top,
+                                                      &to_draw);
+              r = CDRF_SKIPDEFAULT;
+            }
+          }
+        }
+      }
+      if (ImplementPostPaint()) {
+        CRect cell_rect;
+        if (ListView_GetItemRect(list_view_, view_index, &cell_rect,
+                                 LVIR_BOUNDS)) {
+          PostPaint(model_index, 0, false, cell_rect, draw_info->nmcd.hdc);
+          r = CDRF_SKIPDEFAULT;
+        }
+      }
+      return r;
+    }
+    default:
+      return CDRF_DODEFAULT;
+  }
+}
+
+void TableView::UpdateListViewCache(int start, int length, bool add) {
+  ignore_listview_change_ = true;
+  UpdateListViewCache0(start, length, add);
+  ignore_listview_change_ = false;
+}
+
+void TableView::ResetColumnSizes() {
+  if (!list_view_)
+    return;
+
+  // See comment in TableColumn for what this does.
+  int width = this->width();
+  CRect native_bounds;
+  if (GetClientRect(GetNativeControlHWND(), &native_bounds) &&
+      native_bounds.Width() > 0) {
+    // Prefer the bounds of the window over our bounds, which may be different.
+    width = native_bounds.Width();
+  }
+
+  float percent = 0;
+  int fixed_width = 0;
+  int autosize_width = 0;
+
+  for (std::vector<int>::const_iterator i = visible_columns_.begin();
+       i != visible_columns_.end(); ++i) {
+    TableColumn& col = all_columns_[*i];
+    int col_index = static_cast<int>(i - visible_columns_.begin());
+    if (col.width == -1) {
+      if (col.percent > 0) {
+        percent += col.percent;
+      } else {
+        autosize_width += col.min_visible_width;
+      }
+    } else {
+      fixed_width += ListView_GetColumnWidth(list_view_, col_index);
+    }
+  }
+
+  // Now do a pass to set the actual sizes of auto-sized and
+  // percent-sized columns.
+  int available_width = width - fixed_width - autosize_width;
+  for (std::vector<int>::const_iterator i = visible_columns_.begin();
+       i != visible_columns_.end(); ++i) {
+    TableColumn& col = all_columns_[*i];
+    if (col.width == -1) {
+      int col_index = static_cast<int>(i - visible_columns_.begin());
+      if (col.percent > 0) {
+        if (available_width > 0) {
+          int col_width =
+            static_cast<int>(available_width * (col.percent / percent));
+          available_width -= col_width;
+          percent -= col.percent;
+          ListView_SetColumnWidth(list_view_, col_index, col_width);
+        }
+      } else {
+        int col_width = col.min_visible_width;
+        // If no "percent" columns, the last column acts as one, if auto-sized.
+        if (percent == 0.f && available_width > 0 &&
+            col_index == column_count_ - 1) {
+          col_width += available_width;
+        }
+        ListView_SetColumnWidth(list_view_, col_index, col_width);
+      }
+    }
+  }
+}
+
+gfx::Size TableView::GetPreferredSize() {
+  return preferred_size_;
+}
+
+void TableView::UpdateListViewCache0(int start, int length, bool add) {
+  if (is_sorted()) {
+    if (add)
+      UpdateItemsLParams(start, length);
+    else
+      UpdateItemsLParams(0, 0);
+  }
+
+  LVITEM item = {0};
+  int start_column = 0;
+  int max_row = start + length;
+  const bool has_groups =
+      (win_util::GetWinVersion() > win_util::WINVERSION_2000 &&
+       model_->HasGroups());
+  if (add) {
+    if (has_groups)
+      item.mask = LVIF_GROUPID;
+    item.mask |= LVIF_PARAM;
+    for (int i = start; i < max_row; ++i) {
+      item.iItem = i;
+      if (has_groups)
+        item.iGroupId = model_->GetGroupID(i);
+      item.lParam = i;
+      ListView_InsertItem(list_view_, &item);
+    }
+  }
+
+  memset(&item, 0, sizeof(LVITEM));
+
+  // NOTE: I don't quite get why the iSubItem in the following is not offset
+  // by 1. According to the docs it should be offset by one, but that doesn't
+  // work.
+  if (table_type_ == CHECK_BOX_AND_TEXT) {
+    start_column = 1;
+    item.iSubItem = 0;
+    item.mask = LVIF_TEXT | LVIF_STATE;
+    item.stateMask = LVIS_STATEIMAGEMASK;
+    for (int i = start; i < max_row; ++i) {
+      std::wstring text = model_->GetText(i, visible_columns_[0]);
+      item.iItem = add ? i : model_to_view(i);
+      item.pszText = const_cast<LPWSTR>(text.c_str());
+      item.state = INDEXTOSTATEIMAGEMASK(model_->IsChecked(i) ? 2 : 1);
+      ListView_SetItem(list_view_, &item);
+    }
+  }
+
+  item.stateMask = 0;
+  item.mask = LVIF_TEXT;
+  if (table_type_ == ICON_AND_TEXT) {
+    item.mask |= LVIF_IMAGE;
+  }
+  for (int j = start_column; j < column_count_; ++j) {
+    TableColumn& col = all_columns_[visible_columns_[j]];
+    int max_text_width = ListView_GetStringWidth(list_view_, col.title.c_str());
+    for (int i = start; i < max_row; ++i) {
+      item.iItem = add ? i : model_to_view(i);
+      item.iSubItem = j;
+      std::wstring text = model_->GetText(i, visible_columns_[j]);
+      item.pszText = const_cast<LPWSTR>(text.c_str());
+      item.iImage = 0;
+      ListView_SetItem(list_view_, &item);
+
+      // Compute width in px, using current font.
+      int string_width = ListView_GetStringWidth(list_view_, item.pszText);
+      // The width of an icon belongs to the first column.
+      if (j == 0 && table_type_ == ICON_AND_TEXT)
+        string_width += kListViewIconWidthAndPadding;
+      max_text_width = std::max(string_width, max_text_width);
+    }
+
+    // ListView_GetStringWidth must be padded or else truncation will occur
+    // (MSDN). 15px matches the Win32/LVSCW_AUTOSIZE_USEHEADER behavior.
+    max_text_width += kListViewTextPadding;
+
+    // Protect against partial update.
+    if (max_text_width > col.min_visible_width ||
+        (start == 0 && length == model_->RowCount())) {
+      col.min_visible_width = max_text_width;
+    }
+  }
+
+  if (is_sorted()) {
+    // NOTE: As most of our tables are smallish I'm not going to optimize this.
+    // If our tables become large and frequently update, then it'll make sense
+    // to optimize this.
+
+    SortItemsAndUpdateMapping();
+  }
+}
+
+void TableView::OnDoubleClick() {
+  if (!ignore_listview_change_ && table_view_observer_) {
+    table_view_observer_->OnDoubleClick();
+  }
+}
+
+void TableView::OnSelectedStateChanged() {
+  if (!ignore_listview_change_ && table_view_observer_) {
+    table_view_observer_->OnSelectionChanged();
+  }
+}
+
+void TableView::OnKeyDown(unsigned short virtual_keycode) {
+  if (!ignore_listview_change_ && table_view_observer_) {
+    table_view_observer_->OnKeyDown(virtual_keycode);
+  }
+}
+
+void TableView::OnCheckedStateChanged(int model_row, bool is_checked) {
+  if (!ignore_listview_change_)
+    model_->SetChecked(model_row, is_checked);
+}
+
+int TableView::PreviousSelectedViewIndex(int view_index) {
+  DCHECK(view_index >= 0);
+  if (!list_view_ || view_index <= 0)
+    return -1;
+
+  int row_count = RowCount();
+  if (row_count == 0)
+    return -1;  // Empty table, nothing can be selected.
+
+  // For some reason
+  // ListView_GetNextItem(list_view_,item, LVNI_SELECTED | LVNI_ABOVE)
+  // fails on Vista (always returns -1), so we iterate through the indices.
+  view_index = std::min(view_index, row_count);
+  while (--view_index >= 0 && !IsItemSelected(view_to_model(view_index)));
+  return view_index;
+}
+
+int TableView::LastSelectedViewIndex() {
+  return PreviousSelectedViewIndex(RowCount());
+}
+
+void TableView::UpdateContentOffset() {
+  content_offset_ = 0;
+
+  if (!list_view_)
+    return;
+
+  HWND header = ListView_GetHeader(list_view_);
+  if (!header)
+    return;
+
+  POINT origin = {0, 0};
+  MapWindowPoints(header, list_view_, &origin, 1);
+
+  CRect header_bounds;
+  GetWindowRect(header, &header_bounds);
+
+  content_offset_ = origin.y + header_bounds.Height();
+}
+
+//
+// TableSelectionIterator
+//
+TableSelectionIterator::TableSelectionIterator(TableView* view,
+                                               int view_index)
+    : table_view_(view),
+      view_index_(view_index) {
+  UpdateModelIndexFromViewIndex();
+}
+
+TableSelectionIterator& TableSelectionIterator::operator=(
+    const TableSelectionIterator& other) {
+  view_index_ = other.view_index_;
+  model_index_ = other.model_index_;
+  return *this;
+}
+
+bool TableSelectionIterator::operator==(const TableSelectionIterator& other) {
+  return (other.view_index_ == view_index_);
+}
+
+bool TableSelectionIterator::operator!=(const TableSelectionIterator& other) {
+  return (other.view_index_ != view_index_);
+}
+
+TableSelectionIterator& TableSelectionIterator::operator++() {
+  view_index_ = table_view_->PreviousSelectedViewIndex(view_index_);
+  UpdateModelIndexFromViewIndex();
+  return *this;
+}
+
+int TableSelectionIterator::operator*() {
+  return model_index_;
+}
+
+void TableSelectionIterator::UpdateModelIndexFromViewIndex() {
+  if (view_index_ == -1)
+    model_index_ = -1;
+  else
+    model_index_ = table_view_->view_to_model(view_index_);
+}
+
+}  // namespace views
diff --git a/views/controls/table/table_view.h b/views/controls/table/table_view.h
new file mode 100644
index 0000000..8061d27
--- /dev/null
+++ b/views/controls/table/table_view.h
@@ -0,0 +1,676 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_TABLE_TABLE_VIEW_H_
+#define VIEWS_CONTROLS_TABLE_TABLE_VIEW_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif  // defined(OS_WIN)
+
+#include <map>
+#include <unicode/coll.h>
+#include <unicode/uchar.h>
+#include <vector>
+
+#include "app/l10n_util.h"
+#include "base/logging.h"
+#include "skia/include/SkColor.h"
+#if defined(OS_WIN)
+// TODO(port): remove the ifdef when native_control.h is ported.
+#include "views/controls/native_control.h"
+#endif  // defined(OS_WIN)
+
+class SkBitmap;
+
+// A TableView is a view that displays multiple rows with any number of columns.
+// TableView is driven by a TableModel. The model returns the contents
+// to display. TableModel also has an Observer which is used to notify
+// TableView of changes to the model so that the display may be updated
+// appropriately.
+//
+// TableView itself has an observer that is notified when the selection
+// changes.
+//
+// Tables may be sorted either by directly invoking SetSortDescriptors or by
+// marking the column as sortable and the user doing a gesture to sort the
+// contents. TableView itself maintains the sort so that the underlying model
+// isn't effected.
+//
+// When a table is sorted the model coordinates do not necessarily match the
+// view coordinates. All table methods are in terms of the model. If you need to
+// convert to view coordinates use model_to_view.
+//
+// Sorting is done by a locale sensitive string sort. You can customize the
+// sort by way of overriding CompareValues.
+//
+// TableView is a wrapper around the window type ListView in report mode.
+namespace views {
+
+class ListView;
+class ListViewParent;
+class TableView;
+struct TableColumn;
+
+// The cells in the first column of a table can contain:
+// - only text
+// - a small icon (16x16) and some text
+// - a check box and some text
+enum TableTypes {
+  TEXT_ONLY = 0,
+  ICON_AND_TEXT,
+  CHECK_BOX_AND_TEXT
+};
+
+// Any time the TableModel changes, it must notify its observer.
+class TableModelObserver {
+ public:
+  // Invoked when the model has been completely changed.
+  virtual void OnModelChanged() = 0;
+
+  // Invoked when a range of items has changed.
+  virtual void OnItemsChanged(int start, int length) = 0;
+
+  // Invoked when new items are added.
+  virtual void OnItemsAdded(int start, int length) = 0;
+
+  // Invoked when a range of items has been removed.
+  virtual void OnItemsRemoved(int start, int length) = 0;
+};
+
+// The model driving the TableView.
+class TableModel {
+ public:
+  // See HasGroups, get GetGroupID for details as to how this is used.
+  struct Group {
+    // The title text for the group.
+    std::wstring title;
+
+    // Unique id for the group.
+    int id;
+  };
+  typedef std::vector<Group> Groups;
+
+  // Number of rows in the model.
+  virtual int RowCount() = 0;
+
+  // Returns the value at a particular location in text.
+  virtual std::wstring GetText(int row, int column_id) = 0;
+
+  // Returns the small icon (16x16) that should be displayed in the first
+  // column before the text. This is only used when the TableView was created
+  // with the ICON_AND_TEXT table type. Returns an isNull() bitmap if there is
+  // no bitmap.
+  virtual SkBitmap GetIcon(int row);
+
+  // Sets whether a particular row is checked. This is only invoked
+  // if the TableView was created with show_check_in_first_column true.
+  virtual void SetChecked(int row, bool is_checked) {
+    NOTREACHED();
+  }
+
+  // Returns whether a particular row is checked. This is only invoked
+  // if the TableView was created with show_check_in_first_column true.
+  virtual bool IsChecked(int row) {
+    return false;
+  }
+
+  // Returns true if the TableView has groups. Groups provide a way to visually
+  // delineate the rows in a table view. When groups are enabled table view
+  // shows a visual separator for each group, followed by all the rows in
+  // the group.
+  //
+  // On win2k a visual separator is not rendered for the group headers.
+  virtual bool HasGroups() { return false; }
+
+  // Returns the groups.
+  // This is only used if HasGroups returns true.
+  virtual Groups GetGroups() {
+    // If you override HasGroups to return true, you must override this as
+    // well.
+    NOTREACHED();
+    return std::vector<Group>();
+  }
+
+  // Returns the group id of the specified row.
+  // This is only used if HasGroups returns true.
+  virtual int GetGroupID(int row) {
+    // If you override HasGroups to return true, you must override this as
+    // well.
+    NOTREACHED();
+    return 0;
+  }
+
+  // Sets the observer for the model. The TableView should NOT take ownership
+  // of the observer.
+  virtual void SetObserver(TableModelObserver* observer) = 0;
+
+  // Compares the values in the column with id |column_id| for the two rows.
+  // Returns a value < 0, == 0 or > 0 as to whether the first value is
+  // <, == or > the second value.
+  //
+  // This implementation does a case insensitive locale specific string
+  // comparison.
+  virtual int CompareValues(int row1, int row2, int column_id);
+
+ protected:
+  // Returns the collator used by CompareValues.
+  Collator* GetCollator();
+};
+
+// TableColumn specifies the title, alignment and size of a particular column.
+struct TableColumn {
+  enum Alignment {
+    LEFT, RIGHT, CENTER
+  };
+
+  TableColumn()
+      : id(0),
+        title(),
+        alignment(LEFT),
+        width(-1),
+        percent(),
+        min_visible_width(0),
+        sortable(false) {
+  }
+  TableColumn(int id, const std::wstring title, Alignment alignment, int width)
+      : id(id),
+        title(title),
+        alignment(alignment),
+        width(width),
+        percent(0),
+        min_visible_width(0),
+        sortable(false) {
+  }
+  TableColumn(int id, const std::wstring title, Alignment alignment, int width,
+              float percent)
+      : id(id),
+        title(title),
+        alignment(alignment),
+        width(width),
+        percent(percent),
+        min_visible_width(0),
+        sortable(false) {
+  }
+  // It's common (but not required) to use the title's IDS_* tag as the column
+  // id. In this case, the provided conveniences look up the title string on
+  // bahalf of the caller.
+  TableColumn(int id, Alignment alignment, int width)
+      : id(id),
+        alignment(alignment),
+        width(width),
+        percent(0),
+        min_visible_width(0),
+        sortable(false) {
+    title = l10n_util::GetString(id);
+  }
+  TableColumn(int id, Alignment alignment, int width, float percent)
+      : id(id),
+        alignment(alignment),
+        width(width),
+        percent(percent),
+        min_visible_width(0),
+        sortable(false) {
+    title = l10n_util::GetString(id);
+  }
+
+  // A unique identifier for the column.
+  int id;
+
+  // The title for the column.
+  std::wstring title;
+
+  // Alignment for the content.
+  Alignment alignment;
+
+  // The size of a column may be specified in two ways:
+  // 1. A fixed width. Set the width field to a positive number and the
+  //    column will be given that width, in pixels.
+  // 2. As a percentage of the available width. If width is -1, and percent is
+  //    > 0, the column is given a width of
+  //    available_width * percent / total_percent.
+  // 3. If the width == -1 and percent == 0, the column is autosized based on
+  //    the width of the column header text.
+  //
+  // Sizing is done in four passes. Fixed width columns are given
+  // their width, percentages are applied, autosized columns are autosized,
+  // and finally percentages are applied again taking into account the widths
+  // of autosized columns.
+  int width;
+  float percent;
+
+  // The minimum width required for all items in this column
+  // (including the header)
+  // to be visible.
+  int min_visible_width;
+
+  // Is this column sortable? Default is false
+  bool sortable;
+};
+
+// Returned from SelectionBegin/SelectionEnd
+class TableSelectionIterator {
+ public:
+  TableSelectionIterator(TableView* view, int view_index);
+  TableSelectionIterator& operator=(const TableSelectionIterator& other);
+  bool operator==(const TableSelectionIterator& other);
+  bool operator!=(const TableSelectionIterator& other);
+  TableSelectionIterator& operator++();
+  int operator*();
+
+ private:
+  void UpdateModelIndexFromViewIndex();
+
+  TableView* table_view_;
+  int view_index_;
+
+  // The index in terms of the model. This is returned from the * operator. This
+  // is cached to avoid dependencies on the view_to_model mapping.
+  int model_index_;
+};
+
+// TableViewObserver is notified about the TableView selection.
+class TableViewObserver {
+ public:
+  virtual ~TableViewObserver() {}
+
+  // Invoked when the selection changes.
+  virtual void OnSelectionChanged() = 0;
+
+  // Optional method invoked when the user double clicks on the table.
+  virtual void OnDoubleClick() {}
+
+  // Optional method invoked when the user hits a key with the table in focus.
+  virtual void OnKeyDown(unsigned short virtual_keycode) {}
+
+  // Invoked when the user presses the delete key.
+  virtual void OnTableViewDelete(TableView* table_view) {}
+};
+
+#if defined(OS_WIN)
+// TODO(port): Port TableView.
+class TableView : public NativeControl,
+                  public TableModelObserver {
+ public:
+  typedef TableSelectionIterator iterator;
+
+  // A helper struct for GetCellColors. Set |color_is_set| to true if color is
+  // set.  See OnCustomDraw for more details on why we need this.
+  struct ItemColor {
+    bool color_is_set;
+    SkColor color;
+  };
+
+  // Describes a sorted column.
+  struct SortDescriptor {
+    SortDescriptor() : column_id(-1), ascending(true) {}
+    SortDescriptor(int column_id, bool ascending)
+        : column_id(column_id),
+          ascending(ascending) { }
+
+    // ID of the sorted column.
+    int column_id;
+
+    // Is the sort ascending?
+    bool ascending;
+  };
+
+  typedef std::vector<SortDescriptor> SortDescriptors;
+
+  // Creates a new table using the model and columns specified.
+  // The table type applies to the content of the first column (text, icon and
+  // text, checkbox and text).
+  // When autosize_columns is true, columns always fill the available width. If
+  // false, columns are not resized when the table is resized. An extra empty
+  // column at the right fills the remaining space.
+  // When resizable_columns is true, users can resize columns by dragging the
+  // separator on the column header.  NOTE: Right now this is always true.  The
+  // code to set it false is still in place to be a base for future, better
+  // resizing behavior (see http://b/issue?id=874646 ), but no one uses or
+  // tests the case where this flag is false.
+  // Note that setting both resizable_columns and autosize_columns to false is
+  // probably not a good idea, as there is no way for the user to increase a
+  // column's size in that case.
+  TableView(TableModel* model, const std::vector<TableColumn>& columns,
+            TableTypes table_type, bool single_selection,
+            bool resizable_columns, bool autosize_columns);
+  virtual ~TableView();
+
+  // Assigns a new model to the table view, detaching the old one if present.
+  // If |model| is NULL, the table view cannot be used after this call. This
+  // should be called in the containing view's destructor to avoid destruction
+  // issues when the model needs to be deleted before the table.
+  void SetModel(TableModel* model);
+  TableModel* model() const { return model_; }
+
+  // Resorts the contents.
+  void SetSortDescriptors(const SortDescriptors& sort_descriptors);
+
+  // Current sort.
+  const SortDescriptors& sort_descriptors() const { return sort_descriptors_; }
+
+  void DidChangeBounds(const gfx::Rect& previous,
+                       const gfx::Rect& current);
+
+  // Returns the number of rows in the TableView.
+  int RowCount();
+
+  // Returns the number of selected rows.
+  int SelectedRowCount();
+
+  // Selects the specified item, making sure it's visible.
+  void Select(int model_row);
+
+  // Sets the selected state of an item (without sending any selection
+  // notifications). Note that this routine does NOT set the focus to the
+  // item at the given index.
+  void SetSelectedState(int model_row, bool state);
+
+  // Sets the focus to the item at the given index.
+  void SetFocusOnItem(int model_row);
+
+  // Returns the first selected row in terms of the model.
+  int FirstSelectedRow();
+
+  // Returns true if the item at the specified index is selected.
+  bool IsItemSelected(int model_row);
+
+  // Returns true if the item at the specified index has the focus.
+  bool ItemHasTheFocus(int model_row);
+
+  // Returns an iterator over the selection. The iterator proceeds from the
+  // last index to the first.
+  //
+  // NOTE: the iterator iterates over the visual order (but returns coordinates
+  // in terms of the model).
+  iterator SelectionBegin();
+  iterator SelectionEnd();
+
+  // TableModelObserver methods.
+  virtual void OnModelChanged();
+  virtual void OnItemsChanged(int start, int length);
+  virtual void OnItemsAdded(int start, int length);
+  virtual void OnItemsRemoved(int start, int length);
+
+  void SetObserver(TableViewObserver* observer) {
+    table_view_observer_ = observer;
+  }
+  TableViewObserver* observer() const { return table_view_observer_; }
+
+  // Replaces the set of known columns without changing the current visible
+  // columns.
+  void SetColumns(const std::vector<TableColumn>& columns);
+  void AddColumn(const TableColumn& col);
+  bool HasColumn(int id);
+
+  // Sets which columns (by id) are displayed.  All transient size and position
+  // information is lost.
+  void SetVisibleColumns(const std::vector<int>& columns);
+  void SetColumnVisibility(int id, bool is_visible);
+  bool IsColumnVisible(int id) const;
+
+  // Resets the size of the columns based on the sizes passed to the
+  // constructor. Your normally needn't invoked this, it's done for you the
+  // first time the TableView is given a valid size.
+  void ResetColumnSizes();
+
+  // Sometimes we may want to size the TableView to a specific width and
+  // height.
+  virtual gfx::Size GetPreferredSize();
+  void set_preferred_size(const gfx::Size& size) { preferred_size_ = size; }
+
+  // Is the table sorted?
+  bool is_sorted() const { return !sort_descriptors_.empty(); }
+
+  // Maps from the index in terms of the model to that of the view.
+  int model_to_view(int model_index) const {
+    return model_to_view_.get() ? model_to_view_[model_index] : model_index;
+  }
+
+  // Maps from the index in terms of the view to that of the model.
+  int view_to_model(int view_index) const {
+    return view_to_model_.get() ? view_to_model_[view_index] : view_index;
+  }
+
+ protected:
+  // Overriden to return the position of the first selected row.
+  virtual gfx::Point GetKeyboardContextMenuLocation();
+
+  // Subclasses that want to customize the colors of a particular row/column,
+  // must invoke this passing in true. The default value is false, such that
+  // GetCellColors is never invoked.
+  void SetCustomColorsEnabled(bool custom_colors_enabled);
+
+  // Notification from the ListView that the selected state of an item has
+  // changed.
+  virtual void OnSelectedStateChanged();
+
+  // Notification from the ListView that the used double clicked the table.
+  virtual void OnDoubleClick();
+
+  // Subclasses can implement this method if they need to be notified of a key
+  // press event.  Other wise, it appeals to table_view_observer_
+  virtual void OnKeyDown(unsigned short virtual_keycode);
+
+  // Invoked to customize the colors or font at a particular cell. If you
+  // change the colors or font, return true. This is only invoked if
+  // SetCustomColorsEnabled(true) has been invoked.
+  virtual bool GetCellColors(int model_row,
+                             int column,
+                             ItemColor* foreground,
+                             ItemColor* background,
+                             LOGFONT* logfont);
+
+  // Subclasses that want to perform some custom painting (on top of the regular
+  // list view painting) should return true here and implement the PostPaint
+  // method.
+  virtual bool ImplementPostPaint() { return false; }
+  // Subclasses can implement in this method extra-painting for cells.
+  virtual void PostPaint(int model_row, int column, bool selected,
+                         const CRect& bounds, HDC device_context) { }
+  virtual void PostPaint() {}
+
+  virtual HWND CreateNativeControl(HWND parent_container);
+
+  virtual LRESULT OnNotify(int w_param, LPNMHDR l_param);
+
+  // Overriden to destroy the image list.
+  virtual void OnDestroy();
+
+  // Used to sort the two rows. Returns a value < 0, == 0 or > 0 indicating
+  // whether the row2 comes before row1, row2 is the same as row1 or row1 comes
+  // after row2. This invokes CompareValues on the model with the sorted column.
+  virtual int CompareRows(int model_row1, int model_row2);
+
+  // Called before sorting. This does nothing and is intended for subclasses
+  // that need to cache state used during sorting.
+  virtual void PrepareForSort() {}
+
+  // Returns the width of the specified column by id, or -1 if the column isn't
+  // visible.
+  int GetColumnWidth(int column_id);
+
+  // Returns the offset from the top of the client area to the start of the
+  // content.
+  int content_offset() const { return content_offset_; }
+
+  // Size (width and height) of images.
+  static const int kImageSize;
+
+ private:
+  // Direction of a sort.
+  enum SortDirection {
+    ASCENDING_SORT,
+    DESCENDING_SORT,
+    NO_SORT
+  };
+
+  // We need this wrapper to pass the table view to the windows proc handler
+  // when subclassing the list view and list view header, as the reinterpret
+  // cast from GetWindowLongPtr would break the pointer if it is pointing to a
+  // subclass (in the OO sense of TableView).
+  struct TableViewWrapper {
+    explicit TableViewWrapper(TableView* view) : table_view(view) { }
+    TableView* table_view;
+  };
+
+  friend class ListViewParent;
+  friend class TableSelectionIterator;
+
+  LRESULT OnCustomDraw(NMLVCUSTOMDRAW* draw_info);
+
+  // Invoked when the user clicks on a column to toggle the sort order. If
+  // column_id is the primary sorted column the direction of the sort is
+  // toggled, otherwise column_id is made the primary sorted column.
+  void ToggleSortOrder(int column_id);
+
+  // Updates the lparam of each of the list view items to be the model index.
+  // If length is > 0, all items with an index >= start get offset by length.
+  // This is used during sorting to determine how the items were sorted.
+  void UpdateItemsLParams(int start, int length);
+
+  // Does the actual sort and updates the mappings (view_to_model and
+  // model_to_view) appropriately.
+  void SortItemsAndUpdateMapping();
+
+  // Method invoked by ListView to compare the two values. Invokes CompareRows.
+  static int CALLBACK SortFunc(LPARAM model_index_1_p,
+                               LPARAM model_index_2_p,
+                               LPARAM table_view_param);
+
+  // Method invoked by ListView when sorting back to natural state. Returns
+  // model_index_1_p - model_index_2_p.
+  static int CALLBACK NaturalSortFunc(LPARAM model_index_1_p,
+                                      LPARAM model_index_2_p,
+                                      LPARAM table_view_param);
+
+  // Resets the sort image displayed for the specified column.
+  void ResetColumnSortImage(int column_id, SortDirection direction);
+
+  // Adds a new column.
+  void InsertColumn(const TableColumn& tc, int index);
+
+  // Update headers and internal state after columns have changed
+  void OnColumnsChanged();
+
+  // Updates the ListView with values from the model. See UpdateListViewCache0
+  // for a complete description.
+  // This turns off redrawing, and invokes UpdateListViewCache0 to do the
+  // actual updating.
+  void UpdateListViewCache(int start, int length, bool add);
+
+  // Updates ListView with values from the model.
+  // If add is true, this adds length items starting at index start.
+  // If add is not true, the items are not added, the but the values in the
+  // range start - [start + length] are updated from the model.
+  void UpdateListViewCache0(int start, int length, bool add);
+
+  // Notification from the ListView that the checked state of the item has
+  // changed.
+  void OnCheckedStateChanged(int model_row, bool is_checked);
+
+  // Returns the index of the selected item before |view_index|, or -1 if
+  // |view_index| is the first selected item.
+  //
+  // WARNING: this returns coordinates in terms of the view, NOT the model.
+  int PreviousSelectedViewIndex(int view_index);
+
+  // Returns the last selected view index in the table view, or -1 if the table
+  // is empty, or nothing is selected.
+  //
+  // WARNING: this returns coordinates in terms of the view, NOT the model.
+  int LastSelectedViewIndex();
+
+  // The TableColumn visible at position pos.
+  const TableColumn& GetColumnAtPosition(int pos);
+
+  // Window procedure of the list view class. We subclass the list view to
+  // ignore WM_ERASEBKGND, which gives smoother painting during resizing.
+  static LRESULT CALLBACK TableWndProc(HWND window,
+                                       UINT message,
+                                       WPARAM w_param,
+                                       LPARAM l_param);
+
+  // Window procedure of the header class. We subclass the header of the table
+  // to disable resizing of columns.
+  static LRESULT CALLBACK TableHeaderWndProc(HWND window, UINT message,
+                                             WPARAM w_param, LPARAM l_param);
+
+  // Updates content_offset_ from the position of the header.
+  void UpdateContentOffset();
+
+  TableModel* model_;
+  TableTypes table_type_;
+  TableViewObserver* table_view_observer_;
+
+  // An ordered list of id's into all_columns_ representing current visible
+  // columns.
+  std::vector<int> visible_columns_;
+
+  // Mapping of an int id to a TableColumn representing all possible columns.
+  std::map<int, TableColumn> all_columns_;
+
+  // Cached value of columns_.size()
+  int column_count_;
+
+  // Selection mode.
+  bool single_selection_;
+
+  // If true, any events that would normally be propagated to the observer
+  // are ignored. For example, if this is true and the selection changes in
+  // the listview, the observer is not notified.
+  bool ignore_listview_change_;
+
+  // Reflects the value passed to SetCustomColorsEnabled.
+  bool custom_colors_enabled_;
+
+  // Whether or not the columns have been sized in the ListView. This is
+  // set to true the first time Layout() is invoked and we have a valid size.
+  bool sized_columns_;
+
+  // Whether or not columns should automatically be resized to fill the
+  // the available width when the list view is resized.
+  bool autosize_columns_;
+
+  // Whether or not the user can resize columns.
+  bool resizable_columns_;
+
+  // NOTE: While this has the name View in it, it's not a view. Rather it's
+  // a wrapper around the List-View window.
+  HWND list_view_;
+
+  // The list view's header original proc handler. It is required when
+  // subclassing.
+  WNDPROC header_original_handler_;
+
+  // Window procedure of the listview before we subclassed it.
+  WNDPROC original_handler_;
+
+  // A wrapper around 'this' used when "subclassing" the list view and header.
+  TableViewWrapper table_view_wrapper_;
+
+  // A custom font we use when overriding the font type for a specific cell.
+  HFONT custom_cell_font_;
+
+  // The preferred size of the table view.
+  gfx::Size preferred_size_;
+
+  int content_offset_;
+
+  // Current sort.
+  SortDescriptors sort_descriptors_;
+
+  // Mappings used when sorted.
+  scoped_array<int> view_to_model_;
+  scoped_array<int> model_to_view_;
+
+  DISALLOW_COPY_AND_ASSIGN(TableView);
+};
+#endif  // defined(OS_WIN)
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_TABLE_TABLE_VIEW_H_
diff --git a/views/controls/table/table_view_unittest.cc b/views/controls/table/table_view_unittest.cc
new file mode 100644
index 0000000..e0f08e24
--- /dev/null
+++ b/views/controls/table/table_view_unittest.cc
@@ -0,0 +1,381 @@
+// Copyright (c) 2006-2008 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 <vector>
+
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "views/controls/table/table_view.h"
+#include "views/window/window_delegate.h"
+#include "views/window/window_win.h"
+
+using views::TableView;
+
+// TestTableModel --------------------------------------------------------------
+
+// Trivial TableModel implementation that is backed by a vector of vectors.
+// Provides methods for adding/removing/changing the contents that notify the
+// observer appropriately.
+//
+// Initial contents are:
+// 0, 1
+// 1, 1
+// 2, 2
+class TestTableModel : public views::TableModel {
+ public:
+  TestTableModel();
+
+  // Adds a new row at index |row| with values |c1_value| and |c2_value|.
+  void AddRow(int row, int c1_value, int c2_value);
+
+  // Removes the row at index |row|.
+  void RemoveRow(int row);
+
+  // Changes the values of the row at |row|.
+  void ChangeRow(int row, int c1_value, int c2_value);
+
+  // TableModel
+  virtual int RowCount();
+  virtual std::wstring GetText(int row, int column_id);
+  virtual void SetObserver(views::TableModelObserver* observer);
+  virtual int CompareValues(int row1, int row2, int column_id);
+
+ private:
+  views::TableModelObserver* observer_;
+
+  // The data.
+  std::vector<std::vector<int>> rows_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestTableModel);
+};
+
+TestTableModel::TestTableModel() : observer_(NULL) {
+  AddRow(0, 0, 1);
+  AddRow(1, 1, 1);
+  AddRow(2, 2, 2);
+}
+
+void TestTableModel::AddRow(int row, int c1_value, int c2_value) {
+  DCHECK(row >= 0 && row <= static_cast<int>(rows_.size()));
+  std::vector<int> new_row;
+  new_row.push_back(c1_value);
+  new_row.push_back(c2_value);
+  rows_.insert(rows_.begin() + row, new_row);
+  if (observer_)
+    observer_->OnItemsAdded(row, 1);
+}
+void TestTableModel::RemoveRow(int row) {
+  DCHECK(row >= 0 && row <= static_cast<int>(rows_.size()));
+  rows_.erase(rows_.begin() + row);
+  if (observer_)
+    observer_->OnItemsRemoved(row, 1);
+}
+
+void TestTableModel::ChangeRow(int row, int c1_value, int c2_value) {
+  DCHECK(row >= 0 && row < static_cast<int>(rows_.size()));
+  rows_[row][0] = c1_value;
+  rows_[row][1] = c2_value;
+  if (observer_)
+    observer_->OnItemsChanged(row, 1);
+}
+
+int TestTableModel::RowCount() {
+  return static_cast<int>(rows_.size());
+}
+
+std::wstring TestTableModel::GetText(int row, int column_id) {
+  return IntToWString(rows_[row][column_id]);
+}
+
+void TestTableModel::SetObserver(views::TableModelObserver* observer) {
+  observer_ = observer;
+}
+
+int TestTableModel::CompareValues(int row1, int row2, int column_id) {
+  return rows_[row1][column_id] - rows_[row2][column_id];
+}
+
+// TableViewTest ---------------------------------------------------------------
+
+class TableViewTest : public testing::Test, views::WindowDelegate {
+ public:
+  virtual void SetUp();
+  virtual void TearDown();
+
+  virtual views::View* GetContentsView() {
+    return table_;
+  }
+
+ protected:
+  // Creates the model.
+  TestTableModel* CreateModel();
+
+  // Verifies the view order matches that of the supplied arguments. The
+  // arguments are in terms of the model. For example, values of '1, 0' indicate
+  // the model index at row 0 is 1 and the model index at row 1 is 0.
+  void VeriyViewOrder(int first, ...);
+
+  // Verifies the selection matches the supplied arguments. The supplied
+  // arguments are in terms of this model. This uses the iterator returned by
+  // SelectionBegin.
+  void VerifySelectedRows(int first, ...);
+
+  // Configures the state for the various multi-selection tests.
+  // This selects model rows 0 and 1, and if |sort| is true the first column
+  // is sorted in descending order.
+  void SetUpMultiSelectTestState(bool sort);
+
+  scoped_ptr<TestTableModel> model_;
+
+  // The table. This is owned by the window.
+  TableView* table_;
+
+ private:
+  MessageLoopForUI message_loop_;
+  views::Window* window_;
+};
+
+void TableViewTest::SetUp() {
+  OleInitialize(NULL);
+  model_.reset(CreateModel());
+  std::vector<views::TableColumn> columns;
+  columns.resize(2);
+  columns[0].id = 0;
+  columns[1].id = 1;
+  table_ = new TableView(model_.get(), columns, views::ICON_AND_TEXT,
+                         false, false, false);
+  window_ =
+      views::Window::CreateChromeWindow(NULL,
+                                              gfx::Rect(100, 100, 512, 512),
+                                              this);
+}
+
+void TableViewTest::TearDown() {
+  window_->Close();
+  // Temporary workaround to avoid leak of RootView::pending_paint_task_.
+  message_loop_.RunAllPending();
+  OleUninitialize();
+}
+
+void TableViewTest::VeriyViewOrder(int first, ...) {
+  va_list marker;
+  va_start(marker, first);
+  int value = first;
+  int index = 0;
+  for (int value = first, index = 0; value != -1; index++) {
+    ASSERT_EQ(value, table_->view_to_model(index));
+    value = va_arg(marker, int);
+  }
+  va_end(marker);
+}
+
+void TableViewTest::VerifySelectedRows(int first, ...) {
+  va_list marker;
+  va_start(marker, first);
+  int value = first;
+  int index = 0;
+  TableView::iterator selection_iterator = table_->SelectionBegin();
+  for (int value = first, index = 0; value != -1; index++) {
+    ASSERT_TRUE(selection_iterator != table_->SelectionEnd());
+    ASSERT_EQ(value, *selection_iterator);
+    value = va_arg(marker, int);
+    ++selection_iterator;
+  }
+  ASSERT_TRUE(selection_iterator == table_->SelectionEnd());
+  va_end(marker);
+}
+
+void TableViewTest::SetUpMultiSelectTestState(bool sort) {
+  // Select two rows.
+  table_->SetSelectedState(0, true);
+  table_->SetSelectedState(1, true);
+
+  VerifySelectedRows(1, 0, -1);
+  if (!sort || HasFatalFailure())
+    return;
+
+  // Sort by first column descending.
+  TableView::SortDescriptors sd;
+  sd.push_back(TableView::SortDescriptor(0, false));
+  table_->SetSortDescriptors(sd);
+  VeriyViewOrder(2, 1, 0, -1);
+  if (HasFatalFailure())
+    return;
+
+  // Make sure the two rows are sorted.
+  // NOTE: the order changed because iteration happens over view indices.
+  VerifySelectedRows(0, 1, -1);
+}
+
+TestTableModel* TableViewTest::CreateModel() {
+  return new TestTableModel();
+}
+
+// NullModelTableViewTest ------------------------------------------------------
+
+class NullModelTableViewTest : public TableViewTest {
+ protected:
+  // Creates the model.
+  TestTableModel* CreateModel() {
+    return NULL;
+  }
+};
+
+// Tests -----------------------------------------------------------------------
+
+// Tests various sorting permutations.
+TEST_F(TableViewTest, Sort) {
+  // Sort by first column descending.
+  TableView::SortDescriptors sort;
+  sort.push_back(TableView::SortDescriptor(0, false));
+  table_->SetSortDescriptors(sort);
+  VeriyViewOrder(2, 1, 0, -1);
+  if (HasFatalFailure())
+    return;
+
+  // Sort by second column ascending, first column descending.
+  sort.clear();
+  sort.push_back(TableView::SortDescriptor(1, true));
+  sort.push_back(TableView::SortDescriptor(0, false));
+  sort[1].ascending = false;
+  table_->SetSortDescriptors(sort);
+  VeriyViewOrder(1, 0, 2, -1);
+  if (HasFatalFailure())
+    return;
+
+  // Clear the sort.
+  table_->SetSortDescriptors(TableView::SortDescriptors());
+  VeriyViewOrder(0, 1, 2, -1);
+  if (HasFatalFailure())
+    return;
+}
+
+// Tests changing the model while sorted.
+TEST_F(TableViewTest, SortThenChange) {
+  // Sort by first column descending.
+  TableView::SortDescriptors sort;
+  sort.push_back(TableView::SortDescriptor(0, false));
+  table_->SetSortDescriptors(sort);
+  VeriyViewOrder(2, 1, 0, -1);
+  if (HasFatalFailure())
+    return;
+
+  model_->ChangeRow(0, 3, 1);
+  VeriyViewOrder(0, 2, 1, -1);
+}
+
+// Tests adding to the model while sorted.
+TEST_F(TableViewTest, AddToSorted) {
+  // Sort by first column descending.
+  TableView::SortDescriptors sort;
+  sort.push_back(TableView::SortDescriptor(0, false));
+  table_->SetSortDescriptors(sort);
+  VeriyViewOrder(2, 1, 0, -1);
+  if (HasFatalFailure())
+    return;
+
+  // Add row so that it occurs first.
+  model_->AddRow(0, 5, -1);
+  VeriyViewOrder(0, 3, 2, 1, -1);
+  if (HasFatalFailure())
+    return;
+
+  // Add row so that it occurs last.
+  model_->AddRow(0, -1, -1);
+  VeriyViewOrder(1, 4, 3, 2, 0, -1);
+}
+
+// Tests selection on sort.
+TEST_F(TableViewTest, PersistSelectionOnSort) {
+  // Select row 0.
+  table_->Select(0);
+
+  // Sort by first column descending.
+  TableView::SortDescriptors sort;
+  sort.push_back(TableView::SortDescriptor(0, false));
+  table_->SetSortDescriptors(sort);
+  VeriyViewOrder(2, 1, 0, -1);
+  if (HasFatalFailure())
+    return;
+
+  // Make sure 0 is still selected.
+  EXPECT_EQ(0, table_->FirstSelectedRow());
+}
+
+// Tests selection iterator with sort.
+TEST_F(TableViewTest, PersistMultiSelectionOnSort) {
+  SetUpMultiSelectTestState(true);
+}
+
+// Tests selection persists after a change when sorted with iterator.
+TEST_F(TableViewTest, PersistMultiSelectionOnChangeWithSort) {
+  SetUpMultiSelectTestState(true);
+  if (HasFatalFailure())
+    return;
+
+  model_->ChangeRow(0, 3, 1);
+
+  VerifySelectedRows(1, 0, -1);
+}
+
+// Tests selection persists after a remove when sorted with iterator.
+TEST_F(TableViewTest, PersistMultiSelectionOnRemoveWithSort) {
+  SetUpMultiSelectTestState(true);
+  if (HasFatalFailure())
+    return;
+
+  model_->RemoveRow(0);
+
+  VerifySelectedRows(0, -1);
+}
+
+// Tests selection persists after a add when sorted with iterator.
+TEST_F(TableViewTest, PersistMultiSelectionOnAddWithSort) {
+  SetUpMultiSelectTestState(true);
+  if (HasFatalFailure())
+    return;
+
+  model_->AddRow(3, 4, 4);
+
+  VerifySelectedRows(0, 1, -1);
+}
+
+// Tests selection persists after a change with iterator.
+TEST_F(TableViewTest, PersistMultiSelectionOnChange) {
+  SetUpMultiSelectTestState(false);
+  if (HasFatalFailure())
+    return;
+
+  model_->ChangeRow(0, 3, 1);
+
+  VerifySelectedRows(1, 0, -1);
+}
+
+// Tests selection persists after a remove with iterator.
+TEST_F(TableViewTest, PersistMultiSelectionOnRemove) {
+  SetUpMultiSelectTestState(false);
+  if (HasFatalFailure())
+    return;
+
+  model_->RemoveRow(0);
+
+  VerifySelectedRows(0, -1);
+}
+
+// Tests selection persists after a add with iterator.
+TEST_F(TableViewTest, PersistMultiSelectionOnAdd) {
+  SetUpMultiSelectTestState(false);
+  if (HasFatalFailure())
+    return;
+
+  model_->AddRow(3, 4, 4);
+
+  VerifySelectedRows(1, 0, -1);
+}
+
+TEST_F(NullModelTableViewTest, NullModel) {
+  // There's nothing explicit to test. If there is a bug in TableView relating
+  // to a NULL model we'll crash.
+}
diff --git a/views/controls/text_field.cc b/views/controls/text_field.cc
new file mode 100644
index 0000000..2981282
--- /dev/null
+++ b/views/controls/text_field.cc
@@ -0,0 +1,1192 @@
+// Copyright (c) 2009 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 "views/controls/text_field.h"
+
+#include <atlbase.h>
+#include <atlapp.h>
+#include <atlcrack.h>
+#include <atlctrls.h>
+#include <tom.h>  // For ITextDocument, a COM interface to CRichEditCtrl
+#include <vsstyle.h>
+
+#include "app/gfx/insets.h"
+#include "app/l10n_util.h"
+#include "app/l10n_util_win.h"
+#include "base/clipboard.h"
+#include "base/gfx/native_theme.h"
+#include "base/scoped_clipboard_writer.h"
+#include "base/string_util.h"
+#include "base/win_util.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/common/win_util.h"
+#include "grit/generated_resources.h"
+#include "skia/ext/skia_utils_win.h"
+#include "views/controls/hwnd_view.h"
+#include "views/controls/menu/menu.h"
+#include "views/focus/focus_util_win.h"
+#include "views/widget/widget.h"
+
+using gfx::NativeTheme;
+
+namespace views {
+
+static const int kDefaultEditStyle = WS_CHILD | WS_VISIBLE;
+
+class TextField::Edit
+    : public CWindowImpl<TextField::Edit, CRichEditCtrl,
+                         CWinTraits<kDefaultEditStyle> >,
+      public CRichEditCommands<TextField::Edit>,
+      public Menu::Delegate {
+ public:
+  DECLARE_WND_CLASS(L"ChromeViewsTextFieldEdit");
+
+  Edit(TextField* parent, bool draw_border);
+  ~Edit();
+
+  std::wstring GetText() const;
+  void SetText(const std::wstring& text);
+  void AppendText(const std::wstring& text);
+
+  std::wstring GetSelectedText() const;
+
+  // Selects all the text in the edit.  Use this in place of SetSelAll() to
+  // avoid selecting the "phantom newline" at the end of the edit.
+  void SelectAll();
+
+  // Clears the selection within the edit field and sets the caret to the end.
+  void ClearSelection();
+
+  // Removes the border.
+  void RemoveBorder();
+
+  void SetEnabled(bool enabled);
+
+  void SetBackgroundColor(COLORREF bg_color);
+
+  // CWindowImpl
+  BEGIN_MSG_MAP(Edit)
+    MSG_WM_CHAR(OnChar)
+    MSG_WM_CONTEXTMENU(OnContextMenu)
+    MSG_WM_COPY(OnCopy)
+    MSG_WM_CREATE(OnCreate)
+    MSG_WM_CUT(OnCut)
+    MSG_WM_DESTROY(OnDestroy)
+    MESSAGE_HANDLER_EX(WM_IME_CHAR, OnImeChar)
+    MESSAGE_HANDLER_EX(WM_IME_STARTCOMPOSITION, OnImeStartComposition)
+    MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeComposition)
+    MSG_WM_KEYDOWN(OnKeyDown)
+    MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
+    MSG_WM_LBUTTONDOWN(OnLButtonDown)
+    MSG_WM_LBUTTONUP(OnLButtonUp)
+    MSG_WM_MBUTTONDOWN(OnNonLButtonDown)
+    MSG_WM_MOUSEMOVE(OnMouseMove)
+    MSG_WM_MOUSELEAVE(OnMouseLeave)
+    MESSAGE_HANDLER_EX(WM_MOUSEWHEEL, OnMouseWheel)
+    MSG_WM_NCCALCSIZE(OnNCCalcSize)
+    MSG_WM_NCPAINT(OnNCPaint)
+    MSG_WM_RBUTTONDOWN(OnNonLButtonDown)
+    MSG_WM_PASTE(OnPaste)
+    MSG_WM_SYSCHAR(OnSysChar)  // WM_SYSxxx == WM_xxx with ALT down
+    MSG_WM_SYSKEYDOWN(OnKeyDown)
+  END_MSG_MAP()
+
+  // Menu::Delegate
+  virtual bool IsCommandEnabled(int id) const;
+  virtual void ExecuteCommand(int id);
+
+ private:
+  // This object freezes repainting of the edit until the object is destroyed.
+  // Some methods of the CRichEditCtrl draw synchronously to the screen.  If we
+  // don't freeze, the user will see a rapid series of calls to these as
+  // flickers.
+  //
+  // Freezing the control while it is already frozen is permitted; the control
+  // will unfreeze once both freezes are released (the freezes stack).
+  class ScopedFreeze {
+   public:
+    ScopedFreeze(Edit* edit, ITextDocument* text_object_model);
+    ~ScopedFreeze();
+
+   private:
+    Edit* const edit_;
+    ITextDocument* const text_object_model_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedFreeze);
+  };
+
+  // message handlers
+  void OnChar(TCHAR key, UINT repeat_count, UINT flags);
+  void OnContextMenu(HWND window, const CPoint& point);
+  void OnCopy();
+  LRESULT OnCreate(CREATESTRUCT* create_struct);
+  void OnCut();
+  void OnDestroy();
+  LRESULT OnImeChar(UINT message, WPARAM wparam, LPARAM lparam);
+  LRESULT OnImeStartComposition(UINT message, WPARAM wparam, LPARAM lparam);
+  LRESULT OnImeComposition(UINT message, WPARAM wparam, LPARAM lparam);
+  void OnKeyDown(TCHAR key, UINT repeat_count, UINT flags);
+  void OnLButtonDblClk(UINT keys, const CPoint& point);
+  void OnLButtonDown(UINT keys, const CPoint& point);
+  void OnLButtonUp(UINT keys, const CPoint& point);
+  void OnMouseLeave();
+  LRESULT OnMouseWheel(UINT message, WPARAM w_param, LPARAM l_param);
+  void OnMouseMove(UINT keys, const CPoint& point);
+  int OnNCCalcSize(BOOL w_param, LPARAM l_param);
+  void OnNCPaint(HRGN region);
+  void OnNonLButtonDown(UINT keys, const CPoint& point);
+  void OnPaste();
+  void OnSysChar(TCHAR ch, UINT repeat_count, UINT flags);
+
+  // Helper function for OnChar() and OnKeyDown() that handles keystrokes that
+  // could change the text in the edit.
+  void HandleKeystroke(UINT message, TCHAR key, UINT repeat_count, UINT flags);
+
+  // Every piece of code that can change the edit should call these functions
+  // before and after the change.  These functions determine if anything
+  // meaningful changed, and do any necessary updating and notification.
+  void OnBeforePossibleChange();
+  void OnAfterPossibleChange();
+
+  // Given an X coordinate in client coordinates, returns that coordinate
+  // clipped to be within the horizontal bounds of the visible text.
+  //
+  // This is used in our mouse handlers to work around quirky behaviors of the
+  // underlying CRichEditCtrl like not supporting triple-click when the user
+  // doesn't click on the text itself.
+  //
+  // |is_triple_click| should be true iff this is the third click of a triple
+  // click.  Sadly, we need to clip slightly differently in this case.
+  LONG ClipXCoordToVisibleText(LONG x, bool is_triple_click) const;
+
+  // Sets whether the mouse is in the edit. As necessary this redraws the
+  // edit.
+  void SetContainsMouse(bool contains_mouse);
+
+  // Getter for the text_object_model_, used by the ScopedFreeze class.  Note
+  // that the pointer returned here is only valid as long as the Edit is still
+  // alive.
+  ITextDocument* GetTextObjectModel() const;
+
+  // We need to know if the user triple-clicks, so track double click points
+  // and times so we can see if subsequent clicks are actually triple clicks.
+  bool tracking_double_click_;
+  CPoint double_click_point_;
+  DWORD double_click_time_;
+
+  // Used to discard unnecessary WM_MOUSEMOVE events after the first such
+  // unnecessary event.  See detailed comments in OnMouseMove().
+  bool can_discard_mousemove_;
+
+  // The text of this control before a possible change.
+  std::wstring text_before_change_;
+
+  // If true, the mouse is over the edit.
+  bool contains_mouse_;
+
+  static bool did_load_library_;
+
+  TextField* parent_;
+
+  // The context menu for the edit.
+  scoped_ptr<Menu> context_menu_;
+
+  // Border insets.
+  gfx::Insets content_insets_;
+
+  // Whether the border is drawn.
+  bool draw_border_;
+
+  // This interface is useful for accessing the CRichEditCtrl at a low level.
+  mutable CComQIPtr<ITextDocument> text_object_model_;
+
+  // The position and the length of the ongoing composition string.
+  // These values are used for removing a composition string from a search
+  // text to emulate Firefox.
+  bool ime_discard_composition_;
+  int ime_composition_start_;
+  int ime_composition_length_;
+
+  COLORREF bg_color_;
+
+  DISALLOW_COPY_AND_ASSIGN(Edit);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Helper classes
+
+TextField::Edit::ScopedFreeze::ScopedFreeze(TextField::Edit* edit,
+                                            ITextDocument* text_object_model)
+    : edit_(edit),
+      text_object_model_(text_object_model) {
+  // Freeze the screen.
+  if (text_object_model_) {
+    long count;
+    text_object_model_->Freeze(&count);
+  }
+}
+
+TextField::Edit::ScopedFreeze::~ScopedFreeze() {
+  // Unfreeze the screen.
+  if (text_object_model_) {
+    long count;
+    text_object_model_->Unfreeze(&count);
+    if (count == 0) {
+      // We need to UpdateWindow() here instead of InvalidateRect() because, as
+      // far as I can tell, the edit likes to synchronously erase its background
+      // when unfreezing, thus requiring us to synchronously redraw if we don't
+      // want flicker.
+      edit_->UpdateWindow();
+    }
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// TextField::Edit
+
+bool TextField::Edit::did_load_library_ = false;
+
+TextField::Edit::Edit(TextField* parent, bool draw_border)
+    : parent_(parent),
+      tracking_double_click_(false),
+      double_click_time_(0),
+      can_discard_mousemove_(false),
+      contains_mouse_(false),
+      draw_border_(draw_border),
+      ime_discard_composition_(false),
+      ime_composition_start_(0),
+      ime_composition_length_(0),
+      bg_color_(0) {
+  if (!did_load_library_)
+    did_load_library_ = !!LoadLibrary(L"riched20.dll");
+
+  DWORD style = kDefaultEditStyle;
+  if (parent->GetStyle() & TextField::STYLE_PASSWORD)
+    style |= ES_PASSWORD;
+
+  if (parent->read_only_)
+    style |= ES_READONLY;
+
+  if (parent->GetStyle() & TextField::STYLE_MULTILINE)
+    style |= ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL;
+  else
+    style |= ES_AUTOHSCROLL;
+  // Make sure we apply RTL related extended window styles if necessary.
+  DWORD ex_style = l10n_util::GetExtendedStyles();
+
+  RECT r = {0, 0, parent_->width(), parent_->height()};
+  Create(parent_->GetWidget()->GetNativeView(), r, NULL, style, ex_style);
+
+  if (parent->GetStyle() & TextField::STYLE_LOWERCASE) {
+    DCHECK((parent->GetStyle() & TextField::STYLE_PASSWORD) == 0);
+    SetEditStyle(SES_LOWERCASE, SES_LOWERCASE);
+  }
+
+  // Set up the text_object_model_.
+  CComPtr<IRichEditOle> ole_interface;
+  ole_interface.Attach(GetOleInterface());
+  text_object_model_ = ole_interface;
+
+  context_menu_.reset(new Menu(this, Menu::TOPLEFT, m_hWnd));
+  context_menu_->AppendMenuItemWithLabel(IDS_UNDO,
+                                         l10n_util::GetString(IDS_UNDO));
+  context_menu_->AppendSeparator();
+  context_menu_->AppendMenuItemWithLabel(IDS_CUT,
+                                         l10n_util::GetString(IDS_CUT));
+  context_menu_->AppendMenuItemWithLabel(IDS_COPY,
+                                         l10n_util::GetString(IDS_COPY));
+  context_menu_->AppendMenuItemWithLabel(IDS_PASTE,
+                                         l10n_util::GetString(IDS_PASTE));
+  context_menu_->AppendSeparator();
+  context_menu_->AppendMenuItemWithLabel(IDS_SELECT_ALL,
+                                         l10n_util::GetString(IDS_SELECT_ALL));
+}
+
+TextField::Edit::~Edit() {
+}
+
+std::wstring TextField::Edit::GetText() const {
+  int len = GetTextLength() + 1;
+  std::wstring str;
+  GetWindowText(WriteInto(&str, len), len);
+  return str;
+}
+
+void TextField::Edit::SetText(const std::wstring& text) {
+  // Adjusting the string direction before setting the text in order to make
+  // sure both RTL and LTR strings are displayed properly.
+  std::wstring text_to_set;
+  if (!l10n_util::AdjustStringForLocaleDirection(text, &text_to_set))
+    text_to_set = text;
+  if (parent_->GetStyle() & STYLE_LOWERCASE)
+    text_to_set = l10n_util::ToLower(text_to_set);
+  SetWindowText(text_to_set.c_str());
+}
+
+void TextField::Edit::AppendText(const std::wstring& text) {
+  int text_length = GetWindowTextLength();
+  ::SendMessage(m_hWnd, TBM_SETSEL, true, MAKELPARAM(text_length, text_length));
+  ::SendMessage(m_hWnd, EM_REPLACESEL, false,
+                reinterpret_cast<LPARAM>(text.c_str()));
+}
+
+std::wstring TextField::Edit::GetSelectedText() const {
+  // Figure out the length of the selection.
+  long start;
+  long end;
+  GetSel(start, end);
+
+  // Grab the selected text.
+  std::wstring str;
+  GetSelText(WriteInto(&str, end - start + 1));
+
+  return str;
+}
+
+void TextField::Edit::SelectAll() {
+  // Select from the end to the front so that the first part of the text is
+  // always visible.
+  SetSel(GetTextLength(), 0);
+}
+
+void TextField::Edit::ClearSelection() {
+  SetSel(GetTextLength(), GetTextLength());
+}
+
+void TextField::Edit::RemoveBorder() {
+  if (!draw_border_)
+    return;
+
+  draw_border_ = false;
+  SetWindowPos(NULL, 0, 0, 0, 0,
+               SWP_NOMOVE | SWP_FRAMECHANGED | SWP_NOACTIVATE |
+               SWP_NOOWNERZORDER | SWP_NOSIZE);
+}
+
+void TextField::Edit::SetEnabled(bool enabled) {
+  SendMessage(parent_->GetNativeComponent(), WM_ENABLE,
+              static_cast<WPARAM>(enabled), 0);
+}
+
+void TextField::Edit::SetBackgroundColor(COLORREF bg_color) {
+  CRichEditCtrl::SetBackgroundColor(bg_color);
+  bg_color_ = bg_color;
+}
+
+bool TextField::Edit::IsCommandEnabled(int id) const {
+  switch (id) {
+    case IDS_UNDO:       return !parent_->IsReadOnly() && !!CanUndo();
+    case IDS_CUT:        return !parent_->IsReadOnly() &&
+                                !parent_->IsPassword() && !!CanCut();
+    case IDS_COPY:       return !!CanCopy() && !parent_->IsPassword();
+    case IDS_PASTE:      return !parent_->IsReadOnly() && !!CanPaste();
+    case IDS_SELECT_ALL: return !!CanSelectAll();
+    default:             NOTREACHED();
+                         return false;
+  }
+}
+
+void TextField::Edit::ExecuteCommand(int id) {
+  ScopedFreeze freeze(this, GetTextObjectModel());
+  OnBeforePossibleChange();
+  switch (id) {
+    case IDS_UNDO:       Undo();       break;
+    case IDS_CUT:        Cut();        break;
+    case IDS_COPY:       Copy();       break;
+    case IDS_PASTE:      Paste();      break;
+    case IDS_SELECT_ALL: SelectAll();  break;
+    default:             NOTREACHED(); break;
+  }
+  OnAfterPossibleChange();
+}
+
+void TextField::Edit::OnChar(TCHAR ch, UINT repeat_count, UINT flags) {
+  HandleKeystroke(GetCurrentMessage()->message, ch, repeat_count, flags);
+}
+
+void TextField::Edit::OnContextMenu(HWND window, const CPoint& point) {
+  CPoint p(point);
+  if (point.x == -1 || point.y == -1) {
+    GetCaretPos(&p);
+    MapWindowPoints(HWND_DESKTOP, &p, 1);
+  }
+  context_menu_->RunMenuAt(p.x, p.y);
+}
+
+void TextField::Edit::OnCopy() {
+  if (parent_->IsPassword())
+    return;
+
+  const std::wstring text(GetSelectedText());
+
+  if (!text.empty()) {
+    ScopedClipboardWriter scw(g_browser_process->clipboard());
+    scw.WriteText(text);
+  }
+}
+
+LRESULT TextField::Edit::OnCreate(CREATESTRUCT* create_struct) {
+  SetMsgHandled(FALSE);
+  TRACK_HWND_CREATION(m_hWnd);
+  return 0;
+}
+
+void TextField::Edit::OnCut() {
+  if (parent_->IsReadOnly() || parent_->IsPassword())
+    return;
+
+  OnCopy();
+
+  // This replace selection will have no effect (even on the undo stack) if the
+  // current selection is empty.
+  ReplaceSel(L"", true);
+}
+
+void TextField::Edit::OnDestroy() {
+  TRACK_HWND_DESTRUCTION(m_hWnd);
+}
+
+LRESULT TextField::Edit::OnImeChar(UINT message, WPARAM wparam, LPARAM lparam) {
+  // http://crbug.com/7707: a rich-edit control may crash when it receives a
+  // WM_IME_CHAR message while it is processing a WM_IME_COMPOSITION message.
+  // Since view controls don't need WM_IME_CHAR messages, we prevent WM_IME_CHAR
+  // messages from being dispatched to view controls via the CallWindowProc()
+  // call.
+  return 0;
+}
+
+LRESULT TextField::Edit::OnImeStartComposition(UINT message,
+                                               WPARAM wparam,
+                                               LPARAM lparam) {
+  // Users may press alt+shift or control+shift keys to change their keyboard
+  // layouts. So, we retrieve the input locale identifier everytime we start
+  // an IME composition.
+  int language_id = PRIMARYLANGID(GetKeyboardLayout(0));
+  ime_discard_composition_ =
+      language_id == LANG_JAPANESE || language_id == LANG_CHINESE;
+  ime_composition_start_ = 0;
+  ime_composition_length_ = 0;
+
+  return DefWindowProc(message, wparam, lparam);
+}
+
+LRESULT TextField::Edit::OnImeComposition(UINT message,
+                                          WPARAM wparam,
+                                          LPARAM lparam) {
+  text_before_change_.clear();
+  LRESULT result = DefWindowProc(message, wparam, lparam);
+
+  ime_composition_start_ = 0;
+  ime_composition_length_ = 0;
+  if (ime_discard_composition_) {
+    // Call IMM32 functions to retrieve the position and the length of the
+    // ongoing composition string and notify the OnAfterPossibleChange()
+    // function that it should discard the composition string from a search
+    // string. We should not call IMM32 functions in the function because it
+    // is called when an IME is not composing a string.
+    HIMC imm_context = ImmGetContext(m_hWnd);
+    if (imm_context) {
+      CHARRANGE selection;
+      GetSel(selection);
+      const int cursor_position =
+          ImmGetCompositionString(imm_context, GCS_CURSORPOS, NULL, 0);
+      if (cursor_position >= 0)
+        ime_composition_start_ = selection.cpMin - cursor_position;
+
+      const int composition_size =
+          ImmGetCompositionString(imm_context, GCS_COMPSTR, NULL, 0);
+      if (composition_size >= 0)
+        ime_composition_length_ = composition_size / sizeof(wchar_t);
+
+      ImmReleaseContext(m_hWnd, imm_context);
+    }
+  }
+
+  OnAfterPossibleChange();
+  return result;
+}
+
+void TextField::Edit::OnKeyDown(TCHAR key, UINT repeat_count, UINT flags) {
+  // NOTE: Annoyingly, ctrl-alt-<key> generates WM_KEYDOWN rather than
+  // WM_SYSKEYDOWN, so we need to check (flags & KF_ALTDOWN) in various places
+  // in this function even with a WM_SYSKEYDOWN handler.
+
+  switch (key) {
+    case VK_RETURN:
+      // If we are multi-line, we want to let returns through so they start a
+      // new line.
+      if (parent_->IsMultiLine())
+        break;
+      else
+        return;
+    // Hijacking Editing Commands
+    //
+    // We hijack the keyboard short-cuts for Cut, Copy, and Paste here so that
+    // they go through our clipboard routines.  This allows us to be smarter
+    // about how we interact with the clipboard and avoid bugs in the
+    // CRichEditCtrl.  If we didn't hijack here, the edit control would handle
+    // these internally with sending the WM_CUT, WM_COPY, or WM_PASTE messages.
+    //
+    // Cut:   Shift-Delete and Ctrl-x are treated as cut.  Ctrl-Shift-Delete and
+    //        Ctrl-Shift-x are not treated as cut even though the underlying
+    //        CRichTextEdit would treat them as such.
+    // Copy:  Ctrl-v is treated as copy.  Shift-Ctrl-v is not.
+    // Paste: Shift-Insert and Ctrl-v are tread as paste.  Ctrl-Shift-Insert and
+    //        Ctrl-Shift-v are not.
+    //
+    // This behavior matches most, but not all Windows programs, and largely
+    // conforms to what users expect.
+
+    case VK_DELETE:
+    case 'X':
+      if ((flags & KF_ALTDOWN) ||
+          (GetKeyState((key == 'X') ? VK_CONTROL : VK_SHIFT) >= 0))
+        break;
+      if (GetKeyState((key == 'X') ? VK_SHIFT : VK_CONTROL) >= 0) {
+        ScopedFreeze freeze(this, GetTextObjectModel());
+        OnBeforePossibleChange();
+        Cut();
+        OnAfterPossibleChange();
+      }
+      return;
+
+    case 'C':
+      if ((flags & KF_ALTDOWN) || (GetKeyState(VK_CONTROL) >= 0))
+        break;
+      if (GetKeyState(VK_SHIFT) >= 0)
+        Copy();
+      return;
+
+    case VK_INSERT:
+    case 'V':
+      if ((flags & KF_ALTDOWN) ||
+          (GetKeyState((key == 'V') ? VK_CONTROL : VK_SHIFT) >= 0))
+        break;
+      if (GetKeyState((key == 'V') ? VK_SHIFT : VK_CONTROL) >= 0) {
+        ScopedFreeze freeze(this, GetTextObjectModel());
+        OnBeforePossibleChange();
+        Paste();
+        OnAfterPossibleChange();
+      }
+      return;
+
+    case 0xbb:  // Ctrl-'='.  Triggers subscripting, even in plain text mode.
+      return;
+
+    case VK_PROCESSKEY:
+      // This key event is consumed by an IME.
+      // We ignore this event because an IME sends WM_IME_COMPOSITION messages
+      // when it updates the CRichEditCtrl text.
+      return;
+  }
+
+  // CRichEditCtrl changes its text on WM_KEYDOWN instead of WM_CHAR for many
+  // different keys (backspace, ctrl-v, ...), so we call this in both cases.
+  HandleKeystroke(GetCurrentMessage()->message, key, repeat_count, flags);
+}
+
+void TextField::Edit::OnLButtonDblClk(UINT keys, const CPoint& point) {
+  // Save the double click info for later triple-click detection.
+  tracking_double_click_ = true;
+  double_click_point_ = point;
+  double_click_time_ = GetCurrentMessage()->time;
+
+  ScopedFreeze freeze(this, GetTextObjectModel());
+  OnBeforePossibleChange();
+  DefWindowProc(WM_LBUTTONDBLCLK, keys,
+                MAKELPARAM(ClipXCoordToVisibleText(point.x, false), point.y));
+  OnAfterPossibleChange();
+}
+
+void TextField::Edit::OnLButtonDown(UINT keys, const CPoint& point) {
+  // Check for triple click, then reset tracker.  Should be safe to subtract
+  // double_click_time_ from the current message's time even if the timer has
+  // wrapped in between.
+  const bool is_triple_click = tracking_double_click_ &&
+      win_util::IsDoubleClick(double_click_point_, point,
+                              GetCurrentMessage()->time - double_click_time_);
+  tracking_double_click_ = false;
+
+  ScopedFreeze freeze(this, GetTextObjectModel());
+  OnBeforePossibleChange();
+  DefWindowProc(WM_LBUTTONDOWN, keys,
+                MAKELPARAM(ClipXCoordToVisibleText(point.x, is_triple_click),
+                           point.y));
+  OnAfterPossibleChange();
+}
+
+void TextField::Edit::OnLButtonUp(UINT keys, const CPoint& point) {
+  ScopedFreeze freeze(this, GetTextObjectModel());
+  OnBeforePossibleChange();
+  DefWindowProc(WM_LBUTTONUP, keys,
+                MAKELPARAM(ClipXCoordToVisibleText(point.x, false), point.y));
+  OnAfterPossibleChange();
+}
+
+void TextField::Edit::OnMouseLeave() {
+  SetContainsMouse(false);
+}
+
+LRESULT TextField::Edit::OnMouseWheel(UINT message,
+                                      WPARAM w_param, LPARAM l_param) {
+  // Reroute the mouse-wheel to the window under the mouse pointer if
+  // applicable.
+  if (views::RerouteMouseWheel(m_hWnd, w_param, l_param))
+    return 0;
+  return DefWindowProc(message, w_param, l_param);;
+}
+
+void TextField::Edit::OnMouseMove(UINT keys, const CPoint& point) {
+  SetContainsMouse(true);
+  // Clamp the selection to the visible text so the user can't drag to select
+  // the "phantom newline".  In theory we could achieve this by clipping the X
+  // coordinate, but in practice the edit seems to behave nondeterministically
+  // with similar sequences of clipped input coordinates fed to it.  Maybe it's
+  // reading the mouse cursor position directly?
+  //
+  // This solution has a minor visual flaw, however: if there's a visible
+  // cursor at the edge of the text (only true when there's no selection),
+  // dragging the mouse around outside that edge repaints the cursor on every
+  // WM_MOUSEMOVE instead of allowing it to blink normally.  To fix this, we
+  // special-case this exact case and discard the WM_MOUSEMOVE messages instead
+  // of passing them along.
+  //
+  // But even this solution has a flaw!  (Argh.)  In the case where the user
+  // has a selection that starts at the edge of the edit, and proceeds to the
+  // middle of the edit, and the user is dragging back past the start edge to
+  // remove the selection, there's a redraw problem where the change between
+  // having the last few bits of text still selected and having nothing
+  // selected can be slow to repaint (which feels noticeably strange).  This
+  // occurs if you only let the edit receive a single WM_MOUSEMOVE past the
+  // edge of the text.  I think on each WM_MOUSEMOVE the edit is repainting its
+  // previous state, then updating its internal variables to the new state but
+  // not repainting.  To fix this, we allow one more WM_MOUSEMOVE through after
+  // the selection has supposedly been shrunk to nothing; this makes the edit
+  // redraw the selection quickly so it feels smooth.
+  CHARRANGE selection;
+  GetSel(selection);
+  const bool possibly_can_discard_mousemove =
+      (selection.cpMin == selection.cpMax) &&
+      (((selection.cpMin == 0) &&
+        (ClipXCoordToVisibleText(point.x, false) > point.x)) ||
+       ((selection.cpMin == GetTextLength()) &&
+        (ClipXCoordToVisibleText(point.x, false) < point.x)));
+  if (!can_discard_mousemove_ || !possibly_can_discard_mousemove) {
+    can_discard_mousemove_ = possibly_can_discard_mousemove;
+    ScopedFreeze freeze(this, GetTextObjectModel());
+    OnBeforePossibleChange();
+    // Force the Y coordinate to the center of the clip rect.  The edit
+    // behaves strangely when the cursor is dragged vertically: if the cursor
+    // is in the middle of the text, drags inside the clip rect do nothing,
+    // and drags outside the clip rect act as if the cursor jumped to the
+    // left edge of the text.  When the cursor is at the right edge, drags of
+    // just a few pixels vertically end up selecting the "phantom newline"...
+    // sometimes.
+    RECT r;
+    GetRect(&r);
+    DefWindowProc(WM_MOUSEMOVE, keys,
+                  MAKELPARAM(point.x, (r.bottom - r.top) / 2));
+    OnAfterPossibleChange();
+  }
+}
+
+int TextField::Edit::OnNCCalcSize(BOOL w_param, LPARAM l_param) {
+  content_insets_.Set(0, 0, 0, 0);
+  parent_->CalculateInsets(&content_insets_);
+  if (w_param) {
+    NCCALCSIZE_PARAMS* nc_params =
+        reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param);
+    nc_params->rgrc[0].left += content_insets_.left();
+    nc_params->rgrc[0].right -= content_insets_.right();
+    nc_params->rgrc[0].top += content_insets_.top();
+    nc_params->rgrc[0].bottom -= content_insets_.bottom();
+  } else {
+    RECT* rect = reinterpret_cast<RECT*>(l_param);
+    rect->left += content_insets_.left();
+    rect->right -= content_insets_.right();
+    rect->top += content_insets_.top();
+    rect->bottom -= content_insets_.bottom();
+  }
+  return 0;
+}
+
+void TextField::Edit::OnNCPaint(HRGN region) {
+  if (!draw_border_)
+    return;
+
+  HDC hdc = GetWindowDC();
+
+  CRect window_rect;
+  GetWindowRect(&window_rect);
+  // Convert to be relative to 0x0.
+  window_rect.MoveToXY(0, 0);
+
+  ExcludeClipRect(hdc,
+                  window_rect.left + content_insets_.left(),
+                  window_rect.top + content_insets_.top(),
+                  window_rect.right - content_insets_.right(),
+                  window_rect.bottom - content_insets_.bottom());
+
+  HBRUSH brush = CreateSolidBrush(bg_color_);
+  FillRect(hdc, &window_rect, brush);
+  DeleteObject(brush);
+
+  int part;
+  int state;
+
+  if (win_util::GetWinVersion() < win_util::WINVERSION_VISTA) {
+    part = EP_EDITTEXT;
+
+    if (!parent_->IsEnabled())
+      state = ETS_DISABLED;
+    else if (parent_->IsReadOnly())
+      state = ETS_READONLY;
+    else if (!contains_mouse_)
+      state = ETS_NORMAL;
+    else
+      state = ETS_HOT;
+  } else {
+    part = EP_EDITBORDER_HVSCROLL;
+
+    if (!parent_->IsEnabled())
+      state = EPSHV_DISABLED;
+    else if (GetFocus() == m_hWnd)
+      state = EPSHV_FOCUSED;
+    else if (contains_mouse_)
+      state = EPSHV_HOT;
+    else
+      state = EPSHV_NORMAL;
+    // Vista doesn't appear to have a unique state for readonly.
+  }
+
+  int classic_state =
+      (!parent_->IsEnabled() || parent_->IsReadOnly()) ? DFCS_INACTIVE : 0;
+
+  NativeTheme::instance()->PaintTextField(hdc, part, state, classic_state,
+                                          &window_rect, bg_color_, false,
+                                          true);
+
+  // NOTE: I tried checking the transparent property of the theme and invoking
+  // drawParentBackground, but it didn't seem to make a difference.
+
+  ReleaseDC(hdc);
+}
+
+void TextField::Edit::OnNonLButtonDown(UINT keys, const CPoint& point) {
+  // Interestingly, the edit doesn't seem to cancel triple clicking when the
+  // x-buttons (which usually means "thumb buttons") are pressed, so we only
+  // call this for M and R down.
+  tracking_double_click_ = false;
+  SetMsgHandled(false);
+}
+
+void TextField::Edit::OnPaste() {
+  if (parent_->IsReadOnly())
+    return;
+
+  Clipboard* clipboard = g_browser_process->clipboard();
+
+  if (!clipboard->IsFormatAvailable(Clipboard::GetPlainTextWFormatType()))
+    return;
+
+  std::wstring clipboard_str;
+  clipboard->ReadText(&clipboard_str);
+  if (!clipboard_str.empty()) {
+    std::wstring collapsed(CollapseWhitespace(clipboard_str, false));
+    if (parent_->GetStyle() & STYLE_LOWERCASE)
+      collapsed = l10n_util::ToLower(collapsed);
+    // Force a Paste operation to trigger OnContentsChanged, even if identical
+    // contents are pasted into the text box.
+    text_before_change_.clear();
+    ReplaceSel(collapsed.c_str(), true);
+  }
+}
+
+void TextField::Edit::OnSysChar(TCHAR ch, UINT repeat_count, UINT flags) {
+  // Nearly all alt-<xxx> combos result in beeping rather than doing something
+  // useful, so we discard most.  Exceptions:
+  //   * ctrl-alt-<xxx>, which is sometimes important, generates WM_CHAR instead
+  //     of WM_SYSCHAR, so it doesn't need to be handled here.
+  //   * alt-space gets translated by the default WM_SYSCHAR handler to a
+  //     WM_SYSCOMMAND to open the application context menu, so we need to allow
+  //     it through.
+  if (ch == VK_SPACE)
+    SetMsgHandled(false);
+}
+
+void TextField::Edit::HandleKeystroke(UINT message,
+                                      TCHAR key,
+                                      UINT repeat_count,
+                                      UINT flags) {
+  ScopedFreeze freeze(this, GetTextObjectModel());
+
+  TextField::Controller* controller = parent_->GetController();
+  bool handled = false;
+  if (controller) {
+    handled =
+        controller->HandleKeystroke(parent_, message, key, repeat_count, flags);
+  }
+
+  if (!handled) {
+    OnBeforePossibleChange();
+    DefWindowProc(message, key, MAKELPARAM(repeat_count, flags));
+    OnAfterPossibleChange();
+  }
+}
+
+void TextField::Edit::OnBeforePossibleChange() {
+  // Record our state.
+  text_before_change_ = GetText();
+}
+
+void TextField::Edit::OnAfterPossibleChange() {
+  // Prevent the user from selecting the "phantom newline" at the end of the
+  // edit.  If they try, we just silently move the end of the selection back to
+  // the end of the real text.
+  CHARRANGE new_sel;
+  GetSel(new_sel);
+  const int length = GetTextLength();
+  if (new_sel.cpMax > length) {
+    new_sel.cpMax = length;
+    if (new_sel.cpMin > length)
+      new_sel.cpMin = length;
+    SetSel(new_sel);
+  }
+
+  std::wstring new_text(GetText());
+  if (new_text != text_before_change_) {
+    if (ime_discard_composition_ && ime_composition_start_ >= 0 &&
+        ime_composition_length_ > 0) {
+      // A string retrieved with a GetText() call contains a string being
+      // composed by an IME. We remove the composition string from this search
+      // string.
+      new_text.erase(ime_composition_start_, ime_composition_length_);
+      ime_composition_start_ = 0;
+      ime_composition_length_ = 0;
+      if (new_text.empty())
+        return;
+    }
+    parent_->SyncText();
+    if (parent_->GetController())
+      parent_->GetController()->ContentsChanged(parent_, new_text);
+  }
+}
+
+LONG TextField::Edit::ClipXCoordToVisibleText(LONG x,
+                                              bool is_triple_click) const {
+  // Clip the X coordinate to the left edge of the text.  Careful:
+  // PosFromChar(0) may return a negative X coordinate if the beginning of the
+  // text has scrolled off the edit, so don't go past the clip rect's edge.
+  PARAFORMAT2 pf2;
+  GetParaFormat(pf2);
+  // Calculation of the clipped coordinate is more complicated if the paragraph
+  // layout is RTL layout, or if there is RTL characters inside the LTR layout
+  // paragraph.
+  bool ltr_text_in_ltr_layout = true;
+  if ((pf2.wEffects & PFE_RTLPARA) ||
+      l10n_util::StringContainsStrongRTLChars(GetText())) {
+    ltr_text_in_ltr_layout = false;
+  }
+  const int length = GetTextLength();
+  RECT r;
+  GetRect(&r);
+  // The values returned by PosFromChar() seem to refer always
+  // to the left edge of the character's bounding box.
+  const LONG first_position_x = PosFromChar(0).x;
+  LONG min_x = first_position_x;
+  if (!ltr_text_in_ltr_layout) {
+    for (int i = 1; i < length; ++i)
+      min_x = std::min(min_x, PosFromChar(i).x);
+  }
+  const LONG left_bound = std::max(r.left, min_x);
+
+  // PosFromChar(length) is a phantom character past the end of the text. It is
+  // not necessarily a right bound; in RTL controls it may be a left bound. So
+  // treat it as a right bound only if it is to the right of the first
+  // character.
+  LONG right_bound = r.right;
+  LONG end_position_x = PosFromChar(length).x;
+  if (end_position_x >= first_position_x) {
+    right_bound = std::min(right_bound, end_position_x);  // LTR case.
+  }
+  // For trailing characters that are 2 pixels wide of less (like "l" in some
+  // fonts), we have a problem:
+  //   * Clicks on any pixel within the character will place the cursor before
+  //     the character.
+  //   * Clicks on the pixel just after the character will not allow triple-
+  //     click to work properly (true for any last character width).
+  // So, we move to the last pixel of the character when this is a
+  // triple-click, and moving to one past the last pixel in all other
+  // scenarios.  This way, all clicks that can move the cursor will place it at
+  // the end of the text, but triple-click will still work.
+  if (x < left_bound) {
+    return (is_triple_click && ltr_text_in_ltr_layout) ? left_bound - 1 :
+                                                         left_bound;
+  }
+  if ((length == 0) || (x < right_bound))
+    return x;
+  return is_triple_click ? (right_bound - 1) : right_bound;
+}
+
+void TextField::Edit::SetContainsMouse(bool contains_mouse) {
+  if (contains_mouse == contains_mouse_)
+    return;
+
+  contains_mouse_ = contains_mouse;
+
+  if (!draw_border_)
+    return;
+
+  if (contains_mouse_) {
+    // Register for notification when the mouse leaves. Need to do this so
+    // that we can reset contains mouse properly.
+    TRACKMOUSEEVENT tme;
+    tme.cbSize = sizeof(tme);
+    tme.dwFlags = TME_LEAVE;
+    tme.hwndTrack = m_hWnd;
+    tme.dwHoverTime = 0;
+    TrackMouseEvent(&tme);
+  }
+  RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME);
+}
+
+ITextDocument* TextField::Edit::GetTextObjectModel() const {
+  if (!text_object_model_) {
+    CComPtr<IRichEditOle> ole_interface;
+    ole_interface.Attach(GetOleInterface());
+    text_object_model_ = ole_interface;
+  }
+  return text_object_model_;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// TextField
+
+TextField::~TextField() {
+  if (edit_) {
+    // If the edit hwnd still exists, we need to destroy it explicitly.
+    if (*edit_)
+      edit_->DestroyWindow();
+    delete edit_;
+  }
+}
+
+void TextField::ViewHierarchyChanged(bool is_add, View* parent, View* child) {
+  Widget* widget;
+
+  if (is_add && (widget = GetWidget())) {
+    // This notification is called from the AddChildView call below. Ignore it.
+    if (native_view_ && !edit_)
+      return;
+
+    if (!native_view_) {
+      native_view_ = new HWNDView();  // Deleted from our superclass destructor
+      AddChildView(native_view_);
+
+      // Maps the focus of the native control to the focus of this view.
+      native_view_->SetAssociatedFocusView(this);
+    }
+
+    // If edit_ is invalid from a previous use. Reset it.
+    if (edit_ && !IsWindow(edit_->m_hWnd)) {
+      native_view_->Detach();
+      delete edit_;
+      edit_ = NULL;
+    }
+
+    if (!edit_) {
+      edit_ = new Edit(this, draw_border_);
+      edit_->SetFont(font_.hfont());
+      native_view_->Attach(*edit_);
+      if (!text_.empty())
+        edit_->SetText(text_);
+      UpdateEditBackgroundColor();
+      Layout();
+    }
+  } else if (!is_add && edit_ && IsWindow(edit_->m_hWnd)) {
+    edit_->SetParent(NULL);
+  }
+}
+
+void TextField::Layout() {
+  if (native_view_) {
+    native_view_->SetBounds(GetLocalBounds(true));
+    native_view_->Layout();
+  }
+}
+
+gfx::Size TextField::GetPreferredSize() {
+  gfx::Insets insets;
+  CalculateInsets(&insets);
+  return gfx::Size(font_.GetExpectedTextWidth(default_width_in_chars_) +
+                       insets.width(),
+                   num_lines_ * font_.height() + insets.height());
+}
+
+std::wstring TextField::GetText() const {
+  return text_;
+}
+
+void TextField::SetText(const std::wstring& text) {
+  text_ = text;
+  if (edit_)
+    edit_->SetText(text);
+}
+
+void TextField::AppendText(const std::wstring& text) {
+  text_ += text;
+  if (edit_)
+    edit_->AppendText(text);
+}
+
+void TextField::CalculateInsets(gfx::Insets* insets) {
+  DCHECK(insets);
+
+  if (!draw_border_)
+    return;
+
+  // NOTE: One would think GetThemeMargins would return the insets we should
+  // use, but it doesn't. The margins returned by GetThemeMargins are always
+  // 0.
+
+  // This appears to be the insets used by Windows.
+  insets->Set(3, 3, 3, 3);
+}
+
+void TextField::SyncText() {
+  if (edit_)
+    text_ = edit_->GetText();
+}
+
+void TextField::SetController(Controller* controller) {
+  controller_ = controller;
+}
+
+TextField::Controller* TextField::GetController() const {
+  return controller_;
+}
+
+bool TextField::IsReadOnly() const {
+  return edit_ ? ((edit_->GetStyle() & ES_READONLY) != 0) : read_only_;
+}
+
+bool TextField::IsPassword() const {
+  return GetStyle() & TextField::STYLE_PASSWORD;
+}
+
+bool TextField::IsMultiLine() const {
+  return (style_ & STYLE_MULTILINE) != 0;
+}
+
+void TextField::SetReadOnly(bool read_only) {
+  read_only_ = read_only;
+  if (edit_) {
+    edit_->SetReadOnly(read_only);
+    UpdateEditBackgroundColor();
+  }
+}
+
+void TextField::Focus() {
+  ::SetFocus(native_view_->GetHWND());
+}
+
+void TextField::SelectAll() {
+  if (edit_)
+    edit_->SelectAll();
+}
+
+void TextField::ClearSelection() const {
+  if (edit_)
+    edit_->ClearSelection();
+}
+
+HWND TextField::GetNativeComponent() {
+  return native_view_->GetHWND();
+}
+
+void TextField::SetBackgroundColor(SkColor color) {
+  background_color_ = color;
+  use_default_background_color_ = false;
+  UpdateEditBackgroundColor();
+}
+
+void TextField::SetDefaultBackgroundColor() {
+  use_default_background_color_ = true;
+  UpdateEditBackgroundColor();
+}
+
+void TextField::SetFont(const ChromeFont& font) {
+  font_ = font;
+  if (edit_)
+    edit_->SetFont(font.hfont());
+}
+
+ChromeFont TextField::GetFont() const {
+  return font_;
+}
+
+bool TextField::SetHorizontalMargins(int left, int right) {
+  // SendMessage expects the two values to be packed into one using MAKELONG
+  // so we truncate to 16 bits if necessary.
+  return ERROR_SUCCESS == SendMessage(GetNativeComponent(),
+                                      (UINT) EM_SETMARGINS,
+                                      (WPARAM) EC_LEFTMARGIN | EC_RIGHTMARGIN,
+                                      (LPARAM) MAKELONG(left  & 0xFFFF,
+                                                        right & 0xFFFF));
+}
+
+void TextField::SetHeightInLines(int num_lines) {
+  DCHECK(IsMultiLine());
+  num_lines_ = num_lines;
+}
+
+void TextField::RemoveBorder() {
+  if (!draw_border_)
+    return;
+
+  draw_border_ = false;
+  if (edit_)
+    edit_->RemoveBorder();
+}
+
+void TextField::SetEnabled(bool enabled) {
+  View::SetEnabled(enabled);
+  edit_->SetEnabled(enabled);
+}
+
+bool TextField::IsFocusable() const {
+  return IsEnabled() && !IsReadOnly();
+}
+
+void TextField::AboutToRequestFocusFromTabTraversal(bool reverse) {
+  SelectAll();
+}
+
+bool TextField::ShouldLookupAccelerators(const KeyEvent& e) {
+  // TODO(hamaji): Figure out which keyboard combinations we need to add here,
+  //               similar to LocationBarView::ShouldLookupAccelerators.
+  if (e.GetCharacter() == VK_BACK)
+    return false;  // We'll handle BackSpace ourselves.
+
+  // We don't translate accelerators for ALT + NumPad digit, they are used for
+  // entering special characters.
+  if (!e.IsAltDown())
+    return true;
+
+  return !win_util::IsNumPadDigit(e.GetCharacter(), e.IsExtendedKey());
+}
+
+void TextField::UpdateEditBackgroundColor() {
+  if (!edit_)
+    return;
+
+  COLORREF bg_color;
+  if (!use_default_background_color_)
+    bg_color = skia::SkColorToCOLORREF(background_color_);
+  else
+    bg_color = GetSysColor(read_only_ ? COLOR_3DFACE : COLOR_WINDOW);
+  edit_->SetBackgroundColor(bg_color);
+}
+
+}  // namespace views
diff --git a/views/controls/text_field.h b/views/controls/text_field.h
new file mode 100644
index 0000000..3b030baf
--- /dev/null
+++ b/views/controls/text_field.h
@@ -0,0 +1,208 @@
+// Copyright (c) 2009 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.
+
+// These classes define a text field widget that can be used in the views UI
+// toolkit.
+
+#ifndef VIEWS_CONTROLS_TEXT_FIELD_H_
+#define VIEWS_CONTROLS_TEXT_FIELD_H_
+
+#include <string>
+
+#include "app/gfx/chrome_font.h"
+#include "base/basictypes.h"
+#include "views/view.h"
+#include "skia/include/SkColor.h"
+
+namespace views {
+
+class HWNDView;
+
+// This class implements a ChromeView that wraps a native text (edit) field.
+class TextField : public View {
+ public:
+  // This defines the callback interface for other code to be notified of
+  // changes in the state of a text field.
+  class Controller {
+   public:
+    // This method is called whenever the text in the field changes.
+    virtual void ContentsChanged(TextField* sender,
+                                 const std::wstring& new_contents) = 0;
+
+    // This method is called to get notified about keystrokes in the edit.
+    // This method returns true if the message was handled and should not be
+    // processed further. If it returns false the processing continues.
+    virtual bool HandleKeystroke(TextField* sender,
+                                 UINT message, TCHAR key, UINT repeat_count,
+                                 UINT flags) = 0;
+  };
+
+  enum StyleFlags {
+    STYLE_DEFAULT = 0,
+    STYLE_PASSWORD = 1<<0,
+    STYLE_MULTILINE = 1<<1,
+    STYLE_LOWERCASE = 1<<2
+  };
+
+  TextField::TextField()
+      : native_view_(NULL),
+        edit_(NULL),
+        controller_(NULL),
+        style_(STYLE_DEFAULT),
+        read_only_(false),
+        default_width_in_chars_(0),
+        draw_border_(true),
+        use_default_background_color_(true),
+        num_lines_(1) {
+    SetFocusable(true);
+  }
+  explicit TextField::TextField(StyleFlags style)
+      : native_view_(NULL),
+        edit_(NULL),
+        controller_(NULL),
+        style_(style),
+        read_only_(false),
+        default_width_in_chars_(0),
+        draw_border_(true),
+        use_default_background_color_(true),
+        num_lines_(1) {
+    SetFocusable(true);
+  }
+  virtual ~TextField();
+
+  void ViewHierarchyChanged(bool is_add, View* parent, View* child);
+
+  // Overridden for layout purposes
+  virtual void Layout();
+  virtual gfx::Size GetPreferredSize();
+
+  // Controller accessors
+  void SetController(Controller* controller);
+  Controller* GetController() const;
+
+  void SetReadOnly(bool read_only);
+  bool IsReadOnly() const;
+
+  bool IsPassword() const;
+
+  // Whether the text field is multi-line or not, must be set when the text
+  // field is created, using StyleFlags.
+  bool IsMultiLine() const;
+
+  virtual bool IsFocusable() const;
+  virtual void AboutToRequestFocusFromTabTraversal(bool reverse);
+
+  // Overridden from Chrome::View.
+  virtual bool ShouldLookupAccelerators(const KeyEvent& e);
+
+  virtual HWND GetNativeComponent();
+
+  // Returns the text currently displayed in the text field.
+  std::wstring GetText() const;
+
+  // Sets the text currently displayed in the text field.
+  void SetText(const std::wstring& text);
+
+  // Appends the given string to the previously-existing text in the field.
+  void AppendText(const std::wstring& text);
+
+  virtual void Focus();
+
+  // Causes the edit field to be fully selected.
+  void SelectAll();
+
+  // Clears the selection within the edit field and sets the caret to the end.
+  void ClearSelection() const;
+
+  StyleFlags GetStyle() const { return style_; }
+
+  void SetBackgroundColor(SkColor color);
+  void SetDefaultBackgroundColor();
+
+  // Set the font.
+  void SetFont(const ChromeFont& font);
+
+  // Return the font used by this TextField.
+  ChromeFont GetFont() const;
+
+  // Sets the left and right margin (in pixels) within the text box. On Windows
+  // this is accomplished by packing the left and right margin into a single
+  // 32 bit number, so the left and right margins are effectively 16 bits.
+  bool SetHorizontalMargins(int left, int right);
+
+  // Should only be called on a multi-line text field. Sets how many lines of
+  // text can be displayed at once by this text field.
+  void SetHeightInLines(int num_lines);
+
+  // Sets the default width of the text control. See default_width_in_chars_.
+  void set_default_width_in_chars(int default_width) {
+    default_width_in_chars_ = default_width;
+  }
+
+  // Removes the border from the edit box, giving it a 2D look.
+  void RemoveBorder();
+
+  // Disable the edit control.
+  // NOTE: this does NOT change the read only property.
+  void SetEnabled(bool enabled);
+
+ private:
+  class Edit;
+
+  // Invoked by the edit control when the value changes. This method set
+  // the text_ member variable to the value contained in edit control.
+  // This is important because the edit control can be replaced if it has
+  // been deleted during a window close.
+  void SyncText();
+
+  // Reset the text field native control.
+  void ResetNativeControl();
+
+  // Resets the background color of the edit.
+  void UpdateEditBackgroundColor();
+
+  // This encapsulates the HWND of the native text field.
+  HWNDView* native_view_;
+
+  // This inherits from the native text field.
+  Edit* edit_;
+
+  // This is the current listener for events from this control.
+  Controller* controller_;
+
+  StyleFlags style_;
+
+  ChromeFont font_;
+
+  // NOTE: this is temporary until we rewrite TextField to always work whether
+  // there is an HWND or not.
+  // Used if the HWND hasn't been created yet.
+  std::wstring text_;
+
+  bool read_only_;
+
+  // The default number of average characters for the width of this text field.
+  // This will be reported as the "desired size". Defaults to 0.
+  int default_width_in_chars_;
+
+  // Whether the border is drawn.
+  bool draw_border_;
+
+  SkColor background_color_;
+
+  bool use_default_background_color_;
+
+  // The number of lines of text this textfield displays at once.
+  int num_lines_;
+
+ protected:
+  // Calculates the insets for the text field.
+  void CalculateInsets(gfx::Insets* insets);
+
+  DISALLOW_COPY_AND_ASSIGN(TextField);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_TEXT_FIELD_H_
diff --git a/views/controls/throbber.cc b/views/controls/throbber.cc
new file mode 100644
index 0000000..d230c55b
--- /dev/null
+++ b/views/controls/throbber.cc
@@ -0,0 +1,170 @@
+// Copyright (c) 2006-2008 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 "views/controls/throbber.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/resource_bundle.h"
+#include "base/time.h"
+#include "grit/theme_resources.h"
+#include "skia/include/SkBitmap.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)) {
+  ResourceBundle &rb = ResourceBundle::GetSharedInstance();
+  frames_ = rb.GetBitmapNamed(IDR_THROBBER);
+  DCHECK(frames_->width() > 0 && frames_->height() > 0);
+  DCHECK(frames_->width() % frames_->height() == 0);
+  frame_count_ = frames_->width() / frames_->height();
+}
+
+Throbber::~Throbber() {
+  Stop();
+}
+
+void Throbber::Start() {
+  if (running_)
+    return;
+
+  start_time_ = Time::Now();
+
+  timer_.Start(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::Run() {
+  DCHECK(running_);
+
+  SchedulePaint();
+}
+
+gfx::Size Throbber::GetPreferredSize() {
+  return gfx::Size(frames_->height(), frames_->height());
+}
+
+void Throbber::Paint(ChromeCanvas* 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) {
+}
+
+void SmoothedThrobber::Start() {
+  stop_timer_.Stop();
+
+  if (!running_ && !start_timer_.IsRunning()) {
+    start_timer_.Start(TimeDelta::FromMilliseconds(kStartDelay), this,
+                       &SmoothedThrobber::StartDelayOver);
+  }
+}
+
+void SmoothedThrobber::StartDelayOver() {
+  Throbber::Start();
+}
+
+void SmoothedThrobber::Stop() {
+  if (!running_)
+    start_timer_.Stop();
+
+  stop_timer_.Stop();
+  stop_timer_.Start(TimeDelta::FromMilliseconds(kStopDelay), 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::Paint(ChromeCanvas* canvas) {
+  if (running_) {
+    // Let the throbber throb...
+    Throbber::Paint(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_INPUT_GOOD);
+    initialized = true;
+  }
+}
+
+// static
+SkBitmap* CheckmarkThrobber::checkmark_ = NULL;
+
+}  // namespace views
diff --git a/views/controls/throbber.h b/views/controls/throbber.h
new file mode 100644
index 0000000..bd0e67a
--- /dev/null
+++ b/views/controls/throbber.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2006-2008 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.
+
+// Throbbers display an animation, usually used as a status indicator.
+
+#ifndef VIEWS_CONTROLS_THROBBER_H_
+#define VIEWS_CONTROLS_THROBBER_H_
+
+#include "base/basictypes.h"
+#include "base/time.h"
+#include "base/timer.h"
+#include "views/view.h"
+
+class SkBitmap;
+
+namespace views {
+
+class 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);
+  virtual ~Throbber();
+
+  // Start and stop the throbber animation
+  virtual void Start();
+  virtual void Stop();
+
+  // overridden from View
+  virtual gfx::Size GetPreferredSize();
+  virtual void Paint(ChromeCanvas* canvas);
+
+ 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 SmoothedThrobber : public Throbber {
+ public:
+  SmoothedThrobber(int frame_delay_ms);
+
+  virtual void Start();
+  virtual void Stop();
+
+ 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();
+
+  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 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 Paint(ChromeCanvas* canvas);
+
+ 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  // VIEWS_CONTROLS_THROBBER_H_
diff --git a/views/controls/tree/tree_model.h b/views/controls/tree/tree_model.h
new file mode 100644
index 0000000..7fec5a8
--- /dev/null
+++ b/views/controls/tree/tree_model.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2008 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 VIEWS_CONTROLS_TREE_TREE_MODEL_H_
+#define VIEWS_CONTROLS_TREE_TREE_MODEL_H_
+
+#include <string>
+
+#include "base/logging.h"
+
+class SkBitmap;
+
+namespace views {
+
+class TreeModel;
+
+// TreeModelNode --------------------------------------------------------------
+
+// Type of class returned from the model.
+class TreeModelNode {
+ public:
+  // Returns the title for the node.
+  virtual std::wstring GetTitle() = 0;
+};
+
+// Observer for the TreeModel. Notified of significant events to the model.
+class TreeModelObserver {
+ public:
+  // Notification that nodes were added to the specified parent.
+  virtual void TreeNodesAdded(TreeModel* model,
+                              TreeModelNode* parent,
+                              int start,
+                              int count) = 0;
+
+  // Notification that nodes were removed from the specified parent.
+  virtual void TreeNodesRemoved(TreeModel* model,
+                                TreeModelNode* parent,
+                                int start,
+                                int count) = 0;
+
+  // Notification the children of |parent| have been reordered. Note, only
+  // the direct children of |parent| have been reordered, not descendants.
+  virtual void TreeNodeChildrenReordered(TreeModel* model,
+                                         TreeModelNode* parent) = 0;
+
+  // Notification that the contents of a node has changed.
+  virtual void TreeNodeChanged(TreeModel* model, TreeModelNode* node) = 0;
+};
+
+// TreeModel ------------------------------------------------------------------
+
+// The model for TreeView.
+class TreeModel {
+ public:
+  // Returns the root of the tree. This may or may not be shown in the tree,
+  // see SetRootShown for details.
+  virtual TreeModelNode* GetRoot() = 0;
+
+  // Returns the number of children in the specified node.
+  virtual int GetChildCount(TreeModelNode* parent) = 0;
+
+  // Returns the child node at the specified index.
+  virtual TreeModelNode* GetChild(TreeModelNode* parent, int index) = 0;
+
+  // Returns the parent of a node, or NULL if node is the root.
+  virtual TreeModelNode* GetParent(TreeModelNode* node) = 0;
+
+  // Sets the observer of the model.
+  virtual void SetObserver(TreeModelObserver* observer) = 0;
+
+  // Sets the title of the specified node.
+  // This is only invoked if the node is editable and the user edits a node.
+  virtual void SetTitle(TreeModelNode* node,
+                        const std::wstring& title) {
+    NOTREACHED();
+  }
+
+  // Returns the set of icons for the nodes in the tree. You only need override
+  // this if you don't want to use the default folder icons.
+  virtual void GetIcons(std::vector<SkBitmap>* icons) {}
+
+  // Returns the index of the icon to use for |node|. Return -1 to use the
+  // default icon. The index is relative to the list of icons returned from
+  // GetIcons.
+  virtual int GetIconIndex(TreeModelNode* node) { return -1; }
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_TREE_TREE_MODEL_H_
diff --git a/views/controls/tree/tree_node_iterator.h b/views/controls/tree/tree_node_iterator.h
new file mode 100644
index 0000000..76618e78
--- /dev/null
+++ b/views/controls/tree/tree_node_iterator.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_TREE_TREE_NODE_ITERATOR_H_
+#define VIEWS_CONTROLS_TREE_TREE_NODE_ITERATOR_H_
+
+#include <stack>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace views {
+
+// Iterator that iterates over the descendants of a node. The iteration does
+// not include the node itself, only the descendants. The following illustrates
+// typical usage:
+// while (iterator.has_next()) {
+//   Node* node = iterator.Next();
+//   // do something with node.
+// }
+template <class NodeType>
+class TreeNodeIterator {
+ public:
+  explicit TreeNodeIterator(NodeType* node) {
+    if (node->GetChildCount() > 0)
+      positions_.push(Position<NodeType>(node, 0));
+  }
+
+  // Returns true if there are more descendants.
+  bool has_next() const { return !positions_.empty(); }
+
+  // Returns the next descendant.
+  NodeType* Next() {
+    if (!has_next()) {
+      NOTREACHED();
+      return NULL;
+    }
+
+    NodeType* result = positions_.top().node->GetChild(positions_.top().index);
+
+    // Make sure we don't attempt to visit result again.
+    positions_.top().index++;
+
+    // Iterate over result's children.
+    positions_.push(Position<NodeType>(result, 0));
+
+    // Advance to next position.
+    while (!positions_.empty() && positions_.top().index >=
+           positions_.top().node->GetChildCount()) {
+      positions_.pop();
+    }
+
+    return result;
+  }
+
+ private:
+  template <class PositionNodeType>
+  struct Position {
+    Position(PositionNodeType* node, int index) : node(node), index(index) {}
+    Position() : node(NULL), index(-1) {}
+
+    PositionNodeType* node;
+    int index;
+  };
+
+  std::stack<Position<NodeType> > positions_;
+
+  DISALLOW_COPY_AND_ASSIGN(TreeNodeIterator);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_TREE_TREE_NODE_ITERATOR_H_
diff --git a/views/controls/tree/tree_node_iterator_unittest.cc b/views/controls/tree/tree_node_iterator_unittest.cc
new file mode 100644
index 0000000..e5353fc
--- /dev/null
+++ b/views/controls/tree/tree_node_iterator_unittest.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2006-2008 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 "testing/gtest/include/gtest/gtest.h"
+
+#include "views/controls/tree/tree_node_iterator.h"
+#include "views/controls/tree/tree_node_model.h"
+
+typedef testing::Test TreeNodeIteratorTest;
+
+using views::TreeNodeWithValue;
+
+TEST_F(TreeNodeIteratorTest, Test) {
+  TreeNodeWithValue<int> root;
+  root.Add(0, new TreeNodeWithValue<int>(1));
+  root.Add(1, new TreeNodeWithValue<int>(2));
+  TreeNodeWithValue<int>* f3 = new TreeNodeWithValue<int>(3);
+  root.Add(2, f3);
+  TreeNodeWithValue<int>* f4 = new TreeNodeWithValue<int>(4);
+  f3->Add(0, f4);
+  f4->Add(0, new TreeNodeWithValue<int>(5));
+
+  views::TreeNodeIterator<TreeNodeWithValue<int> > iterator(&root);
+  ASSERT_TRUE(iterator.has_next());
+  ASSERT_EQ(root.GetChild(0), iterator.Next());
+
+  ASSERT_TRUE(iterator.has_next());
+  ASSERT_EQ(root.GetChild(1), iterator.Next());
+
+  ASSERT_TRUE(iterator.has_next());
+  ASSERT_EQ(root.GetChild(2), iterator.Next());
+
+  ASSERT_TRUE(iterator.has_next());
+  ASSERT_EQ(f4, iterator.Next());
+
+  ASSERT_TRUE(iterator.has_next());
+  ASSERT_EQ(f4->GetChild(0), iterator.Next());
+
+  ASSERT_FALSE(iterator.has_next());
+}
diff --git a/views/controls/tree/tree_node_model.h b/views/controls/tree/tree_node_model.h
new file mode 100644
index 0000000..f1e1c16
--- /dev/null
+++ b/views/controls/tree/tree_node_model.h
@@ -0,0 +1,283 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_TREE_TREE_NODE_MODEL_H_
+#define VIEWS_CONTROLS_TREE_TREE_NODE_MODEL_H_
+
+#include <algorithm>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_vector.h"
+#include "base/stl_util-inl.h"
+#include "views/controls/tree/tree_model.h"
+
+namespace views {
+
+// TreeNodeModel and TreeNodes provide an implementation of TreeModel around
+// TreeNodes. TreeNodes form a directed acyclic graph.
+//
+// TreeNodes own their children, so that deleting a node deletes all
+// descendants.
+//
+// TreeNodes do NOT maintain a pointer back to the model. As such, if you
+// are using TreeNodes with a TreeNodeModel you will need to notify the observer
+// yourself any time you make any change directly to the TreeNodes. For example,
+// if you directly invoke SetTitle on a node it does not notify the
+// observer, you will need to do it yourself. This includes the following
+// methods: SetTitle, Remove and Add. TreeNodeModel provides cover
+// methods that mutate the TreeNodes and notify the observer. If you are using
+// TreeNodes with a TreeNodeModel use the cover methods to save yourself the
+// headache.
+//
+// The following example creates a TreeNode with two children and then
+// creates a TreeNodeModel from it:
+//
+// TreeNodeWithValue<int> root = new TreeNodeWithValue<int>(0, L"root");
+// root.add(new TreeNodeWithValue<int>(1, L"child 1"));
+// root.add(new TreeNodeWithValue<int>(1, L"child 2"));
+// TreeNodeModel<TreeNodeWithValue<int>>* model =
+//     new TreeNodeModel<TreeNodeWithValue<int>>(root);
+//
+// Two variants of TreeNode are provided here:
+//
+// . TreeNode itself is intended for subclassing. It has one type parameter
+//   that corresponds to the type of the node. When subclassing use your class
+//   name as the type parameter, eg:
+//   class MyTreeNode : public TreeNode<MyTreeNode> .
+// . TreeNodeWithValue is a trivial subclass of TreeNode that has one type
+//   type parameter: a value type that is associated with the node.
+//
+// Which you use depends upon the situation. If you want to subclass and add
+// methods, then use TreeNode. If you don't need any extra methods and just
+// want to associate a value with each node, then use TreeNodeWithValue.
+//
+// Regardless of which TreeNode you use, if you are using the nodes with a
+// TreeView take care to notify the observer when mutating the nodes.
+
+template <class NodeType>
+class TreeNodeModel;
+
+// TreeNode -------------------------------------------------------------------
+
+template <class NodeType>
+class TreeNode : public TreeModelNode {
+ public:
+  TreeNode() : parent_(NULL) { }
+
+  explicit TreeNode(const std::wstring& title)
+      : title_(title), parent_(NULL) {}
+
+  virtual ~TreeNode() {
+  }
+
+  // Adds the specified child node.
+  virtual void Add(int index, NodeType* child) {
+    DCHECK(child && index >= 0 && index <= GetChildCount());
+    // If the node has a parent, remove it from its parent.
+    NodeType* node_parent = child->GetParent();
+    if (node_parent)
+      node_parent->Remove(node_parent->IndexOfChild(child));
+    child->parent_ = static_cast<NodeType*>(this);
+    children_->insert(children_->begin() + index, child);
+  }
+
+  // Removes the node by index. This does NOT delete the specified node, it is
+  // up to the caller to delete it when done.
+  virtual NodeType* Remove(int index) {
+    DCHECK(index >= 0 && index < GetChildCount());
+    NodeType* node = GetChild(index);
+    node->parent_ = NULL;
+    children_->erase(index + children_->begin());
+    return node;
+  }
+
+  // Removes all the children from this node. This does NOT delete the nodes.
+  void RemoveAll() {
+    for (size_t i = 0; i < children_->size(); ++i)
+      children_[i]->parent_ = NULL;
+    children_->clear();
+  }
+
+  // Returns the number of children.
+  int GetChildCount() {
+    return static_cast<int>(children_->size());
+  }
+
+  // Returns a child by index.
+  NodeType* GetChild(int index) {
+    DCHECK(index >= 0 && index < GetChildCount());
+    return children_[index];
+  }
+
+  // Returns the parent.
+  NodeType* GetParent() {
+    return parent_;
+  }
+
+  // Returns the index of the specified child, or -1 if node is a not a child.
+  int IndexOfChild(const NodeType* node) {
+    DCHECK(node);
+    typename std::vector<NodeType*>::iterator i =
+        std::find(children_->begin(), children_->end(), node);
+    if (i != children_->end())
+      return static_cast<int>(i - children_->begin());
+    return -1;
+  }
+
+  // Sets the title of the node.
+  void SetTitle(const std::wstring& string) {
+    title_ = string;
+  }
+
+  // Returns the title of the node.
+  std::wstring GetTitle() {
+    return title_;
+  }
+
+  // Returns true if this is the root.
+  bool IsRoot() { return (parent_ == NULL); }
+
+  // Returns true if this == ancestor, or one of this nodes parents is
+  // ancestor.
+  bool HasAncestor(NodeType* ancestor) const {
+    if (ancestor == this)
+      return true;
+    if (!ancestor)
+      return false;
+    return parent_ ? parent_->HasAncestor(ancestor) : false;
+  }
+
+ protected:
+  std::vector<NodeType*>& children() { return children_.get(); }
+
+ private:
+  // Title displayed in the tree.
+  std::wstring title_;
+
+  NodeType* parent_;
+
+  // Children.
+  ScopedVector<NodeType> children_;
+
+  DISALLOW_COPY_AND_ASSIGN(TreeNode);
+};
+
+// TreeNodeWithValue ----------------------------------------------------------
+
+template <class ValueType>
+class TreeNodeWithValue : public TreeNode< TreeNodeWithValue<ValueType> > {
+ private:
+  typedef TreeNode< TreeNodeWithValue<ValueType> > ParentType;
+
+ public:
+  TreeNodeWithValue() { }
+
+  TreeNodeWithValue(const ValueType& value)
+      : ParentType(std::wstring()), value(value) { }
+
+  TreeNodeWithValue(const std::wstring& title, const ValueType& value)
+      : ParentType(title), value(value) { }
+
+  ValueType value;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TreeNodeWithValue);
+};
+
+// TreeNodeModel --------------------------------------------------------------
+
+// TreeModel implementation intended to be used with TreeNodes.
+template <class NodeType>
+class TreeNodeModel : public TreeModel {
+ public:
+  // Creates a TreeNodeModel with the specified root node. The root is owned
+  // by the TreeNodeModel.
+  explicit TreeNodeModel(NodeType* root)
+      : root_(root),
+        observer_(NULL) {
+  }
+
+  virtual ~TreeNodeModel() {}
+
+  virtual void SetObserver(TreeModelObserver* observer) {
+    observer_ = observer;
+  }
+
+  TreeModelObserver* GetObserver() {
+    return observer_;
+  }
+
+  // TreeModel methods, all forward to the nodes.
+  virtual NodeType* GetRoot() { return root_.get(); }
+
+  virtual int GetChildCount(TreeModelNode* parent) {
+    DCHECK(parent);
+    return AsNode(parent)->GetChildCount();
+  }
+
+  virtual NodeType* GetChild(TreeModelNode* parent, int index) {
+    DCHECK(parent);
+    return AsNode(parent)->GetChild(index);
+  }
+
+  virtual TreeModelNode* GetParent(TreeModelNode* node) {
+    DCHECK(node);
+    return AsNode(node)->GetParent();
+  }
+
+  NodeType* AsNode(TreeModelNode* model_node) {
+    return reinterpret_cast<NodeType*>(model_node);
+  }
+
+  // Sets the title of the specified node.
+  virtual void SetTitle(TreeModelNode* node,
+                        const std::wstring& title) {
+    DCHECK(node);
+    AsNode(node)->SetTitle(title);
+    NotifyObserverTreeNodeChanged(node);
+  }
+
+  void Add(NodeType* parent, int index, NodeType* child) {
+    DCHECK(parent && child);
+    parent->Add(index, child);
+    NotifyObserverTreeNodesAdded(parent, index, 1);
+  }
+
+  NodeType* Remove(NodeType* parent, int index) {
+    DCHECK(parent);
+    NodeType* child = parent->Remove(index);
+    NotifyObserverTreeNodesRemoved(parent, index, 1);
+    return child;
+  }
+
+  void NotifyObserverTreeNodesAdded(NodeType* parent, int start, int count) {
+    if (observer_)
+      observer_->TreeNodesAdded(this, parent, start, count);
+  }
+
+  void NotifyObserverTreeNodesRemoved(NodeType* parent, int start, int count) {
+    if (observer_)
+      observer_->TreeNodesRemoved(this, parent, start, count);
+  }
+
+  virtual void NotifyObserverTreeNodeChanged(TreeModelNode* node) {
+    if (observer_)
+      observer_->TreeNodeChanged(this, node);
+  }
+
+ private:
+  // The root.
+  scoped_ptr<NodeType> root_;
+
+  // The observer.
+  TreeModelObserver* observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(TreeNodeModel);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_TREE_TREE_NODE_MODEL_H_
diff --git a/views/controls/tree/tree_view.cc b/views/controls/tree/tree_view.cc
new file mode 100644
index 0000000..08f2255
--- /dev/null
+++ b/views/controls/tree/tree_view.cc
@@ -0,0 +1,745 @@
+// Copyright (c) 2006-2008 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 "views/controls/tree/tree_view.h"
+
+#include <shellapi.h>
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/gfx/icon_util.h"
+#include "app/l10n_util.h"
+#include "app/l10n_util_win.h"
+#include "app/resource_bundle.h"
+#include "base/stl_util-inl.h"
+#include "base/win_util.h"
+#include "grit/theme_resources.h"
+#include "views/focus/focus_manager.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+TreeView::TreeView()
+    : tree_view_(NULL),
+      model_(NULL),
+      editable_(true),
+      next_id_(0),
+      controller_(NULL),
+      editing_node_(NULL),
+      root_shown_(true),
+      process_enter_(false),
+      show_context_menu_only_when_node_selected_(true),
+      select_on_right_mouse_down_(true),
+      wrapper_(this),
+      original_handler_(NULL),
+      drag_enabled_(false),
+      has_custom_icons_(false),
+      image_list_(NULL) {
+}
+
+TreeView::~TreeView() {
+  if (model_)
+    model_->SetObserver(NULL);
+  // Both param_to_details_map_ and node_to_details_map_ have the same value,
+  // as such only need to delete from one.
+  STLDeleteContainerPairSecondPointers(id_to_details_map_.begin(),
+                                       id_to_details_map_.end());
+  if (image_list_)
+    ImageList_Destroy(image_list_);
+}
+
+void TreeView::SetModel(TreeModel* model) {
+  if (model == model_)
+    return;
+  if(model_ && tree_view_)
+    DeleteRootItems();
+  if (model_)
+    model_->SetObserver(NULL);
+  model_ = model;
+  if (tree_view_ && model_) {
+    CreateRootItems();
+    model_->SetObserver(this);
+    HIMAGELIST last_image_list = image_list_;
+    image_list_ = CreateImageList();
+    TreeView_SetImageList(tree_view_, image_list_, TVSIL_NORMAL);
+    if (last_image_list)
+      ImageList_Destroy(last_image_list);
+  }
+}
+
+// Sets whether the user can edit the nodes. The default is true.
+void TreeView::SetEditable(bool editable) {
+  if (editable == editable_)
+    return;
+  editable_ = editable;
+  if (!tree_view_)
+    return;
+  LONG_PTR style = GetWindowLongPtr(tree_view_, GWL_STYLE);
+  style &= ~TVS_EDITLABELS;
+  SetWindowLongPtr(tree_view_, GWL_STYLE, style);
+}
+
+void TreeView::StartEditing(TreeModelNode* node) {
+  DCHECK(node && tree_view_);
+  // Cancel the current edit.
+  CancelEdit();
+  // Make sure all ancestors are expanded.
+  if (model_->GetParent(node))
+    Expand(model_->GetParent(node));
+  const NodeDetails* details = GetNodeDetails(node);
+  // Tree needs focus for editing to work.
+  SetFocus(tree_view_);
+  // Select the node, else if the user commits the edit the selection reverts.
+  SetSelectedNode(node);
+  TreeView_EditLabel(tree_view_, details->tree_item);
+}
+
+void TreeView::CancelEdit() {
+  DCHECK(tree_view_);
+  TreeView_EndEditLabelNow(tree_view_, TRUE);
+}
+
+void TreeView::CommitEdit() {
+  DCHECK(tree_view_);
+  TreeView_EndEditLabelNow(tree_view_, FALSE);
+}
+
+TreeModelNode* TreeView::GetEditingNode() {
+  // I couldn't find a way to dynamically query for this, so it is cached.
+  return editing_node_;
+}
+
+void TreeView::SetSelectedNode(TreeModelNode* node) {
+  DCHECK(tree_view_);
+  if (!node) {
+    TreeView_SelectItem(tree_view_, NULL);
+    return;
+  }
+  if (node != model_->GetRoot())
+    Expand(model_->GetParent(node));
+  if (!root_shown_ && node == model_->GetRoot()) {
+    // If the root isn't shown, we can't select it, clear out the selection
+    // instead.
+    TreeView_SelectItem(tree_view_, NULL);
+  } else {
+    // Select the node and make sure it is visible.
+    TreeView_SelectItem(tree_view_, GetNodeDetails(node)->tree_item);
+  }
+}
+
+TreeModelNode* TreeView::GetSelectedNode() {
+  if (!tree_view_)
+    return NULL;
+  HTREEITEM selected_item = TreeView_GetSelection(tree_view_);
+  if (!selected_item)
+    return NULL;
+  NodeDetails* details = GetNodeDetailsByTreeItem(selected_item);
+  DCHECK(details);
+  return details->node;
+}
+
+void TreeView::Expand(TreeModelNode* node) {
+  DCHECK(model_ && node);
+  if (!root_shown_ && model_->GetRoot() == node) {
+    // Can only expand the root if it is showing.
+    return;
+  }
+  TreeModelNode* parent = model_->GetParent(node);
+  if (parent) {
+    // Make sure all the parents are expanded.
+    Expand(parent);
+  }
+  // And expand this item.
+  TreeView_Expand(tree_view_, GetNodeDetails(node)->tree_item, TVE_EXPAND);
+}
+
+void TreeView::ExpandAll() {
+  DCHECK(model_);
+  ExpandAll(model_->GetRoot());
+}
+
+void TreeView::ExpandAll(TreeModelNode* node) {
+  DCHECK(node);
+  // Expand the node.
+  if (node != model_->GetRoot() || root_shown_)
+    TreeView_Expand(tree_view_, GetNodeDetails(node)->tree_item, TVE_EXPAND);
+  // And recursively expand all the children.
+  for (int i = model_->GetChildCount(node) - 1; i >= 0; --i) {
+    TreeModelNode* child = model_->GetChild(node, i);
+    ExpandAll(child);
+  }
+}
+
+bool TreeView::IsExpanded(TreeModelNode* node) {
+  TreeModelNode* parent = model_->GetParent(node);
+  if (!parent)
+    return true;
+  if (!IsExpanded(parent))
+    return false;
+  NodeDetails* details = GetNodeDetails(node);
+  return (TreeView_GetItemState(tree_view_, details->tree_item, TVIS_EXPANDED) &
+          TVIS_EXPANDED) != 0;
+}
+
+void TreeView::SetRootShown(bool root_shown) {
+  if (root_shown_ == root_shown)
+    return;
+  root_shown_ = root_shown;
+  if (!model_)
+    return;
+  // Repopulate the tree.
+  DeleteRootItems();
+  CreateRootItems();
+}
+
+void TreeView::TreeNodesAdded(TreeModel* model,
+                              TreeModelNode* parent,
+                              int start,
+                              int count) {
+  DCHECK(parent && start >= 0 && count > 0);
+  if (node_to_details_map_.find(parent) == node_to_details_map_.end()) {
+    // User hasn't navigated to this entry yet. Ignore the change.
+    return;
+  }
+  HTREEITEM parent_tree_item = NULL;
+  if (root_shown_ || parent != model_->GetRoot()) {
+    const NodeDetails* details = GetNodeDetails(parent);
+    if (!details->loaded_children) {
+      if (count == model_->GetChildCount(parent)) {
+        // Reset the treeviews child count. This triggers the treeview to call
+        // us back.
+        TV_ITEM tv_item = {0};
+        tv_item.mask = TVIF_CHILDREN;
+        tv_item.cChildren = count;
+        tv_item.hItem = details->tree_item;
+        TreeView_SetItem(tree_view_, &tv_item);
+      }
+
+      // Ignore the change, we haven't actually created entries in the tree
+      // for the children.
+      return;
+    }
+    parent_tree_item = details->tree_item;
+  }
+
+  // The user has expanded this node, add the items to it.
+  for (int i = 0; i < count; ++i) {
+    if (i == 0 && start == 0) {
+      CreateItem(parent_tree_item, TVI_FIRST, model_->GetChild(parent, 0));
+    } else {
+      TreeModelNode* previous_sibling = model_->GetChild(parent, i + start - 1);
+      CreateItem(parent_tree_item,
+                   GetNodeDetails(previous_sibling)->tree_item,
+                   model_->GetChild(parent, i + start));
+    }
+  }
+}
+
+void TreeView::TreeNodesRemoved(TreeModel* model,
+                                TreeModelNode* parent,
+                                int start,
+                                int count) {
+  DCHECK(parent && start >= 0 && count > 0);
+  HTREEITEM parent_tree_item = GetTreeItemForNodeDuringMutation(parent);
+  if (!parent_tree_item)
+    return;
+
+  // Find the last item. Windows doesn't offer a convenient way to get the
+  // TREEITEM at a particular index, so we iterate.
+  HTREEITEM tree_item = TreeView_GetChild(tree_view_, parent_tree_item);
+  for (int i = 0; i < (start + count - 1); ++i) {
+    tree_item = TreeView_GetNextSibling(tree_view_, tree_item);
+  }
+  // NOTE: the direction doesn't matter here. I've made it backwards to
+  // reinforce we're deleting from the end forward.
+  for (int i = count - 1; i >= 0; --i) {
+    HTREEITEM previous = (start + i) > 0 ?
+        TreeView_GetPrevSibling(tree_view_, tree_item) : NULL;
+    RecursivelyDelete(GetNodeDetailsByTreeItem(tree_item));
+    tree_item = previous;
+  }
+}
+
+namespace {
+
+// Callback function used to compare two items. The first two args are the
+// LPARAMs of the HTREEITEMs being compared. The last arg maps from LPARAM
+// to order. This is invoked from TreeNodeChildrenReordered.
+int CALLBACK CompareTreeItems(LPARAM item1_lparam,
+                              LPARAM item2_lparam,
+                              LPARAM map_as_lparam) {
+  std::map<int, int>& mapping =
+      *reinterpret_cast<std::map<int, int>*>(map_as_lparam);
+  return mapping[static_cast<int>(item1_lparam)] -
+         mapping[static_cast<int>(item2_lparam)];
+}
+
+}  // namespace
+
+void TreeView::TreeNodeChildrenReordered(TreeModel* model,
+                                         TreeModelNode* parent) {
+  DCHECK(parent);
+  if (model_->GetChildCount(parent) <= 1)
+    return;
+
+  TVSORTCB sort_details;
+  sort_details.hParent = GetTreeItemForNodeDuringMutation(parent);
+  if (!sort_details.hParent)
+    return;
+
+  std::map<int, int> lparam_to_order_map;
+  for (int i = 0; i < model_->GetChildCount(parent); ++i) {
+    TreeModelNode* node = model_->GetChild(parent, i);
+    lparam_to_order_map[GetNodeDetails(node)->id] = i;
+  }
+
+  sort_details.lpfnCompare = &CompareTreeItems;
+  sort_details.lParam = reinterpret_cast<LPARAM>(&lparam_to_order_map);
+  TreeView_SortChildrenCB(tree_view_, &sort_details, 0);
+}
+
+void TreeView::TreeNodeChanged(TreeModel* model, TreeModelNode* node) {
+  if (node_to_details_map_.find(node) == node_to_details_map_.end()) {
+    // User hasn't navigated to this entry yet. Ignore the change.
+    return;
+  }
+  const NodeDetails* details = GetNodeDetails(node);
+  TV_ITEM tv_item = {0};
+  tv_item.mask = TVIF_TEXT;
+  tv_item.hItem = details->tree_item;
+  tv_item.pszText = LPSTR_TEXTCALLBACK;
+  TreeView_SetItem(tree_view_, &tv_item);
+}
+
+gfx::Point TreeView::GetKeyboardContextMenuLocation() {
+  int y = height() / 2;
+  if (GetSelectedNode()) {
+    RECT bounds;
+    RECT client_rect;
+    if (TreeView_GetItemRect(tree_view_,
+                             GetNodeDetails(GetSelectedNode())->tree_item,
+                             &bounds, TRUE) &&
+        GetClientRect(tree_view_, &client_rect) &&
+        bounds.bottom >= 0 && bounds.bottom < client_rect.bottom) {
+      y = bounds.bottom;
+    }
+  }
+  gfx::Point screen_loc(0, y);
+  if (UILayoutIsRightToLeft())
+    screen_loc.set_x(width());
+  ConvertPointToScreen(this, &screen_loc);
+  return screen_loc;
+}
+
+HWND TreeView::CreateNativeControl(HWND parent_container) {
+  int style = WS_CHILD | TVS_HASBUTTONS | TVS_HASLINES | TVS_SHOWSELALWAYS;
+  if (!drag_enabled_)
+    style |= TVS_DISABLEDRAGDROP;
+  if (editable_)
+    style |= TVS_EDITLABELS;
+  tree_view_ = ::CreateWindowEx(WS_EX_CLIENTEDGE | GetAdditionalExStyle(),
+                                WC_TREEVIEW,
+                                L"",
+                                style,
+                                0, 0, width(), height(),
+                                parent_container, NULL, NULL, NULL);
+  SetWindowLongPtr(tree_view_, GWLP_USERDATA,
+                   reinterpret_cast<LONG_PTR>(&wrapper_));
+  original_handler_ = win_util::SetWindowProc(tree_view_,
+                                              &TreeWndProc);
+  l10n_util::AdjustUIFontForWindow(tree_view_);
+
+  if (model_) {
+    CreateRootItems();
+    model_->SetObserver(this);
+    image_list_ = CreateImageList();
+    TreeView_SetImageList(tree_view_, image_list_, TVSIL_NORMAL);
+  }
+
+  // Bug 964884: detach the IME attached to this window.
+  // We should attach IMEs only when we need to input CJK strings.
+  ::ImmAssociateContextEx(tree_view_, NULL, 0);
+  return tree_view_;
+}
+
+LRESULT TreeView::OnNotify(int w_param, LPNMHDR l_param) {
+  switch (l_param->code) {
+    case TVN_GETDISPINFO: {
+      // Windows is requesting more information about an item.
+      // WARNING: At the time this is called the tree_item of the NodeDetails
+      // in the maps is NULL.
+      DCHECK(model_);
+      NMTVDISPINFO* info = reinterpret_cast<NMTVDISPINFO*>(l_param);
+      const NodeDetails* details =
+          GetNodeDetailsByID(static_cast<int>(info->item.lParam));
+      if (info->item.mask & TVIF_CHILDREN)
+        info->item.cChildren = model_->GetChildCount(details->node);
+      if (info->item.mask & TVIF_TEXT) {
+        std::wstring text = details->node->GetTitle();
+        DCHECK(info->item.cchTextMax);
+
+        // Adjust the string direction if such adjustment is required.
+        std::wstring localized_text;
+        if (l10n_util::AdjustStringForLocaleDirection(text, &localized_text))
+          text.swap(localized_text);
+
+        wcsncpy_s(info->item.pszText, info->item.cchTextMax, text.c_str(),
+                  _TRUNCATE);
+      }
+      // Instructs windows to cache the values for this node.
+      info->item.mask |= TVIF_DI_SETITEM;
+      // Return value ignored.
+      return 0;
+    }
+
+    case TVN_ITEMEXPANDING: {
+      // Notification that a node is expanding. If we haven't populated the
+      // tree view with the contents of the model, we do it here.
+      DCHECK(model_);
+      NMTREEVIEW* info = reinterpret_cast<NMTREEVIEW*>(l_param);
+      NodeDetails* details =
+          GetNodeDetailsByID(static_cast<int>(info->itemNew.lParam));
+      if (!details->loaded_children) {
+        details->loaded_children = true;
+        for (int i = 0; i < model_->GetChildCount(details->node); ++i)
+          CreateItem(details->tree_item, TVI_LAST,
+                       model_->GetChild(details->node, i));
+      }
+      // Return FALSE to allow the item to be expanded.
+      return FALSE;
+    }
+
+    case TVN_SELCHANGED:
+      if (controller_)
+        controller_->OnTreeViewSelectionChanged(this);
+      break;
+
+    case TVN_BEGINLABELEDIT: {
+      NMTVDISPINFO* info = reinterpret_cast<NMTVDISPINFO*>(l_param);
+      NodeDetails* details =
+          GetNodeDetailsByID(static_cast<int>(info->item.lParam));
+      // Return FALSE to allow editing.
+      if (!controller_ || controller_->CanEdit(this, details->node)) {
+        editing_node_ = details->node;
+        return FALSE;
+      }
+      return TRUE;
+    }
+
+    case TVN_ENDLABELEDIT: {
+      NMTVDISPINFO* info = reinterpret_cast<NMTVDISPINFO*>(l_param);
+      if (info->item.pszText) {
+        // User accepted edit.
+        NodeDetails* details =
+            GetNodeDetailsByID(static_cast<int>(info->item.lParam));
+        model_->SetTitle(details->node, info->item.pszText);
+        editing_node_ = NULL;
+        // Return FALSE so that the tree item doesn't change its text (if the
+        // model changed the value, it should have sent out notification which
+        // will have updated the value).
+        return FALSE;
+      }
+      editing_node_ = NULL;
+      // Return value ignored.
+      return 0;
+    }
+
+    case TVN_KEYDOWN:
+      if (controller_) {
+        NMTVKEYDOWN* key_down_message =
+            reinterpret_cast<NMTVKEYDOWN*>(l_param);
+        controller_->OnTreeViewKeyDown(key_down_message->wVKey);
+      }
+      break;
+
+    default:
+      break;
+  }
+  return 0;
+}
+
+bool TreeView::OnKeyDown(int virtual_key_code) {
+  if (virtual_key_code == VK_F2) {
+    if (!GetEditingNode()) {
+      TreeModelNode* selected_node = GetSelectedNode();
+      if (selected_node)
+        StartEditing(selected_node);
+    }
+    return true;
+  } else if (virtual_key_code == VK_RETURN && !process_enter_) {
+    Widget* widget = GetWidget();
+    DCHECK(widget);
+    FocusManager* fm = FocusManager::GetFocusManager(widget->GetNativeView());
+    DCHECK(fm);
+    Accelerator accelerator(Accelerator(static_cast<int>(virtual_key_code),
+                                        win_util::IsShiftPressed(),
+                                        win_util::IsCtrlPressed(),
+                                        win_util::IsAltPressed()));
+    fm->ProcessAccelerator(accelerator);
+    return true;
+  }
+  return false;
+}
+
+void TreeView::OnContextMenu(const CPoint& location) {
+  if (!GetContextMenuController())
+    return;
+
+  if (location.x == -1 && location.y == -1) {
+    // Let NativeControl's implementation handle keyboard gesture.
+    NativeControl::OnContextMenu(location);
+    return;
+  }
+
+  if (show_context_menu_only_when_node_selected_) {
+    if (!GetSelectedNode())
+      return;
+
+    // Make sure the mouse is over the selected node.
+    TVHITTESTINFO hit_info;
+    gfx::Point local_loc(location);
+    ConvertPointToView(NULL, this, &local_loc);
+    hit_info.pt.x = local_loc.x();
+    hit_info.pt.y = local_loc.y();
+    HTREEITEM hit_item = TreeView_HitTest(tree_view_, &hit_info);
+    if (!hit_item ||
+        GetNodeDetails(GetSelectedNode())->tree_item != hit_item ||
+        (hit_info.flags & (TVHT_ONITEM | TVHT_ONITEMRIGHT |
+                          TVHT_ONITEMINDENT)) == 0) {
+      return;
+    }
+  }
+  ShowContextMenu(location.x, location.y, true);
+}
+
+TreeModelNode* TreeView::GetNodeForTreeItem(HTREEITEM tree_item) {
+  NodeDetails* details = GetNodeDetailsByTreeItem(tree_item);
+  return details ? details->node : NULL;
+}
+
+HTREEITEM TreeView::GetTreeItemForNode(TreeModelNode* node) {
+  NodeDetails* details = GetNodeDetails(node);
+  return details ? details->tree_item : NULL;
+}
+
+void TreeView::DeleteRootItems() {
+  HTREEITEM root = TreeView_GetRoot(tree_view_);
+  if (root) {
+    if (root_shown_) {
+      RecursivelyDelete(GetNodeDetailsByTreeItem(root));
+    } else {
+      do {
+        RecursivelyDelete(GetNodeDetailsByTreeItem(root));
+      } while ((root = TreeView_GetRoot(tree_view_)));
+    }
+  }
+}
+
+void TreeView::CreateRootItems() {
+  DCHECK(model_);
+  TreeModelNode* root = model_->GetRoot();
+  if (root_shown_) {
+    CreateItem(NULL, TVI_LAST, root);
+  } else {
+    for (int i = 0; i < model_->GetChildCount(root); ++i)
+      CreateItem(NULL, TVI_LAST, model_->GetChild(root, i));
+  }
+}
+
+void TreeView::CreateItem(HTREEITEM parent_item,
+                          HTREEITEM after,
+                          TreeModelNode* node) {
+  DCHECK(node);
+  TVINSERTSTRUCT insert_struct = {0};
+  insert_struct.hParent = parent_item;
+  insert_struct.hInsertAfter = after;
+  insert_struct.itemex.mask = TVIF_PARAM | TVIF_CHILDREN | TVIF_TEXT |
+                              TVIF_SELECTEDIMAGE | TVIF_IMAGE;
+  // Call us back for the text.
+  insert_struct.itemex.pszText = LPSTR_TEXTCALLBACK;
+  // And the number of children.
+  insert_struct.itemex.cChildren = I_CHILDRENCALLBACK;
+  // Set the index of the icons to use. These are relative to the imagelist
+  // created in CreateImageList.
+  int icon_index = model_->GetIconIndex(node);
+  if (icon_index == -1) {
+    insert_struct.itemex.iImage = 0;
+    insert_struct.itemex.iSelectedImage = 1;
+  } else {
+    // The first two images are the default ones.
+    insert_struct.itemex.iImage = icon_index + 2;
+    insert_struct.itemex.iSelectedImage = icon_index + 2;
+  }
+  int node_id = next_id_++;
+  insert_struct.itemex.lParam = node_id;
+
+  // Invoking TreeView_InsertItem triggers OnNotify to be called. As such,
+  // we set the map entries before adding the item.
+  NodeDetails* node_details = new NodeDetails(node_id, node);
+
+  node_to_details_map_[node] = node_details;
+  id_to_details_map_[node_id] = node_details;
+
+  node_details->tree_item = TreeView_InsertItem(tree_view_, &insert_struct);
+}
+
+void TreeView::RecursivelyDelete(NodeDetails* node) {
+  DCHECK(node);
+  HTREEITEM item = node->tree_item;
+  DCHECK(item);
+
+  // Recurse through children.
+  for (HTREEITEM child = TreeView_GetChild(tree_view_, item);
+       child ; child = TreeView_GetNextSibling(tree_view_, child)) {
+    RecursivelyDelete(GetNodeDetailsByTreeItem(child));
+  }
+
+  TreeView_DeleteItem(tree_view_, item);
+
+  // finally, it is safe to delete the data for this node.
+  id_to_details_map_.erase(node->id);
+  node_to_details_map_.erase(node->node);
+  delete node;
+}
+
+TreeView::NodeDetails* TreeView::GetNodeDetailsByTreeItem(HTREEITEM tree_item) {
+  DCHECK(tree_view_ && tree_item);
+  TV_ITEM tv_item = {0};
+  tv_item.hItem = tree_item;
+  tv_item.mask = TVIF_PARAM;
+  if (TreeView_GetItem(tree_view_, &tv_item))
+    return GetNodeDetailsByID(static_cast<int>(tv_item.lParam));
+  return NULL;
+}
+
+HIMAGELIST TreeView::CreateImageList() {
+  std::vector<SkBitmap> model_images;
+  model_->GetIcons(&model_images);
+
+  bool rtl = UILayoutIsRightToLeft();
+  // Creates the default image list used for trees.
+  SkBitmap* closed_icon =
+      ResourceBundle::GetSharedInstance().GetBitmapNamed(
+          (rtl ? IDR_FOLDER_CLOSED_RTL : IDR_FOLDER_CLOSED));
+  SkBitmap* opened_icon =
+      ResourceBundle::GetSharedInstance().GetBitmapNamed(
+          (rtl ? IDR_FOLDER_OPEN_RTL : IDR_FOLDER_OPEN));
+  int width = closed_icon->width();
+  int height = closed_icon->height();
+  DCHECK(opened_icon->width() == width && opened_icon->height() == height);
+  HIMAGELIST image_list =
+      ImageList_Create(width, height, ILC_COLOR32, model_images.size() + 2,
+                       model_images.size() + 2);
+  if (image_list) {
+    // NOTE: the order the images are added in effects the selected
+    // image index when adding items to the tree. If you change the
+    // order you'll undoubtedly need to update itemex.iSelectedImage
+    // when the item is added.
+    HICON h_closed_icon = IconUtil::CreateHICONFromSkBitmap(*closed_icon);
+    HICON h_opened_icon = IconUtil::CreateHICONFromSkBitmap(*opened_icon);
+    ImageList_AddIcon(image_list, h_closed_icon);
+    ImageList_AddIcon(image_list, h_opened_icon);
+    DestroyIcon(h_closed_icon);
+    DestroyIcon(h_opened_icon);
+    for (size_t i = 0; i < model_images.size(); ++i) {
+      HICON model_icon = IconUtil::CreateHICONFromSkBitmap(model_images[i]);
+      ImageList_AddIcon(image_list, model_icon);
+      DestroyIcon(model_icon);
+    }
+  }
+  return image_list;
+}
+
+HTREEITEM TreeView::GetTreeItemForNodeDuringMutation(TreeModelNode* node) {
+  if (node_to_details_map_.find(node) == node_to_details_map_.end()) {
+    // User hasn't navigated to this entry yet. Ignore the change.
+    return NULL;
+  }
+  if (!root_shown_ || node != model_->GetRoot()) {
+    const NodeDetails* details = GetNodeDetails(node);
+    if (!details->loaded_children)
+      return NULL;
+    return details->tree_item;
+  }
+  return TreeView_GetRoot(tree_view_);
+}
+
+LRESULT CALLBACK TreeView::TreeWndProc(HWND window,
+                                       UINT message,
+                                       WPARAM w_param,
+                                       LPARAM l_param) {
+  TreeViewWrapper* wrapper = reinterpret_cast<TreeViewWrapper*>(
+      GetWindowLongPtr(window, GWLP_USERDATA));
+  DCHECK(wrapper);
+  TreeView* tree = wrapper->tree_view;
+
+  // We handle the messages WM_ERASEBKGND and WM_PAINT such that we paint into
+  // a DIB first and then perform a BitBlt from the DIB into the underlying
+  // window's DC. This double buffering code prevents the tree view from
+  // flickering during resize.
+  switch (message) {
+    case WM_ERASEBKGND:
+      return 1;
+
+    case WM_PAINT: {
+      ChromeCanvasPaint canvas(window);
+      if (canvas.isEmpty())
+        return 0;
+
+      HDC dc = canvas.beginPlatformPaint();
+      if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) {
+        // ChromeCanvas ends up configuring the DC with a mode of GM_ADVANCED.
+        // For some reason a graphics mode of ADVANCED triggers all the text
+        // to be mirrored when RTL. Set the mode back to COMPATIBLE and
+        // explicitly set the layout. Additionally SetWorldTransform and
+        // COMPATIBLE don't play nicely together. We need to use
+        // SetViewportOrgEx when using a mode of COMPATIBLE.
+        //
+        // Reset the transform to the identify transform. Even though
+        // SetWorldTransform and COMPATIBLE don't play nicely, bits of the
+        // transform still carry over when we set the mode.
+        XFORM xform = {0};
+        xform.eM11 = xform.eM22 = 1;
+        SetWorldTransform(dc, &xform);
+
+        // Set the mode and layout.
+        SetGraphicsMode(dc, GM_COMPATIBLE);
+        SetLayout(dc, LAYOUT_RTL);
+
+        // Transform the viewport such that the origin of the dc is that of
+        // the dirty region. This way when we invoke WM_PRINTCLIENT tree-view
+        // draws the dirty region at the origin of the DC so that when we
+        // copy the bits everything lines up nicely. Without this we end up
+        // copying the upper-left corner to the redraw region.
+        SetViewportOrgEx(dc, -canvas.paintStruct().rcPaint.left,
+                         -canvas.paintStruct().rcPaint.top, NULL);
+      }
+      SendMessage(window, WM_PRINTCLIENT, reinterpret_cast<WPARAM>(dc), 0);
+      if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) {
+        // Reset the origin of the dc back to 0. This way when we copy the bits
+        // over we copy the right bits.
+        SetViewportOrgEx(dc, 0, 0, NULL);
+      }
+      canvas.endPlatformPaint();
+      return 0;
+    }
+
+    case WM_RBUTTONDOWN:
+      if (tree->select_on_right_mouse_down_) {
+        TVHITTESTINFO hit_info;
+        hit_info.pt.x = GET_X_LPARAM(l_param);
+        hit_info.pt.y = GET_Y_LPARAM(l_param);
+        HTREEITEM hit_item = TreeView_HitTest(window, &hit_info);
+        if (hit_item && (hit_info.flags & (TVHT_ONITEM | TVHT_ONITEMRIGHT |
+                                           TVHT_ONITEMINDENT)) != 0)
+          TreeView_SelectItem(tree->tree_view_, hit_item);
+      }
+      // Fall through and let the default handler process as well.
+      break;
+  }
+  WNDPROC handler = tree->original_handler_;
+  DCHECK(handler);
+  return CallWindowProc(handler, window, message, w_param, l_param);
+}
+
+}  // namespace views
diff --git a/views/controls/tree/tree_view.h b/views/controls/tree/tree_view.h
new file mode 100644
index 0000000..1ded058
--- /dev/null
+++ b/views/controls/tree/tree_view.h
@@ -0,0 +1,305 @@
+// Copyright (c) 2006-2008 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 VIEWS_CONTROLS_TREE_TREE_VIEW_H_
+#define VIEWS_CONTROLS_TREE_TREE_VIEW_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "views/controls/native_control.h"
+#include "views/controls/tree/tree_model.h"
+
+namespace views {
+
+class TreeView;
+
+// TreeViewController ---------------------------------------------------------
+
+// Controller for the treeview.
+class TreeViewController {
+ public:
+  // Notification that the selection of the tree view has changed. Use
+  // GetSelectedNode to find the current selection.
+  virtual void OnTreeViewSelectionChanged(TreeView* tree_view) = 0;
+
+  // Returns true if the node can be edited. This is only used if the
+  // TreeView is editable.
+  virtual bool CanEdit(TreeView* tree_view, TreeModelNode* node) {
+    return true;
+  }
+
+  // Invoked when a key is pressed on the tree view.
+  virtual void OnTreeViewKeyDown(unsigned short virtual_keycode) {}
+};
+
+// TreeView -------------------------------------------------------------------
+
+// TreeView displays hierarchical data as returned from a TreeModel. The user
+// can expand, collapse and edit the items. A Controller may be attached to
+// receive notification of selection changes and restrict editing.
+class TreeView : public NativeControl, TreeModelObserver {
+ public:
+  TreeView();
+  virtual ~TreeView();
+
+  // Is dragging enabled? The default is false.
+  void set_drag_enabled(bool drag_enabled) { drag_enabled_ = drag_enabled; }
+  bool drag_enabled() const { return drag_enabled_; }
+
+  // Sets the model. TreeView does not take ownership of the model.
+  void SetModel(TreeModel* model);
+  TreeModel* model() const { return model_; }
+
+  // Sets whether the user can edit the nodes. The default is true. If true,
+  // the Controller is queried to determine if a particular node can be edited.
+  void SetEditable(bool editable);
+
+  // Edits the specified node. This cancels the current edit and expands
+  // all parents of node.
+  void StartEditing(TreeModelNode* node);
+
+  // Cancels the current edit. Does nothing if not editing.
+  void CancelEdit();
+
+  // Commits the current edit. Does nothing if not editing.
+  void CommitEdit();
+
+  // If the user is editing a node, it is returned. If the user is not
+  // editing a node, NULL is returned.
+  TreeModelNode* GetEditingNode();
+
+  // Selects the specified node. This expands all the parents of node.
+  void SetSelectedNode(TreeModelNode* node);
+
+  // Returns the selected node, or NULL if nothing is selected.
+  TreeModelNode* GetSelectedNode();
+
+  // Make sure node and all its parents are expanded.
+  void Expand(TreeModelNode* node);
+
+  // Convenience to expand ALL nodes in the tree.
+  void ExpandAll();
+
+  // Invoked from ExpandAll(). Expands the supplied node and recursively
+  // invokes itself with all children.
+  void ExpandAll(TreeModelNode* node);
+
+  // Returns true if the specified node is expanded.
+  bool IsExpanded(TreeModelNode* node);
+
+  // Sets whether the root is shown. If true, the root node of the tree is
+  // shown, if false only the children of the root are shown. The default is
+  // true.
+  void SetRootShown(bool root_visible);
+
+  // TreeModelObserver methods. Don't call these directly, instead your model
+  // should notify the observer TreeView adds to it.
+  virtual void TreeNodesAdded(TreeModel* model,
+                              TreeModelNode* parent,
+                              int start,
+                              int count);
+  virtual void TreeNodesRemoved(TreeModel* model,
+                                TreeModelNode* parent,
+                                int start,
+                                int count);
+  virtual void TreeNodeChildrenReordered(TreeModel* model,
+                                         TreeModelNode* parent);
+  virtual void TreeNodeChanged(TreeModel* model, TreeModelNode* node);
+
+  // Sets the controller, which may be null. TreeView does not take ownership
+  // of the controller.
+  void SetController(TreeViewController* controller) {
+    controller_ = controller;
+  }
+
+  // Sets whether enter is processed when not editing. If true, enter will
+  // expand/collapse the node. If false, enter is passed to the focus manager
+  // so that an enter accelerator can be enabled. The default is false.
+  //
+  // NOTE: Changing this has no effect after the hwnd has been created.
+  void SetProcessesEnter(bool process_enter) {
+    process_enter_ = process_enter;
+  }
+  bool GetProcessedEnter() { return process_enter_; }
+
+  // Sets when the ContextMenuController is notified. If true, the
+  // ContextMenuController is only notified when a node is selected and the
+  // mouse is over a node. The default is true.
+  void SetShowContextMenuOnlyWhenNodeSelected(bool value) {
+    show_context_menu_only_when_node_selected_ = value;
+  }
+  bool GetShowContextMenuOnlyWhenNodeSelected() {
+    return show_context_menu_only_when_node_selected_;
+  }
+
+  // If true, a right click selects the node under the mouse. The default
+  // is true.
+  void SetSelectOnRightMouseDown(bool value) {
+    select_on_right_mouse_down_ = value;
+  }
+  bool GetSelectOnRightMouseDown() { return select_on_right_mouse_down_; }
+
+ protected:
+  // Overriden to return a location based on the selected node.
+  virtual gfx::Point GetKeyboardContextMenuLocation();
+
+  // Creates and configures the tree_view.
+  virtual HWND CreateNativeControl(HWND parent_container);
+
+  // Invoked when the native control sends a WM_NOTIFY message to its parent.
+  // Handles a variety of potential TreeView messages.
+  virtual LRESULT OnNotify(int w_param, LPNMHDR l_param);
+
+  // Yes, we want to be notified of key down for two reasons. To circumvent
+  // VK_ENTER from toggling the expaned state when processes_enter_ is false,
+  // and to have F2 start editting.
+  virtual bool NotifyOnKeyDown() const { return true; }
+  virtual bool OnKeyDown(int virtual_key_code);
+
+  virtual void OnContextMenu(const CPoint& location);
+
+  // Returns the TreeModelNode for |tree_item|.
+  TreeModelNode* GetNodeForTreeItem(HTREEITEM tree_item);
+
+  // Returns the tree item for |node|.
+  HTREEITEM GetTreeItemForNode(TreeModelNode* node);
+
+ private:
+  // See notes in TableView::TableViewWrapper for why this is needed.
+  struct TreeViewWrapper {
+    explicit TreeViewWrapper(TreeView* view) : tree_view(view) { }
+    TreeView* tree_view;
+  };
+
+  // Internally used to track the state of nodes. NodeDetails are lazily created
+  // as the user expands nodes.
+  struct NodeDetails {
+    NodeDetails(int id, TreeModelNode* node)
+        : id(id), node(node), tree_item(NULL), loaded_children(false) {}
+
+    // Unique identifier for the node. This corresponds to the lParam of
+    // the tree item.
+    const int id;
+
+    // The node from the model.
+    TreeModelNode* node;
+
+    // From the native TreeView.
+    //
+    // This should be treated as const, but can't due to timing in creating the
+    // entry.
+    HTREEITEM tree_item;
+
+    // Whether the children have been loaded.
+    bool loaded_children;
+  };
+
+  // Deletes the root items from the treeview. This is used when the model
+  // changes.
+  void DeleteRootItems();
+
+  // Creates the root items in the treeview from the model. This is used when
+  // the model changes.
+  void CreateRootItems();
+
+  // Creates and adds an item to the treeview. parent_item identifies the
+  // parent and is null for root items. after dictates where among the
+  // children of parent_item the item is to be created. node is the node from
+  // the model.
+  void CreateItem(HTREEITEM parent_item, HTREEITEM after, TreeModelNode* node);
+
+  // Removes entries from the map for item. This method will also
+  // remove the items from the TreeView because the process of
+  // deleting an item will send an TVN_GETDISPINFO message, consulting
+  // our internal map data.
+  void RecursivelyDelete(NodeDetails* node);
+
+  // Returns the NodeDetails by node from the model.
+  NodeDetails* GetNodeDetails(TreeModelNode* node) {
+    DCHECK(node &&
+           node_to_details_map_.find(node) != node_to_details_map_.end());
+    return node_to_details_map_[node];
+  }
+
+  // Returns the NodeDetails by identifier (lparam of the HTREEITEM).
+  NodeDetails* GetNodeDetailsByID(int id) {
+    DCHECK(id_to_details_map_.find(id) != id_to_details_map_.end());
+    return id_to_details_map_[id];
+  }
+
+  // Returns the NodeDetails by HTREEITEM.
+  NodeDetails* GetNodeDetailsByTreeItem(HTREEITEM tree_item);
+
+  // Creates the image list to use for the tree.
+  HIMAGELIST CreateImageList();
+
+  // Returns the HTREEITEM for |node|. This is intended to be called when a
+  // model mutation event occur with |node| as the parent. This returns null
+  // if the user has never expanded |node| or all of its parents.
+  HTREEITEM GetTreeItemForNodeDuringMutation(TreeModelNode* node);
+
+  // The window function installed on the treeview.
+  static LRESULT CALLBACK TreeWndProc(HWND window,
+                                      UINT message,
+                                      WPARAM w_param,
+                                      LPARAM l_param);
+
+  // Handle to the tree window.
+  HWND tree_view_;
+
+  // The model, may be null.
+  TreeModel* model_;
+
+  // Maps from id to NodeDetails.
+  std::map<int,NodeDetails*> id_to_details_map_;
+
+  // Maps from model entry to NodeDetails.
+  std::map<TreeModelNode*,NodeDetails*> node_to_details_map_;
+
+  // Whether the user can edit the items.
+  bool editable_;
+
+  // Next id to create. Any time an item is added this is incremented by one.
+  int next_id_;
+
+  // The controller.
+  TreeViewController* controller_;
+
+  // Node being edited. If null, not editing.
+  TreeModelNode* editing_node_;
+
+  // Whether or not the root is shown in the tree.
+  bool root_shown_;
+
+  // Whether enter should be processed by the tree when not editing.
+  bool process_enter_;
+
+  // Whether we notify context menu controller only when mouse is over node
+  // and node is selected.
+  bool show_context_menu_only_when_node_selected_;
+
+  // Whether the selection is changed on right mouse down.
+  bool select_on_right_mouse_down_;
+
+  // A wrapper around 'this', used for subclassing the TreeView control.
+  TreeViewWrapper wrapper_;
+
+  // Original handler installed on the TreeView.
+  WNDPROC original_handler_;
+
+  bool drag_enabled_;
+
+  // Did the model return a non-empty set of icons from GetIcons?
+  bool has_custom_icons_;
+
+  HIMAGELIST image_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(TreeView);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_CONTROLS_TREE_TREE_VIEW_H_
diff --git a/views/event.cc b/views/event.cc
new file mode 100644
index 0000000..8e6a0f15
--- /dev/null
+++ b/views/event.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2006-2008 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 "views/event.h"
+
+#include "views/view.h"
+
+namespace views {
+
+Event::Event(EventType type, int flags)
+    : type_(type),
+#if defined(OS_WIN)
+      time_stamp_(GetTickCount()),
+#else
+      time_stamp_(0),
+#endif
+      flags_(flags) {
+}
+
+LocatedEvent::LocatedEvent(const LocatedEvent& model, View* from, View* to)
+    : Event(model),
+      location_(model.location_) {
+  if (to)
+    View::ConvertPointToView(from, to, &location_);
+}
+
+MouseEvent::MouseEvent(EventType type,
+                       View* from,
+                       View* to,
+                       const gfx::Point &l,
+                       int flags)
+    : LocatedEvent(LocatedEvent(type, gfx::Point(l.x(), l.y()), flags),
+                                from,
+                                to) {
+};
+
+MouseEvent::MouseEvent(const MouseEvent& model, View* from, View* to)
+    : LocatedEvent(model, from, to) {
+}
+
+}  // namespace views
diff --git a/views/event.h b/views/event.h
new file mode 100644
index 0000000..f0ab24a8
--- /dev/null
+++ b/views/event.h
@@ -0,0 +1,324 @@
+// Copyright (c) 2006-2008 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 VIEWS_EVENT_H_
+#define VIEWS_EVENT_H_
+
+#include "base/basictypes.h"
+
+#if defined(OS_LINUX)
+#include <gdk/gdk.h>
+#endif
+
+#include "base/gfx/point.h"
+
+class OSExchangeData;
+
+namespace views {
+
+class View;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Event class
+//
+// An event encapsulates an input event that can be propagated into view
+// hierarchies. An event has a type, some flags and a time stamp.
+//
+// Each major event type has a corresponding Event subclass.
+//
+// Events are immutable but support copy
+//
+////////////////////////////////////////////////////////////////////////////////
+class Event {
+ public:
+  // Event types. (prefixed because of a conflict with windows headers)
+  enum EventType { ET_UNKNOWN = 0,
+                   ET_MOUSE_PRESSED,
+                   ET_MOUSE_DRAGGED,
+                   ET_MOUSE_RELEASED,
+                   ET_MOUSE_MOVED,
+                   ET_MOUSE_ENTERED,
+                   ET_MOUSE_EXITED,
+                   ET_KEY_PRESSED,
+                   ET_KEY_RELEASED,
+                   ET_MOUSEWHEEL,
+                   ET_DROP_TARGET_EVENT };
+
+  // Event flags currently supported
+  enum EventFlags { EF_SHIFT_DOWN         = 1 << 0,
+                    EF_CONTROL_DOWN       = 1 << 1,
+                    EF_ALT_DOWN           = 1 << 2,
+                    EF_LEFT_BUTTON_DOWN   = 1 << 3,
+                    EF_MIDDLE_BUTTON_DOWN = 1 << 4,
+                    EF_RIGHT_BUTTON_DOWN  = 1 << 5 };
+
+  // Return the event type
+  EventType GetType() const {
+    return type_;
+  }
+
+  // Return the event time stamp in ticks
+  int GetTimeStamp() const {
+    return time_stamp_;
+  }
+
+  // Return the flags
+  int GetFlags() const {
+    return flags_;
+  }
+
+  void set_flags(int flags) {
+    flags_ = flags;
+  }
+
+  // Return whether the shift modifier is down
+  bool IsShiftDown() const {
+    return (flags_ & EF_SHIFT_DOWN) != 0;
+  }
+
+  // Return whether the control modifier is down
+  bool IsControlDown() const {
+    return (flags_ & EF_CONTROL_DOWN) != 0;
+  }
+
+  // Return whether the alt modifier is down
+  bool IsAltDown() const {
+    return (flags_ & EF_ALT_DOWN) != 0;
+  }
+
+#if defined(OS_WIN)
+  // Returns the EventFlags in terms of windows flags.
+  int GetWindowsFlags() const;
+
+  // Convert windows flags to views::Event flags
+  static int ConvertWindowsFlags(uint32 win_flags);
+#elif defined(OS_LINUX)
+  // Convert the state member on a GdkEvent to views::Event flags
+  static int GetFlagsFromGdkState(int state);
+#endif
+
+ protected:
+  Event(EventType type, int flags);
+
+  Event(const Event& model)
+      : type_(model.GetType()),
+        time_stamp_(model.GetTimeStamp()),
+        flags_(model.GetFlags()) {
+  }
+
+ private:
+  void operator=(const Event&);
+
+  EventType type_;
+  int time_stamp_;
+  int flags_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// LocatedEvent class
+//
+// A generic event that is used for any events that is located at a specific
+// position in the screen.
+//
+////////////////////////////////////////////////////////////////////////////////
+class LocatedEvent : public Event {
+ public:
+  LocatedEvent(EventType type, const gfx::Point& location, int flags)
+      : Event(type, flags),
+        location_(location) {
+  }
+
+  // Create a new LocatedEvent which is identical to the provided model.
+  // If from / to views are provided, the model location will be converted
+  // from 'from' coordinate system to 'to' coordinate system
+  LocatedEvent(const LocatedEvent& model, View* from, View* to);
+
+  // Returns the X location.
+  int x() const {
+    return location_.x();
+  }
+
+  // Returns the Y location.
+  int y() const {
+    return location_.y();
+  }
+
+  // Returns the location.
+  const gfx::Point& location() const {
+    return location_;
+  }
+
+ private:
+  gfx::Point location_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// MouseEvent class
+//
+// A mouse event is used for any input event related to the mouse.
+//
+////////////////////////////////////////////////////////////////////////////////
+class MouseEvent : public LocatedEvent {
+ public:
+  // Flags specific to mouse events
+  enum MouseEventFlags {
+    EF_IS_DOUBLE_CLICK = 1 << 16,
+    EF_IS_NON_CLIENT = 1 << 17
+  };
+
+  // Create a new mouse event
+  MouseEvent(EventType type, int x, int y, int flags)
+      : LocatedEvent(type, gfx::Point(x, y), flags) {
+  }
+
+  // Create a new mouse event from a type and a point. If from / to views
+  // are provided, the point will be converted from 'from' coordinate system to
+  // 'to' coordinate system.
+  MouseEvent(EventType type,
+             View* from,
+             View* to,
+             const gfx::Point &l,
+             int flags);
+
+  // Create a new MouseEvent which is identical to the provided model.
+  // If from / to views are provided, the model location will be converted
+  // from 'from' coordinate system to 'to' coordinate system
+  MouseEvent(const MouseEvent& model, View* from, View* to);
+
+  // Conveniences to quickly test what button is down
+  bool IsOnlyLeftMouseButton() const {
+    return (GetFlags() & EF_LEFT_BUTTON_DOWN) &&
+      !(GetFlags() & (EF_MIDDLE_BUTTON_DOWN | EF_RIGHT_BUTTON_DOWN));
+  }
+
+  bool IsLeftMouseButton() const {
+    return (GetFlags() & EF_LEFT_BUTTON_DOWN) != 0;
+  }
+
+  bool IsOnlyMiddleMouseButton() const {
+    return (GetFlags() & EF_MIDDLE_BUTTON_DOWN) &&
+      !(GetFlags() & (EF_LEFT_BUTTON_DOWN | EF_RIGHT_BUTTON_DOWN));
+  }
+
+  bool IsMiddleMouseButton() const {
+    return (GetFlags() & EF_MIDDLE_BUTTON_DOWN) != 0;
+  }
+
+  bool IsOnlyRightMouseButton() const {
+    return (GetFlags() & EF_RIGHT_BUTTON_DOWN) &&
+      !(GetFlags() & (EF_LEFT_BUTTON_DOWN | EF_MIDDLE_BUTTON_DOWN));
+  }
+
+  bool IsRightMouseButton() const {
+    return (GetFlags() & EF_RIGHT_BUTTON_DOWN) != 0;
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(MouseEvent);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// KeyEvent class
+//
+// A key event is used for any input event related to the keyboard.
+// Note: this event is about key pressed, not typed characters.
+//
+////////////////////////////////////////////////////////////////////////////////
+class KeyEvent : public Event {
+ public:
+#if defined(OS_WIN)
+  // Create a new key event
+  KeyEvent(EventType type, int ch, int repeat_count, int message_flags);
+#elif defined(OS_LINUX)
+  KeyEvent(GdkEventKey* event);
+#endif
+
+  int GetCharacter() const {
+    return character_;
+  }
+
+#if defined(OS_WIN)
+  bool IsExtendedKey() const;
+#endif
+
+  int GetRepeatCount() const {
+    return repeat_count_;
+  }
+
+ private:
+#if defined(OS_WIN)
+  int GetKeyStateFlags() const;
+#endif
+
+  int character_;
+  int repeat_count_;
+  int message_flags_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(KeyEvent);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// MouseWheelEvent class
+//
+// A MouseWheelEvent is used to propagate mouse wheel user events
+//
+////////////////////////////////////////////////////////////////////////////////
+class MouseWheelEvent : public LocatedEvent {
+ public:
+  // Create a new key event
+  MouseWheelEvent(int offset, int x, int y, int flags)
+      : LocatedEvent(ET_MOUSEWHEEL, gfx::Point(x, y), flags),
+        offset_(offset) {
+  }
+
+  int GetOffset() const {
+    return offset_;
+  }
+
+ private:
+  int offset_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(MouseWheelEvent);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// DropTargetEvent class
+//
+// A DropTargetEvent is sent to the view the mouse is over during a drag and
+// drop operation.
+//
+////////////////////////////////////////////////////////////////////////////////
+class DropTargetEvent : public LocatedEvent {
+ public:
+  DropTargetEvent(const OSExchangeData& data,
+                  int x,
+                  int y,
+                  int source_operations)
+      : LocatedEvent(ET_DROP_TARGET_EVENT, gfx::Point(x, y), 0),
+        data_(data),
+        source_operations_(source_operations) {
+  }
+
+  // Data associated with the drag/drop session.
+  const OSExchangeData& GetData() const { return data_; }
+
+  // Bitmask of supported DragDropTypes::DragOperation by the source.
+  int GetSourceOperations() const { return source_operations_; }
+
+ private:
+  const OSExchangeData& data_;
+  int source_operations_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(DropTargetEvent);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_EVENT_H_
diff --git a/views/event_gtk.cc b/views/event_gtk.cc
new file mode 100644
index 0000000..ac5a2ce
--- /dev/null
+++ b/views/event_gtk.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2009 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 "views/event.h"
+
+namespace views {
+
+KeyEvent::KeyEvent(GdkEventKey* event)
+    : Event(event->type == GDK_KEY_PRESS ?
+            Event::ET_KEY_PRESSED : Event::ET_KEY_RELEASED,
+            GetFlagsFromGdkState(event->state)),
+      // TODO(erg): All these values are iffy.
+      character_(event->keyval),
+      repeat_count_(0),
+      message_flags_(0) {
+}
+
+int Event::GetFlagsFromGdkState(int state) {
+  int flags = 0;
+  if (state & GDK_CONTROL_MASK)
+    flags |= Event::EF_CONTROL_DOWN;
+  if (state & GDK_SHIFT_MASK)
+    flags |= Event::EF_SHIFT_DOWN;
+  if (state & GDK_MOD1_MASK)
+    flags |= Event::EF_ALT_DOWN;
+  if (state & GDK_BUTTON1_MASK)
+    flags |= Event::EF_LEFT_BUTTON_DOWN;
+  if (state & GDK_BUTTON2_MASK)
+    flags |= Event::EF_MIDDLE_BUTTON_DOWN;
+  if (state & GDK_BUTTON3_MASK)
+    flags |= Event::EF_RIGHT_BUTTON_DOWN;
+  return flags;
+}
+
+}  // namespace views
diff --git a/views/event_win.cc b/views/event_win.cc
new file mode 100644
index 0000000..28d1330
--- /dev/null
+++ b/views/event_win.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2009 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 "views/event.h"
+
+#include <windows.h>
+
+namespace views {
+
+int Event::GetWindowsFlags() const {
+  // TODO: need support for x1/x2.
+  int result = 0;
+  result |= (flags_ & EF_SHIFT_DOWN) ? MK_SHIFT : 0;
+  result |= (flags_ & EF_CONTROL_DOWN) ? MK_CONTROL : 0;
+  result |= (flags_ & EF_LEFT_BUTTON_DOWN) ? MK_LBUTTON : 0;
+  result |= (flags_ & EF_MIDDLE_BUTTON_DOWN) ? MK_MBUTTON : 0;
+  result |= (flags_ & EF_RIGHT_BUTTON_DOWN) ? MK_RBUTTON : 0;
+  return result;
+}
+
+//static
+int Event::ConvertWindowsFlags(UINT win_flags) {
+  int r = 0;
+  if (win_flags & MK_CONTROL)
+    r |= EF_CONTROL_DOWN;
+  if (win_flags & MK_SHIFT)
+    r |= EF_SHIFT_DOWN;
+  if (GetKeyState(VK_MENU) < 0)
+    r |= EF_ALT_DOWN;
+  if (win_flags & MK_LBUTTON)
+    r |= EF_LEFT_BUTTON_DOWN;
+  if (win_flags & MK_MBUTTON)
+    r |= EF_MIDDLE_BUTTON_DOWN;
+  if (win_flags & MK_RBUTTON)
+    r |= EF_RIGHT_BUTTON_DOWN;
+  return r;
+}
+
+KeyEvent::KeyEvent(EventType type, int ch, int repeat_count, int message_flags)
+    : Event(type, GetKeyStateFlags()),
+      character_(ch),
+      repeat_count_(repeat_count),
+      message_flags_(message_flags) {
+      }
+
+int KeyEvent::GetKeyStateFlags() const {
+  // Windows Keyboard messages don't come with control key state as parameters
+  // like mouse messages do, so we need to explicitly probe for these key
+  // states.
+  int flags = 0;
+  if (GetKeyState(VK_MENU) & 0x80)
+    flags |= Event::EF_ALT_DOWN;
+  if (GetKeyState(VK_SHIFT) & 0x80)
+    flags |= Event::EF_SHIFT_DOWN;
+  if (GetKeyState(VK_CONTROL) & 0x80)
+    flags |= Event::EF_CONTROL_DOWN;
+  return flags;
+}
+
+bool KeyEvent::IsExtendedKey() const {
+  return (message_flags_ & KF_EXTENDED) == KF_EXTENDED;
+}
+
+}  // namespace views
diff --git a/views/fill_layout.cc b/views/fill_layout.cc
new file mode 100644
index 0000000..7bd1430a
--- /dev/null
+++ b/views/fill_layout.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2009 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 "views/fill_layout.h"
+
+#include "base/logging.h"
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+// FillLayout
+
+FillLayout::FillLayout() {
+}
+
+FillLayout::~FillLayout() {
+}
+
+void FillLayout::Layout(View* host) {
+  if (host->GetChildViewCount() == 0)
+    return;
+
+  View* frame_view = host->GetChildViewAt(0);
+  frame_view->SetBounds(0, 0, host->width(), host->height());
+}
+
+gfx::Size FillLayout::GetPreferredSize(View* host) {
+  DCHECK(host->GetChildViewCount() == 1);
+  return host->GetChildViewAt(0)->GetPreferredSize();
+}
+
+}  // namespace views
diff --git a/views/fill_layout.h b/views/fill_layout.h
new file mode 100644
index 0000000..e47a639
--- /dev/null
+++ b/views/fill_layout.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2009 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 VIEWS_FILL_LAYOUT_H_
+#define VIEWS_FILL_LAYOUT_H_
+
+#include "views/layout_manager.h"
+#include "views/view.h"
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// FillLayout
+//  A simple LayoutManager that causes the associated view's one child to be
+//  sized to match the bounds of its parent.
+//
+///////////////////////////////////////////////////////////////////////////////
+class FillLayout : public LayoutManager {
+ public:
+  FillLayout();
+  virtual ~FillLayout();
+
+  // Overridden from LayoutManager:
+  virtual void Layout(View* host);
+  virtual gfx::Size GetPreferredSize(View* host);
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(FillLayout);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_FILL_LAYOUT_H_
diff --git a/views/focus/external_focus_tracker.cc b/views/focus/external_focus_tracker.cc
new file mode 100644
index 0000000..8f8bfdf
--- /dev/null
+++ b/views/focus/external_focus_tracker.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2006-2008 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 "views/focus/external_focus_tracker.h"
+
+#include "views/view.h"
+#include "views/focus/view_storage.h"
+
+namespace views {
+
+ExternalFocusTracker::ExternalFocusTracker(View* parent_view,
+                                           FocusManager* focus_manager)
+    : focus_manager_(focus_manager),
+      parent_view_(parent_view) {
+  view_storage_ = ViewStorage::GetSharedInstance();
+  last_focused_view_storage_id_ = view_storage_->CreateStorageID();
+  // Store the view which is focused when we're created.
+  StartTracking();
+}
+
+ExternalFocusTracker::~ExternalFocusTracker() {
+  view_storage_->RemoveView(last_focused_view_storage_id_);
+  if (focus_manager_)
+    focus_manager_->RemoveFocusChangeListener(this);
+}
+
+void ExternalFocusTracker::FocusWillChange(View* focused_before,
+                                           View* focused_now) {
+  if (focused_now && !parent_view_->IsParentOf(focused_now) &&
+      parent_view_ != focused_now) {
+    // Store the newly focused view.
+    StoreLastFocusedView(focused_now);
+  }
+}
+
+void ExternalFocusTracker::FocusLastFocusedExternalView() {
+  View* last_focused_view =
+      view_storage_->RetrieveView(last_focused_view_storage_id_);
+  if (last_focused_view)
+    last_focused_view->RequestFocus();
+}
+
+void ExternalFocusTracker::SetFocusManager(FocusManager* focus_manager) {
+  if (focus_manager_)
+    focus_manager_->RemoveFocusChangeListener(this);
+  focus_manager_ = focus_manager;
+  if (focus_manager_)
+    StartTracking();
+}
+
+void ExternalFocusTracker::StoreLastFocusedView(View* view) {
+  view_storage_->RemoveView(last_focused_view_storage_id_);
+  // If the view is NULL, remove the last focused view from storage, but don't
+  // try to store NULL.
+  if (view != NULL)
+    view_storage_->StoreView(last_focused_view_storage_id_, view);
+}
+
+void ExternalFocusTracker::StartTracking() {
+  StoreLastFocusedView(focus_manager_->GetFocusedView());
+  focus_manager_->AddFocusChangeListener(this);
+}
+
+}  // namespace views
diff --git a/views/focus/external_focus_tracker.h b/views/focus/external_focus_tracker.h
new file mode 100644
index 0000000..22e9b7e
--- /dev/null
+++ b/views/focus/external_focus_tracker.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2006-2008 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 VIEWS_FOCUS_EXTERNAL_FOCUS_TRACKER_H_
+#define VIEWS_FOCUS_EXTERNAL_FOCUS_TRACKER_H_
+
+#include "views/focus/focus_manager.h"
+
+namespace views {
+
+class View;
+class ViewStorage;
+
+// ExternalFocusTracker tracks the last focused view which belongs to the
+// provided focus manager and is not either the provided parent view or one of
+// its descendants. This is generally used if the parent view want to return
+// focus to some other view once it is dismissed. The parent view and the focus
+// manager must exist for the duration of the tracking. If the focus manager
+// must be deleted before this object is deleted, make sure to call
+// SetFocusManager(NULL) first.
+//
+// Typical use: When a view is added to the view hierarchy, it instantiates an
+// ExternalFocusTracker and passes in itself and its focus manager. Then,
+// when that view wants to return focus to the last focused view which is not
+// itself and not a descandant of itself, (usually when it is being closed)
+// it calls FocusLastFocusedExternalView.
+class ExternalFocusTracker : public FocusChangeListener {
+ public:
+  ExternalFocusTracker(View* parent_view, FocusManager* focus_manager);
+
+  virtual ~ExternalFocusTracker();
+  // FocusChangeListener implementation.
+  virtual void FocusWillChange(View* focused_before, View* focused_now);
+
+  // Focuses last focused view which is not a child of parent view and is not
+  // parent view itself. Returns true if focus for a view was requested, false
+  // otherwise.
+  void FocusLastFocusedExternalView();
+
+  // Sets the focus manager whose focus we are tracking. |focus_manager| can
+  // be NULL, but no focus changes will be tracked. This is useful if the focus
+  // manager went away, but you might later want to start tracking with a new
+  // manager later, or call FocusLastFocusedExternalView to focus the previous
+  // view.
+  void SetFocusManager(FocusManager* focus_manager);
+
+ private:
+  // Store the provided view. This view will be focused when
+  // FocusLastFocusedExternalView is called.
+  void StoreLastFocusedView(View* view);
+
+  // Store the currently focused view for our view manager and register as a
+  // listener for future focus changes.
+  void StartTracking();
+
+  // Focus manager which we are a listener for.
+  FocusManager* focus_manager_;
+
+  // ID of the last focused view, which we store in view_storage_.
+  int last_focused_view_storage_id_;
+
+  // Used to store the last focused view which is not a child of
+  // ExternalFocusTracker.
+  ViewStorage* view_storage_;
+
+  // The parent view of views which we should not track focus changes to. We
+  // also do not track changes to parent_view_ itself.
+  View* parent_view_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ExternalFocusTracker);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_FOCUS_EXTERNAL_FOCUS_TRACKER_H_
diff --git a/views/focus/focus_manager.cc b/views/focus/focus_manager.cc
new file mode 100644
index 0000000..5653e7a
--- /dev/null
+++ b/views/focus/focus_manager.cc
@@ -0,0 +1,716 @@
+// Copyright (c) 2006-2008 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 <algorithm>
+
+#include "base/histogram.h"
+#include "base/logging.h"
+#include "base/win_util.h"
+#include "chrome/browser/renderer_host/render_widget_host_view_win.h"
+#include "views/accelerator.h"
+#include "views/focus/focus_manager.h"
+#include "views/focus/view_storage.h"
+#include "views/view.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+
+// The following keys are used in SetProp/GetProp to associate additional
+// information needed for focus tracking with a window.
+
+// Maps to the FocusManager instance for a top level window. See
+// CreateFocusManager/DestoryFocusManager for usage.
+static const wchar_t* const kFocusManagerKey = L"__VIEW_CONTAINER__";
+
+// Maps to the View associated with a window.
+// We register views with window so we can:
+// - keep in sync the native focus with the view focus (when the native
+//   component gets the focus, we get the WM_SETFOCUS event and we can focus the
+//   associated view).
+// - prevent tab key events from being sent to views.
+static const wchar_t* const kViewKey = L"__CHROME_VIEW__";
+
+// A property set to 1 to indicate whether the focus manager has subclassed that
+// window.  We are doing this to ensure we are not subclassing several times.
+// Subclassing twice is not a problem if no one is subclassing the HWND between
+// the 2 subclassings (the 2nd subclassing is ignored since the WinProc is the
+// same as the current one).  However if some other app goes and subclasses the
+// HWND between the 2 subclassings, we will end up subclassing twice.
+// This flag lets us test that whether we have or not subclassed yet.
+static const wchar_t* const kFocusSubclassInstalled =
+    L"__FOCUS_SUBCLASS_INSTALLED__";
+
+namespace views {
+
+// Callback installed via InstallFocusSubclass.
+static LRESULT CALLBACK FocusWindowCallback(HWND window, UINT message,
+                                            WPARAM wParam, LPARAM lParam) {
+  if (!::IsWindow(window)) {
+    // QEMU has reported crashes when calling GetProp (this seems to happen for
+    // some weird messages, not sure what they are).
+    // Here we are just trying to avoid the crasher.
+    NOTREACHED();
+    return 0;
+  }
+
+  WNDPROC original_handler = win_util::GetSuperclassWNDPROC(window);
+  DCHECK(original_handler);
+  FocusManager* focus_manager = FocusManager::GetFocusManager(window);
+  // There are cases when we have no FocusManager for the window. This happens
+  // because we subclass certain windows (such as the TabContents window)
+  // but that window may not have an associated FocusManager.
+  if (focus_manager) {
+    switch (message) {
+      case WM_SETFOCUS:
+        if (!focus_manager->OnSetFocus(window))
+          return 0;
+        break;
+      case WM_NCDESTROY:
+        if (!focus_manager->OnNCDestroy(window))
+          return 0;
+        break;
+      case WM_ACTIVATE: {
+        // We call the DefWindowProc before calling OnActivate as some of our
+        // windows need the OnActivate notifications.  The default activation on
+        // the window causes it to focus the main window, and since
+        // FocusManager::OnActivate attempts to restore the focused view, it
+        // needs to be called last so the focus it is setting does not get
+        // overridden.
+        LRESULT result = CallWindowProc(original_handler, window, WM_ACTIVATE,
+                                        wParam, lParam);
+        if (!focus_manager->OnPostActivate(window,
+                                           LOWORD(wParam), HIWORD(wParam)))
+          return 0;
+        return result;
+      }
+      default:
+        break;
+    }
+  }
+  return CallWindowProc(original_handler, window, message, wParam, lParam);
+}
+
+// FocusManager -----------------------------------------------------
+
+// static
+FocusManager* FocusManager::CreateFocusManager(HWND window,
+                                               RootView* root_view) {
+  DCHECK(window);
+  DCHECK(root_view);
+  InstallFocusSubclass(window, NULL);
+  FocusManager* focus_manager = new FocusManager(window, root_view);
+  SetProp(window, kFocusManagerKey, focus_manager);
+
+  return focus_manager;
+}
+
+// static
+void FocusManager::InstallFocusSubclass(HWND window, View* view) {
+  DCHECK(window);
+
+  bool already_subclassed =
+      reinterpret_cast<bool>(GetProp(window,
+                                     kFocusSubclassInstalled));
+  if (already_subclassed &&
+      !win_util::IsSubclassed(window, &FocusWindowCallback)) {
+    NOTREACHED() << "window sub-classed by someone other than the FocusManager";
+    // Track in UMA so we know if this case happens.
+    UMA_HISTOGRAM_COUNTS("FocusManager.MultipleSubclass", 1);
+  } else {
+    win_util::Subclass(window, &FocusWindowCallback);
+    SetProp(window, kFocusSubclassInstalled, reinterpret_cast<HANDLE>(true));
+  }
+  if (view)
+    SetProp(window, kViewKey, view);
+}
+
+void FocusManager::UninstallFocusSubclass(HWND window) {
+  DCHECK(window);
+  if (win_util::Unsubclass(window, &FocusWindowCallback)) {
+    RemoveProp(window, kViewKey);
+    RemoveProp(window, kFocusSubclassInstalled);
+  }
+}
+
+// static
+FocusManager* FocusManager::GetFocusManager(HWND window) {
+  DCHECK(window);
+
+  // In case parent windows belong to a different process, yet
+  // have the kFocusManagerKey property set, we have to be careful
+  // to also check the process id of the window we're checking.
+  DWORD window_pid = 0, current_pid = GetCurrentProcessId();
+  FocusManager* focus_manager;
+  for (focus_manager = NULL; focus_manager == NULL && IsWindow(window);
+       window = GetParent(window)) {
+    GetWindowThreadProcessId(window, &window_pid);
+    if (current_pid != window_pid)
+      break;
+    focus_manager = reinterpret_cast<FocusManager*>(
+        GetProp(window, kFocusManagerKey));
+  }
+  return focus_manager;
+}
+
+// static
+View* FocusManager::GetViewForWindow(HWND window, bool look_in_parents) {
+  DCHECK(window);
+  do {
+    View* v = reinterpret_cast<View*>(GetProp(window, kViewKey));
+    if (v)
+      return v;
+  } while (look_in_parents && (window = ::GetParent(window)));
+
+  return NULL;
+}
+
+FocusManager::FocusManager(HWND root, RootView* root_view)
+    : root_(root),
+      top_root_view_(root_view),
+      focused_view_(NULL),
+      ignore_set_focus_msg_(false) {
+  stored_focused_view_storage_id_ =
+      ViewStorage::GetSharedInstance()->CreateStorageID();
+  DCHECK(root_);
+}
+
+FocusManager::~FocusManager() {
+  // If there are still registered FocusChange listeners, chances are they were
+  // leaked so warn about them.
+  DCHECK(focus_change_listeners_.empty());
+}
+
+// Message handlers.
+bool FocusManager::OnSetFocus(HWND window) {
+  if (ignore_set_focus_msg_)
+    return true;
+
+  // Focus the view associated with that window.
+  View* v = static_cast<View*>(GetProp(window, kViewKey));
+  if (v && v->IsFocusable()) {
+    v->GetRootView()->FocusView(v);
+  } else {
+    SetFocusedView(NULL);
+  }
+
+  return true;
+}
+
+bool FocusManager::OnNCDestroy(HWND window) {
+  // Window is being destroyed, undo the subclassing.
+  FocusManager::UninstallFocusSubclass(window);
+
+  if (window == root_) {
+    // We are the top window.
+
+    DCHECK(GetProp(window, kFocusManagerKey));
+
+    // Make sure this is called on the window that was set with the
+    // FocusManager.
+    RemoveProp(window, kFocusManagerKey);
+
+    delete this;
+  }
+  return true;
+}
+
+bool FocusManager::OnKeyDown(HWND window, UINT message, WPARAM wparam,
+                             LPARAM lparam) {
+  DCHECK((message == WM_KEYDOWN) || (message == WM_SYSKEYDOWN));
+
+  if (!IsWindowVisible(root_)) {
+    // We got a message for a hidden window. Because WidgetWin::Close hides the
+    // window, then destroys it, it it possible to get a message after we've
+    // hidden the window. If we allow the message to be dispatched chances are
+    // we'll crash in some weird place. By returning false we make sure the
+    // message isn't dispatched.
+    return false;
+  }
+
+  // First give the registered keystroke handlers a chance a processing
+  // the message
+  // Do some basic checking to try to catch evil listeners that change the list
+  // from under us.
+  KeystrokeListenerList::size_type original_count =
+      keystroke_listeners_.size();
+  for (int i = 0; i < static_cast<int>(keystroke_listeners_.size()); i++) {
+    if (keystroke_listeners_[i]->ProcessKeyStroke(window, message, wparam,
+                                                  lparam)) {
+      return false;
+    }
+  }
+  DCHECK_EQ(original_count, keystroke_listeners_.size())
+      << "KeystrokeListener list modified during notification";
+
+  int virtual_key_code = static_cast<int>(wparam);
+  // Intercept Tab related messages for focus traversal.
+  // Note that we don't do focus traversal if the root window is not part of the
+  // active window hierarchy as this would mean we have no focused view and
+  // would focus the first focusable view.
+  HWND active_window = ::GetActiveWindow();
+  if ((active_window == root_ || ::IsChild(active_window, root_)) &&
+      (virtual_key_code == VK_TAB) && !win_util::IsCtrlPressed()) {
+    if (!focused_view_ || !focused_view_->CanProcessTabKeyEvents()) {
+      AdvanceFocus(win_util::IsShiftPressed());
+      return false;
+    }
+  }
+
+  // Intercept arrow key messages to switch between grouped views.
+  if (focused_view_ && focused_view_->GetGroup() != -1 &&
+      (virtual_key_code == VK_UP || virtual_key_code == VK_DOWN ||
+       virtual_key_code == VK_LEFT || virtual_key_code == VK_RIGHT)) {
+    bool next = (virtual_key_code == VK_RIGHT || virtual_key_code == VK_DOWN);
+    std::vector<View*> views;
+    focused_view_->GetParent()->GetViewsWithGroup(focused_view_->GetGroup(),
+                                                  &views);
+    std::vector<View*>::const_iterator iter = std::find(views.begin(),
+                                                        views.end(),
+                                                        focused_view_);
+    DCHECK(iter != views.end());
+    int index = static_cast<int>(iter - views.begin());
+    index += next ? 1 : -1;
+    if (index < 0) {
+      index = static_cast<int>(views.size()) - 1;
+    } else if (index >= static_cast<int>(views.size())) {
+      index = 0;
+    }
+    views[index]->RequestFocus();
+    return false;
+  }
+
+  int repeat_count = LOWORD(lparam);
+  int flags = HIWORD(lparam);
+  if (focused_view_ &&
+      !focused_view_->ShouldLookupAccelerators(KeyEvent(
+          Event::ET_KEY_PRESSED, virtual_key_code,
+          repeat_count, flags))) {
+    // This should not be processed as an accelerator.
+    return true;
+  }
+
+  // Process keyboard accelerators.
+  // We process accelerators here as we have no way of knowing if a HWND has
+  // really processed a key event. If the key combination matches an
+  // accelerator, the accelerator is triggered, otherwise we forward the
+  // event to the HWND.
+  Accelerator accelerator(Accelerator(static_cast<int>(virtual_key_code),
+                                      win_util::IsShiftPressed(),
+                                      win_util::IsCtrlPressed(),
+                                      win_util::IsAltPressed()));
+  if (ProcessAccelerator(accelerator)) {
+    // If a shortcut was activated for this keydown message, do not
+    // propagate the message further.
+    return false;
+  }
+  return true;
+}
+
+bool FocusManager::OnKeyUp(HWND window, UINT message, WPARAM wparam,
+                           LPARAM lparam) {
+  for (int i = 0; i < static_cast<int>(keystroke_listeners_.size()); ++i) {
+    if (keystroke_listeners_[i]->ProcessKeyStroke(window, message, wparam,
+                                                  lparam)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool FocusManager::OnPostActivate(HWND window,
+                                  int activation_state,
+                                  int minimized_state) {
+  if (WA_INACTIVE == LOWORD(activation_state)) {
+    StoreFocusedView();
+  } else {
+    RestoreFocusedView();
+  }
+  return false;
+}
+
+void FocusManager::ValidateFocusedView() {
+  if (focused_view_) {
+    if (!ContainsView(focused_view_)) {
+      focused_view_ = NULL;
+    }
+  }
+}
+
+// Tests whether a view is valid, whether it still belongs to the window
+// hierarchy of the FocusManager.
+bool FocusManager::ContainsView(View* view) {
+  DCHECK(view);
+  RootView* root_view = view->GetRootView();
+  if (!root_view)
+    return false;
+
+  Widget* widget = root_view->GetWidget();
+  if (!widget)
+    return false;
+
+  HWND window = widget->GetNativeView();
+  while (window) {
+    if (window == root_)
+      return true;
+    window = ::GetParent(window);
+  }
+  return false;
+}
+
+void FocusManager::AdvanceFocus(bool reverse) {
+  View* v = GetNextFocusableView(focused_view_, reverse, false);
+  // Note: Do not skip this next block when v == focused_view_.  If the user
+  // tabs past the last focusable element in a webpage, we'll get here, and if
+  // the TabContentsContainerView is the only focusable view (possible in
+  // fullscreen mode), we need to run this block in order to cycle around to the
+  // first element on the page.
+  if (v) {
+    v->AboutToRequestFocusFromTabTraversal(reverse);
+    v->RequestFocus();
+  }
+}
+
+View* FocusManager::GetNextFocusableView(View* original_starting_view,
+                                         bool reverse,
+                                         bool dont_loop) {
+  FocusTraversable* focus_traversable = NULL;
+
+  // Let's revalidate the focused view.
+  ValidateFocusedView();
+
+  View* starting_view = NULL;
+  if (original_starting_view) {
+    // If the starting view has a focus traversable, use it.
+    // This is the case with WidgetWins for example.
+    focus_traversable = original_starting_view->GetFocusTraversable();
+
+    // Otherwise default to the root view.
+    if (!focus_traversable) {
+      focus_traversable = original_starting_view->GetRootView();
+      starting_view = original_starting_view;
+    }
+  } else {
+    focus_traversable = top_root_view_;
+  }
+
+  // Traverse the FocusTraversable tree down to find the focusable view.
+  View* v = FindFocusableView(focus_traversable, starting_view,
+                              reverse, dont_loop);
+  if (v) {
+    return v;
+  } else {
+    // Let's go up in the FocusTraversable tree.
+    FocusTraversable* parent_focus_traversable =
+        focus_traversable->GetFocusTraversableParent();
+    starting_view = focus_traversable->GetFocusTraversableParentView();
+    while (parent_focus_traversable) {
+      FocusTraversable* new_focus_traversable = NULL;
+      View* new_starting_view = NULL;
+      v = parent_focus_traversable ->FindNextFocusableView(
+          starting_view, reverse, FocusTraversable::UP, dont_loop,
+          &new_focus_traversable, &new_starting_view);
+
+      if (new_focus_traversable) {
+        DCHECK(!v);
+
+        // There is a FocusTraversable, traverse it down.
+        v = FindFocusableView(new_focus_traversable, NULL, reverse, dont_loop);
+      }
+
+      if (v)
+        return v;
+
+      starting_view = focus_traversable->GetFocusTraversableParentView();
+      parent_focus_traversable =
+          parent_focus_traversable->GetFocusTraversableParent();
+    }
+
+    if (!dont_loop) {
+      // If we get here, we have reached the end of the focus hierarchy, let's
+      // loop.
+      if (reverse) {
+         // When reversing from the top, the next focusable view is at the end
+         // of the focus hierarchy.
+        return FindLastFocusableView();
+      } else {
+        // Easy, just clear the selection and press tab again.
+        if (original_starting_view) {  // Make sure there was at least a view to
+                                       // start with, to prevent infinitely
+                                       // looping in empty windows.
+          // By calling with NULL as the starting view, we'll start from the
+          // top_root_view.
+          return GetNextFocusableView(NULL, false, true);
+        }
+      }
+    }
+  }
+  return NULL;
+}
+
+View* FocusManager::FindLastFocusableView() {
+  // Just walk the entire focus loop from where we're at until we reach the end.
+  View* new_focused = NULL;
+  View* last_focused = focused_view_;
+  while (new_focused = GetNextFocusableView(last_focused, false, true))
+    last_focused = new_focused;
+  return last_focused;
+}
+
+void FocusManager::SetFocusedView(View* view) {
+  if (focused_view_ != view) {
+    View* prev_focused_view = focused_view_;
+    if (focused_view_)
+      focused_view_->WillLoseFocus();
+
+    if (view)
+      view->WillGainFocus();
+
+    // Notified listeners that the focus changed.
+    FocusChangeListenerList::const_iterator iter;
+    for (iter = focus_change_listeners_.begin();
+         iter != focus_change_listeners_.end(); ++iter) {
+      (*iter)->FocusWillChange(prev_focused_view, view);
+    }
+
+    focused_view_ = view;
+
+    if (prev_focused_view)
+      prev_focused_view->SchedulePaint();  // Remove focus artifacts.
+
+    if (view) {
+      view->SchedulePaint();
+      view->Focus();
+      view->DidGainFocus();
+    }
+  }
+}
+
+void FocusManager::ClearFocus() {
+  SetFocusedView(NULL);
+  ClearHWNDFocus();
+}
+
+void FocusManager::ClearHWNDFocus() {
+  // Keep the top root window focused so we get keyboard events.
+  ignore_set_focus_msg_ = true;
+  ::SetFocus(root_);
+  ignore_set_focus_msg_ = false;
+}
+
+void FocusManager::FocusHWND(HWND hwnd) {
+  ignore_set_focus_msg_ = true;
+  // Only reset focus if hwnd is not already focused.
+  if (hwnd && ::GetFocus() != hwnd)
+    ::SetFocus(hwnd);
+  ignore_set_focus_msg_ = false;
+}
+
+void FocusManager::StoreFocusedView() {
+  ViewStorage* view_storage = ViewStorage::GetSharedInstance();
+  if (!view_storage) {
+    // This should never happen but bug 981648 seems to indicate it could.
+    NOTREACHED();
+    return;
+  }
+
+  // TODO (jcampan): when a TabContents containing a popup is closed, the focus
+  // is stored twice causing an assert. We should find a better alternative than
+  // removing the view from the storage explicitly.
+  view_storage->RemoveView(stored_focused_view_storage_id_);
+
+  if (!focused_view_)
+    return;
+
+  view_storage->StoreView(stored_focused_view_storage_id_, focused_view_);
+
+  View* v = focused_view_;
+  focused_view_ = NULL;
+
+  if (v)
+    v->SchedulePaint();  // Remove focus border.
+}
+
+void FocusManager::RestoreFocusedView() {
+  ViewStorage* view_storage = ViewStorage::GetSharedInstance();
+  if (!view_storage) {
+    // This should never happen but bug 981648 seems to indicate it could.
+    NOTREACHED();
+    return;
+  }
+
+  View* view = view_storage->RetrieveView(stored_focused_view_storage_id_);
+  if (view) {
+    if (ContainsView(view))
+      view->RequestFocus();
+  } else {
+    // Clearing the focus will focus the root window, so we still get key
+    // events.
+    ClearFocus();
+  }
+}
+
+void FocusManager::ClearStoredFocusedView() {
+  ViewStorage* view_storage = ViewStorage::GetSharedInstance();
+  if (!view_storage) {
+    // This should never happen but bug 981648 seems to indicate it could.
+    NOTREACHED();
+    return;
+  }
+  view_storage->RemoveView(stored_focused_view_storage_id_);
+}
+
+FocusManager* FocusManager::GetParentFocusManager() const {
+  HWND parent = ::GetParent(root_);
+  // If we are a top window, we don't have a parent FocusManager.
+  if (!parent)
+    return NULL;
+
+  return GetFocusManager(parent);
+}
+
+// Find the next (previous if reverse is true) focusable view for the specified
+// FocusTraversable, starting at the specified view, traversing down the
+// FocusTraversable hierarchy.
+View* FocusManager::FindFocusableView(FocusTraversable* focus_traversable,
+                                      View* starting_view,
+                                      bool reverse,
+                                      bool dont_loop) {
+  FocusTraversable* new_focus_traversable = NULL;
+  View* new_starting_view = NULL;
+  View* v = focus_traversable->FindNextFocusableView(starting_view,
+                                                     reverse,
+                                                     FocusTraversable::DOWN,
+                                                     dont_loop,
+                                                     &new_focus_traversable,
+                                                     &new_starting_view);
+
+  // Let's go down the FocusTraversable tree as much as we can.
+  while (new_focus_traversable) {
+    DCHECK(!v);
+    focus_traversable = new_focus_traversable;
+    starting_view = new_starting_view;
+    new_focus_traversable = NULL;
+    starting_view = NULL;
+    v = focus_traversable->FindNextFocusableView(starting_view,
+                                                 reverse,
+                                                 FocusTraversable::DOWN,
+                                                 dont_loop,
+                                                 &new_focus_traversable,
+                                                 &new_starting_view);
+  }
+  return v;
+}
+
+AcceleratorTarget* FocusManager::RegisterAccelerator(
+    const Accelerator& accelerator,
+    AcceleratorTarget* target) {
+  AcceleratorMap::const_iterator iter = accelerators_.find(accelerator);
+  AcceleratorTarget* previous_target = NULL;
+  if (iter != accelerators_.end())
+    previous_target = iter->second;
+
+  accelerators_[accelerator] = target;
+
+  return previous_target;
+}
+
+void FocusManager::UnregisterAccelerator(const Accelerator& accelerator,
+                                         AcceleratorTarget* target) {
+  AcceleratorMap::iterator iter = accelerators_.find(accelerator);
+  if (iter == accelerators_.end()) {
+    NOTREACHED() << "Unregistering non-existing accelerator";
+    return;
+  }
+
+  if (iter->second != target) {
+    NOTREACHED() << "Unregistering accelerator for wrong target";
+    return;
+  }
+
+  accelerators_.erase(iter);
+}
+
+void FocusManager::UnregisterAccelerators(AcceleratorTarget* target) {
+  for (AcceleratorMap::iterator iter = accelerators_.begin();
+       iter != accelerators_.end();) {
+    if (iter->second == target)
+      accelerators_.erase(iter++);
+    else
+      ++iter;
+  }
+}
+
+bool FocusManager::ProcessAccelerator(const Accelerator& accelerator) {
+  FocusManager* focus_manager = this;
+  do {
+    AcceleratorTarget* target =
+        focus_manager->GetTargetForAccelerator(accelerator);
+    if (target) {
+      // If there is focused view, we give it a chance to process that
+      // accelerator.
+      if (!focused_view_ ||
+          !focused_view_->OverrideAccelerator(accelerator)) {
+        if (target->AcceleratorPressed(accelerator))
+          return true;
+      }
+    }
+
+    // When dealing with child windows that have their own FocusManager (such
+    // as ConstrainedWindow), we still want the parent FocusManager to process
+    // the accelerator if the child window did not process it.
+    focus_manager = focus_manager->GetParentFocusManager();
+  } while (focus_manager);
+  return false;
+}
+
+AcceleratorTarget* FocusManager::GetTargetForAccelerator(
+    const Accelerator& accelerator) const {
+  AcceleratorMap::const_iterator iter = accelerators_.find(accelerator);
+  if (iter != accelerators_.end())
+    return iter->second;
+  return NULL;
+}
+
+void FocusManager::ViewRemoved(View* parent, View* removed) {
+  if (focused_view_ && focused_view_ == removed)
+    focused_view_ = NULL;
+}
+
+void FocusManager::AddKeystrokeListener(KeystrokeListener* listener) {
+  DCHECK(std::find(keystroke_listeners_.begin(), keystroke_listeners_.end(),
+                   listener) == keystroke_listeners_.end())
+                       << "Adding a listener twice.";
+  keystroke_listeners_.push_back(listener);
+}
+
+void FocusManager::RemoveKeystrokeListener(KeystrokeListener* listener) {
+  KeystrokeListenerList::iterator place =
+      std::find(keystroke_listeners_.begin(), keystroke_listeners_.end(),
+                listener);
+  if (place == keystroke_listeners_.end()) {
+    NOTREACHED() << "Removing a listener that isn't registered.";
+    return;
+  }
+  keystroke_listeners_.erase(place);
+}
+
+void FocusManager::AddFocusChangeListener(FocusChangeListener* listener) {
+  DCHECK(std::find(focus_change_listeners_.begin(),
+                   focus_change_listeners_.end(), listener) ==
+      focus_change_listeners_.end()) << "Adding a listener twice.";
+  focus_change_listeners_.push_back(listener);
+}
+
+void FocusManager::RemoveFocusChangeListener(FocusChangeListener* listener) {
+  FocusChangeListenerList::iterator place =
+      std::find(focus_change_listeners_.begin(), focus_change_listeners_.end(),
+                listener);
+  if (place == focus_change_listeners_.end()) {
+    NOTREACHED() << "Removing a listener that isn't registered.";
+    return;
+  }
+  focus_change_listeners_.erase(place);
+}
+
+}  // namespace views
diff --git a/views/focus/focus_manager.h b/views/focus/focus_manager.h
new file mode 100644
index 0000000..8c330362
--- /dev/null
+++ b/views/focus/focus_manager.h
@@ -0,0 +1,343 @@
+// Copyright (c) 2006-2008 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 VIEWS_FOCUS_FOCUS_MANAGER_H_
+#define VIEWS_FOCUS_FOCUS_MANAGER_H_
+
+#include "base/basictypes.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#include <vector>
+#include <map>
+
+#include "views/accelerator.h"
+
+// The FocusManager class is used to handle focus traversal, store/restore
+// focused views and handle keyboard accelerators.
+//
+// There are 2 types of focus:
+// - the native focus, which is the focus that an HWND has.
+// - the view focus, which is the focus that a views::View has.
+//
+// Each native view must register with their Focus Manager so the focus manager
+// gets notified when they are focused (and keeps track of the native focus) and
+// as well so that the tab key events can be intercepted.
+// They can provide when they register a View that is kept in synch in term of
+// focus. This is used in NativeControl for example, where a View wraps an
+// actual native window.
+// This is already done for you if you subclass the NativeControl class or if
+// you use the HWNDView class.
+//
+// When creating a top window, if it derives from WidgetWin, the
+// |has_own_focus_manager| of the Init method lets you specify whether that
+// window should have its own focus manager (so focus traversal stays confined
+// in that window). If you are not deriving from WidgetWin or one of its
+// derived classes (Window, FramelessWindow, ConstrainedWindow), you must
+// create a FocusManager when the window is created (it is automatically deleted
+// when the window is destroyed).
+//
+// The FocusTraversable interface exposes the methods a class should implement
+// in order to be able to be focus traversed when tab key is pressed.
+// RootViews implement FocusTraversable.
+// The FocusManager contains a top FocusTraversable instance, which is the top
+// RootView.
+//
+// If you just use views, then the focus traversal is handled for you by the
+// RootView. The default traversal order is the order in which the views have
+// been added to their container. You can modify this order by using the View
+// method SetNextFocusableView().
+//
+// If you are embedding a native view containing a nested RootView (for example
+// by adding a NativeControl that contains a WidgetWin as its native
+// component), then you need to:
+// - override the View::GetFocusTraversable() method in your outter component.
+//   It should return the RootView of the inner component. This is used when
+//   the focus traversal traverse down the focus hierarchy to enter the nested
+//   RootView. In the example mentioned above, the NativeControl overrides
+//   GetFocusTraversable() and returns hwnd_view_container_->GetRootView().
+// - call RootView::SetFocusTraversableParent() on the nested RootView and point
+//   it to the outter RootView. This is used when the focus goes out of the
+//   nested RootView. In the example:
+//   hwnd_view_container_->GetRootView()->SetFocusTraversableParent(
+//      native_control->GetRootView());
+// - call RootView::SetFocusTraversableParentView() on the nested RootView with
+//   the parent view that directly contains the native window. This is needed
+//   when traversing up from the nested RootView to know which view to start
+//   with when going to the next/previous view.
+//   In our example:
+//   hwnd_view_container_->GetRootView()->SetFocusTraversableParent(
+//      native_control);
+//
+// Note that FocusTraversable do not have to be RootViews: TabContents is
+// FocusTraversable.
+
+namespace views {
+
+class View;
+class RootView;
+
+// The FocusTraversable interface is used by components that want to process
+// focus traversal events (due to Tab/Shift-Tab key events).
+class FocusTraversable {
+ public:
+  // The direction in which the focus traversal is going.
+  // TODO (jcampan): add support for lateral (left, right) focus traversal. The
+  // goal is to switch to focusable views on the same level when using the arrow
+  // keys (ala Windows: in a dialog box, arrow keys typically move between the
+  // dialog OK, Cancel buttons).
+  enum Direction {
+    UP = 0,
+    DOWN
+  };
+
+  // Should find the next view that should be focused and return it. If a
+  // FocusTraversable is found while searching for the focusable view, NULL
+  // should be returned, focus_traversable should be set to the FocusTraversable
+  // and focus_traversable_view should be set to the view associated with the
+  // FocusTraversable.
+  // This call should return NULL if the end of the focus loop is reached.
+  // - |starting_view| is the view that should be used as the starting point
+  //   when looking for the previous/next view. It may be NULL (in which case
+  //   the first/last view should be used depending if normal/reverse).
+  // - |reverse| whether we should find the next (reverse is false) or the
+  //   previous (reverse is true) view.
+  // - |direction| specifies whether we are traversing down (meaning we should
+  //   look into child views) or traversing up (don't look at child views).
+  // - |dont_loop| if true specifies that if there is a loop in the focus
+  //   hierarchy, we should keep traversing after the last view of the loop.
+  // - |focus_traversable| is set to the focus traversable that should be
+  //   traversed if one is found (in which case the call returns NULL).
+  // - |focus_traversable_view| is set to the view associated with the
+  //   FocusTraversable set in the previous parameter (it is used as the
+  //   starting view when looking for the next focusable view).
+
+  virtual View* FindNextFocusableView(View* starting_view,
+                                      bool reverse,
+                                      Direction direction,
+                                      bool dont_loop,
+                                      FocusTraversable** focus_traversable,
+                                      View** focus_traversable_view) = 0;
+
+  // Should return the parent FocusTraversable.
+  // The top RootView which is the top FocusTraversable returns NULL.
+  virtual FocusTraversable* GetFocusTraversableParent() = 0;
+
+  // This should return the View this FocusTraversable belongs to.
+  // It is used when walking up the view hierarchy tree to find which view
+  // should be used as the starting view for finding the next/previous view.
+  virtual View* GetFocusTraversableParentView() = 0;
+};
+
+// The KeystrokeListener interface is used by components (such as the
+// ExternalTabContainer class) which need a crack at handling all
+// keystrokes.
+class KeystrokeListener {
+ public:
+  // If this returns true, then the component handled the keystroke and ate
+  // it.
+#if defined(OS_WIN)
+  virtual bool ProcessKeyStroke(HWND window, UINT message, WPARAM wparam,
+                                LPARAM lparam) = 0;
+#endif
+};
+
+// This interface should be implemented by classes that want to be notified when
+// the focus is about to change.  See the Add/RemoveFocusChangeListener methods.
+class FocusChangeListener {
+ public:
+  virtual void FocusWillChange(View* focused_before, View* focused_now) = 0;
+};
+
+class FocusManager {
+ public:
+#if defined(OS_WIN)
+  // Creates a FocusManager for the specified window. Top level windows
+  // must invoked this when created.
+  // The RootView specified should be the top RootView of the window.
+  // This also invokes InstallFocusSubclass.
+  static FocusManager* CreateFocusManager(HWND window, RootView* root_view);
+
+  // Subclasses the specified window. The subclassed window procedure listens
+  // for WM_SETFOCUS notification and keeps the FocusManager's focus owner
+  // property in sync.
+  // It's not necessary to explicitly invoke Uninstall, it's automatically done
+  // when the window is destroyed and Uninstall wasn't invoked.
+  static void InstallFocusSubclass(HWND window, View* view);
+
+  // Uninstalls the window subclass installed by InstallFocusSubclass.
+  static void UninstallFocusSubclass(HWND window);
+
+  static FocusManager* GetFocusManager(HWND window);
+
+  // Message handlers (for messages received from registered windows).
+  // Should return true if the message should be forwarded to the window
+  // original proc function, false otherwise.
+  bool OnSetFocus(HWND window);
+  bool OnNCDestroy(HWND window);
+  // OnKeyDown covers WM_KEYDOWN and WM_SYSKEYDOWN.
+  bool OnKeyDown(HWND window,
+                 UINT message,
+                 WPARAM wparam,
+                 LPARAM lparam);
+  bool OnKeyUp(HWND window,
+               UINT message,
+               WPARAM wparam,
+               LPARAM lparam);
+  // OnPostActivate is called after WM_ACTIVATE has been propagated to the
+  // DefWindowProc.
+  bool OnPostActivate(HWND window, int activation_state, int minimized_state);
+#endif
+
+  // Returns true is the specified is part of the hierarchy of the window
+  // associated with this FocusManager.
+  bool ContainsView(View* view);
+
+  // Advances the focus (backward if reverse is true).
+  void AdvanceFocus(bool reverse);
+
+  // The FocusManager is handling the selected view for the RootView.
+  View* GetFocusedView() const { return focused_view_; }
+  void SetFocusedView(View* view);
+
+  // Clears the focused view. The window associated with the top root view gets
+  // the native focus (so we still get keyboard events).
+  void ClearFocus();
+
+  // Clears the HWND that has the focus by focusing the HWND from the top
+  // RootView (so we still get keyboard events).
+  // Note that this does not change the currently focused view.
+  void ClearHWNDFocus();
+
+#if defined(OS_WIN)
+  // Focus the specified |hwnd| without changing the focused view.
+  void FocusHWND(HWND hwnd);
+#endif
+
+  // Validates the focused view, clearing it if the window it belongs too is not
+  // attached to the window hierarchy anymore.
+  void ValidateFocusedView();
+
+#if defined(OS_WIN)
+  // Returns the view associated with the specified window if any.
+  // If |look_in_parents| is true, it goes up the window parents until it find
+  // a view.
+  static View* GetViewForWindow(HWND window, bool look_in_parents);
+#endif
+
+  // Stores and restores the focused view. Used when the window becomes
+  // active/inactive.
+  void StoreFocusedView();
+  void RestoreFocusedView();
+
+  // Clears the stored focused view.
+  void ClearStoredFocusedView();
+
+  // Returns the FocusManager of the parent window of the window that is the
+  // root of this FocusManager. This is useful with ConstrainedWindows that have
+  // their own FocusManager and need to return focus to the browser when closed.
+  FocusManager* GetParentFocusManager() const;
+
+  // Register a keyboard accelerator for the specified target.  If an
+  // AcceleratorTarget is already registered for that accelerator, it is
+  // returned.
+  // Note that we are currently limited to accelerators that are either:
+  // - a key combination including Ctrl or Alt
+  // - the escape key
+  // - the enter key
+  // - any F key (F1, F2, F3 ...)
+  // - any browser specific keys (as available on special keyboards)
+  AcceleratorTarget* RegisterAccelerator(const Accelerator& accelerator,
+                                         AcceleratorTarget* target);
+
+  // Unregister the specified keyboard accelerator for the specified target.
+  void UnregisterAccelerator(const Accelerator& accelerator,
+                             AcceleratorTarget* target);
+
+  // Unregister all keyboard accelerator for the specified target.
+  void UnregisterAccelerators(AcceleratorTarget* target);
+
+  // Activate the target associated with the specified accelerator if any.
+  // Returns true if an accelerator was activated.
+  bool ProcessAccelerator(const Accelerator& accelerator);
+
+  // Called by a RootView when a view within its hierarchy is removed from its
+  // parent. This will only be called by a RootView in a hierarchy of Widgets
+  // that this FocusManager is attached to the parent Widget of.
+  void ViewRemoved(View* parent, View* removed);
+
+  void AddKeystrokeListener(KeystrokeListener* listener);
+  void RemoveKeystrokeListener(KeystrokeListener* listener);
+
+  // Adds/removes a listener.  The FocusChangeListener is notified every time
+  // the focused view is about to change.
+  void AddFocusChangeListener(FocusChangeListener* listener);
+  void RemoveFocusChangeListener(FocusChangeListener* listener);
+
+  // Returns the AcceleratorTarget that should be activated for the specified
+  // keyboard accelerator, or NULL if no view is registered for that keyboard
+  // accelerator.
+  // TODO(finnur): http://b/1307173 Make this private once the bug is fixed.
+  AcceleratorTarget* GetTargetForAccelerator(
+      const Accelerator& accelerator) const;
+
+ private:
+#if defined(OS_WIN)
+  explicit FocusManager(HWND root, RootView* root_view);
+#endif
+  ~FocusManager();
+
+  // Returns the next focusable view.
+  View* GetNextFocusableView(View* starting_view, bool reverse, bool dont_loop);
+
+  // Returns the last view of the focus traversal hierarchy.
+  View* FindLastFocusableView();
+
+  // Returns the focusable view found in the FocusTraversable specified starting
+  // at the specified view. This traverses down along the FocusTraversable
+  // hierarchy.
+  // Returns NULL if no focusable view were found.
+  View* FindFocusableView(FocusTraversable* focus_traversable,
+                          View* starting_view,
+                          bool reverse,
+                          bool dont_loop);
+
+  // The RootView of the window associated with this FocusManager.
+  RootView* top_root_view_;
+
+  // The view that currently is focused.
+  View* focused_view_;
+
+  // The storage id used in the ViewStorage to store/restore the view that last
+  // had focus.
+  int stored_focused_view_storage_id_;
+
+#if defined(OS_WIN)
+  // The window associated with this focus manager.
+  HWND root_;
+#endif
+
+  // Used to allow setting the focus on an HWND without changing the currently
+  // focused view.
+  bool ignore_set_focus_msg_;
+
+  // The accelerators and associated targets.
+  typedef std::map<Accelerator, AcceleratorTarget*> AcceleratorMap;
+  AcceleratorMap accelerators_;
+
+  // The list of registered keystroke listeners
+  typedef std::vector<KeystrokeListener*> KeystrokeListenerList;
+  KeystrokeListenerList keystroke_listeners_;
+
+  // The list of registered FocusChange listeners.
+  typedef std::vector<FocusChangeListener*> FocusChangeListenerList;
+  FocusChangeListenerList focus_change_listeners_;
+
+  DISALLOW_COPY_AND_ASSIGN(FocusManager);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_FOCUS_FOCUS_MANAGER_H_
diff --git a/views/focus/focus_manager_unittest.cc b/views/focus/focus_manager_unittest.cc
new file mode 100644
index 0000000..234db1d
--- /dev/null
+++ b/views/focus/focus_manager_unittest.cc
@@ -0,0 +1,666 @@
+// Copyright (c) 2006-2008 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.
+
+// Disabled right now as this won't work on BuildBots right now as this test
+// require the box it runs on to be unlocked (and no screen-savers).
+// The test actually simulates mouse and key events, so if the screen is locked,
+// the events don't go to the Chrome window.
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "app/resource_bundle.h"
+#include "base/gfx/rect.h"
+#include "skia/include/SkColor.h"
+#include "views/background.h"
+#include "views/border.h"
+#include "views/controls/button/checkbox.h"
+#include "views/controls/button/native_button.h"
+#include "views/controls/button/radio_button.h"
+#include "views/controls/label.h"
+#include "views/controls/link.h"
+#include "views/controls/scroll_view.h"
+#include "views/controls/tabbed_pane.h"
+#include "views/controls/text_field.h"
+#include "views/widget/accelerator_handler.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget_win.h"
+#include "views/window/window.h"
+#include "views/window/window_delegate.h"
+
+
+
+namespace {
+
+static const int kWindowWidth = 600;
+static const int kWindowHeight = 500;
+
+static int count = 1;
+
+static const int kTopCheckBoxID = count++;  // 1
+static const int kLeftContainerID = count++;
+static const int kAppleLabelID = count++;
+static const int kAppleTextFieldID = count++;
+static const int kOrangeLabelID = count++;  // 5
+static const int kOrangeTextFieldID = count++;
+static const int kBananaLabelID = count++;
+static const int kBananaTextFieldID = count++;
+static const int kKiwiLabelID = count++;
+static const int kKiwiTextFieldID = count++; // 10
+static const int kFruitButtonID = count++;
+static const int kFruitCheckBoxID = count++;
+
+static const int kRightContainerID = count++;
+static const int kAsparagusButtonID = count++;
+static const int kBroccoliButtonID = count++;  // 15
+static const int kCauliflowerButtonID = count++;
+
+static const int kInnerContainerID = count++;
+static const int kScrollViewID = count++;
+static const int kScrollContentViewID = count++;
+static const int kRosettaLinkID = count++;  // 20
+static const int kStupeurEtTremblementLinkID = count++;
+static const int kDinerGameLinkID = count++;
+static const int kRidiculeLinkID = count++;
+static const int kClosetLinkID = count++;
+static const int kVisitingLinkID = count++;  // 25
+static const int kAmelieLinkID = count++;
+static const int kJoyeuxNoelLinkID = count++;
+static const int kCampingLinkID = count++;
+static const int kBriceDeNiceLinkID = count++;
+static const int kTaxiLinkID = count++;  // 30
+static const int kAsterixLinkID = count++;
+
+static const int kOKButtonID = count++;
+static const int kCancelButtonID = count++;
+static const int kHelpButtonID = count++;
+
+static const int kStyleContainerID = count++;  // 35
+static const int kBoldCheckBoxID = count++;
+static const int kItalicCheckBoxID = count++;
+static const int kUnderlinedCheckBoxID = count++;
+
+static const int kSearchContainerID = count++;
+static const int kSearchTextFieldID = count++;  // 40
+static const int kSearchButtonID = count++;
+static const int kHelpLinkID = count++;
+
+static const int kThumbnailContainerID = count++;
+static const int kThumbnailStarID = count++;
+static const int kThumbnailSuperStarID = count++;
+
+class FocusManagerTest;
+
+// BorderView is a NativeControl that creates a tab control as its child and
+// takes a View to add as the child of the tab control. The tab control is used
+// to give a nice background for the view. At some point we'll have a real
+// wrapper for TabControl, and this can be nuked in favor of it.
+// Taken from keyword_editor_view.cc.
+// It is interesting in our test as it is a native control containing another
+// RootView.
+class BorderView : public views::NativeControl {
+ public:
+  explicit BorderView(View* child) : child_(child) {
+    DCHECK(child);
+    SetFocusable(false);
+  }
+
+  virtual ~BorderView() {}
+
+  virtual HWND CreateNativeControl(HWND parent_container) {
+    // Create the tab control.
+    HWND tab_control = ::CreateWindowEx(GetAdditionalExStyle(),
+                                        WC_TABCONTROL,
+                                        L"",
+                                        WS_CHILD,
+                                        0, 0, width(), height(),
+                                        parent_container, NULL, NULL, NULL);
+    // Create the view container which is a child of the TabControl.
+    widget_ = new views::WidgetWin();
+    widget_->Init(tab_control, gfx::Rect(), false);
+    widget_->SetContentsView(child_);
+    widget_->SetFocusTraversableParentView(this);
+    ResizeContents(tab_control);
+    return tab_control;
+  }
+
+  virtual LRESULT OnNotify(int w_param, LPNMHDR l_param) {
+    return 0;
+  }
+
+  virtual void Layout() {
+    NativeControl::Layout();
+    ResizeContents(GetNativeControlHWND());
+  }
+
+  virtual views::RootView* GetContentsRootView() {
+    return widget_->GetRootView();
+  }
+
+  virtual views::FocusTraversable* GetFocusTraversable() {
+    return widget_;
+  }
+
+  virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child) {
+    NativeControl::ViewHierarchyChanged(is_add, parent, child);
+
+    if (child == this && is_add) {
+      // We have been added to a view hierarchy, update the FocusTraversable
+      // parent.
+      widget_->SetFocusTraversableParent(GetRootView());
+    }
+  }
+
+private:
+  void ResizeContents(HWND tab_control) {
+    DCHECK(tab_control);
+    CRect content_bounds;
+    if (!GetClientRect(tab_control, &content_bounds))
+      return;
+    TabCtrl_AdjustRect(tab_control, FALSE, &content_bounds);
+    widget_->MoveWindow(content_bounds.left, content_bounds.top,
+      content_bounds.Width(), content_bounds.Height(),
+      TRUE);
+  }
+
+  View* child_;
+  views::WidgetWin* widget_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(BorderView);
+};
+
+class TestViewWindow : public views::WidgetWin {
+ public:
+  explicit TestViewWindow(FocusManagerTest* test);
+  ~TestViewWindow() { }
+
+  void Init();
+
+  views::View* contents() const { return contents_; }
+
+
+  // Return the ID of the component that currently has the focus.
+  int GetFocusedComponentID();
+
+  // Simulate pressing the tab button in the window.
+  void PressTab(bool shift_pressed, bool ctrl_pressed);
+
+  views::RootView* GetContentsRootView() const {
+    return contents_->GetRootView();
+  }
+
+  views::RootView* GetStyleRootView() const {
+    return style_tab_->GetContentsRootView();
+  }
+
+  views::RootView* GetSearchRootView() const {
+    return search_border_view_->GetContentsRootView();
+  }
+
+ private:
+  views::View* contents_;
+
+  views::TabbedPane* style_tab_;
+  BorderView* search_border_view_;
+
+  FocusManagerTest* test_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(TestViewWindow);
+};
+
+class FocusManagerTest : public testing::Test {
+ public:
+  TestViewWindow* GetWindow();
+  ~FocusManagerTest();
+
+ protected:
+  FocusManagerTest();
+
+  virtual void SetUp();
+  virtual void TearDown();
+
+  MessageLoopForUI message_loop_;
+  TestViewWindow* test_window_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// TestViewWindow
+////////////////////////////////////////////////////////////////////////////////
+
+TestViewWindow::TestViewWindow(FocusManagerTest* test)
+    : test_(test),
+      contents_(NULL),
+      style_tab_(NULL),
+      search_border_view_(NULL) {
+}
+
+// Initializes and shows the window with the contents view.
+void TestViewWindow::Init() {
+  gfx::Rect bounds(0, 0, 600, 460);
+  contents_ = new views::View();
+  contents_->set_background(
+      views::Background::CreateSolidBackground(255, 255, 255));
+
+  WidgetWin::Init(NULL, bounds, true);
+  SetContentsView(contents_);
+
+  views::Checkbox* cb =
+      new views::Checkbox(L"This is a checkbox");
+  contents_->AddChildView(cb);
+  // In this fast paced world, who really has time for non hard-coded layout?
+  cb->SetBounds(10, 10, 200, 20);
+  cb->SetID(kTopCheckBoxID);
+
+  views::View* left_container = new views::View();
+  left_container->set_border(
+      views::Border::CreateSolidBorder(1, SK_ColorBLACK));
+  left_container->set_background(
+      views::Background::CreateSolidBackground(240, 240, 240));
+  left_container->SetID(kLeftContainerID);
+  contents_->AddChildView(left_container);
+  left_container->SetBounds(10, 35, 250, 200);
+
+  int label_x = 5;
+  int label_width = 50;
+  int label_height = 15;
+  int text_field_width = 150;
+  int y = 10;
+  int gap_between_labels = 10;
+
+  views::Label* label = new views::Label(L"Apple:");
+  label->SetID(kAppleLabelID);
+  left_container->AddChildView(label);
+  label->SetBounds(label_x, y, label_width, label_height);
+
+  views::TextField* text_field = new views::TextField();
+  text_field->SetID(kAppleTextFieldID);
+  left_container->AddChildView(text_field);
+  text_field->SetBounds(label_x + label_width + 5, y,
+                        text_field_width, label_height);
+
+  y += label_height + gap_between_labels;
+
+  label = new views::Label(L"Orange:");
+  label->SetID(kOrangeLabelID);
+  left_container->AddChildView(label);
+  label->SetBounds(label_x, y, label_width, label_height);
+
+  text_field = new views::TextField();
+  text_field->SetID(kOrangeTextFieldID);
+  left_container->AddChildView(text_field);
+  text_field->SetBounds(label_x + label_width + 5, y,
+                        text_field_width, label_height);
+
+  y += label_height + gap_between_labels;
+
+  label = new views::Label(L"Banana:");
+  label->SetID(kBananaLabelID);
+  left_container->AddChildView(label);
+  label->SetBounds(label_x, y, label_width, label_height);
+
+  text_field = new views::TextField();
+  text_field->SetID(kBananaTextFieldID);
+  left_container->AddChildView(text_field);
+  text_field->SetBounds(label_x + label_width + 5, y,
+                        text_field_width, label_height);
+
+  y += label_height + gap_between_labels;
+
+  label = new views::Label(L"Kiwi:");
+  label->SetID(kKiwiLabelID);
+  left_container->AddChildView(label);
+  label->SetBounds(label_x, y, label_width, label_height);
+
+  text_field = new views::TextField();
+  text_field->SetID(kKiwiTextFieldID);
+  left_container->AddChildView(text_field);
+  text_field->SetBounds(label_x + label_width + 5, y,
+                        text_field_width, label_height);
+
+  y += label_height + gap_between_labels;
+
+  views::NativeButton* button = new views::NativeButton(NULL, L"Click me");
+  button->SetBounds(label_x, y + 10, 50, 20);
+  button->SetID(kFruitButtonID);
+  left_container->AddChildView(button);
+  y += 40;
+
+  cb =  new views::Checkbox(L"This is another check box");
+  cb->SetBounds(label_x + label_width + 5, y, 100, 20);
+  cb->SetID(kFruitCheckBoxID);
+  left_container->AddChildView(cb);
+
+  views::View* right_container = new views::View();
+  right_container->set_border(
+      views::Border::CreateSolidBorder(1, SK_ColorBLACK));
+  right_container->set_background(
+      views::Background::CreateSolidBackground(240, 240, 240));
+  right_container->SetID(kRightContainerID);
+  contents_->AddChildView(right_container);
+  right_container->SetBounds(270, 35, 300, 200);
+
+  y = 10;
+  int radio_button_height = 15;
+  int gap_between_radio_buttons = 10;
+  views::View* radio_button =
+      new views::RadioButton(L"Asparagus", 1);
+  radio_button->SetID(kAsparagusButtonID);
+  right_container->AddChildView(radio_button);
+  radio_button->SetBounds(5, y, 70, radio_button_height);
+  radio_button->SetGroup(1);
+  y += radio_button_height + gap_between_radio_buttons;
+  radio_button = new views::RadioButton(L"Broccoli", 1);
+  radio_button->SetID(kBroccoliButtonID);
+  right_container->AddChildView(radio_button);
+  radio_button->SetBounds(5, y, 70, radio_button_height);
+  radio_button->SetGroup(1);
+  y += radio_button_height + gap_between_radio_buttons;
+  radio_button = new views::RadioButton(L"Cauliflower", 1);
+  radio_button->SetID(kCauliflowerButtonID);
+  right_container->AddChildView(radio_button);
+  radio_button->SetBounds(5, y, 70, radio_button_height);
+  radio_button->SetGroup(1);
+  y += radio_button_height + gap_between_radio_buttons;
+
+  views::View* inner_container = new views::View();
+  inner_container->set_border(
+      views::Border::CreateSolidBorder(1, SK_ColorBLACK));
+  inner_container->set_background(
+      views::Background::CreateSolidBackground(230, 230, 230));
+  inner_container->SetID(kInnerContainerID);
+  right_container->AddChildView(inner_container);
+  inner_container->SetBounds(100, 10, 150, 180);
+
+  views::ScrollView* scroll_view = new views::ScrollView();
+  scroll_view->SetID(kScrollViewID);
+  inner_container->AddChildView(scroll_view);
+  scroll_view->SetBounds(1, 1, 148, 178);
+
+  views::View* scroll_content = new views::View();
+  scroll_content->SetBounds(0, 0, 200, 200);
+  scroll_content->set_background(
+      views::Background::CreateSolidBackground(200, 200, 200));
+  scroll_view->SetContents(scroll_content);
+
+  static const wchar_t* const kTitles[] = {
+      L"Rosetta", L"Stupeur et tremblement", L"The diner game",
+      L"Ridicule", L"Le placard", L"Les Visiteurs", L"Amelie",
+      L"Joyeux Noel", L"Camping", L"Brice de Nice",
+      L"Taxi", L"Asterix"
+  };
+
+  static const int kIDs[] = {
+      kRosettaLinkID, kStupeurEtTremblementLinkID, kDinerGameLinkID,
+      kRidiculeLinkID, kClosetLinkID, kVisitingLinkID, kAmelieLinkID,
+      kJoyeuxNoelLinkID, kCampingLinkID, kBriceDeNiceLinkID,
+      kTaxiLinkID, kAsterixLinkID
+  };
+
+  DCHECK(arraysize(kTitles) == arraysize(kIDs));
+
+  y = 5;
+  for (int i = 0; i < arraysize(kTitles); ++i) {
+    views::Link* link = new views::Link(kTitles[i]);
+    link->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+    link->SetID(kIDs[i]);
+    scroll_content->AddChildView(link);
+    link->SetBounds(5, y, 300, 15);
+    y += 15;
+  }
+
+  y = 250;
+  int width = 50;
+  button = new views::NativeButton(NULL, L"OK");
+  button->SetID(kOKButtonID);
+
+  contents_->AddChildView(button);
+  button->SetBounds(150, y, width, 20);
+
+  button = new views::NativeButton(NULL, L"Cancel");
+  button->SetID(kCancelButtonID);
+  contents_->AddChildView(button);
+  button->SetBounds(250, y, width, 20);
+
+  button = new views::NativeButton(NULL, L"Help");
+  button->SetID(kHelpButtonID);
+  contents_->AddChildView(button);
+  button->SetBounds(350, y, width, 20);
+
+  y += 40;
+
+  // Left bottom box with style checkboxes.
+  views::View* contents = new views::View();
+  contents->set_background(
+      views::Background::CreateSolidBackground(SK_ColorWHITE));
+  cb = new views::Checkbox(L"Bold");
+  contents->AddChildView(cb);
+  cb->SetBounds(10, 10, 50, 20);
+  cb->SetID(kBoldCheckBoxID);
+
+  cb = new views::Checkbox(L"Italic");
+  contents->AddChildView(cb);
+  cb->SetBounds(70, 10, 50, 20);
+  cb->SetID(kItalicCheckBoxID);
+
+  cb = new views::Checkbox(L"Underlined");
+  contents->AddChildView(cb);
+  cb->SetBounds(130, 10, 70, 20);
+  cb->SetID(kUnderlinedCheckBoxID);
+
+  style_tab_ = new views::TabbedPane();
+  style_tab_->SetID(kStyleContainerID);
+  contents_->AddChildView(style_tab_);
+  style_tab_->SetBounds(10, y, 210, 50);
+  style_tab_->AddTab(L"Style", contents);
+  style_tab_->AddTab(L"Other", new views::View());
+
+  // Right bottom box with search.
+  contents = new views::View();
+  contents->set_background(
+      views::Background::CreateSolidBackground(SK_ColorWHITE));
+  text_field = new views::TextField();
+  contents->AddChildView(text_field);
+  text_field->SetBounds(10, 10, 100, 20);
+  text_field->SetID(kSearchTextFieldID);
+
+  button = new views::NativeButton(NULL, L"Search");
+  contents->AddChildView(button);
+  button->SetBounds(115, 10, 50, 20);
+  button->SetID(kSearchButtonID);
+
+  views::Link* link = new views::Link(L"Help");
+  link->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+  link->SetID(kHelpLinkID);
+  contents->AddChildView(link);
+  link->SetBounds(170, 10, 30, 15);
+
+  search_border_view_ = new BorderView(contents);
+  search_border_view_->SetID(kSearchContainerID);
+
+  contents_->AddChildView(search_border_view_);
+  search_border_view_->SetBounds(300, y, 200, 50);
+
+  y += 60;
+
+  contents = new views::View();
+  contents->SetFocusable(true);
+  contents->set_background(
+      views::Background::CreateSolidBackground(SK_ColorBLUE));
+  contents->SetID(kThumbnailContainerID);
+  button = new views::NativeButton(NULL, L"Star");
+  contents->AddChildView(button);
+  button->SetBounds(5, 5, 50, 20);
+  button->SetID(kThumbnailStarID);
+  button = new views::NativeButton(NULL, L"SuperStar");
+  contents->AddChildView(button);
+  button->SetBounds(60, 5, 100, 20);
+  button->SetID(kThumbnailSuperStarID);
+
+  contents_->AddChildView(contents);
+  contents->SetBounds(200, y, 200, 50);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FocusManagerTest
+////////////////////////////////////////////////////////////////////////////////
+
+FocusManagerTest::FocusManagerTest() {
+}
+
+FocusManagerTest::~FocusManagerTest() {
+}
+
+TestViewWindow* FocusManagerTest::GetWindow() {
+  return test_window_;
+}
+
+void FocusManagerTest::SetUp() {
+  OleInitialize(NULL);
+  test_window_ = new TestViewWindow(this);
+  test_window_->Init();
+  ShowWindow(test_window_->GetNativeView(), SW_SHOW);
+}
+
+void FocusManagerTest::TearDown() {
+  test_window_->CloseNow();
+
+  // Flush the message loop to make Purify happy.
+  message_loop_.RunAllPending();
+  OleUninitialize();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// The tests
+////////////////////////////////////////////////////////////////////////////////
+
+
+TEST_F(FocusManagerTest, NormalTraversal) {
+  const int kTraversalIDs[] = { kTopCheckBoxID,  kAppleTextFieldID,
+      kOrangeTextFieldID, kBananaTextFieldID, kKiwiTextFieldID,
+      kFruitButtonID, kFruitCheckBoxID, kAsparagusButtonID, kRosettaLinkID,
+      kStupeurEtTremblementLinkID,
+      kDinerGameLinkID, kRidiculeLinkID, kClosetLinkID, kVisitingLinkID,
+      kAmelieLinkID, kJoyeuxNoelLinkID, kCampingLinkID, kBriceDeNiceLinkID,
+      kTaxiLinkID, kAsterixLinkID, kOKButtonID, kCancelButtonID, kHelpButtonID,
+      kStyleContainerID, kBoldCheckBoxID, kItalicCheckBoxID,
+      kUnderlinedCheckBoxID, kSearchTextFieldID, kSearchButtonID, kHelpLinkID,
+      kThumbnailContainerID, kThumbnailStarID, kThumbnailSuperStarID };
+
+  // Uncomment the following line if you want to test manually the UI of this
+  // test.
+  // MessageLoop::current()->Run(new views::AcceleratorHandler());
+
+  views::FocusManager* focus_manager =
+      views::FocusManager::GetFocusManager(test_window_->GetNativeView());
+  // Let's traverse the whole focus hierarchy (several times, to make sure it
+  // loops OK).
+  focus_manager->SetFocusedView(NULL);
+  for (int i = 0; i < 3; ++i) {
+    for (int j = 0; j < arraysize(kTraversalIDs); j++) {
+      focus_manager->AdvanceFocus(false);
+      views::View* focused_view = focus_manager->GetFocusedView();
+      EXPECT_TRUE(focused_view != NULL);
+      if (focused_view)
+        EXPECT_EQ(kTraversalIDs[j], focused_view->GetID());
+    }
+  }
+
+  // Focus the 1st item.
+  views::RootView* root_view = test_window_->GetContentsRootView();
+  focus_manager->SetFocusedView(root_view->GetViewByID(kTraversalIDs[0]));
+
+  /* BROKEN because of bug #1153276.  The reverse order of traversal in Tabbed
+     Panes is broken (we go to the tab before going to the content
+  // Let's traverse in reverse order.
+  for (int i = 0; i < 3; ++i) {
+    for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) {
+      focus_manager->AdvanceFocus(true);
+      views::View* focused_view = focus_manager->GetFocusedView();
+      EXPECT_TRUE(focused_view != NULL);
+      if (focused_view)
+        EXPECT_EQ(kTraversalIDs[j], focused_view->GetID());
+    }
+  }
+  */
+}
+
+TEST_F(FocusManagerTest, TraversalWithNonEnabledViews) {
+  const int kMainContentsDisabledIDs[] = {
+      kBananaTextFieldID, kFruitCheckBoxID, kAsparagusButtonID,
+      kCauliflowerButtonID, kClosetLinkID, kVisitingLinkID, kBriceDeNiceLinkID,
+      kTaxiLinkID, kAsterixLinkID, kHelpButtonID };
+
+  const int kStyleContentsDisabledIDs[] = { kBoldCheckBoxID };
+
+  const int kSearchContentsDisabledIDs[] = { kSearchTextFieldID, kHelpLinkID };
+
+  const int kTraversalIDs[] = { kTopCheckBoxID,  kAppleTextFieldID,
+      kOrangeTextFieldID, kKiwiTextFieldID, kFruitButtonID, kBroccoliButtonID,
+      kRosettaLinkID, kStupeurEtTremblementLinkID, kDinerGameLinkID,
+      kRidiculeLinkID, kAmelieLinkID, kJoyeuxNoelLinkID, kCampingLinkID,
+      kOKButtonID, kCancelButtonID, kStyleContainerID,
+      kItalicCheckBoxID, kUnderlinedCheckBoxID, kSearchButtonID,
+      kThumbnailContainerID, kThumbnailStarID, kThumbnailSuperStarID };
+
+  // Let's disable some views.
+  views::RootView* root_view = test_window_->GetContentsRootView();
+  for (int i = 0; i < arraysize(kMainContentsDisabledIDs); i++) {
+    views::View* v = root_view->GetViewByID(kMainContentsDisabledIDs[i]);
+    ASSERT_TRUE(v != NULL);
+    if (v)
+      v->SetEnabled(false);
+  }
+  root_view = test_window_->GetStyleRootView();
+  for (int i = 0; i < arraysize(kStyleContentsDisabledIDs); i++) {
+    views::View* v = root_view->GetViewByID(kStyleContentsDisabledIDs[i]);
+    ASSERT_TRUE(v != NULL);
+    if (v)
+      v->SetEnabled(false);
+  }
+  root_view = test_window_->GetSearchRootView();
+  for (int i = 0; i < arraysize(kSearchContentsDisabledIDs); i++) {
+    views::View* v =
+        root_view->GetViewByID(kSearchContentsDisabledIDs[i]);
+    ASSERT_TRUE(v != NULL);
+    if (v)
+      v->SetEnabled(false);
+  }
+
+
+  views::FocusManager* focus_manager =
+      views::FocusManager::GetFocusManager(test_window_->GetNativeView());
+  views::View* focused_view;
+  // Let's do one traversal (several times, to make sure it loops ok).
+  for (int i = 0; i < 3;++i) {
+    for (int j = 0; j < arraysize(kTraversalIDs); j++) {
+      focus_manager->AdvanceFocus(false);
+      focused_view = focus_manager->GetFocusedView();
+      EXPECT_TRUE(focused_view != NULL);
+      if (focused_view)
+        EXPECT_EQ(kTraversalIDs[j], focused_view->GetID());
+    }
+  }
+
+  // Focus the 1st item.
+  focus_manager->AdvanceFocus(false);
+  focused_view = focus_manager->GetFocusedView();
+  EXPECT_TRUE(focused_view != NULL);
+  if (focused_view)
+    EXPECT_EQ(kTraversalIDs[0], focused_view->GetID());
+
+  // Same thing in reverse.
+  /* BROKEN because of bug #1153276.  The reverse order of traversal in Tabbed
+  Panes is broken (we go to the tab before going to the content
+
+  for (int i = 0; i < 3; ++i) {
+    for (int j = arraysize(kTraversalIDs) - 1; j >= 0; --j) {
+      focus_manager->AdvanceFocus(true);
+      focused_view = focus_manager->GetFocusedView();
+      EXPECT_TRUE(focused_view != NULL);
+      if (focused_view)
+        EXPECT_EQ(kTraversalIDs[j], focused_view->GetID());
+    }
+  }
+  */
+}
+
+}
diff --git a/views/focus/focus_util_win.cc b/views/focus/focus_util_win.cc
new file mode 100644
index 0000000..046df70
--- /dev/null
+++ b/views/focus/focus_util_win.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2009 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 "views/focus/focus_util_win.h"
+
+#include <windowsx.h>
+
+#include "base/win_util.h"
+
+namespace views {
+
+// Property used to indicate the HWND supports having mouse wheel messages
+// rerouted to it.
+static const wchar_t* const kHWNDSupportMouseWheelRerouting =
+    L"__HWND_MW_REROUTE_OK";
+
+static bool WindowSupportsRerouteMouseWheel(HWND window) {
+  while (GetWindowLong(window, GWL_STYLE) & WS_CHILD) {
+    if (!IsWindow(window))
+      break;
+
+    if (reinterpret_cast<bool>(GetProp(window,
+                                       kHWNDSupportMouseWheelRerouting))) {
+      return true;
+    }
+    window = GetParent(window);
+  }
+  return false;
+}
+
+static bool IsCompatibleWithMouseWheelRedirection(HWND window) {
+  std::wstring class_name = win_util::GetClassName(window);
+  // Mousewheel redirection to comboboxes is a surprising and
+  // undesireable user behavior.
+  return !(class_name == L"ComboBox" ||
+           class_name == L"ComboBoxEx32");
+}
+
+static bool CanRedirectMouseWheelFrom(HWND window) {
+  std::wstring class_name = win_util::GetClassName(window);
+
+  // Older Thinkpad mouse wheel drivers create a window under mouse wheel
+  // pointer. Detect if we are dealing with this window. In this case we
+  // don't need to do anything as the Thinkpad mouse driver will send
+  // mouse wheel messages to the right window.
+  if ((class_name == L"Syn Visual Class") ||
+     (class_name == L"SynTrackCursorWindowClass"))
+    return false;
+
+  return true;
+}
+
+void SetWindowSupportsRerouteMouseWheel(HWND hwnd) {
+  SetProp(hwnd, kHWNDSupportMouseWheelRerouting,
+          reinterpret_cast<HANDLE>(true));
+}
+
+bool RerouteMouseWheel(HWND window, WPARAM w_param, LPARAM l_param) {
+  // Since this is called from a subclass for every window, we can get
+  // here recursively. This will happen if, for example, a control
+  // reflects wheel scroll messages to its parent. Bail out if we got
+  // here recursively.
+  static bool recursion_break = false;
+  if (recursion_break)
+    return false;
+  // Check if this window's class has a bad interaction with rerouting.
+  if (!IsCompatibleWithMouseWheelRedirection(window))
+    return false;
+
+  DWORD current_process = GetCurrentProcessId();
+  POINT wheel_location = { GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param) };
+  HWND window_under_wheel = WindowFromPoint(wheel_location);
+
+  if (!CanRedirectMouseWheelFrom(window_under_wheel))
+    return false;
+
+  // Find the lowest Chrome window in the hierarchy that can be the
+  // target of mouse wheel redirection.
+  while (window != window_under_wheel) {
+    // If window_under_wheel is not a valid Chrome window, then return true to
+    // suppress further processing of the message.
+    if (!::IsWindow(window_under_wheel))
+      return true;
+    DWORD wheel_window_process = 0;
+    GetWindowThreadProcessId(window_under_wheel, &wheel_window_process);
+    if (current_process != wheel_window_process) {
+      if (IsChild(window, window_under_wheel)) {
+        // If this message is reflected from a child window in a different
+        // process (happens with out of process windowed plugins) then
+        // we don't want to reroute the wheel message.
+        return false;
+      } else {
+        // The wheel is scrolling over an unrelated window. Make sure that we
+        // have marked that window as supporting mouse wheel rerouting.
+        // Otherwise, we cannot send random WM_MOUSEWHEEL messages to arbitrary
+        // windows. So just drop the message.
+        if (!WindowSupportsRerouteMouseWheel(window_under_wheel))
+          return true;
+      }
+    }
+
+    // window_under_wheel is a Chrome window.  If allowed, redirect.
+    if (IsCompatibleWithMouseWheelRedirection(window_under_wheel)) {
+      recursion_break = true;
+      SendMessage(window_under_wheel, WM_MOUSEWHEEL, w_param, l_param);
+      recursion_break = false;
+      return true;
+    }
+    // If redirection is disallowed, try the parent.
+    window_under_wheel = GetAncestor(window_under_wheel, GA_PARENT);
+  }
+  // If we traversed back to the starting point, we should process
+  // this message normally; return false.
+  return false;
+}
+
+}  // namespace views
diff --git a/views/focus/focus_util_win.h b/views/focus/focus_util_win.h
new file mode 100644
index 0000000..832a6df
--- /dev/null
+++ b/views/focus/focus_util_win.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2009 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 VIEWS_FOCUS_FOCUS_UTIL_WIN_H_
+#define VIEWS_FOCUS_FOCUS_UTIL_WIN_H_
+
+#include <windows.h>
+
+namespace views {
+
+// Marks the passed |hwnd| as supporting mouse-wheel message rerouting.
+// We reroute the mouse wheel messages to such HWND when they are under the
+// mouse pointer (but are not the active window)
+void SetWindowSupportsRerouteMouseWheel(HWND hwnd);
+
+// Forwards mouse wheel messages to the window under it.
+// Windows sends mouse wheel messages to the currently active window.
+// This causes a window to scroll even if it is not currently under the mouse
+// wheel. The following code gives mouse wheel messages to the window under the
+// mouse wheel in order to scroll that window. This is arguably a better user
+// experience.  The returns value says whether the mouse wheel message was
+// successfully redirected.
+bool RerouteMouseWheel(HWND window, WPARAM w_param, LPARAM l_param);
+
+}   // namespace views
+
+#endif  // VIEWS_FOCUS_FOCUS_UTIL_WIN_H_
diff --git a/views/focus/view_storage.cc b/views/focus/view_storage.cc
new file mode 100644
index 0000000..a108530
--- /dev/null
+++ b/views/focus/view_storage.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2006-2008 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 "views/focus/view_storage.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/stl_util-inl.h"
+
+namespace views {
+
+// This struct contains the information to locate a specific view.
+// Locating a view is not always straight-forward as a view can be a floating
+// view, or the child of a floating view. Floating views are frequently deleted
+// and recreated (typically when their container is laid out).
+struct ViewLocationInfo {
+  // True if the view is floating or the child of a floating view. False
+  // otherwise.
+  bool is_floating_view;
+
+  // If non floating, this is the stored view. If floating, the parent of the
+  // floating view.
+  View*  view;
+
+  // The id of the floating view.
+  int floating_view_id;
+
+  // The path from the floating view to the stored view.  The path is composed
+  // of the indexes of the views in the hierarchy.
+  std::vector<int> floating_view_to_view_path;
+};
+
+// static
+ViewStorage* ViewStorage::GetSharedInstance() {
+  return Singleton<ViewStorage>::get();
+}
+
+ViewStorage::ViewStorage() : view_storage_next_id_(0) {
+}
+
+ViewStorage::~ViewStorage() {
+  STLDeleteContainerPairSecondPointers(id_to_view_location_.begin(),
+                                       id_to_view_location_.end());
+
+  STLDeleteContainerPairSecondPointers(view_to_ids_.begin(),
+                                       view_to_ids_.end());
+}
+
+int ViewStorage::CreateStorageID() {
+  return view_storage_next_id_++;
+}
+
+void ViewStorage::StoreView(int storage_id, View* view) {
+  DCHECK(view);
+  std::map<int, ViewLocationInfo*>::iterator iter =
+      id_to_view_location_.find(storage_id);
+  DCHECK(iter == id_to_view_location_.end());
+
+  if (iter != id_to_view_location_.end())
+    RemoveView(storage_id);
+
+  ViewLocationInfo* view_location_info = new ViewLocationInfo();
+  View* floating_view_parent = view->RetrieveFloatingViewParent();
+  if (floating_view_parent) {
+    // The view is a floating view or is a child of a floating view.
+    view_location_info->is_floating_view = true;
+    view_location_info->view = floating_view_parent->GetParent();
+    view_location_info->floating_view_id =
+        floating_view_parent->GetFloatingViewID();
+    // Ley's store the path from the floating view to the actual view so we can
+    // locate it when restoring.
+    View::GetViewPath(floating_view_parent, view,
+                      &(view_location_info->floating_view_to_view_path));
+  } else {
+    // It is a non floating view, it can be stored as is.
+    view_location_info->is_floating_view = false;
+    view_location_info->view = view;
+  }
+  id_to_view_location_[storage_id] = view_location_info;
+
+  std::vector<int>* ids = NULL;
+  std::map<View*, std::vector<int>*>::iterator id_iter =
+      view_to_ids_.find(view_location_info->view);
+  if (id_iter == view_to_ids_.end()) {
+    ids = new std::vector<int>();
+    view_to_ids_[view_location_info->view] = ids;
+  } else {
+    ids = id_iter->second;
+  }
+  ids->push_back(storage_id);
+}
+
+View* ViewStorage::RetrieveView(int storage_id) {
+  std::map<int, ViewLocationInfo*>::iterator iter =
+      id_to_view_location_.find(storage_id);
+  if (iter == id_to_view_location_.end())
+    return NULL;
+
+  ViewLocationInfo* view_location_info = iter->second;
+  if (view_location_info->is_floating_view) {
+    View* floating_view = view_location_info->view->
+        RetrieveFloatingViewForID(view_location_info->floating_view_id);
+    View* v = NULL;
+    if (floating_view) {
+      v = View::GetViewForPath(floating_view,
+                               view_location_info->floating_view_to_view_path);
+    }
+    if (!v) {
+      // If we have not found the view, it means either the floating view with
+      // the id we have is gone, or it has changed and the actual child view
+      // we have the path for is not accessible.  In that case, let's make sure
+      // we don't leak the ViewLocationInfo.
+      RemoveView(storage_id);
+    }
+    return v;
+  } else {
+    return view_location_info->view;
+  }
+}
+
+void ViewStorage::RemoveView(int storage_id) {
+  EraseView(storage_id, false);
+}
+
+void ViewStorage::ViewRemoved(View* parent, View* removed) {
+  // Let's first retrieve the ids for that view.
+  std::map<View*, std::vector<int>*>::iterator ids_iter =
+      view_to_ids_.find(removed);
+
+  if (ids_iter == view_to_ids_.end()) {
+    // That view is not in the view storage.
+    return;
+  }
+
+  std::vector<int>* ids = ids_iter->second;
+  DCHECK(!ids->empty());
+  EraseView((*ids)[0], true);
+}
+
+void ViewStorage::EraseView(int storage_id, bool remove_all_ids) {
+  // Remove the view from id_to_view_location_.
+  std::map<int, ViewLocationInfo*>::iterator location_iter =
+      id_to_view_location_.find(storage_id);
+  if (location_iter == id_to_view_location_.end())
+    return;
+
+  ViewLocationInfo* view_location = location_iter->second;
+  View* view = view_location->view;
+  delete view_location;
+  id_to_view_location_.erase(location_iter);
+
+  // Also update view_to_ids_.
+  std::map<View*, std::vector<int>*>::iterator ids_iter =
+      view_to_ids_.find(view);
+  DCHECK(ids_iter != view_to_ids_.end());
+  std::vector<int>* ids = ids_iter->second;
+
+  if (remove_all_ids) {
+    for (size_t i = 0; i < ids->size(); ++i) {
+      location_iter = id_to_view_location_.find((*ids)[i]);
+      if (location_iter != id_to_view_location_.end()) {
+        delete location_iter->second;
+        id_to_view_location_.erase(location_iter);
+      }
+    }
+    ids->clear();
+  } else {
+    std::vector<int>::iterator id_iter =
+        std::find(ids->begin(), ids->end(), storage_id);
+    DCHECK(id_iter != ids->end());
+    ids->erase(id_iter);
+  }
+
+  if (ids->empty()) {
+    delete ids;
+    view_to_ids_.erase(ids_iter);
+  }
+}
+
+}  // namespace views
diff --git a/views/focus/view_storage.h b/views/focus/view_storage.h
new file mode 100644
index 0000000..9182429
--- /dev/null
+++ b/views/focus/view_storage.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2006-2008 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 VIEWS_FOCUS_VIEW_STORAGE_H_
+#define VIEWS_FOCUS_VIEW_STORAGE_H_
+
+#include "base/singleton.h"
+#include "views/view.h"
+
+// This class is a simple storage place for storing/retrieving views.  It is
+// used for example in the FocusManager to store/restore focused views when the
+// main window becomes active/inactive.  It supports floating views, meaning
+// that when you store a view, it can be retrieved even if it is a floating
+// view or the child of a floating view that has been detached since the view
+// was stored (in which case the floating view is recreated and reattached).
+// It also automatically removes a view from the storage if the view is removed
+// from the tree hierarchy (or in the case of a floating view, if the view
+// containing the floating view is removed).
+//
+// To use it, you first need to create a view storage id that can then be used
+// to store/retrieve views.
+
+namespace views {
+
+struct ViewLocationInfo;
+
+class ViewStorage {
+ public:
+  // Returns the global ViewStorage instance.
+  // It is guaranted to be non NULL.
+  static ViewStorage* GetSharedInstance();
+
+  // Returns a unique storage id that can be used to store/retrieve views.
+  int CreateStorageID();
+
+  // Associates |view| with the specified |storage_id|.
+  void StoreView(int storage_id, View* view);
+
+  // Returns the view associated with |storage_id| if any, NULL otherwise.
+  View* RetrieveView(int storage_id);
+
+  // Removes the view associated with |storage_id| if any.
+  void RemoveView(int storage_id);
+
+  // Notifies the ViewStorage that a view was removed from its parent somewhere.
+  void ViewRemoved(View* parent, View* removed);
+
+#ifdef UNIT_TEST
+  size_t view_count() const { return view_to_ids_.size(); }
+#endif
+
+ private:
+  friend struct DefaultSingletonTraits<ViewStorage>;
+
+  ViewStorage();
+  ~ViewStorage();
+
+  // Removes the view associated with |storage_id|. If |remove_all_ids| is true,
+  // all other mapping pointing to the same view are removed as well.
+  void EraseView(int storage_id, bool remove_all_ids);
+
+  // Next id for the view storage.
+  int view_storage_next_id_;
+
+  // The association id to View used for the view storage.  The ViewStorage owns
+  // the ViewLocationInfo.
+  std::map<int, ViewLocationInfo*> id_to_view_location_;
+
+  // Association View to id, used to speed up view notification removal.
+  std::map<View*, std::vector<int>*> view_to_ids_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewStorage);
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_FOCUS_VIEW_STORAGE_H_
diff --git a/views/grid_layout.cc b/views/grid_layout.cc
new file mode 100644
index 0000000..7eb07d1
--- /dev/null
+++ b/views/grid_layout.cc
@@ -0,0 +1,1013 @@
+// Copyright (c) 2006-2008 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 "views/grid_layout.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "views/view.h"
+
+namespace views {
+
+// LayoutElement ------------------------------------------------------
+
+// A LayoutElement has a size and location along one axis. It contains
+// methods that are used along both axis.
+class LayoutElement {
+ public:
+  // Invokes ResetSize on all the layout elements.
+  template <class T>
+  static void ResetSizes(std::vector<T*>* elements) {
+    // Reset the layout width of each column.
+    for (typename std::vector<T*>::iterator i = elements->begin();
+         i != elements->end(); ++i) {
+      (*i)->ResetSize();
+    }
+  }
+
+  // Sets the location of each element to be the sum of the sizes of the
+  // preceding elements.
+  template <class T>
+  static void CalculateLocationsFromSize(std::vector<T*>* elements) {
+    // Reset the layout width of each column.
+    int location = 0;
+    for (typename std::vector<T*>::iterator i = elements->begin();
+         i != elements->end(); ++i) {
+      (*i)->SetLocation(location);
+      location += (*i)->Size();
+    }
+  }
+
+  // Distributes delta among the resizable elements.
+  // Each resizable element is given ResizePercent / total_percent * delta
+  // pixels extra of space.
+  template <class T>
+  static void DistributeDelta(int delta, std::vector<T*>* elements) {
+    if (delta == 0)
+      return;
+
+    float total_percent = 0;
+    int resize_count = 0;
+    for (typename std::vector<T*>::iterator i = elements->begin();
+         i != elements->end(); ++i) {
+      total_percent += (*i)->ResizePercent();
+      resize_count++;
+    }
+    if (total_percent == 0) {
+      // None of the elements are resizable, return.
+      return;
+    }
+    int remaining = delta;
+    int resized = resize_count;
+    for (typename std::vector<T*>::iterator i = elements->begin();
+         i != elements->end(); ++i) {
+      T* element = *i;
+      if (element->ResizePercent() > 0) {
+        int to_give;
+        if (--resized == 0) {
+          to_give = remaining;
+        } else {
+          to_give = static_cast<int>(delta *
+                                    (element->resize_percent_ / total_percent));
+          remaining -= to_give;
+        }
+        element->SetSize(element->Size() + to_give);
+      }
+    }
+  }
+
+  // Returns the sum of the size of the elements from start to start + length.
+  template <class T>
+  static int TotalSize(int start, int length, std::vector<T*>* elements) {
+    DCHECK(start >= 0 && length > 0 &&
+           start + length <= static_cast<int>(elements->size()));
+    int size = 0;
+    for (int i = start, max = start + length; i < max; ++i) {
+      size += (*elements)[i]->Size();
+    }
+    return size;
+  }
+
+  explicit LayoutElement(float resize_percent)
+      : resize_percent_(resize_percent) {
+    DCHECK(resize_percent >= 0);
+  }
+
+  virtual ~LayoutElement() {}
+
+  void SetLocation(int location) {
+    location_ = location;
+  }
+
+  int Location() {
+    return location_;
+  }
+
+  // Adjusts the size of this LayoutElement to be the max of the current size
+  // and the specified size.
+  virtual void AdjustSize(int size) {
+    size_ = std::max(size_, size);
+  }
+
+  // Resets the size to the initial size. This sets the size to 0, but
+  // subclasses that have a different initial size should override.
+  virtual void ResetSize() {
+    SetSize(0);
+  }
+
+  void SetSize(int size) {
+    size_ = size;
+  }
+
+  int Size() {
+    return size_;
+  }
+
+  void SetResizePercent(float percent) {
+    resize_percent_ = percent;
+  }
+
+  float ResizePercent() {
+    return resize_percent_;
+  }
+
+  bool IsResizable() {
+    return resize_percent_ > 0;
+  }
+
+ private:
+  float resize_percent_;
+  int location_;
+  int size_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(LayoutElement);
+};
+
+// Column -------------------------------------------------------------
+
+// As the name implies, this represents a Column. Column contains default
+// values for views originating in this column.
+class Column : public LayoutElement {
+ public:
+  Column(GridLayout::Alignment h_align,
+         GridLayout::Alignment v_align,
+         float resize_percent,
+         GridLayout::SizeType size_type,
+         int fixed_width,
+         int min_width,
+         size_t index,
+         bool is_padding)
+    : LayoutElement(resize_percent),
+      h_align_(h_align),
+      v_align_(v_align),
+      size_type_(size_type),
+      same_size_column_(-1),
+      fixed_width_(fixed_width),
+      min_width_(min_width),
+      index_(index),
+      is_padding_(is_padding),
+      master_column_(NULL) {}
+
+  virtual ~Column() {}
+
+  GridLayout::Alignment h_align() { return h_align_; }
+  GridLayout::Alignment v_align() { return v_align_; }
+
+  virtual void ResetSize();
+
+ private:
+  friend class ColumnSet;
+  friend class GridLayout;
+
+  Column* GetLastMasterColumn();
+
+  // Determines the max size of all linked columns, and sets each column
+  // to that size. This should only be used for the master column.
+  void UnifySameSizedColumnSizes();
+
+  virtual void AdjustSize(int size);
+
+  const GridLayout::Alignment h_align_;
+  const GridLayout::Alignment v_align_;
+  const GridLayout::SizeType size_type_;
+  int same_size_column_;
+  const int fixed_width_;
+  const int min_width_;
+
+  // Index of this column in the ColumnSet.
+  const size_t index_;
+
+  const bool is_padding_;
+
+  // If multiple columns have their sizes linked, one is the
+  // master column. The master column is identified by the
+  // master_column field being equal to itself. The master columns
+  // same_size_columns field contains the set of Columns with the
+  // the same size. Columns who are linked to other columns, but
+  // are not the master column have their master_column pointing to
+  // one of the other linked columns. Use the method GetLastMasterColumn
+  // to resolve the true master column.
+  std::vector<Column*> same_size_columns_;
+  Column* master_column_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Column);
+};
+
+void Column::ResetSize() {
+  if (size_type_ == GridLayout::FIXED) {
+    SetSize(fixed_width_);
+  } else {
+    SetSize(min_width_);
+  }
+}
+
+Column* Column::GetLastMasterColumn() {
+  if (master_column_ == NULL) {
+    return NULL;
+  }
+  if (master_column_ == this) {
+    return this;
+  }
+  return master_column_->GetLastMasterColumn();
+}
+
+void Column::UnifySameSizedColumnSizes() {
+  DCHECK(master_column_ == this);
+
+  // Accumulate the size first.
+  int size = 0;
+  for (std::vector<Column*>::iterator i = same_size_columns_.begin();
+       i != same_size_columns_.end(); ++i) {
+      size = std::max(size, (*i)->Size());
+  }
+
+  // Then apply it.
+  for (std::vector<Column*>::iterator i = same_size_columns_.begin();
+       i != same_size_columns_.end(); ++i) {
+      (*i)->SetSize(size);
+  }
+}
+
+void Column::AdjustSize(int size) {
+  if (size_type_ == GridLayout::USE_PREF)
+    LayoutElement::AdjustSize(size);
+}
+
+// Row -------------------------------------------------------------
+
+class Row : public LayoutElement {
+ public:
+  Row(bool fixed_height, int height, float resize_percent,
+      ColumnSet* column_set)
+    : LayoutElement(resize_percent),
+      fixed_height_(fixed_height),
+      height_(height),
+      column_set_(column_set) {
+  }
+
+  virtual ~Row() {}
+
+  virtual void ResetSize() {
+    SetSize(height_);
+  }
+
+  ColumnSet* column_set() {
+    return column_set_;
+  }
+
+ private:
+  const bool fixed_height_;
+  const int height_;
+  // The column set used for this row; null for padding rows.
+  ColumnSet* column_set_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Row);
+};
+
+// ViewState -------------------------------------------------------------
+
+// Identifies the location in the grid of a particular view, along with
+// placement information and size information.
+struct ViewState {
+  ViewState(ColumnSet* column_set, View* view, int start_col, int start_row,
+            int col_span, int row_span, GridLayout::Alignment h_align,
+            GridLayout::Alignment v_align, int pref_width, int pref_height)
+      : column_set(column_set),
+        view(view),
+        start_col(start_col),
+        start_row(start_row),
+        col_span(col_span),
+        row_span(row_span),
+        h_align(h_align),
+        v_align(v_align),
+        pref_width_fixed(pref_width > 0),
+        pref_height_fixed(pref_height > 0),
+        pref_width(pref_width),
+        pref_height(pref_height),
+        remaining_width(0),
+        remaining_height(0) {
+    DCHECK(view && start_col >= 0 && start_row >= 0 && col_span > 0 &&
+           row_span > 0 && start_col < column_set->num_columns() &&
+           (start_col + col_span) <= column_set->num_columns());
+  }
+
+  ColumnSet* const column_set;
+  View* const view;
+  const int start_col;
+  const int start_row;
+  const int col_span;
+  const int row_span;
+  const GridLayout::Alignment h_align;
+  const GridLayout::Alignment v_align;
+
+  // If true, the pref_width/pref_height were explicitly set and the view's
+  // preferred size is ignored.
+  const bool pref_width_fixed;
+  const bool pref_height_fixed;
+
+  // The preferred width/height. These are reset during the layout process.
+  int pref_width;
+  int pref_height;
+
+  // Used during layout. Gives how much width/height has not yet been
+  // distributed to the columns/rows the view is in.
+  int remaining_width;
+  int remaining_height;
+};
+
+static bool CompareByColumnSpan(const ViewState* v1, const ViewState* v2) {
+  return v1->col_span < v2->col_span;
+}
+
+static bool CompareByRowSpan(const ViewState* v1, const ViewState* v2) {
+  return v1->row_span < v2->row_span;
+}
+
+// ColumnSet -------------------------------------------------------------
+
+ColumnSet::ColumnSet(int id) : id_(id) {
+}
+
+ColumnSet::~ColumnSet() {
+  for (std::vector<Column*>::iterator i = columns_.begin();
+       i != columns_.end(); ++i) {
+    delete *i;
+  }
+}
+
+void ColumnSet::AddPaddingColumn(float resize_percent, int width) {
+  AddColumn(GridLayout::FILL, GridLayout::FILL, resize_percent,
+            GridLayout::FIXED, width, width, true);
+}
+
+void ColumnSet::AddColumn(GridLayout::Alignment h_align,
+                          GridLayout::Alignment v_align,
+                          float resize_percent,
+                          GridLayout::SizeType size_type,
+                          int fixed_width,
+                          int min_width) {
+  AddColumn(h_align, v_align, resize_percent, size_type, fixed_width,
+            min_width, false);
+}
+
+
+void ColumnSet::LinkColumnSizes(int first, ...) {
+  va_list marker;
+  va_start(marker, first);
+  DCHECK(first >= 0 && first < num_columns());
+  for (int last = first, next = va_arg(marker, int); next != -1;
+       next = va_arg(marker, int)) {
+    DCHECK(next >= 0 && next < num_columns());
+    columns_[last]->same_size_column_ = next;
+    last = next;
+  }
+  va_end(marker);
+}
+
+void ColumnSet::AddColumn(GridLayout::Alignment h_align,
+                          GridLayout::Alignment v_align,
+                          float resize_percent,
+                          GridLayout::SizeType size_type,
+                          int fixed_width,
+                          int min_width,
+                          bool is_padding) {
+  Column* column = new Column(h_align, v_align, resize_percent, size_type,
+                              fixed_width, min_width, columns_.size(),
+                              is_padding);
+  columns_.push_back(column);
+}
+
+void ColumnSet::AddViewState(ViewState* view_state) {
+  // view_states are ordered by column_span (in ascending order).
+  std::vector<ViewState*>::iterator i = lower_bound(view_states_.begin(),
+                                                    view_states_.end(),
+                                                    view_state,
+                                                    CompareByColumnSpan);
+  view_states_.insert(i, view_state);
+}
+
+void ColumnSet::CalculateMasterColumns() {
+  for (std::vector<Column*>::iterator i = columns_.begin();
+       i != columns_.end(); ++i) {
+    Column* column = *i;
+    int same_size_column_index = column->same_size_column_;
+    if (same_size_column_index != -1) {
+      DCHECK(same_size_column_index >= 0 &&
+             same_size_column_index < static_cast<int>(columns_.size()));
+      Column* master_column = column->master_column_;
+      Column* same_size_column = columns_[same_size_column_index];
+      Column* same_size_column_master = same_size_column->master_column_;
+      if (master_column == NULL) {
+        // Current column is not linked to any other column.
+        if (same_size_column_master == NULL) {
+          // Both columns are not linked.
+          column->master_column_ = column;
+          same_size_column->master_column_ = column;
+          column->same_size_columns_.push_back(same_size_column);
+          column->same_size_columns_.push_back(column);
+        } else {
+          // Column to link to is linked with other columns.
+          // Add current column to list of linked columns in other columns
+          // master column.
+          same_size_column->GetLastMasterColumn()->
+              same_size_columns_.push_back(column);
+          // And update the master column for the current column to that
+          // of the same sized column.
+          column->master_column_ = same_size_column;
+        }
+      } else {
+        // Current column is already linked with another column.
+        if (same_size_column_master == NULL) {
+          // Column to link with is not linked to any other columns.
+          // Update it's master_column.
+          same_size_column->master_column_ = column;
+          // Add linked column to list of linked column.
+          column->GetLastMasterColumn()->same_size_columns_.
+              push_back(same_size_column);
+        } else if (column->GetLastMasterColumn() !=
+                   same_size_column->GetLastMasterColumn()) {
+          // The two columns are already linked with other columns.
+          std::vector<Column*>* same_size_columns =
+              &(column->GetLastMasterColumn()->same_size_columns_);
+          std::vector<Column*>* other_same_size_columns =
+              &(same_size_column->GetLastMasterColumn()->same_size_columns_);
+          // Add all the columns from the others master to current columns
+          // master.
+          same_size_columns->insert(same_size_columns->end(),
+                                     other_same_size_columns->begin(),
+                                     other_same_size_columns->end());
+          // The other master is no longer a master, clear its vector of
+          // linked columns, and reset its master_column.
+          other_same_size_columns->clear();
+          same_size_column->GetLastMasterColumn()->master_column_ = column;
+        }
+      }
+    }
+  }
+  AccumulateMasterColumns();
+}
+
+void ColumnSet::AccumulateMasterColumns() {
+  DCHECK(master_columns_.empty());
+  for (std::vector<Column*>::iterator i = columns_.begin();
+       i != columns_.end(); ++i) {
+    Column* column = *i;
+    Column* master_column = column->GetLastMasterColumn();
+    if (master_column &&
+        find(master_columns_.begin(), master_columns_.end(),
+             master_column) == master_columns_.end()) {
+      master_columns_.push_back(master_column);
+    }
+    // At this point, GetLastMasterColumn may not == master_column
+    // (may have to go through a few Columns)_. Reset master_column to
+    // avoid hops.
+    column->master_column_ = master_column;
+  }
+}
+
+void ColumnSet::UnifySameSizedColumnSizes() {
+  for (std::vector<Column*>::iterator i = master_columns_.begin();
+       i != master_columns_.end(); ++i) {
+    (*i)->UnifySameSizedColumnSizes();
+  }
+}
+
+void ColumnSet::UpdateRemainingWidth(ViewState* view_state) {
+  for (int i = view_state->start_col; i < view_state->col_span; ++i) {
+    view_state->remaining_width -= columns_[i]->Size();
+  }
+}
+
+void ColumnSet::DistributeRemainingWidth(ViewState* view_state) {
+  // This is nearly the same as that for rows, but differs in so far as how
+  // Rows and Columns are treated. Rows have two states, resizable or not.
+  // Columns have three, resizable, USE_PREF or not resizable. This results
+  // in slightly different handling for distributing unaccounted size.
+  int width = view_state->remaining_width;
+  if (width <= 0) {
+    // The columns this view is in are big enough to accommodate it.
+    return;
+  }
+
+  // Determine which columns are resizable, and which have a size type
+  // of USE_PREF.
+  int resizable_columns = 0;
+  int pref_size_columns = 0;
+  int start_col = view_state->start_col;
+  int max_col = view_state->start_col + view_state->col_span;
+  for (int i = start_col; i < max_col; ++i) {
+    if (columns_[i]->IsResizable()) {
+      resizable_columns++;
+    } else if (columns_[i]->size_type_ == GridLayout::USE_PREF) {
+      pref_size_columns++;
+    }
+  }
+
+  if (resizable_columns > 0) {
+    // There are resizable columns, give the remaining width to them.
+    int to_distribute = width / resizable_columns;
+    for (int i = start_col; i < max_col; ++i) {
+      if (columns_[i]->IsResizable()) {
+        width -= to_distribute;
+        if (width < to_distribute) {
+          // Give all slop to the last column.
+          to_distribute += width;
+        }
+        columns_[i]->SetSize(columns_[i]->Size() + to_distribute);
+      }
+    }
+  } else if (pref_size_columns > 0) {
+    // None of the columns are resizable, distribute the width among those
+    // that use the preferred size.
+    int to_distribute = width / pref_size_columns;
+    for (int i = start_col; i < max_col; ++i) {
+      if (columns_[i]->size_type_ == GridLayout::USE_PREF) {
+        width -= to_distribute;
+        if (width < to_distribute)
+          to_distribute += width;
+        columns_[i]->SetSize(columns_[i]->Size() + to_distribute);
+      }
+    }
+  }
+}
+
+int ColumnSet::LayoutWidth() {
+  int width = 0;
+  for (std::vector<Column*>::iterator i = columns_.begin();
+       i != columns_.end(); ++i) {
+    width += (*i)->Size();
+  }
+  return width;
+}
+
+int ColumnSet::GetColumnWidth(int start_col, int col_span) {
+  return LayoutElement::TotalSize(start_col, col_span, &columns_);
+}
+
+void ColumnSet::ResetColumnXCoordinates() {
+  LayoutElement::CalculateLocationsFromSize(&columns_);
+}
+
+void ColumnSet::CalculateSize() {
+  gfx::Size pref;
+  // Reset the preferred and remaining sizes.
+  for (std::vector<ViewState*>::iterator i = view_states_.begin();
+       i != view_states_.end(); ++i) {
+    ViewState* view_state = *i;
+    if (!view_state->pref_width_fixed || !view_state->pref_height_fixed) {
+      pref = view_state->view->GetPreferredSize();
+      if (!view_state->pref_width_fixed)
+        view_state->pref_width = pref.width();
+      if (!view_state->pref_height_fixed)
+        view_state->pref_height = pref.height();
+    }
+    view_state->remaining_width = pref.width();
+    view_state->remaining_height = pref.height();
+  }
+
+  // Let layout element reset the sizes for us.
+  LayoutElement::ResetSizes(&columns_);
+
+  // Distribute the size of each view with a col span == 1.
+  std::vector<ViewState*>::iterator view_state_iterator =
+      view_states_.begin();
+  for (; view_state_iterator != view_states_.end() &&
+         (*view_state_iterator)->col_span == 1; ++view_state_iterator) {
+    ViewState* view_state = *view_state_iterator;
+    Column* column = columns_[view_state->start_col];
+    column->AdjustSize(view_state->pref_width);
+    view_state->remaining_width -= column->Size();
+  }
+
+  // Make sure all linked columns have the same size.
+  UnifySameSizedColumnSizes();
+
+  // Distribute the size of each view with a column span > 1.
+  for (; view_state_iterator != view_states_.end(); ++view_state_iterator) {
+    ViewState* view_state = *view_state_iterator;
+
+    // Update the remaining_width from columns this view_state touches.
+    UpdateRemainingWidth(view_state);
+
+    // Distribute the remaining width.
+    DistributeRemainingWidth(view_state);
+
+    // Update the size of linked columns.
+    // This may need to be combined with previous step.
+    UnifySameSizedColumnSizes();
+  }
+}
+
+void ColumnSet::Resize(int delta) {
+  LayoutElement::DistributeDelta(delta, &columns_);
+}
+
+// GridLayout -------------------------------------------------------------
+
+GridLayout::GridLayout(View* host)
+    : host_(host),
+      calculated_master_columns_(false),
+      remaining_row_span_(0),
+      current_row_(-1),
+      next_column_(0),
+      current_row_col_set_(NULL),
+      top_inset_(0),
+      bottom_inset_(0),
+      left_inset_(0),
+      right_inset_(0),
+      adding_view_(false) {
+  DCHECK(host);
+}
+
+GridLayout::~GridLayout() {
+  for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
+       i != column_sets_.end(); ++i) {
+    delete *i;
+  }
+  for (std::vector<ViewState*>::iterator i = view_states_.begin();
+       i != view_states_.end(); ++i) {
+    delete *i;
+  }
+  for (std::vector<Row*>::iterator i = rows_.begin();
+       i != rows_.end(); ++i) {
+    delete *i;
+  }
+}
+
+void GridLayout::SetInsets(int top, int left, int bottom, int right) {
+  top_inset_ = top;
+  bottom_inset_ = bottom;
+  left_inset_ = left;
+  right_inset_ = right;
+}
+
+ColumnSet* GridLayout::AddColumnSet(int id) {
+  DCHECK(GetColumnSet(id) == NULL);
+  ColumnSet* column_set = new ColumnSet(id);
+  column_sets_.push_back(column_set);
+  return column_set;
+}
+
+void GridLayout::StartRowWithPadding(float vertical_resize, int column_set_id,
+                                     float padding_resize, int padding) {
+  AddPaddingRow(padding_resize, padding);
+  StartRow(vertical_resize, column_set_id);
+}
+
+void GridLayout::StartRow(float vertical_resize, int column_set_id) {
+  ColumnSet* column_set = GetColumnSet(column_set_id);
+  DCHECK(column_set);
+  AddRow(new Row(false, 0, vertical_resize, column_set));
+}
+
+void GridLayout::AddPaddingRow(float vertical_resize, int pixel_count) {
+  AddRow(new Row(true, pixel_count, vertical_resize, NULL));
+}
+
+void GridLayout::SkipColumns(int col_count) {
+  DCHECK(col_count > 0);
+  next_column_ += col_count;
+  DCHECK(current_row_col_set_ &&
+         next_column_ <= current_row_col_set_->num_columns());
+  SkipPaddingColumns();
+}
+
+void GridLayout::AddView(View* view) {
+  AddView(view, 1, 1);
+}
+
+void GridLayout::AddView(View* view, int col_span, int row_span) {
+  DCHECK(current_row_col_set_ &&
+         next_column_ < current_row_col_set_->num_columns());
+  Column* column = current_row_col_set_->columns_[next_column_];
+  AddView(view, col_span, row_span, column->h_align(), column->v_align());
+}
+
+void GridLayout::AddView(View* view, int col_span, int row_span,
+                         Alignment h_align, Alignment v_align) {
+  AddView(view, col_span, row_span, h_align, v_align, 0, 0);
+}
+
+void GridLayout::AddView(View* view, int col_span, int row_span,
+                         Alignment h_align, Alignment v_align,
+                         int pref_width, int pref_height) {
+  DCHECK(current_row_col_set_ && col_span > 0 && row_span > 0 &&
+         (next_column_ + col_span) <= current_row_col_set_->num_columns());
+  ViewState* state =
+      new ViewState(current_row_col_set_, view, next_column_, current_row_,
+                    col_span, row_span, h_align, v_align, pref_width,
+                    pref_height);
+  AddViewState(state);
+}
+
+static void CalculateSize(int pref_size, GridLayout::Alignment alignment,
+                          int* location, int* size) {
+  if (alignment != GridLayout::FILL) {
+    int available_size = *size;
+    *size = std::min(*size, pref_size);
+    switch (alignment) {
+      case GridLayout::LEADING:
+        // Nothing to do, location already points to start.
+        break;
+      case GridLayout::CENTER:
+        *location += (available_size - *size) / 2;
+        break;
+      case GridLayout::TRAILING:
+        *location = *location + available_size - *size;
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
+}
+
+void GridLayout::Installed(View* host) {
+  DCHECK(host_ == host);
+}
+
+void GridLayout::Uninstalled(View* host) {
+  DCHECK(host_ == host);
+}
+
+void GridLayout::ViewAdded(View* host, View* view) {
+  DCHECK(host_ == host && adding_view_);
+}
+
+void GridLayout::ViewRemoved(View* host, View* view) {
+  DCHECK(host_ == host);
+}
+
+void GridLayout::Layout(View* host) {
+  DCHECK(host_ == host);
+  // SizeRowsAndColumns sets the size and location of each row/column, but
+  // not of the views.
+  gfx::Size pref;
+  SizeRowsAndColumns(true, host_->width(), host_->height(), &pref);
+
+  // Size each view.
+  for (std::vector<ViewState*>::iterator i = view_states_.begin();
+       i != view_states_.end(); ++i) {
+    ViewState* view_state = *i;
+    ColumnSet* column_set = view_state->column_set;
+    View* view = (*i)->view;
+    DCHECK(view);
+    int x = column_set->columns_[view_state->start_col]->Location() +
+            left_inset_;
+    int width = column_set->GetColumnWidth(view_state->start_col,
+                                           view_state->col_span);
+    CalculateSize(view_state->pref_width, view_state->h_align,
+                  &x, &width);
+    int y = rows_[view_state->start_row]->Location() + top_inset_;
+    int height = LayoutElement::TotalSize(view_state->start_row,
+                                          view_state->row_span, &rows_);
+    CalculateSize(view_state->pref_height, view_state->v_align,
+                  &y, &height);
+    view->SetBounds(x, y, width, height);
+  }
+}
+
+gfx::Size GridLayout::GetPreferredSize(View* host) {
+  DCHECK(host_ == host);
+  gfx::Size out;
+  SizeRowsAndColumns(false, 0, 0, &out);
+  return out;
+}
+
+int GridLayout::GetPreferredHeightForWidth(View* host, int width) {
+  DCHECK(host_ == host);
+  gfx::Size pref;
+  SizeRowsAndColumns(false, width, 0, &pref);
+  return pref.height();
+}
+
+void GridLayout::SizeRowsAndColumns(bool layout, int width, int height,
+                                    gfx::Size* pref) {
+  // Make sure the master columns have been calculated.
+  CalculateMasterColumnsIfNecessary();
+  pref->SetSize(0, 0);
+  if (rows_.empty())
+    return;
+
+  // Calculate the size of each of the columns. Some views preferred heights are
+  // derived from their width, as such we need to calculate the size of the
+  // columns first.
+  for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
+       i != column_sets_.end(); ++i) {
+    (*i)->CalculateSize();
+    if (layout || width > 0) {
+      // We're doing a layout, divy up any extra space.
+      (*i)->Resize(width - (*i)->LayoutWidth() - left_inset_ - right_inset_);
+      // And reset the x coordinates.
+      (*i)->ResetColumnXCoordinates();
+    }
+    pref->set_width(std::max(pref->width(), (*i)->LayoutWidth()));
+  }
+  pref->set_width(pref->width() + left_inset_ + right_inset_);
+
+  // Reset the height of each row.
+  LayoutElement::ResetSizes(&rows_);
+
+  // Do two things:
+  // . Reset the remaining_height of each view state.
+  // . If the width the view will be given is different than it's pref, ask
+  //   for the height given a particularly width.
+  for (std::vector<ViewState*>::iterator i= view_states_.begin();
+       i != view_states_.end() ; ++i) {
+    ViewState* view_state = *i;
+    view_state->remaining_height = view_state->pref_height;
+    if (view_state->h_align == FILL) {
+      // The view is resizable. As the pref height may vary with the width,
+      // ask for the pref again.
+      int actual_width =
+          view_state->column_set->GetColumnWidth(view_state->start_col,
+                                                 view_state->col_span);
+      if (actual_width != view_state->pref_width &&
+          !view_state->pref_height_fixed) {
+        // The width this view will get differs from it's preferred. Some Views
+        // pref height varies with it's width; ask for the preferred again.
+        view_state->pref_height =
+            view_state->view->GetHeightForWidth(actual_width);
+        view_state->remaining_height = view_state->pref_height;
+      }
+    }
+  }
+
+  // Update the height of each row from the views.
+  std::vector<ViewState*>::iterator view_states_iterator = view_states_.begin();
+  for (; view_states_iterator != view_states_.end() &&
+      (*view_states_iterator)->row_span == 1; ++view_states_iterator) {
+    ViewState* view_state = *view_states_iterator;
+    Row* row = rows_[view_state->start_row];
+    row->AdjustSize(view_state->remaining_height);
+    view_state->remaining_height = 0;
+  }
+
+  // Distribute the height of each view with a row span > 1.
+  for (; view_states_iterator != view_states_.end(); ++view_states_iterator) {
+    ViewState* view_state = *view_states_iterator;
+
+    // Update the remaining_width from columns this view_state touches.
+    UpdateRemainingHeightFromRows(view_state);
+
+    // Distribute the remaining height.
+    DistributeRemainingHeight(view_state);
+  }
+
+  // Update the location of each of the rows.
+  LayoutElement::CalculateLocationsFromSize(&rows_);
+
+  // We now know the preferred height, set it here.
+  pref->set_height(rows_[rows_.size() - 1]->Location() +
+             rows_[rows_.size() - 1]->Size() + top_inset_ + bottom_inset_);
+
+  if (layout && height != pref->height()) {
+    // We're doing a layout, and the height differs from the preferred height,
+    // divy up the extra space.
+    LayoutElement::DistributeDelta(height - pref->height(), &rows_);
+
+    // Reset y locations.
+    LayoutElement::CalculateLocationsFromSize(&rows_);
+  }
+}
+
+void GridLayout::CalculateMasterColumnsIfNecessary() {
+  if (!calculated_master_columns_) {
+    calculated_master_columns_ = true;
+    for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
+         i != column_sets_.end(); ++i) {
+      (*i)->CalculateMasterColumns();
+    }
+  }
+}
+
+void GridLayout::AddViewState(ViewState* view_state) {
+  DCHECK(view_state->view && (view_state->view->GetParent() == NULL ||
+                              view_state->view->GetParent() == host_));
+  if (!view_state->view->GetParent()) {
+    adding_view_ = true;
+    host_->AddChildView(view_state->view);
+    adding_view_ = false;
+  }
+  remaining_row_span_ = std::max(remaining_row_span_, view_state->row_span);
+  next_column_ += view_state->col_span;
+  current_row_col_set_->AddViewState(view_state);
+  // view_states are ordered by row_span (in ascending order).
+  std::vector<ViewState*>::iterator i = lower_bound(view_states_.begin(),
+                                                    view_states_.end(),
+                                                    view_state,
+                                                    CompareByRowSpan);
+  view_states_.insert(i, view_state);
+  SkipPaddingColumns();
+}
+
+ColumnSet* GridLayout::GetColumnSet(int id) {
+  for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
+       i != column_sets_.end(); ++i) {
+    if ((*i)->id_ == id) {
+      return *i;
+    }
+  }
+  return NULL;
+}
+
+void GridLayout::AddRow(Row* row) {
+  current_row_++;
+  remaining_row_span_--;
+  DCHECK(remaining_row_span_ <= 0 ||
+         row->column_set() == NULL ||
+         row->column_set() == GetLastValidColumnSet());
+  next_column_ = 0;
+  rows_.push_back(row);
+  current_row_col_set_ = row->column_set();
+  SkipPaddingColumns();
+}
+
+void GridLayout::UpdateRemainingHeightFromRows(ViewState* view_state) {
+  for (int i = 0, start_row = view_state->start_row;
+       i < view_state->row_span; ++i) {
+    view_state->remaining_height -= rows_[i + start_row]->Size();
+  }
+}
+
+void GridLayout::DistributeRemainingHeight(ViewState* view_state) {
+  int height = view_state->remaining_height;
+  if (height <= 0)
+    return;
+
+  // Determine the number of resizable rows the view touches.
+  int resizable_rows = 0;
+  int start_row = view_state->start_row;
+  int max_row = view_state->start_row + view_state->row_span;
+  for (int i = start_row; i < max_row; ++i) {
+    if (rows_[i]->IsResizable()) {
+      resizable_rows++;
+    }
+  }
+
+  if (resizable_rows > 0) {
+    // There are resizable rows, give the remaining height to them.
+    int to_distribute = height / resizable_rows;
+    for (int i = start_row; i < max_row; ++i) {
+      if (rows_[i]->IsResizable()) {
+        height -= to_distribute;
+        if (height < to_distribute) {
+          // Give all slop to the last column.
+          to_distribute += height;
+        }
+        rows_[i]->SetSize(rows_[i]->Size() + to_distribute);
+      }
+    }
+  } else {
+    // None of the rows are resizable, divy the remaining height up equally
+    // among all rows the view touches.
+    int each_row_height = height / view_state->row_span;
+    for (int i = start_row; i < max_row; ++i) {
+      height -= each_row_height;
+      if (height < each_row_height)
+        each_row_height += height;
+      rows_[i]->SetSize(rows_[i]->Size() + each_row_height);
+    }
+    view_state->remaining_height = 0;
+  }
+}
+
+void GridLayout::SkipPaddingColumns() {
+  if (!current_row_col_set_)
+    return;
+  while (next_column_ < current_row_col_set_->num_columns() &&
+         current_row_col_set_->columns_[next_column_]->is_padding_) {
+    next_column_++;
+  }
+}
+
+ColumnSet* GridLayout::GetLastValidColumnSet() {
+  for (int i = current_row_ - 1; i >= 0; --i) {
+    if (rows_[i]->column_set())
+      return rows_[i]->column_set();
+  }
+  return NULL;
+}
+
+}  // namespace views
diff --git a/views/grid_layout.h b/views/grid_layout.h
new file mode 100644
index 0000000..e3e7a623
--- /dev/null
+++ b/views/grid_layout.h
@@ -0,0 +1,354 @@
+// Copyright (c) 2006-2008 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 VIEWS_GRID_LAYOUT_H_
+#define VIEWS_GRID_LAYOUT_H_
+
+#include <string>
+#include <vector>
+
+#include "views/layout_manager.h"
+#include "views/view.h"
+
+// GridLayout is a LayoutManager that positions child Views in a grid. You
+// define the structure of the Grid first, then add the Views.
+// The following creates a trivial grid with two columns separated by
+// a column with padding:
+// ColumnSet* columns = layout->AddColumnSet(0); // Give this column an
+//                                               // identifier of 0.
+// columns->AddColumn(FILL, // Views are horizontally resized to fill column.
+//                    FILL, // Views starting in this column are vertically
+//                          // resized.
+//                    1,    // This column has a resize weight of 1.
+//                    USE_PREF, // Use the preferred size of the view.
+//                    0,   // Ignored for USE_PREF.
+//                    0);  // A minimum width of 0.
+// columns->AddPaddingColumn(0,   // The padding column is not resizable.
+//                           10); // And has a width of 10 pixels.
+// columns->AddColumn(FILL, FILL, 0, USE_PREF, 0, 0);
+// Now add the views:
+// // First start a row.
+// layout->StartRow(0,  // This row isn't vertically resizable.
+//                  0); // The column set to use for this row.
+// layout->AddView(v1);
+// Notice you need not skip over padding columns, that's done for you.
+// layout->AddView(v2);
+//
+// When adding a Column you give it the default alignment for all views
+// originating in that column. You can override this for specific views
+// when adding them. For example, the following forces a View to have
+// a horizontal and vertical alignment of leading regardless of that defined
+// for the column:
+// layout->AddView(v1, 1, 1, LEADING, LEADING);
+//
+// If the View using GridLayout is given a size bigger than the preferred,
+// columns and rows with a resize percent > 0 are resized. Each column/row
+// is given resize_percent / total_resize_percent * extra_pixels extra
+// pixels. Only Views with an Alignment of FILL are given extra space, others
+// are aligned in the provided space.
+//
+// GridLayout allows you to define multiple column sets. When you start a
+// new row you specify the id of the column set the row is to use.
+//
+// GridLayout allows you to force columns to have the same width. This is
+// done using the LinkColumnSizes method.
+//
+// AddView takes care of adding the View to the View the GridLayout was
+// created with.
+namespace views {
+
+class Column;
+class ColumnSet;
+class Row;
+class View;
+
+struct ViewState;
+
+class GridLayout : public LayoutManager {
+ public:
+  // An enumeration of the possible alignments supported by GridLayout.
+  enum Alignment {
+    // Leading equates to left along the horizontal axis, and top along the
+    // vertical axis.
+    LEADING,
+
+    // Centers the view along the axis.
+    CENTER,
+
+    // Trailing equals to right along the horizontal axis, and bottom along
+    // the vertical axis.
+    TRAILING,
+
+    // The view is resized to fill the space.
+    FILL
+  };
+
+  // An enumeration of the possible ways the size of a column may be obtained.
+  enum SizeType {
+    // The column size is fixed.
+    FIXED,
+
+    // The preferred size of the view is used to determine the column size.
+    USE_PREF
+  };
+
+  explicit GridLayout(View* host);
+  virtual ~GridLayout();
+
+  // Sets the insets. All views are placed relative to these offsets.
+  void SetInsets(int top, int left, int bottom, int right);
+
+  // Creates a new column set with the specified id and returns it.
+  // The id is later used when starting a new row.
+  // GridLayout takes ownership of the ColumnSet and will delete it when
+  // the GridLayout is deleted.
+  ColumnSet* AddColumnSet(int id);
+
+  // Adds a padding row. Padding rows typically don't have any views, and
+  // but are used to provide vertical white space between views.
+  // Size specifies the height of the row.
+  void AddPaddingRow(float vertical_resize, int size);
+
+  // A convenience for AddPaddingRow followed by StartRow.
+  void StartRowWithPadding(float vertical_resize, int column_set_id,
+                           float padding_resize, int padding);
+
+  // Starts a new row with the specified column set.
+  void StartRow(float vertical_resize, int column_set_id);
+
+  // Advances past columns. Use this when the current column should not
+  // contain any views.
+  void SkipColumns(int col_count);
+
+  // Adds a view using the default alignment from the column. The added
+  // view has a column and row span of 1.
+  // As a convenience this adds the view to the host. The view becomes owned
+  // by the host, and NOT this GridLayout.
+  void AddView(View* view);
+
+  // Adds a view using the default alignment from the column.
+  // As a convenience this adds the view to the host. The view becomes owned
+  // by the host, and NOT this GridLayout.
+  void AddView(View* view, int col_span, int row_span);
+
+  // Adds a view with the specified alignment and spans.
+  // As a convenience this adds the view to the host. The view becomes owned
+  // by the host, and NOT this GridLayout.
+  void AddView(View* view, int col_span, int row_span, Alignment h_align,
+               Alignment v_align);
+
+  // Adds a view with the specified alignment and spans. If
+  // pref_width/pref_height is > 0 then the preferred width/height of the view
+  // is fixed to the specified value.
+  // As a convenience this adds the view to the host. The view becomes owned
+  // by the host, and NOT this GridLayout.
+  void AddView(View* view, int col_span, int row_span,
+               Alignment h_align, Alignment v_align,
+               int pref_width, int pref_height);
+
+  // Notification we've been installed on a particular host. Checks that host
+  // is the same as the View supplied in the constructor.
+  virtual void Installed(View* host);
+
+  // Notification we've been uninstalled on a particular host. Checks that host
+  // is the same as the View supplied in the constructor.
+  virtual void Uninstalled(View* host);
+
+  // Notification that a view has been added.
+  virtual void ViewAdded(View* host, View* view);
+
+  // Notification that a view has been removed.
+  virtual void ViewRemoved(View* host, View* view);
+
+  // Layouts out the components.
+  virtual void Layout(View* host);
+
+  // Returns the preferred size for the GridLayout.
+  virtual gfx::Size GetPreferredSize(View* host);
+
+  virtual int GetPreferredHeightForWidth(View* host, int width);
+
+ private:
+  // As both Layout and GetPreferredSize need to do nearly the same thing,
+  // they both call into this method. This sizes the Columns/Rows as
+  // appropriate. If layout is true, width/height give the width/height the
+  // of the host, otherwise they are ignored.
+     void SizeRowsAndColumns(bool layout, int width, int height,
+                             gfx::Size* pref);
+
+  // Calculates the master columns of all the column sets. See Column for
+  // a description of what a master column is.
+  void CalculateMasterColumnsIfNecessary();
+
+  // This is called internally from AddView. It adds the ViewState to the
+  // appropriate structures, and updates internal fields such as next_column_.
+  void AddViewState(ViewState* view_state);
+
+  // Returns the column set for the specified id, or NULL if one doesn't exist.
+  ColumnSet* GetColumnSet(int id);
+
+  // Adds the Row to rows_, as well as updating next_column_,
+  // current_row_col_set ...
+  void AddRow(Row* row);
+
+  // As the name says, updates the remaining_height of the ViewState for
+  // all Rows the supplied ViewState touches.
+  void UpdateRemainingHeightFromRows(ViewState* state);
+
+  // If the view state's remaining height is > 0, it is distributed among
+  // the rows the view state touches. This is used during layout to make
+  // sure the Rows can accommodate a view.
+  void DistributeRemainingHeight(ViewState* state);
+
+  // Advances next_column_ past any padding columns.
+  void SkipPaddingColumns();
+
+  // Returns the column set of the last non-padding row.
+  ColumnSet* GetLastValidColumnSet();
+
+  // The view we were created with. We don't own this.
+  View* const host_;
+
+  // Whether or not we've calculated the master/linked columns.
+  bool calculated_master_columns_;
+
+  // Used to verify a view isn't added with a row span that expands into
+  // another column structure.
+  int remaining_row_span_;
+
+  // Current row.
+  int current_row_;
+
+  // Current column.
+  int next_column_;
+
+  // Column set for the current row. This is null for padding rows.
+  ColumnSet* current_row_col_set_;
+
+  // Insets.
+  int top_inset_;
+  int bottom_inset_;
+  int left_inset_;
+  int right_inset_;
+
+  // Set to true when adding a View.
+  bool adding_view_;
+
+  // ViewStates. This is ordered by row_span in ascending order.
+  std::vector<ViewState*> view_states_;
+
+  // ColumnSets.
+  std::vector<ColumnSet*> column_sets_;
+
+  // Rows.
+  std::vector<Row*> rows_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(GridLayout);
+};
+
+// ColumnSet is used to define a set of columns. GridLayout may have any
+// number of ColumnSets. You don't create a ColumnSet directly, instead
+// use the AddColumnSet method of GridLayout.
+class ColumnSet {
+ public:
+  ~ColumnSet();
+
+  // Adds a column for padding. When adding views, padding columns are
+  // automatically skipped. For example, if you create a column set with
+  // two columns separated by a padding column, the first AddView automatically
+  // skips past the padding column. That is, to add two views, do:
+  // layout->AddView(v1); layout->AddView(v2);, not:
+  // layout->AddView(v1); layout->SkipColumns(1); layout->AddView(v2);
+  void AddPaddingColumn(float resize_percent, int width);
+
+  // Adds a column. The alignment gives the default alignment for views added
+  // with no explicit alignment. fixed_width gives a specific width for the
+  // column, and is only used if size_type == FIXED. min_width gives the
+  // minimum width for the column.
+  void AddColumn(GridLayout::Alignment h_align,
+                 GridLayout::Alignment v_align,
+                 float resize_percent,
+                 GridLayout::SizeType size_type,
+                 int fixed_width,
+                 int min_width);
+
+  // Forces the specified columns to have the same size. The size of
+  // linked columns is that of the max of the specified columns. This
+  // must end with -1. For example, the following forces the first and
+  // second column to have the same size:
+  // LinkColumnSizes(0, 1, -1);
+  void LinkColumnSizes(int first, ...);
+
+  // ID of this ColumnSet.
+  int id() const { return id_; }
+
+  int num_columns() { return static_cast<int>(columns_.size()); }
+
+ private:
+  friend class GridLayout;
+
+  explicit ColumnSet(int id);
+
+  void AddColumn(GridLayout::Alignment h_align,
+                 GridLayout::Alignment v_align,
+                 float resize_percent,
+                 GridLayout::SizeType size_type,
+                 int fixed_width,
+                 int min_width,
+                 bool is_padding);
+
+  void AddViewState(ViewState* view_state);
+
+  // Set description of these.
+  void CalculateMasterColumns();
+  void AccumulateMasterColumns();
+
+  // Sets the size of each linked column to be the same.
+  void UnifySameSizedColumnSizes();
+
+  // Updates the remaining width field of the ViewState from that of the
+  // columns the view spans.
+  void UpdateRemainingWidth(ViewState* view_state);
+
+  // Makes sure the columns touched by view state are big enough for the
+  // view.
+  void DistributeRemainingWidth(ViewState* view_state);
+
+  // Returns the total size needed for this ColumnSet.
+  int LayoutWidth();
+
+  // Returns the width of the specified columns.
+  int GetColumnWidth(int start_col, int col_span);
+
+  // Updates the x coordinate of each column from the previous ones.
+  // NOTE: this doesn't include the insets.
+  void ResetColumnXCoordinates();
+
+  // Calculate the preferred width of each view in this column set, as well
+  // as updating the remaining_width.
+  void CalculateSize();
+
+  // Distributes delta amoung the resizable columns.
+  void Resize(int delta);
+
+  // ID for this columnset.
+  const int id_;
+
+  // The columns.
+  std::vector<Column*> columns_;
+
+  // The ViewStates. This is sorted based on column_span in ascending
+  // order.
+  std::vector<ViewState*> view_states_;
+
+  // The master column of those columns that are linked. See Column
+  // for a description of what the master column is.
+  std::vector<Column*> master_columns_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ColumnSet);
+};
+
+}  // namespace views
+
+#endif // VIEWS_GRID_LAYOUT_H_
diff --git a/views/grid_layout_unittest.cc b/views/grid_layout_unittest.cc
new file mode 100644
index 0000000..57bfa837
--- /dev/null
+++ b/views/grid_layout_unittest.cc
@@ -0,0 +1,514 @@
+// Copyright (c) 2006-2008 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 "testing/gtest/include/gtest/gtest.h"
+#include "views/grid_layout.h"
+#include "views/view.h"
+
+using views::ColumnSet;
+using views::GridLayout;
+using views::View;
+
+static void ExpectViewBoundsEquals(int x, int y, int w, int h,
+                                   const View* view) {
+  EXPECT_EQ(x, view->x());
+  EXPECT_EQ(y, view->y());
+  EXPECT_EQ(w, view->width());
+  EXPECT_EQ(h, view->height());
+}
+
+class SettableSizeView : public View {
+ public:
+  explicit SettableSizeView(const gfx::Size& pref) {
+    pref_ = pref;
+  }
+
+  virtual gfx::Size GetPreferredSize() {
+    return pref_;
+  }
+
+ private:
+   gfx::Size pref_;
+};
+
+class GridLayoutTest : public testing::Test {
+ public:
+  virtual void SetUp() {
+    layout = new GridLayout(&host);
+  }
+
+  virtual void TearDown() {
+    delete layout;
+  }
+
+  virtual void RemoveAll() {
+    for (int i = host.GetChildViewCount() - 1; i >= 0; i--) {
+      host.RemoveChildView(host.GetChildViewAt(i));
+    }
+  }
+
+  void GetPreferredSize() {
+    pref = layout->GetPreferredSize(&host);
+  }
+
+  gfx::Size pref;
+  CRect bounds;
+  View host;
+  GridLayout* layout;
+};
+
+class GridLayoutAlignmentTest : public testing::Test {
+ public:
+   GridLayoutAlignmentTest() :
+       host(),
+         v1(gfx::Size(10, 20)),
+       layout(new GridLayout(&host)) {}
+
+  virtual void SetUp() {
+  }
+
+  virtual void TearDown() {
+    delete layout;
+  }
+
+  virtual void RemoveAll() {
+    for (int i = host.GetChildViewCount() - 1; i >= 0; i--) {
+      host.RemoveChildView(host.GetChildViewAt(i));
+    }
+  }
+
+  void TestAlignment(GridLayout::Alignment alignment, CRect* bounds) {
+    ColumnSet* c1 = layout->AddColumnSet(0);
+    c1->AddColumn(alignment, alignment, 1, GridLayout::USE_PREF, 0, 0);
+    layout->StartRow(1, 0);
+    layout->AddView(&v1);
+    gfx::Size pref = layout->GetPreferredSize(&host);
+    EXPECT_TRUE(gfx::Size(10, 20) == pref);
+    host.SetBounds(0, 0, 100, 100);
+    layout->Layout(&host);
+    *bounds = v1.bounds().ToRECT();
+    RemoveAll();
+  }
+
+  View host;
+  SettableSizeView v1;
+  GridLayout* layout;
+};
+
+TEST_F(GridLayoutAlignmentTest, Fill) {
+  CRect bounds;
+  TestAlignment(GridLayout::FILL, &bounds);
+  EXPECT_TRUE(CRect(0, 0, 100, 100) == bounds);
+}
+
+TEST_F(GridLayoutAlignmentTest, Leading) {
+  CRect bounds;
+  TestAlignment(GridLayout::LEADING, &bounds);
+  EXPECT_TRUE(CRect(0, 0, 10, 20) == bounds);
+}
+
+TEST_F(GridLayoutAlignmentTest, Center) {
+  CRect bounds;
+  TestAlignment(GridLayout::CENTER, &bounds);
+  EXPECT_TRUE(CRect(45, 40, 55, 60) == bounds);
+}
+
+TEST_F(GridLayoutAlignmentTest, Trailing) {
+  CRect bounds;
+  TestAlignment(GridLayout::TRAILING, &bounds);
+  EXPECT_TRUE(CRect(90, 80, 100, 100) == bounds);
+}
+
+TEST_F(GridLayoutTest, TwoColumns) {
+  SettableSizeView v1(gfx::Size(10, 20));
+  SettableSizeView v2(gfx::Size(20, 20));
+  ColumnSet* c1 = layout->AddColumnSet(0);
+  c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                0, GridLayout::USE_PREF, 0, 0);
+  c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                0, GridLayout::USE_PREF, 0, 0);
+  layout->StartRow(0, 0);
+  layout->AddView(&v1);
+  layout->AddView(&v2);
+
+  GetPreferredSize();
+  EXPECT_TRUE(gfx::Size(30, 20) == pref);
+
+  host.SetBounds(0, 0, pref.width(), pref.height());
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(0, 0, 10, 20, &v1);
+  ExpectViewBoundsEquals(10, 0, 20, 20, &v2);
+
+  RemoveAll();
+}
+
+TEST_F(GridLayoutTest, ColSpan1) {
+  SettableSizeView v1(gfx::Size(100, 20));
+  SettableSizeView v2(gfx::Size(10, 40));
+  ColumnSet* c1 = layout->AddColumnSet(0);
+  c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                0, GridLayout::USE_PREF, 0, 0);
+  c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                1, GridLayout::USE_PREF, 0, 0);
+  layout->StartRow(0, 0);
+  layout->AddView(&v1, 2, 1);
+  layout->StartRow(0, 0);
+  layout->AddView(&v2);
+
+  GetPreferredSize();
+  EXPECT_TRUE(gfx::Size(100, 60) == pref);
+
+  host.SetBounds(0, 0, pref.width(), pref.height());
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(0, 0, 100, 20, &v1);
+  ExpectViewBoundsEquals(0, 20, 10, 40, &v2);
+
+  RemoveAll();
+}
+
+TEST_F(GridLayoutTest, ColSpan2) {
+  SettableSizeView v1(gfx::Size(100, 20));
+  SettableSizeView v2(gfx::Size(10, 20));
+  ColumnSet* c1 = layout->AddColumnSet(0);
+  c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                1, GridLayout::USE_PREF, 0, 0);
+  c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                0, GridLayout::USE_PREF, 0, 0);
+  layout->StartRow(0, 0);
+  layout->AddView(&v1, 2, 1);
+  layout->StartRow(0, 0);
+  layout->SkipColumns(1);
+  layout->AddView(&v2);
+
+  GetPreferredSize();
+  EXPECT_TRUE(gfx::Size(100, 40) == pref);
+
+  host.SetBounds(0, 0, pref.width(), pref.height());
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(0, 0, 100, 20, &v1);
+  ExpectViewBoundsEquals(90, 20, 10, 20, &v2);
+
+  RemoveAll();
+}
+
+TEST_F(GridLayoutTest, ColSpan3) {
+  SettableSizeView v1(gfx::Size(100, 20));
+  SettableSizeView v2(gfx::Size(10, 20));
+  SettableSizeView v3(gfx::Size(10, 20));
+  ColumnSet* c1 = layout->AddColumnSet(0);
+  c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                0, GridLayout::USE_PREF, 0, 0);
+  c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                0, GridLayout::USE_PREF, 0, 0);
+  layout->StartRow(0, 0);
+  layout->AddView(&v1, 2, 1);
+  layout->StartRow(0, 0);
+  layout->AddView(&v2);
+  layout->AddView(&v3);
+
+  GetPreferredSize();
+  EXPECT_TRUE(gfx::Size(100, 40) == pref);
+
+  host.SetBounds(0, 0, pref.width(), pref.height());
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(0, 0, 100, 20, &v1);
+  ExpectViewBoundsEquals(0, 20, 10, 20, &v2);
+  ExpectViewBoundsEquals(50, 20, 10, 20, &v3);
+
+  RemoveAll();
+}
+
+
+TEST_F(GridLayoutTest, ColSpan4) {
+  views::ColumnSet* set = layout->AddColumnSet(0);
+
+  set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
+                 GridLayout::USE_PREF, 0, 0);
+  set->AddColumn(GridLayout::LEADING, GridLayout::LEADING, 0,
+                 GridLayout::USE_PREF, 0, 0);
+
+  SettableSizeView v1(gfx::Size(10, 10));
+  SettableSizeView v2(gfx::Size(10, 10));
+  SettableSizeView v3(gfx::Size(25, 20));
+  layout->StartRow(0, 0);
+  layout->AddView(&v1);
+  layout->AddView(&v2);
+  layout->StartRow(0, 0);
+  layout->AddView(&v3, 2, 1);
+
+  GetPreferredSize();
+  EXPECT_TRUE(gfx::Size(25, 30) == pref);
+
+  host.SetBounds(0, 0, pref.width(), pref.height());
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(0, 0, 10, 10, &v1);
+  ExpectViewBoundsEquals(12, 0, 10, 10, &v2);
+  ExpectViewBoundsEquals(0, 10, 25, 20, &v3);
+
+  RemoveAll();
+}
+
+TEST_F(GridLayoutTest, SameSizeColumns) {
+  SettableSizeView v1(gfx::Size(50, 20));
+  SettableSizeView v2(gfx::Size(10, 10));
+  ColumnSet* c1 = layout->AddColumnSet(0);
+  c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                0, GridLayout::USE_PREF, 0, 0);
+  c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                0, GridLayout::USE_PREF, 0, 0);
+  c1->LinkColumnSizes(0, 1, -1);
+  layout->StartRow(0, 0);
+  layout->AddView(&v1);
+  layout->AddView(&v2);
+
+  gfx::Size pref = layout->GetPreferredSize(&host);
+  EXPECT_TRUE(gfx::Size(100, 20) == pref);
+
+  host.SetBounds(0, 0, pref.width(), pref.height());
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(0, 0, 50, 20, &v1);
+  ExpectViewBoundsEquals(50, 0, 10, 10, &v2);
+
+  RemoveAll();
+}
+
+TEST_F(GridLayoutTest, HorizontalResizeTest1) {
+  SettableSizeView v1(gfx::Size(50, 20));
+  SettableSizeView v2(gfx::Size(10, 10));
+  ColumnSet* c1 = layout->AddColumnSet(0);
+  c1->AddColumn(GridLayout::FILL, GridLayout::LEADING,
+                1, GridLayout::USE_PREF, 0, 0);
+  c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                0, GridLayout::USE_PREF, 0, 0);
+  layout->StartRow(0, 0);
+  layout->AddView(&v1);
+  layout->AddView(&v2);
+
+  host.SetBounds(0, 0, 110, 20);
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(0, 0, 100, 20, &v1);
+  ExpectViewBoundsEquals(100, 0, 10, 10, &v2);
+
+  RemoveAll();
+}
+
+TEST_F(GridLayoutTest, HorizontalResizeTest2) {
+  SettableSizeView v1(gfx::Size(50, 20));
+  SettableSizeView v2(gfx::Size(10, 10));
+  ColumnSet* c1 = layout->AddColumnSet(0);
+  c1->AddColumn(GridLayout::FILL, GridLayout::LEADING,
+                1, GridLayout::USE_PREF, 0, 0);
+  c1->AddColumn(GridLayout::TRAILING, GridLayout::LEADING,
+                1, GridLayout::USE_PREF, 0, 0);
+  layout->StartRow(0, 0);
+  layout->AddView(&v1);
+  layout->AddView(&v2);
+
+  host.SetBounds(0, 0, 120, 20);
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(0, 0, 80, 20, &v1);
+  ExpectViewBoundsEquals(110, 0, 10, 10, &v2);
+
+  RemoveAll();
+}
+
+TEST_F(GridLayoutTest, TestVerticalResize1) {
+  SettableSizeView v1(gfx::Size(50, 20));
+  SettableSizeView v2(gfx::Size(10, 10));
+  ColumnSet* c1 = layout->AddColumnSet(0);
+  c1->AddColumn(GridLayout::FILL, GridLayout::FILL,
+                1, GridLayout::USE_PREF, 0, 0);
+  layout->StartRow(1, 0);
+  layout->AddView(&v1);
+  layout->StartRow(0, 0);
+  layout->AddView(&v2);
+
+  GetPreferredSize();
+  EXPECT_TRUE(gfx::Size(50, 30) == pref);
+
+  host.SetBounds(0, 0, 50, 100);
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(0, 0, 50, 90, &v1);
+  ExpectViewBoundsEquals(0, 90, 50, 10, &v2);
+
+  RemoveAll();
+}
+
+TEST_F(GridLayoutTest, Insets) {
+  SettableSizeView v1(gfx::Size(10, 20));
+  ColumnSet* c1 = layout->AddColumnSet(0);
+  layout->SetInsets(1, 2, 3, 4);
+  c1->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                0, GridLayout::USE_PREF, 0, 0);
+  layout->StartRow(0, 0);
+  layout->AddView(&v1);
+
+  GetPreferredSize();
+  EXPECT_TRUE(gfx::Size(16, 24) == pref);
+
+  host.SetBounds(0, 0, pref.width(), pref.height());
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(2, 1, 10, 20, &v1);
+
+  RemoveAll();
+}
+
+TEST_F(GridLayoutTest, FixedSize) {
+  layout->SetInsets(2, 2, 2, 2);
+
+  views::ColumnSet* set = layout->AddColumnSet(0);
+
+  int column_count = 4;
+  int title_width = 100;
+  int row_count = 2;
+  int pref_width = 10;
+  int pref_height = 20;
+
+  for (int i = 0; i < column_count; ++i) {
+    set->AddColumn(views::GridLayout::CENTER,
+                   views::GridLayout::CENTER,
+                   0,
+                   views::GridLayout::FIXED,
+                   title_width,
+                   title_width);
+  }
+
+  for (int row = 0; row < row_count; ++row) {
+    layout->StartRow(0, 0);
+    for (int col = 0; col < column_count; ++col) {
+      layout->AddView(new SettableSizeView(gfx::Size(pref_width, pref_height)));
+    }
+  }
+
+  layout->Layout(&host);
+
+  for (int i = 0; i < column_count; ++i) {
+    for (int row = 0; row < row_count; ++row) {
+      View* view = host.GetChildViewAt(row * column_count + i);
+      ExpectViewBoundsEquals(
+          2 + title_width * i + (title_width - pref_width) / 2,
+          2 + pref_height * row,
+          pref_width,
+          pref_height, view);
+    }
+  }
+
+  GetPreferredSize();
+  EXPECT_TRUE(gfx::Size(column_count * title_width + 4,
+                        row_count * pref_height + 4) == pref);
+}
+
+TEST_F(GridLayoutTest, RowSpanWithPaddingRow) {
+  views::ColumnSet* set = layout->AddColumnSet(0);
+
+  set->AddColumn(views::GridLayout::CENTER,
+                 views::GridLayout::CENTER,
+                 0,
+                 views::GridLayout::FIXED,
+                 10,
+                 10);
+
+  layout->StartRow(0, 0);
+  layout->AddView(new SettableSizeView(gfx::Size(10, 10)), 1, 2);
+  layout->AddPaddingRow(0, 10);
+}
+
+TEST_F(GridLayoutTest, RowSpan) {
+  views::ColumnSet* set = layout->AddColumnSet(0);
+
+  set->AddColumn(views::GridLayout::LEADING,
+                 views::GridLayout::LEADING,
+                 0,
+                 views::GridLayout::USE_PREF,
+                 0,
+                 0);
+  set->AddColumn(views::GridLayout::LEADING,
+                 views::GridLayout::LEADING,
+                 0,
+                 views::GridLayout::USE_PREF,
+                 0,
+                 0);
+
+  layout->StartRow(0, 0);
+  layout->AddView(new SettableSizeView(gfx::Size(20, 10)));
+  layout->AddView(new SettableSizeView(gfx::Size(20, 40)), 1, 2);
+  layout->StartRow(1, 0);
+  views::View* s3 = new SettableSizeView(gfx::Size(20, 10));
+  layout->AddView(s3);
+
+  GetPreferredSize();
+  EXPECT_TRUE(gfx::Size(40, 40) == pref);
+
+  host.SetBounds(0, 0, pref.width(), pref.height());
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(0, 10, 20, 10, s3);
+}
+
+TEST_F(GridLayoutTest, RowSpan2) {
+  views::ColumnSet* set = layout->AddColumnSet(0);
+
+  set->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                 0, GridLayout::USE_PREF, 0, 0);
+  set->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                 0,GridLayout::USE_PREF, 0, 0);
+
+  layout->StartRow(0, 0);
+  layout->AddView(new SettableSizeView(gfx::Size(20, 20)));
+  views::View* s3 = new SettableSizeView(gfx::Size(64, 64));
+  layout->AddView(s3, 1, 3);
+
+  layout->AddPaddingRow(0, 10);
+
+  layout->StartRow(0, 0);
+  layout->AddView(new SettableSizeView(gfx::Size(10, 20)));
+
+  GetPreferredSize();
+  EXPECT_TRUE(gfx::Size(84, 64) == pref);
+
+  host.SetBounds(0, 0, pref.width(), pref.height());
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(20, 0, 64, 64, s3);
+}
+
+TEST_F(GridLayoutTest, FixedViewWidth) {
+  views::ColumnSet* set = layout->AddColumnSet(0);
+
+  set->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                 0, GridLayout::USE_PREF, 0, 0);
+  set->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                 0,GridLayout::USE_PREF, 0, 0);
+
+  layout->StartRow(0, 0);
+  View* view = new SettableSizeView(gfx::Size(30, 40));
+  layout->AddView(view, 1, 1, GridLayout::LEADING, GridLayout::LEADING, 10, 0);
+
+  GetPreferredSize();
+  EXPECT_EQ(10, pref.width());
+  EXPECT_EQ(40, pref.height());
+
+  host.SetBounds(0, 0, pref.width(), pref.height());
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(0, 0, 10, 40, view);
+}
+
+TEST_F(GridLayoutTest, FixedViewHeight) {
+  views::ColumnSet* set = layout->AddColumnSet(0);
+
+  set->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                 0, GridLayout::USE_PREF, 0, 0);
+  set->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
+                 0,GridLayout::USE_PREF, 0, 0);
+
+  layout->StartRow(0, 0);
+  View* view = new SettableSizeView(gfx::Size(30, 40));
+  layout->AddView(view, 1, 1, GridLayout::LEADING, GridLayout::LEADING, 0, 10);
+
+  GetPreferredSize();
+  EXPECT_EQ(30, pref.width());
+  EXPECT_EQ(10, pref.height());
+
+  host.SetBounds(0, 0, pref.width(), pref.height());
+  layout->Layout(&host);
+  ExpectViewBoundsEquals(0, 0, 30, 10, view);
+}
diff --git a/views/layout_manager.cc b/views/layout_manager.cc
new file mode 100644
index 0000000..800dbc2
--- /dev/null
+++ b/views/layout_manager.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2006-2008 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 "views/layout_manager.h"
+
+#include "views/view.h"
+
+namespace views {
+
+int LayoutManager::GetPreferredHeightForWidth(View* host, int width) {
+  return GetPreferredSize(host).height();
+}
+
+}  // namespace views
diff --git a/views/layout_manager.h b/views/layout_manager.h
new file mode 100644
index 0000000..48a9c96
--- /dev/null
+++ b/views/layout_manager.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2006-2008 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 VIEWS_LAYOUT_MANAGER_H_
+#define VIEWS_LAYOUT_MANAGER_H_
+
+#include "views/view.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace views {
+
+class View;
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// LayoutManager interface
+//
+//   The LayoutManager interface provides methods to handle the sizing of
+//   the children of a View according to implementation-specific heuristics.
+//
+/////////////////////////////////////////////////////////////////////////////
+class LayoutManager {
+ public:
+  virtual ~LayoutManager() {}
+
+  // Notification that this LayoutManager has been installed on a particular
+  // host.
+  virtual void Installed(View* host) {}
+
+  // Notification that this LayoutManager has been uninstalled on a particular
+  // host.
+  virtual void Uninstalled(View* host) {}
+
+  // Lay out the children of |host| according to implementation-specific
+  // heuristics. The graphics used during painting is provided to allow for
+  // string sizing.
+  virtual void Layout(View* host) = 0;
+
+  // Return the preferred size which is the size required to give each
+  // children their respective preferred size.
+  virtual gfx::Size GetPreferredSize(View* host) = 0;
+
+  // Returns the preferred height for the specified width. The default
+  // implementation returns the value from GetPreferredSize.
+  virtual int GetPreferredHeightForWidth(View* host, int width);
+
+  // Notification that a view has been added.
+  virtual void ViewAdded(View* host, View* view) {}
+
+  // Notification that a view has been removed.
+  virtual void ViewRemoved(View* host, View* view) {}
+};
+
+}  // namespace views
+
+#endif // VIEWS_LAYOUT_MANAGER_H_
diff --git a/views/painter.cc b/views/painter.cc
new file mode 100644
index 0000000..a2ad4ee
--- /dev/null
+++ b/views/painter.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 2006-2008 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 "views/painter.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/resource_bundle.h"
+#include "base/logging.h"
+#include "skia/include/SkBitmap.h"
+#include "skia/include/SkGradientShader.h"
+
+namespace views {
+
+namespace {
+
+class GradientPainter : public Painter {
+ public:
+  GradientPainter(bool horizontal, const SkColor& top, const SkColor& bottom)
+      : horizontal_(horizontal) {
+    colors_[0] = top;
+    colors_[1] = bottom;
+  }
+
+  virtual ~GradientPainter() {
+  }
+
+  void Paint(int w, int h, ChromeCanvas* canvas) {
+    SkPaint paint;
+    SkPoint p[2];
+    p[0].set(SkIntToScalar(0), SkIntToScalar(0));
+    if (horizontal_)
+      p[1].set(SkIntToScalar(w), SkIntToScalar(0));
+    else
+      p[1].set(SkIntToScalar(0), SkIntToScalar(h));
+
+    SkShader* s =
+        SkGradientShader::CreateLinear(p, colors_, NULL, 2,
+                                       SkShader::kClamp_TileMode, NULL);
+    paint.setStyle(SkPaint::kFill_Style);
+    paint.setShader(s);
+    // Need to unref shader, otherwise never deleted.
+    s->unref();
+
+    canvas->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0),
+                           SkIntToScalar(w), SkIntToScalar(h), paint);
+  }
+
+ private:
+  bool horizontal_;
+  SkColor colors_[2];
+
+  DISALLOW_EVIL_CONSTRUCTORS(GradientPainter);
+};
+
+
+}
+
+// static
+void Painter::PaintPainterAt(int x, int y, int w, int h,
+                             ChromeCanvas* canvas, Painter* painter) {
+  DCHECK(canvas && painter);
+  if (w < 0 || h < 0)
+    return;
+  canvas->save();
+  canvas->TranslateInt(x, y);
+  painter->Paint(w, h, canvas);
+  canvas->restore();
+}
+
+ImagePainter::ImagePainter(const int image_resource_names[],
+                           bool draw_center)
+    : draw_center_(draw_center) {
+  DCHECK(image_resource_names);
+  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+  for (int i = 0, max = draw_center ? 9 : 8; i < max; ++i)
+    images_.push_back(rb.GetBitmapNamed(image_resource_names[i]));
+}
+
+void ImagePainter::Paint(int w, int h, ChromeCanvas* canvas) {
+  canvas->DrawBitmapInt(*images_[BORDER_TOP_LEFT], 0, 0);
+  canvas->TileImageInt(*images_[BORDER_TOP],
+                       images_[BORDER_TOP_LEFT]->width(),
+                       0,
+                       w - images_[BORDER_TOP_LEFT]->width() -
+                       images_[BORDER_TOP_RIGHT]->width(),
+                       images_[BORDER_TOP_LEFT]->height());
+  canvas->DrawBitmapInt(*images_[BORDER_TOP_RIGHT],
+                        w - images_[BORDER_TOP_RIGHT]->width(),
+                        0);
+  canvas->TileImageInt(*images_[BORDER_RIGHT],
+                       w - images_[BORDER_RIGHT]->width(),
+                       images_[BORDER_TOP_RIGHT]->height(),
+                       images_[BORDER_RIGHT]->width(),
+                       h - images_[BORDER_TOP_RIGHT]->height() -
+                       images_[BORDER_BOTTOM_RIGHT]->height());
+  canvas->DrawBitmapInt(*images_[BORDER_BOTTOM_RIGHT],
+                        w - images_[BORDER_BOTTOM_RIGHT]->width(),
+                        h - images_[BORDER_BOTTOM_RIGHT]->height());
+  canvas->TileImageInt(*images_[BORDER_BOTTOM],
+                       images_[BORDER_BOTTOM_LEFT]->width(),
+                       h - images_[BORDER_BOTTOM]->height(),
+                       w - images_[BORDER_BOTTOM_LEFT]->width() -
+                       images_[BORDER_BOTTOM_RIGHT]->width(),
+                       images_[BORDER_BOTTOM]->height());
+  canvas->DrawBitmapInt(*images_[BORDER_BOTTOM_LEFT],
+                        0,
+                        h - images_[BORDER_BOTTOM_LEFT]->height());
+  canvas->TileImageInt(*images_[BORDER_LEFT],
+                       0,
+                       images_[BORDER_TOP_LEFT]->height(),
+                       images_[BORDER_LEFT]->width(),
+                       h - images_[BORDER_TOP_LEFT]->height() -
+                       images_[BORDER_BOTTOM_LEFT]->height());
+  if (draw_center_) {
+    canvas->DrawBitmapInt(*images_[BORDER_CENTER],
+                          0,
+                          0,
+                          images_[BORDER_CENTER]->width(),
+                          images_[BORDER_CENTER]->height(),
+                          images_[BORDER_TOP_LEFT]->width(),
+                          images_[BORDER_TOP_LEFT]->height(),
+                          w - images_[BORDER_TOP_LEFT]->width() -
+                              images_[BORDER_TOP_RIGHT]->width(),
+                          h - images_[BORDER_TOP_LEFT]->height() -
+                              images_[BORDER_TOP_RIGHT]->height(),
+                          false);
+  }
+}
+
+// static
+Painter* Painter::CreateHorizontalGradient(SkColor c1, SkColor c2) {
+  return new GradientPainter(true, c1, c2);
+}
+
+// static
+Painter* Painter::CreateVerticalGradient(SkColor c1, SkColor c2) {
+  return new GradientPainter(false, c1, c2);
+}
+
+HorizontalPainter::HorizontalPainter(const int image_resource_names[]) {
+  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+  for (int i = 0; i < 3; ++i)
+    images_[i] = rb.GetBitmapNamed(image_resource_names[i]);
+  height_ = images_[LEFT]->height();
+  DCHECK(images_[LEFT]->height() == images_[RIGHT]->height() &&
+         images_[LEFT]->height() == images_[CENTER]->height());
+}
+
+void HorizontalPainter::Paint(int w, int h, ChromeCanvas* canvas) {
+  if (w < (images_[LEFT]->width() + images_[CENTER]->width() +
+            images_[RIGHT]->width())) {
+    // No room to paint.
+    return;
+  }
+  canvas->DrawBitmapInt(*images_[LEFT], 0, 0);
+  canvas->DrawBitmapInt(*images_[RIGHT], w - images_[RIGHT]->width(), 0);
+  canvas->TileImageInt(*images_[CENTER],
+                       images_[LEFT]->width(),
+                       0,
+                       w - images_[LEFT]->width() - images_[RIGHT]->width(),
+                       height_);
+}
+
+}  // namespace views
diff --git a/views/painter.h b/views/painter.h
new file mode 100644
index 0000000..83610c3
--- /dev/null
+++ b/views/painter.h
@@ -0,0 +1,120 @@
+// Copyright (c) 2006-2008 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 VIEWS_PAINTER_H_
+#define VIEWS_PAINTER_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "skia/include/SkColor.h"
+
+class ChromeCanvas;
+class SkBitmap;
+
+namespace views {
+
+// Painter, as the name implies, is responsible for painting in a particular
+// region. Think of Painter as a Border or Background that can be painted
+// in any region of a View.
+class Painter {
+ public:
+  // A convenience method for painting a Painter in a particular region.
+  // This translates the canvas to x/y and paints the painter.
+  static void PaintPainterAt(int x, int y, int w, int h,
+                             ChromeCanvas* canvas, Painter* painter);
+
+  // Creates a painter that draws a gradient between the two colors.
+  static Painter* CreateHorizontalGradient(SkColor c1, SkColor c2);
+  static Painter* CreateVerticalGradient(SkColor c1, SkColor c2);
+
+  virtual ~Painter() {}
+
+  // Paints the painter in the specified region.
+  virtual void Paint(int w, int h, ChromeCanvas* canvas) = 0;
+};
+
+// ImagePainter paints 8 (or 9) images into a box. The four corner
+// images are drawn at the size of the image, the top/left/bottom/right
+// images are tiled to fit the area, and the center (if rendered) is
+// stretched.
+class ImagePainter : public Painter {
+ public:
+  enum BorderElements {
+    BORDER_TOP_LEFT = 0,
+    BORDER_TOP,
+    BORDER_TOP_RIGHT,
+    BORDER_RIGHT,
+    BORDER_BOTTOM_RIGHT,
+    BORDER_BOTTOM,
+    BORDER_BOTTOM_LEFT,
+    BORDER_LEFT,
+    BORDER_CENTER
+  };
+
+  // Constructs a new ImagePainter loading the specified image names.
+  // The images must be in the order defined by the BorderElements.
+  // If draw_center is false, there must be 8 image names, if draw_center
+  // is true, there must be 9 image names with the last giving the name
+  // of the center image.
+  ImagePainter(const int image_resource_names[],
+               bool draw_center);
+
+  virtual ~ImagePainter() {}
+
+  // Paints the images.
+  virtual void Paint(int w, int h, ChromeCanvas* canvas);
+
+  // Returns the specified image. The returned image should NOT be deleted.
+  SkBitmap* GetImage(BorderElements element) {
+    return images_[element];
+  }
+
+ private:
+  bool tile_;
+  bool draw_center_;
+  bool tile_center_;
+  // NOTE: the images are owned by ResourceBundle. Don't free them.
+  std::vector<SkBitmap*> images_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ImagePainter);
+};
+
+// HorizontalPainter paints 3 images into a box: left, center and right. The
+// left and right images are drawn to size at the left/right edges of the
+// region. The center is tiled in the remaining space. All images must have the
+// same height.
+class HorizontalPainter : public Painter {
+ public:
+  // Constructs a new HorizontalPainter loading the specified image names.
+  // The images must be in the order left, right and center.
+  explicit HorizontalPainter(const int image_resource_names[]);
+
+  virtual ~HorizontalPainter() {}
+
+  // Paints the images.
+  virtual void Paint(int w, int h, ChromeCanvas* canvas);
+
+  // Height of the images.
+  int height() const { return height_; }
+
+ private:
+  // The image chunks.
+  enum BorderElements {
+    LEFT,
+    CENTER,
+    RIGHT
+  };
+
+  // The height.
+  int height_;
+  // NOTE: the images are owned by ResourceBundle. Don't free them.
+  SkBitmap* images_[3];
+
+  DISALLOW_EVIL_CONSTRUCTORS(HorizontalPainter);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_PAINTER_H_
diff --git a/views/repeat_controller.cc b/views/repeat_controller.cc
new file mode 100644
index 0000000..bb70852
--- /dev/null
+++ b/views/repeat_controller.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2006-2008 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 "views/repeat_controller.h"
+
+using base::TimeDelta;
+
+namespace views {
+
+// The delay before the first and then subsequent repeats. Values taken from
+// XUL code: http://mxr.mozilla.org/seamonkey/source/layout/xul/base/src/nsRepeatService.cpp#52
+static const int kInitialRepeatDelay = 250;
+static const int kRepeatDelay = 50;
+
+///////////////////////////////////////////////////////////////////////////////
+// RepeatController, public:
+
+RepeatController::RepeatController(RepeatCallback* callback)
+    : callback_(callback) {
+}
+
+RepeatController::~RepeatController() {
+}
+
+void RepeatController::Start() {
+  // The first timer is slightly longer than subsequent repeats.
+  timer_.Start(TimeDelta::FromMilliseconds(kInitialRepeatDelay), this,
+               &RepeatController::Run);
+}
+
+void RepeatController::Stop() {
+  timer_.Stop();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// RepeatController, private:
+
+void RepeatController::Run() {
+  timer_.Start(TimeDelta::FromMilliseconds(kRepeatDelay), this,
+               &RepeatController::Run);
+  callback_->Run();
+}
+
+}  // namespace views
diff --git a/views/repeat_controller.h b/views/repeat_controller.h
new file mode 100644
index 0000000..9e01dd1
--- /dev/null
+++ b/views/repeat_controller.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2006-2008 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 VIEWS_REPEAT_CONTROLLER_H_
+#define VIEWS_REPEAT_CONTROLLER_H_
+
+#include "base/scoped_ptr.h"
+#include "base/timer.h"
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// RepeatController
+//
+//  An object that handles auto-repeating UI actions. There is a longer initial
+//  delay after which point repeats become constant. Users provide a callback
+//  that is notified when each repeat occurs so that they can perform the
+//  associated action.
+//
+///////////////////////////////////////////////////////////////////////////////
+class RepeatController {
+ public:
+  typedef Callback0::Type RepeatCallback;
+
+  // The RepeatController takes ownership of this callback object.
+  explicit RepeatController(RepeatCallback* callback);
+  virtual ~RepeatController();
+
+  // Start repeating.
+  void Start();
+
+  // Stop repeating.
+  void Stop();
+
+ private:
+  RepeatController();
+
+  // Called when the timer expires.
+  void Run();
+
+  // The current timer.
+  base::OneShotTimer<RepeatController> timer_;
+
+  scoped_ptr<RepeatCallback> callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(RepeatController);
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_REPEAT_CONTROLLER_H_
diff --git a/views/view.cc b/views/view.cc
new file mode 100644
index 0000000..cb73d74
--- /dev/null
+++ b/views/view.cc
@@ -0,0 +1,1643 @@
+// Copyright (c) 2006-2008 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 "views/view.h"
+
+#include <algorithm>
+#ifndef NDEBUG
+#include <iostream>
+#endif
+
+#include "app/drag_drop_types.h"
+#include "app/gfx/chrome_canvas.h"
+#include "app/l10n_util.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/scoped_handle.h"
+#include "base/string_util.h"
+#include "skia/include/SkShader.h"
+#include "views/background.h"
+#include "views/layout_manager.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+#include "views/window/window.h"
+#if defined(OS_WIN)
+#include "views/widget/tooltip_manager.h"
+#include "views/accessibility/view_accessibility_wrapper.h"
+#endif
+
+namespace views {
+
+// static
+char View::kViewClassName[] = "views/View";
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A task used to automatically restore focus on the last focused floating view
+//
+////////////////////////////////////////////////////////////////////////////////
+
+class RestoreFocusTask : public Task {
+ public:
+  explicit RestoreFocusTask(View* target) : view_(target) {
+  }
+
+  ~RestoreFocusTask() {}
+
+  void Cancel() {
+    view_ = NULL;
+  }
+
+  void Run() {
+    if (view_)
+      view_->RestoreFloatingViewFocus();
+  }
+ private:
+  // The target view.
+  View* view_;
+
+  DISALLOW_COPY_AND_ASSIGN(RestoreFocusTask);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// View - constructors, destructors, initialization
+//
+/////////////////////////////////////////////////////////////////////////////
+
+View::View()
+    : id_(0),
+      group_(-1),
+      enabled_(true),
+      focusable_(false),
+      bounds_(0, 0, 0, 0),
+      parent_(NULL),
+      should_restore_focus_(false),
+      is_visible_(true),
+      is_parent_owned_(true),
+      notify_when_visible_bounds_in_root_changes_(false),
+      registered_for_visible_bounds_notification_(false),
+      next_focusable_view_(NULL),
+      previous_focusable_view_(NULL),
+      restore_focus_view_task_(NULL),
+      context_menu_controller_(NULL),
+#if defined(OS_WIN)
+      accessibility_(NULL),
+#endif
+      drag_controller_(NULL),
+      ui_mirroring_is_enabled_for_rtl_languages_(true),
+      flip_canvas_on_paint_for_rtl_ui_(false) {
+}
+
+View::~View() {
+  if (restore_focus_view_task_)
+    restore_focus_view_task_->Cancel();
+
+  int c = static_cast<int>(child_views_.size());
+  while (--c >= 0) {
+    if (child_views_[c]->IsParentOwned())
+      delete child_views_[c];
+    else
+      child_views_[c]->SetParent(NULL);
+  }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// View - sizing
+//
+/////////////////////////////////////////////////////////////////////////////
+
+gfx::Rect View::GetBounds(PositionMirroringSettings settings) const {
+  gfx::Rect bounds(bounds_);
+
+  // If the parent uses an RTL UI layout and if we are asked to transform the
+  // bounds to their mirrored position if necessary, then we should shift the
+  // rectangle appropriately.
+  if (settings == APPLY_MIRRORING_TRANSFORMATION)
+    bounds.set_x(MirroredX());
+
+  return bounds;
+}
+
+// y(), width() and height() are agnostic to the RTL UI layout of the
+// parent view. x(), on the other hand, is not.
+int View::GetX(PositionMirroringSettings settings) const {
+  return settings == IGNORE_MIRRORING_TRANSFORMATION ? x() : MirroredX();
+}
+
+void View::SetBounds(const gfx::Rect& bounds) {
+  if (bounds == bounds_)
+    return;
+
+  gfx::Rect prev = bounds_;
+  bounds_ = bounds;
+  DidChangeBounds(prev, bounds_);
+
+  RootView* root = GetRootView();
+  if (root) {
+    bool size_changed = prev.size() != bounds_.size();
+    bool position_changed = prev.origin() != bounds_.origin();
+    if (size_changed || position_changed)
+      root->ViewBoundsChanged(this, size_changed, position_changed);
+  }
+}
+
+gfx::Rect View::GetLocalBounds(bool include_border) const {
+  if (include_border || !border_.get())
+    return gfx::Rect(0, 0, width(), height());
+
+  gfx::Insets insets;
+  border_->GetInsets(&insets);
+  return gfx::Rect(insets.left(), insets.top(),
+                   std::max(0, width() - insets.width()),
+                   std::max(0, height() - insets.height()));
+}
+
+gfx::Point View::GetPosition() const {
+  return gfx::Point(GetX(APPLY_MIRRORING_TRANSFORMATION), y());
+}
+
+gfx::Size View::GetPreferredSize() {
+  if (layout_manager_.get())
+    return layout_manager_->GetPreferredSize(this);
+  return gfx::Size();
+}
+
+void View::SizeToPreferredSize() {
+  gfx::Size prefsize = GetPreferredSize();
+  if ((prefsize.width() != width()) || (prefsize.height() != height()))
+    SetBounds(x(), y(), prefsize.width(), prefsize.height());
+}
+
+gfx::Size View::GetMinimumSize() {
+  return GetPreferredSize();
+}
+
+int View::GetHeightForWidth(int w) {
+  if (layout_manager_.get())
+    return layout_manager_->GetPreferredHeightForWidth(this, w);
+  return GetPreferredSize().height();
+}
+
+void View::DidChangeBounds(const gfx::Rect& previous,
+                           const gfx::Rect& current) {
+  Layout();
+}
+
+void View::ScrollRectToVisible(int x, int y, int width, int height) {
+  View* parent = GetParent();
+
+  // We must take RTL UI mirroring into account when adjusting the position of
+  // the region.
+  if (parent)
+    parent->ScrollRectToVisible(
+        GetX(APPLY_MIRRORING_TRANSFORMATION) + x, View::y() + y, width, height);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// View - layout
+//
+/////////////////////////////////////////////////////////////////////////////
+
+void View::Layout() {
+  // Layout child Views
+  if (layout_manager_.get()) {
+    layout_manager_->Layout(this);
+    SchedulePaint();
+    // TODO(beng): We believe the right thing to do here is return since the
+    //             layout manager should be handling things, but it causes
+    //             regressions (missing options from Options dialog and a hang
+    //             in interactive_ui_tests).
+  }
+
+  // Lay out contents of child Views
+  int child_count = GetChildViewCount();
+  for (int i = 0; i < child_count; ++i) {
+    View* child = GetChildViewAt(i);
+    child->Layout();
+  }
+}
+
+LayoutManager* View::GetLayoutManager() const {
+  return layout_manager_.get();
+}
+
+void View::SetLayoutManager(LayoutManager* layout_manager) {
+  if (layout_manager_.get()) {
+    layout_manager_->Uninstalled(this);
+  }
+  layout_manager_.reset(layout_manager);
+  if (layout_manager_.get()) {
+    layout_manager_->Installed(this);
+  }
+}
+
+bool View::UILayoutIsRightToLeft() const {
+  return (ui_mirroring_is_enabled_for_rtl_languages_ &&
+          l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// View - Right-to-left UI layout
+//
+////////////////////////////////////////////////////////////////////////////////
+
+inline int View::MirroredX() const {
+  // TODO(beng): reimplement in terms of MirroredLeftPointForRect.
+  View* parent = GetParent();
+  if (parent && parent->UILayoutIsRightToLeft())
+    return parent->width() - x() - width();
+  return x();
+}
+
+int View::MirroredLeftPointForRect(const gfx::Rect& bounds) const {
+  if (!UILayoutIsRightToLeft()) {
+    return bounds.x();
+  }
+  return width() - bounds.x() - bounds.width();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// View - states
+//
+////////////////////////////////////////////////////////////////////////////////
+
+bool View::IsEnabled() const {
+  return enabled_;
+}
+
+void View::SetEnabled(bool state) {
+  if (enabled_ != state) {
+    enabled_ = state;
+    SchedulePaint();
+  }
+}
+
+bool View::IsFocusable() const {
+  return focusable_ && enabled_ && is_visible_;
+}
+
+void View::SetFocusable(bool focusable) {
+  focusable_ = focusable;
+}
+
+bool View::HasFocus() {
+  FocusManager* focus_manager = GetFocusManager();
+  if (focus_manager)
+    return focus_manager->GetFocusedView() == this;
+  return false;
+}
+
+void View::SetHotTracked(bool flag) {
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// View - painting
+//
+/////////////////////////////////////////////////////////////////////////////
+
+void View::SchedulePaint(const gfx::Rect& r, bool urgent) {
+  if (!IsVisible())
+    return;
+
+  if (parent_) {
+    // Translate the requested paint rect to the parent's coordinate system
+    // then pass this notification up to the parent.
+    gfx::Rect paint_rect = r;
+    paint_rect.Offset(GetPosition());
+    parent_->SchedulePaint(paint_rect, urgent);
+  }
+}
+
+void View::SchedulePaint() {
+  SchedulePaint(GetLocalBounds(true), false);
+}
+
+void View::SchedulePaint(int x, int y, int w, int h) {
+  SchedulePaint(gfx::Rect(x, y, w, h), false);
+}
+
+void View::Paint(ChromeCanvas* canvas) {
+  PaintBackground(canvas);
+  PaintFocusBorder(canvas);
+  PaintBorder(canvas);
+}
+
+void View::PaintBackground(ChromeCanvas* canvas) {
+  if (background_.get())
+    background_->Paint(canvas, this);
+}
+
+void View::PaintBorder(ChromeCanvas* canvas) {
+  if (border_.get())
+    border_->Paint(*this, canvas);
+}
+
+void View::PaintFocusBorder(ChromeCanvas* canvas) {
+  if (HasFocus() && IsFocusable())
+    canvas->DrawFocusRect(0, 0, width(), height());
+}
+
+void View::PaintChildren(ChromeCanvas* canvas) {
+  int i, c;
+  for (i = 0, c = GetChildViewCount(); i < c; ++i) {
+    View* child = GetChildViewAt(i);
+    if (!child) {
+      NOTREACHED() << "Should not have a NULL child View for index in bounds";
+      continue;
+    }
+    child->ProcessPaint(canvas);
+  }
+}
+
+void View::ProcessPaint(ChromeCanvas* canvas) {
+  if (!IsVisible()) {
+    return;
+  }
+
+  // We're going to modify the canvas, save it's state first.
+  canvas->save();
+
+  // Paint this View and its children, setting the clip rect to the bounds
+  // of this View and translating the origin to the local bounds' top left
+  // point.
+  //
+  // Note that the X (or left) position we pass to ClipRectInt takes into
+  // consideration whether or not the view uses a right-to-left layout so that
+  // we paint our view in its mirrored position if need be.
+  if (canvas->ClipRectInt(MirroredX(), y(), width(), height())) {
+    // Non-empty clip, translate the graphics such that 0,0 corresponds to
+    // where this view is located (related to its parent).
+    canvas->TranslateInt(MirroredX(), y());
+
+    // Save the state again, so that any changes don't effect PaintChildren.
+    canvas->save();
+
+    // If the View we are about to paint requested the canvas to be flipped, we
+    // should change the transform appropriately.
+    bool flip_canvas = FlipCanvasOnPaintForRTLUI();
+    if (flip_canvas) {
+      canvas->TranslateInt(width(), 0);
+      canvas->ScaleInt(-1, 1);
+      canvas->save();
+    }
+
+    Paint(canvas);
+
+    // We must undo the canvas mirroring once the View is done painting so that
+    // we don't pass the canvas with the mirrored transform to Views that
+    // didn't request the canvas to be flipped.
+    if (flip_canvas) {
+      canvas->restore();
+    }
+    canvas->restore();
+    PaintChildren(canvas);
+  }
+
+  // Restore the canvas's original transform.
+  canvas->restore();
+}
+
+void View::PaintNow() {
+  if (!IsVisible()) {
+    return;
+  }
+
+  View* view = GetParent();
+  if (view)
+    view->PaintNow();
+}
+
+void View::PaintFloatingView(ChromeCanvas* canvas, View* view,
+                             int x, int y, int w, int h) {
+  if (should_restore_focus_ && ShouldRestoreFloatingViewFocus()) {
+    // We are painting again a floating view, this is a good time to restore the
+    // focus to the last focused floating view if any.
+    should_restore_focus_ = false;
+    restore_focus_view_task_ = new RestoreFocusTask(this);
+    MessageLoop::current()->PostTask(FROM_HERE, restore_focus_view_task_);
+  }
+  View* saved_parent = view->GetParent();
+  view->SetParent(this);
+  view->SetBounds(x, y, w, h);
+  view->Layout();
+  view->ProcessPaint(canvas);
+  view->SetParent(saved_parent);
+}
+
+gfx::Insets View::GetInsets() const {
+  gfx::Insets insets;
+  if (border_.get())
+    border_->GetInsets(&insets);
+  return insets;
+}
+
+void View::SetContextMenuController(ContextMenuController* menu_controller) {
+  context_menu_controller_ = menu_controller;
+}
+
+void View::ShowContextMenu(int x, int y, bool is_mouse_gesture) {
+  if (!context_menu_controller_)
+    return;
+
+  context_menu_controller_->ShowContextMenu(this, x, y, is_mouse_gesture);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// View - tree
+//
+/////////////////////////////////////////////////////////////////////////////
+
+bool View::ProcessMousePressed(const MouseEvent& e, DragInfo* drag_info) {
+  const bool enabled = enabled_;
+  int drag_operations;
+  if (enabled && e.IsOnlyLeftMouseButton() && HitTest(e.location()))
+    drag_operations = GetDragOperations(e.x(), e.y());
+  else
+    drag_operations = 0;
+  ContextMenuController* context_menu_controller =
+      e.IsRightMouseButton() ? context_menu_controller_ : 0;
+
+  const bool result = OnMousePressed(e);
+  // WARNING: we may have been deleted, don't use any View variables;
+
+  if (!enabled)
+    return result;
+
+  if (drag_operations != DragDropTypes::DRAG_NONE) {
+    drag_info->PossibleDrag(e.x(), e.y());
+    return true;
+  }
+  return !!context_menu_controller || result;
+}
+
+bool View::ProcessMouseDragged(const MouseEvent& e, DragInfo* drag_info) {
+  // Copy the field, that way if we're deleted after drag and drop no harm is
+  // done.
+  ContextMenuController* context_menu_controller = context_menu_controller_;
+  const bool possible_drag = drag_info->possible_drag;
+  if (possible_drag && ExceededDragThreshold(drag_info->start_x - e.x(),
+                                             drag_info->start_y - e.y())) {
+    DoDrag(e, drag_info->start_x, drag_info->start_y);
+  } else {
+    if (OnMouseDragged(e))
+      return true;
+    // Fall through to return value based on context menu controller.
+  }
+  // WARNING: we may have been deleted.
+  return (context_menu_controller != NULL) || possible_drag;
+}
+
+void View::ProcessMouseReleased(const MouseEvent& e, bool canceled) {
+  if (!canceled && context_menu_controller_ && e.IsOnlyRightMouseButton()) {
+    // Assume that if there is a context menu controller we won't be deleted
+    // from mouse released.
+    gfx::Point location(e.location());
+    OnMouseReleased(e, canceled);
+    if (HitTest(location)) {
+      ConvertPointToScreen(this, &location);
+      ShowContextMenu(location.x(), location.y(), true);
+    }
+  } else {
+    OnMouseReleased(e, canceled);
+  }
+  // WARNING: we may have been deleted.
+}
+
+void View::AddChildView(View* v) {
+  AddChildView(static_cast<int>(child_views_.size()), v, false);
+}
+
+void View::AddChildView(int index, View* v) {
+  AddChildView(index, v, false);
+}
+
+void View::AddChildView(int index, View* v, bool floating_view) {
+  // Remove the view from its current parent if any.
+  if (v->GetParent())
+    v->GetParent()->RemoveChildView(v);
+
+  if (!floating_view) {
+    // Sets the prev/next focus views.
+    InitFocusSiblings(v, index);
+  }
+
+  // Let's insert the view.
+  child_views_.insert(child_views_.begin() + index, v);
+  v->SetParent(this);
+
+  for (View* p = this; p; p = p->GetParent()) {
+    p->ViewHierarchyChangedImpl(false, true, this, v);
+  }
+  v->PropagateAddNotifications(this, v);
+  UpdateTooltip();
+  RootView* root = GetRootView();
+  if (root)
+    RegisterChildrenForVisibleBoundsNotification(root, v);
+
+  if (layout_manager_.get())
+    layout_manager_->ViewAdded(this, v);
+}
+
+View* View::GetChildViewAt(int index) const {
+  return index < GetChildViewCount() ? child_views_[index] : NULL;
+}
+
+int View::GetChildViewCount() const {
+  return static_cast<int>(child_views_.size());
+}
+
+void View::RemoveChildView(View* a_view) {
+  DoRemoveChildView(a_view, true, true, false);
+}
+
+void View::RemoveAllChildViews(bool delete_views) {
+  ViewList::iterator iter;
+  while ((iter = child_views_.begin()) != child_views_.end()) {
+    DoRemoveChildView(*iter, false, false, delete_views);
+  }
+  UpdateTooltip();
+}
+
+void View::DoRemoveChildView(View* a_view,
+                             bool update_focus_cycle,
+                             bool update_tool_tip,
+                             bool delete_removed_view) {
+#ifndef NDEBUG
+  DCHECK(!IsProcessingPaint()) << "Should not be removing a child view " <<
+                                  "during a paint, this will seriously " <<
+                                  "mess things up!";
+#endif
+  DCHECK(a_view);
+  const ViewList::iterator i =  find(child_views_.begin(),
+                                     child_views_.end(),
+                                     a_view);
+  if (i != child_views_.end()) {
+    if (update_focus_cycle && !a_view->IsFloatingView()) {
+      // Let's remove the view from the focus traversal.
+      View* next_focusable = a_view->next_focusable_view_;
+      View* prev_focusable = a_view->previous_focusable_view_;
+      if (prev_focusable)
+        prev_focusable->next_focusable_view_ = next_focusable;
+      if (next_focusable)
+        next_focusable->previous_focusable_view_ = prev_focusable;
+    }
+
+    RootView* root = GetRootView();
+    if (root)
+      UnregisterChildrenForVisibleBoundsNotification(root, a_view);
+    a_view->PropagateRemoveNotifications(this);
+    a_view->SetParent(NULL);
+
+    if (delete_removed_view && a_view->IsParentOwned())
+      delete a_view;
+
+    child_views_.erase(i);
+  }
+
+  if (update_tool_tip)
+    UpdateTooltip();
+
+  if (layout_manager_.get())
+    layout_manager_->ViewRemoved(this, a_view);
+}
+
+void View::PropagateRemoveNotifications(View* parent) {
+  int i, c;
+  for (i = 0, c = GetChildViewCount(); i < c; ++i) {
+    GetChildViewAt(i)->PropagateRemoveNotifications(parent);
+  }
+
+  View *t;
+  for (t = this; t; t = t->GetParent()) {
+    t->ViewHierarchyChangedImpl(true, false, parent, this);
+  }
+}
+
+void View::PropagateAddNotifications(View* parent, View* child) {
+  int i, c;
+  for (i = 0, c = GetChildViewCount(); i < c; ++i) {
+    GetChildViewAt(i)->PropagateAddNotifications(parent, child);
+  }
+  ViewHierarchyChangedImpl(true, true, parent, child);
+}
+
+void View::ThemeChanged() {
+  int c = GetChildViewCount();
+  for (int i = c - 1; i >= 0; --i)
+    GetChildViewAt(i)->ThemeChanged();
+}
+
+#ifndef NDEBUG
+bool View::IsProcessingPaint() const {
+  return GetParent() && GetParent()->IsProcessingPaint();
+}
+#endif
+
+gfx::Point View::GetKeyboardContextMenuLocation() {
+  gfx::Rect vis_bounds = GetVisibleBounds();
+  gfx::Point screen_point(vis_bounds.x() + vis_bounds.width() / 2,
+                          vis_bounds.y() + vis_bounds.height() / 2);
+  ConvertPointToScreen(this, &screen_point);
+  return screen_point;
+}
+
+bool View::HasHitTestMask() const {
+  return false;
+}
+
+void View::GetHitTestMask(gfx::Path* mask) const {
+  DCHECK(mask);
+}
+
+void View::ViewHierarchyChanged(bool is_add,
+                                View* parent,
+                                View* child) {
+}
+
+void View::ViewHierarchyChangedImpl(bool register_accelerators,
+                                    bool is_add,
+                                    View* parent,
+                                    View* child) {
+  if (register_accelerators) {
+    if (is_add) {
+      // If you get this registration, you are part of a subtree that has been
+      // added to the view hierarchy.
+      RegisterAccelerators();
+    } else {
+      if (child == this)
+        UnregisterAccelerators();
+    }
+  }
+
+  ViewHierarchyChanged(is_add, parent, child);
+}
+
+void View::PropagateVisibilityNotifications(View* start, bool is_visible) {
+  int i, c;
+  for (i = 0, c = GetChildViewCount(); i < c; ++i) {
+    GetChildViewAt(i)->PropagateVisibilityNotifications(start, is_visible);
+  }
+  VisibilityChanged(start, is_visible);
+}
+
+void View::VisibilityChanged(View* starting_from, bool is_visible) {
+}
+
+View* View::GetViewForPoint(const gfx::Point& point) {
+  return GetViewForPoint(point, true);
+}
+
+void View::SetNotifyWhenVisibleBoundsInRootChanges(bool value) {
+  if (notify_when_visible_bounds_in_root_changes_ == value)
+    return;
+  notify_when_visible_bounds_in_root_changes_ = value;
+  RootView* root = GetRootView();
+  if (root) {
+    if (value)
+      root->RegisterViewForVisibleBoundsNotification(this);
+    else
+      root->UnregisterViewForVisibleBoundsNotification(this);
+  }
+}
+
+bool View::GetNotifyWhenVisibleBoundsInRootChanges() {
+  return notify_when_visible_bounds_in_root_changes_;
+}
+
+View* View::GetViewForPoint(const gfx::Point& point,
+                            bool can_create_floating) {
+  // Walk the child Views recursively looking for the View that most
+  // tightly encloses the specified point.
+  for (int i = GetChildViewCount() - 1 ; i >= 0 ; --i) {
+    View* child = GetChildViewAt(i);
+    if (!child->IsVisible())
+      continue;
+
+    gfx::Point point_in_child_coords(point);
+    View::ConvertPointToView(this, child, &point_in_child_coords);
+    if (child->HitTest(point_in_child_coords))
+      return child->GetViewForPoint(point_in_child_coords, true);
+  }
+
+  // We haven't found a view for the point. Try to create floating views
+  // and try again if one was created.
+  // can_create_floating makes sure we don't try forever even if
+  // GetFloatingViewIDForPoint lies or if RetrieveFloatingViewForID creates a
+  // view which doesn't contain the provided point
+  int id;
+  if (can_create_floating &&
+      GetFloatingViewIDForPoint(point.x(), point.y(), &id)) {
+    RetrieveFloatingViewForID(id);  // This creates the floating view.
+    return GetViewForPoint(point, false);
+  }
+  return this;
+}
+
+Widget* View::GetWidget() const {
+  // The root view holds a reference to this view hierarchy's Widget.
+  return parent_ ? parent_->GetWidget() : NULL;
+}
+
+Window* View::GetWindow() const {
+  Widget* widget = GetWidget();
+  return widget ? widget->GetWindow() : NULL;
+}
+
+// Get the containing RootView
+RootView* View::GetRootView() {
+  Widget* widget = GetWidget();
+  return widget ? widget->GetRootView() : NULL;
+}
+
+View* View::GetViewByID(int id) const {
+  if (id == id_)
+    return const_cast<View*>(this);
+
+  int view_count = GetChildViewCount();
+  for (int i = 0; i < view_count; ++i) {
+    View* child = GetChildViewAt(i);
+    View* view = child->GetViewByID(id);
+    if (view)
+      return view;
+  }
+  return NULL;
+}
+
+void View::GetViewsWithGroup(int group_id, std::vector<View*>* out) {
+  if (group_ == group_id)
+    out->push_back(this);
+
+  int view_count = GetChildViewCount();
+  for (int i = 0; i < view_count; ++i)
+    GetChildViewAt(i)->GetViewsWithGroup(group_id, out);
+}
+
+View* View::GetSelectedViewForGroup(int group_id) {
+  std::vector<View*> views;
+  GetRootView()->GetViewsWithGroup(group_id, &views);
+  if (views.size() > 0)
+    return views[0];
+  else
+    return NULL;
+}
+
+void View::SetID(int id) {
+  id_ = id;
+}
+
+int View::GetID() const {
+  return id_;
+}
+
+void View::SetGroup(int gid) {
+  group_ = gid;
+}
+
+int View::GetGroup() const {
+  return group_;
+}
+
+void View::SetParent(View* parent) {
+  if (parent != parent_) {
+    parent_ = parent;
+  }
+}
+
+bool View::IsParentOf(View* v) const {
+  DCHECK(v);
+  View* parent = v->GetParent();
+  while (parent) {
+    if (this == parent)
+      return true;
+    parent = parent->GetParent();
+  }
+  return false;
+}
+
+int View::GetChildIndex(View* v) const {
+  for (int i = 0; i < GetChildViewCount(); i++) {
+    if (v == GetChildViewAt(i))
+      return i;
+  }
+  return -1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// View - focus
+//
+///////////////////////////////////////////////////////////////////////////////
+
+View* View::GetNextFocusableView() {
+  return next_focusable_view_;
+}
+
+View* View::GetPreviousFocusableView() {
+  return previous_focusable_view_;
+}
+
+void View::SetNextFocusableView(View* view) {
+  view->previous_focusable_view_ = this;
+  next_focusable_view_ = view;
+}
+
+void View::InitFocusSiblings(View* v, int index) {
+  int child_count = static_cast<int>(child_views_.size());
+
+  if (child_count == 0) {
+    v->next_focusable_view_ = NULL;
+    v->previous_focusable_view_ = NULL;
+  } else {
+    if (index == child_count) {
+      // We are inserting at the end, but the end of the child list may not be
+      // the last focusable element. Let's try to find an element with no next
+      // focusable element to link to.
+      View* last_focusable_view = NULL;
+      for (std::vector<View*>::iterator iter = child_views_.begin();
+           iter != child_views_.end(); ++iter) {
+          if (!(*iter)->next_focusable_view_) {
+            last_focusable_view = *iter;
+            break;
+          }
+      }
+      if (last_focusable_view == NULL) {
+        // Hum... there is a cycle in the focus list. Let's just insert ourself
+        // after the last child.
+        View* prev = child_views_[index - 1];
+        v->previous_focusable_view_ = prev;
+        v->next_focusable_view_ = prev->next_focusable_view_;
+        prev->next_focusable_view_->previous_focusable_view_ = v;
+        prev->next_focusable_view_ = v;
+      } else {
+        last_focusable_view->next_focusable_view_ = v;
+        v->next_focusable_view_ = NULL;
+        v->previous_focusable_view_ = last_focusable_view;
+      }
+    } else {
+      View* prev = child_views_[index]->GetPreviousFocusableView();
+      v->previous_focusable_view_ = prev;
+      v->next_focusable_view_ = child_views_[index];
+      if (prev)
+        prev->next_focusable_view_ = v;
+      child_views_[index]->previous_focusable_view_ = v;
+    }
+  }
+}
+
+#ifndef NDEBUG
+void View::PrintViewHierarchy() {
+  PrintViewHierarchyImp(0);
+}
+
+void View::PrintViewHierarchyImp(int indent) {
+  std::wostringstream buf;
+  int ind = indent;
+  while (ind-- > 0)
+    buf << L' ';
+  buf << UTF8ToWide(GetClassName());
+  buf << L' ';
+  buf << GetID();
+  buf << L' ';
+  buf << bounds_.x() << L"," << bounds_.y() << L",";
+  buf << bounds_.right() << L"," << bounds_.bottom();
+  buf << L' ';
+  buf << this;
+
+  LOG(INFO) << buf.str();
+  std::cout << buf.str() << std::endl;
+
+  for (int i = 0; i < GetChildViewCount(); ++i) {
+    GetChildViewAt(i)->PrintViewHierarchyImp(indent + 2);
+  }
+}
+
+
+void View::PrintFocusHierarchy() {
+  PrintFocusHierarchyImp(0);
+}
+
+void View::PrintFocusHierarchyImp(int indent) {
+  std::wostringstream buf;
+  int ind = indent;
+  while (ind-- > 0)
+    buf << L' ';
+  buf << UTF8ToWide(GetClassName());
+  buf << L' ';
+  buf << GetID();
+  buf << L' ';
+  buf << GetClassName().c_str();
+  buf << L' ';
+  buf << this;
+
+  LOG(INFO) << buf.str();
+  std::cout << buf.str() << std::endl;
+
+  if (GetChildViewCount() > 0)
+    GetChildViewAt(0)->PrintFocusHierarchyImp(indent + 2);
+
+  View* v = GetNextFocusableView();
+  if (v)
+    v->PrintFocusHierarchyImp(indent);
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// View - accelerators
+//
+////////////////////////////////////////////////////////////////////////////////
+
+void View::AddAccelerator(const Accelerator& accelerator) {
+  if (!accelerators_.get())
+    accelerators_.reset(new std::vector<Accelerator>());
+  accelerators_->push_back(accelerator);
+  RegisterAccelerators();
+}
+
+void View::RemoveAccelerator(const Accelerator& accelerator) {
+  std::vector<Accelerator>::iterator iter;
+  if (!accelerators_.get() ||
+      ((iter = std::find(accelerators_->begin(), accelerators_->end(),
+          accelerator)) == accelerators_->end())) {
+    NOTREACHED() << "Removing non-existing accelerator";
+    return;
+  }
+
+  accelerators_->erase(iter);
+  RootView* root_view = GetRootView();
+  if (!root_view) {
+    // We are not part of a view hierarchy, so there is nothing to do as we
+    // removed ourselves from accelerators_, we won't be registered when added
+    // to one.
+    return;
+  }
+
+  // TODO(port): Fix this once we have a FocusManger for Linux.
+#if defined(OS_WIN)
+  FocusManager* focus_manager = GetFocusManager();
+  if (focus_manager) {
+    // We may not have a FocusManager if the window containing us is being
+    // closed, in which case the FocusManager is being deleted so there is
+    // nothing to unregister.
+    focus_manager->UnregisterAccelerator(accelerator, this);
+  }
+#endif
+}
+
+void View::ResetAccelerators() {
+  if (accelerators_.get()) {
+    UnregisterAccelerators();
+    accelerators_->clear();
+    accelerators_.reset();
+  }
+}
+
+void View::RegisterAccelerators() {
+  if (!accelerators_.get())
+    return;
+
+  RootView* root_view = GetRootView();
+  if (!root_view) {
+    // We are not yet part of a view hierarchy, we'll register ourselves once
+    // added to one.
+    return;
+  }
+
+  // TODO(port): Fix this once we have a FocusManger for Linux.
+#if defined(OS_WIN)
+  FocusManager* focus_manager = GetFocusManager();
+  if (!focus_manager) {
+    // Some crash reports seem to show that we may get cases where we have no
+    // focus manager (see bug #1291225).  This should never be the case, just
+    // making sure we don't crash.
+    NOTREACHED();
+    return;
+  }
+  for (std::vector<Accelerator>::const_iterator iter = accelerators_->begin();
+       iter != accelerators_->end(); ++iter) {
+    focus_manager->RegisterAccelerator(*iter, this);
+  }
+#endif
+}
+
+void View::UnregisterAccelerators() {
+  if (!accelerators_.get())
+    return;
+
+  RootView* root_view = GetRootView();
+  if (root_view) {
+    // TODO(port): Fix this once we have a FocusManger for Linux.
+#if defined(OS_WIN)
+    FocusManager* focus_manager = GetFocusManager();
+    if (focus_manager) {
+      // We may not have a FocusManager if the window containing us is being
+      // closed, in which case the FocusManager is being deleted so there is
+      // nothing to unregister.
+      focus_manager->UnregisterAccelerators(this);
+    }
+#endif
+  }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// View - floating views
+//
+/////////////////////////////////////////////////////////////////////////////
+
+bool View::IsFloatingView() {
+  if (!parent_)
+    return false;
+
+  return parent_->floating_views_ids_.find(this) !=
+      parent_->floating_views_ids_.end();
+}
+
+// default implementation does nothing
+bool View::GetFloatingViewIDForPoint(int x, int y, int* id) {
+  return false;
+}
+
+int View::GetFloatingViewCount() const {
+  return static_cast<int>(floating_views_.size());
+}
+
+View* View::RetrieveFloatingViewParent() {
+  View* v = this;
+  while (v) {
+    if (v->IsFloatingView())
+      return v;
+    v = v->GetParent();
+  }
+  return NULL;
+}
+
+bool View::EnumerateFloatingViews(FloatingViewPosition position,
+                                  int starting_id, int* id) {
+    return false;
+}
+
+int View::GetDragOperations(int press_x, int press_y) {
+  if (!drag_controller_)
+    return DragDropTypes::DRAG_NONE;
+  return drag_controller_->GetDragOperations(this, press_x, press_y);
+}
+
+void View::WriteDragData(int press_x, int press_y, OSExchangeData* data) {
+  DCHECK(drag_controller_);
+  drag_controller_->WriteDragData(this, press_x, press_y, data);
+}
+
+void View::OnDragDone() {
+}
+
+bool View::InDrag() {
+  RootView* root_view = GetRootView();
+  return root_view ? (root_view->GetDragView() == this) : false;
+}
+
+View* View::ValidateFloatingViewForID(int id) {
+  return NULL;
+}
+
+bool View::ShouldRestoreFloatingViewFocus() {
+  return true;
+}
+
+void View::AttachFloatingView(View* v, int id) {
+  floating_views_.push_back(v);
+  floating_views_ids_[v] = id;
+  AddChildView(static_cast<int>(child_views_.size()), v, true);
+}
+
+bool View::HasFloatingViewForPoint(int x, int y) {
+  int i, c;
+  View* v;
+  gfx::Rect r;
+
+  for (i = 0, c = static_cast<int>(floating_views_.size()); i < c; ++i) {
+    v = floating_views_[i];
+    r.SetRect(v->GetX(APPLY_MIRRORING_TRANSFORMATION), v->y(),
+              v->width(), v->height());
+    if (r.Contains(x, y))
+      return true;
+  }
+  return false;
+}
+
+void View::DetachAllFloatingViews() {
+  RootView* root_view = GetRootView();
+  View* focused_view = NULL;
+  FocusManager* focus_manager = NULL;
+  if (root_view) {
+    // We may be called when we are not attached to a root view in which case
+    // there is nothing to do for focus.
+    focus_manager = GetFocusManager();
+    if (focus_manager) {
+      // We may not have a focus manager (if we are detached from a top window).
+      focused_view = focus_manager->GetFocusedView();
+    }
+  }
+
+  int c = static_cast<int>(floating_views_.size());
+  while (--c >= 0) {
+    // If the focused view is a floating view or a floating view's children,
+    // use the focus manager to store it.
+    int tmp_id;
+    if (focused_view &&
+        ((focused_view == floating_views_[c]) ||
+          floating_views_[c]->IsParentOf(focused_view))) {
+      // We call EnumerateFloatingView to make sure the floating view is still
+      // valid: the model may have changed and could not know anything about
+      // that floating view anymore.
+      if (EnumerateFloatingViews(CURRENT,
+                                 floating_views_[c]->GetFloatingViewID(),
+                                 &tmp_id)) {
+        // TODO(port): Fix this once we have a FocusManger for Linux.
+#if defined(OS_WIN)
+        focus_manager->StoreFocusedView();
+#endif
+        should_restore_focus_ = true;
+      }
+      focused_view = NULL;
+    }
+
+    RemoveChildView(floating_views_[c]);
+    delete floating_views_[c];
+  }
+  floating_views_.clear();
+  floating_views_ids_.clear();
+}
+
+int View::GetFloatingViewID() {
+  DCHECK(IsFloatingView());
+  std::map<View*, int>::iterator iter = parent_->floating_views_ids_.find(this);
+  DCHECK(iter != parent_->floating_views_ids_.end());
+  return iter->second;
+}
+
+View* View::RetrieveFloatingViewForID(int id) {
+  for (ViewList::const_iterator iter = floating_views_.begin();
+       iter != floating_views_.end(); ++iter) {
+    if ((*iter)->GetFloatingViewID() == id)
+      return *iter;
+  }
+  return ValidateFloatingViewForID(id);
+}
+
+void View::RestoreFloatingViewFocus() {
+  // Clear the reference to the task as if we have been triggered by it, it will
+  // soon be invalid.
+  restore_focus_view_task_ = NULL;
+  should_restore_focus_ = false;
+
+  // TODO(port): Fix this once we have a FocusManger for Linux.
+#if defined(OS_WIN)
+  FocusManager* focus_manager = GetFocusManager();
+  DCHECK(focus_manager);
+  if (focus_manager)
+    focus_manager->RestoreFocusedView();
+#endif
+}
+
+// static
+bool View::EnumerateFloatingViewsForInterval(int low_bound, int high_bound,
+                                             bool ascending_order,
+                                             FloatingViewPosition position,
+                                             int starting_id,
+                                             int* id) {
+  DCHECK(low_bound <= high_bound);
+  if (low_bound >= high_bound)
+    return false;
+
+  switch (position) {
+    case CURRENT:
+      if ((starting_id >= low_bound) && (starting_id < high_bound)) {
+        *id = starting_id;
+        return true;
+      }
+      return false;
+    case FIRST:
+      *id = ascending_order ? low_bound : high_bound - 1;
+      return true;
+    case LAST:
+      *id = ascending_order ? high_bound - 1 : low_bound;
+      return true;
+    case NEXT:
+    case PREVIOUS:
+      if (((position == NEXT) && ascending_order) ||
+          ((position == PREVIOUS) && !ascending_order)) {
+        starting_id++;
+        if (starting_id < high_bound) {
+          *id = starting_id;
+          return true;
+        }
+        return false;
+      }
+      DCHECK(((position == NEXT) && !ascending_order) ||
+             ((position == PREVIOUS) && ascending_order));
+      starting_id--;
+      if (starting_id >= low_bound) {
+        *id = starting_id;
+        return true;
+      }
+      return false;
+    default:
+      NOTREACHED();
+  }
+  return false;
+}
+
+// static
+void View::ConvertPointToView(const View* src,
+                              const View* dst,
+                              gfx::Point* point) {
+  ConvertPointToView(src, dst, point, true);
+}
+
+// static
+void View::ConvertPointToView(const View* src,
+                              const View* dst,
+                              gfx::Point* point,
+                              bool try_other_direction) {
+  // src can be NULL
+  DCHECK(dst);
+  DCHECK(point);
+
+  const View* v;
+  gfx::Point offset;
+
+  for (v = dst; v && v != src; v = v->GetParent()) {
+    offset.SetPoint(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION),
+                    offset.y() + v->y());
+  }
+
+  // The source was not found. The caller wants a conversion
+  // from a view to a transitive parent.
+  if (src && v == NULL && try_other_direction) {
+    gfx::Point p;
+    // note: try_other_direction is force to FALSE so we don't
+    // end up in an infinite recursion should both src and dst
+    // are not parented.
+    ConvertPointToView(dst, src, &p, false);
+    // since the src and dst are inverted, p should also be negated
+    point->SetPoint(point->x() - p.x(), point->y() - p.y());
+  } else {
+    point->SetPoint(point->x() - offset.x(), point->y() - offset.y());
+
+    // If src is NULL, sp is in the screen coordinate system
+    if (src == NULL) {
+      Widget* widget = dst->GetWidget();
+      if (widget) {
+        gfx::Rect b;
+        widget->GetBounds(&b, false);
+        point->SetPoint(point->x() - b.x(), point->y() - b.y());
+      }
+    }
+  }
+}
+
+// static
+void View::ConvertPointToWidget(const View* src, gfx::Point* p) {
+  DCHECK(src);
+  DCHECK(p);
+
+  gfx::Point offset;
+  for (const View* v = src; v; v = v->GetParent()) {
+    offset.set_x(offset.x() + v->GetX(APPLY_MIRRORING_TRANSFORMATION));
+    offset.set_y(offset.y() + v->y());
+  }
+  p->SetPoint(p->x() + offset.x(), p->y() + offset.y());
+}
+
+// static
+void View::ConvertPointFromWidget(const View* dest, gfx::Point* p) {
+  gfx::Point t;
+  ConvertPointToWidget(dest, &t);
+  p->SetPoint(p->x() - t.x(), p->y() - t.y());
+}
+
+// static
+void View::ConvertPointToScreen(const View* src, gfx::Point* p) {
+  DCHECK(src);
+  DCHECK(p);
+
+  // If the view is not connected to a tree, there's nothing we can do.
+  Widget* widget = src->GetWidget();
+  if (widget) {
+    ConvertPointToWidget(src, p);
+    gfx::Rect r;
+    widget->GetBounds(&r, false);
+    p->SetPoint(p->x() + r.x(), p->y() + r.y());
+  }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// View - event handlers
+//
+/////////////////////////////////////////////////////////////////////////////
+
+bool View::OnMousePressed(const MouseEvent& e) {
+  return false;
+}
+
+bool View::OnMouseDragged(const MouseEvent& e) {
+  return false;
+}
+
+void View::OnMouseReleased(const MouseEvent& e, bool canceled) {
+}
+
+void View::OnMouseMoved(const MouseEvent& e) {
+}
+
+void View::OnMouseEntered(const MouseEvent& e) {
+}
+
+void View::OnMouseExited(const MouseEvent& e) {
+}
+
+void View::SetMouseHandler(View *new_mouse_handler) {
+  // It is valid for new_mouse_handler to be NULL
+  if (parent_) {
+    parent_->SetMouseHandler(new_mouse_handler);
+  }
+}
+
+void View::SetVisible(bool flag) {
+  if (flag != is_visible_) {
+    // If the tab is currently visible, schedule paint to
+    // refresh parent
+    if (IsVisible()) {
+      SchedulePaint();
+    }
+
+    is_visible_ = flag;
+
+    // This notifies all subviews recursively.
+    PropagateVisibilityNotifications(this, flag);
+
+    // If we are newly visible, schedule paint.
+    if (IsVisible()) {
+      SchedulePaint();
+    }
+  }
+}
+
+bool View::IsVisibleInRootView() const {
+  View* parent = GetParent();
+  if (IsVisible() && parent)
+    return parent->IsVisibleInRootView();
+  else
+    return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// View - keyboard and focus
+//
+/////////////////////////////////////////////////////////////////////////////
+
+void View::RequestFocus() {
+  RootView* rv = GetRootView();
+  if (rv && IsFocusable())
+    rv->FocusView(this);
+}
+
+void View::WillGainFocus() {
+}
+
+void View::DidGainFocus() {
+}
+
+void View::WillLoseFocus() {
+}
+
+bool View::OnKeyPressed(const KeyEvent& e) {
+  return false;
+}
+
+bool View::OnKeyReleased(const KeyEvent& e) {
+  return false;
+}
+
+bool View::OnMouseWheel(const MouseWheelEvent& e) {
+  return false;
+}
+
+void View::SetDragController(DragController* drag_controller) {
+    drag_controller_ = drag_controller;
+}
+
+DragController* View::GetDragController() {
+  return drag_controller_;
+}
+
+bool View::CanDrop(const OSExchangeData& data) {
+  return false;
+}
+
+void View::OnDragEntered(const DropTargetEvent& event) {
+}
+
+int View::OnDragUpdated(const DropTargetEvent& event) {
+  return DragDropTypes::DRAG_NONE;
+}
+
+void View::OnDragExited() {
+}
+
+int View::OnPerformDrop(const DropTargetEvent& event) {
+  return DragDropTypes::DRAG_NONE;
+}
+
+// static
+bool View::ExceededDragThreshold(int delta_x, int delta_y) {
+  return (abs(delta_x) > GetHorizontalDragThreshold() ||
+          abs(delta_y) > GetVerticalDragThreshold());
+}
+
+bool View::CanProcessTabKeyEvents() {
+  return false;
+}
+
+// Tooltips -----------------------------------------------------------------
+bool View::GetTooltipText(int x, int y, std::wstring* tooltip) {
+  return false;
+}
+
+bool View::GetTooltipTextOrigin(int x, int y, gfx::Point* loc) {
+  return false;
+}
+
+void View::TooltipTextChanged() {
+#if defined(OS_WIN)
+  Widget* widget = GetWidget();
+  if (widget && widget->GetTooltipManager())
+    widget->GetTooltipManager()->TooltipTextChanged(this);
+#else
+  // TODO(port): Not actually windows specific; I just haven't ported this part
+  // yet.
+  NOTIMPLEMENTED();
+#endif
+}
+
+void View::UpdateTooltip() {
+#if defined(OS_WIN)
+  Widget* widget = GetWidget();
+  if (widget && widget->GetTooltipManager())
+    widget->GetTooltipManager()->UpdateTooltip();
+#else
+  // TODO(port): Not actually windows specific; I just haven't ported this part
+  // yet.
+  NOTIMPLEMENTED();
+#endif
+}
+
+void View::SetParentOwned(bool f) {
+  is_parent_owned_ = f;
+}
+
+bool View::IsParentOwned() const {
+  return is_parent_owned_;
+}
+
+std::string View::GetClassName() const {
+  return kViewClassName;
+}
+
+View* View::GetAncestorWithClassName(const std::string& name) {
+  for (View* view = this; view; view = view->GetParent()) {
+    if (view->GetClassName() == name)
+      return view;
+  }
+  return NULL;
+}
+
+gfx::Rect View::GetVisibleBounds() {
+  if (!IsVisibleInRootView())
+    return gfx::Rect();
+  gfx::Rect vis_bounds(0, 0, width(), height());
+  gfx::Rect ancestor_bounds;
+  View* view = this;
+  int root_x = 0;
+  int root_y = 0;
+  while (view != NULL && !vis_bounds.IsEmpty()) {
+    root_x += view->GetX(APPLY_MIRRORING_TRANSFORMATION);
+    root_y += view->y();
+    vis_bounds.Offset(view->GetX(APPLY_MIRRORING_TRANSFORMATION), view->y());
+    View* ancestor = view->GetParent();
+    if (ancestor != NULL) {
+      ancestor_bounds.SetRect(0, 0, ancestor->width(),
+                              ancestor->height());
+      vis_bounds = vis_bounds.Intersect(ancestor_bounds);
+    } else if (!view->GetWidget()) {
+      // If the view has no Widget, we're not visible. Return an empty rect.
+      return gfx::Rect();
+    }
+    view = ancestor;
+  }
+  if (vis_bounds.IsEmpty())
+    return vis_bounds;
+  // Convert back to this views coordinate system.
+  vis_bounds.Offset(-root_x, -root_y);
+  return vis_bounds;
+}
+
+int View::GetPageScrollIncrement(ScrollView* scroll_view,
+                                 bool is_horizontal, bool is_positive) {
+  return 0;
+}
+
+int View::GetLineScrollIncrement(ScrollView* scroll_view,
+                                 bool is_horizontal, bool is_positive) {
+  return 0;
+}
+
+// static
+void View::RegisterChildrenForVisibleBoundsNotification(
+    RootView* root, View* view) {
+  DCHECK(root && view);
+  if (view->GetNotifyWhenVisibleBoundsInRootChanges())
+    root->RegisterViewForVisibleBoundsNotification(view);
+  for (int i = 0; i < view->GetChildViewCount(); ++i)
+    RegisterChildrenForVisibleBoundsNotification(root, view->GetChildViewAt(i));
+}
+
+// static
+void View::UnregisterChildrenForVisibleBoundsNotification(
+    RootView* root, View* view) {
+  DCHECK(root && view);
+  if (view->GetNotifyWhenVisibleBoundsInRootChanges())
+    root->UnregisterViewForVisibleBoundsNotification(view);
+  for (int i = 0; i < view->GetChildViewCount(); ++i)
+    UnregisterChildrenForVisibleBoundsNotification(root,
+                                                   view->GetChildViewAt(i));
+}
+
+void View::AddDescendantToNotify(View* view) {
+  DCHECK(view);
+  if (!descendants_to_notify_.get())
+    descendants_to_notify_.reset(new ViewList());
+  descendants_to_notify_->push_back(view);
+}
+
+void View::RemoveDescendantToNotify(View* view) {
+  DCHECK(view && descendants_to_notify_.get());
+  ViewList::iterator i = find(descendants_to_notify_->begin(),
+                              descendants_to_notify_->end(),
+                              view);
+  DCHECK(i != descendants_to_notify_->end());
+  descendants_to_notify_->erase(i);
+  if (descendants_to_notify_->empty())
+    descendants_to_notify_.reset();
+}
+
+// static
+bool View::GetViewPath(View* start, View* end, std::vector<int>* path) {
+  while (end && (end != start)) {
+    View* parent = end->GetParent();
+    if (!parent)
+      return false;
+    path->insert(path->begin(), parent->GetChildIndex(end));
+    end = parent;
+  }
+  return end == start;
+}
+
+// static
+View* View::GetViewForPath(View* start, const std::vector<int>& path) {
+  View* v = start;
+  for (std::vector<int>::const_iterator iter = path.begin();
+       iter != path.end(); ++iter) {
+    int index = *iter;
+    if (index >= v->GetChildViewCount())
+      return NULL;
+    v = v->GetChildViewAt(index);
+  }
+  return v;
+}
+
+// DropInfo --------------------------------------------------------------------
+
+void View::DragInfo::Reset() {
+  possible_drag = false;
+  start_x = start_y = 0;
+}
+
+void View::DragInfo::PossibleDrag(int x, int y) {
+  possible_drag = true;
+  start_x = x;
+  start_y = y;
+}
+
+}  // namespace
diff --git a/views/view.h b/views/view.h
new file mode 100644
index 0000000..d2d8e52
--- /dev/null
+++ b/views/view.h
@@ -0,0 +1,1351 @@
+// Copyright (c) 2006-2008 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 VIEWS_VIEW_H_
+#define VIEWS_VIEW_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <atlbase.h>
+#include <atlapp.h>
+#include <atlmisc.h>
+#endif  // defined(OS_WIN)
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/gfx/rect.h"
+#include "base/scoped_ptr.h"
+#include "chrome/common/accessibility_types.h"
+#include "views/accelerator.h"
+#include "views/background.h"
+#include "views/border.h"
+
+namespace gfx {
+class Insets;
+class Path;
+}
+
+class ChromeCanvas;
+class OSExchangeData;
+class ViewAccessibilityWrapper;
+
+namespace views {
+
+class Background;
+class Border;
+class FocusManager;
+class FocusTraversable;
+class LayoutManager;
+class RestoreFocusTask;
+class RootView;
+class ScrollView;
+class Widget;
+class Window;
+
+// ContextMenuController is responsible for showing the context menu for a
+// View. To use a ContextMenuController invoke SetContextMenuController on a
+// View. When the appropriate user gesture occurs ShowContextMenu is invoked
+// on the ContextMenuController.
+//
+// Setting a ContextMenuController on a view makes the view process mouse
+// events.
+//
+// It is up to subclasses that do their own mouse processing to invoke
+// the appropriate ContextMenuController method, typically by invoking super's
+// implementation for mouse processing.
+//
+class ContextMenuController {
+ public:
+  // Invoked to show the context menu for the source view. If is_mouse_gesture
+  // is true, the x/y coordinate are the location of the mouse. If
+  // is_mouse_gesture is false, this method was not invoked by a mouse gesture
+  // and x/y is the recommended location to show the menu at.
+  //
+  // x/y is in screen coordinates.
+  virtual void ShowContextMenu(View* source,
+                               int x,
+                               int y,
+                               bool is_mouse_gesture) = 0;
+};
+
+// DragController is responsible for writing drag data for a view, as well as
+// supplying the supported drag operations. Use DragController if you don't
+// want to subclass.
+
+class DragController {
+ public:
+  // Writes the data for the drag.
+  virtual void WriteDragData(View* sender,
+                             int press_x,
+                             int press_y,
+                             OSExchangeData* data) = 0;
+
+  // Returns the supported drag operations (see DragDropTypes for possible
+  // values). A drag is only started if this returns a non-zero value.
+  virtual int GetDragOperations(View* sender, int x, int y) = 0;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// View class
+//
+//   A View is a rectangle within the views View hierarchy. It is the base
+//   class for all Views.
+//
+//   A View is a container of other Views (there is no such thing as a Leaf
+//   View - makes code simpler, reduces type conversion headaches, design
+//   mistakes etc)
+//
+//   The View contains basic properties for sizing (bounds), layout (flex,
+//   orientation, etc), painting of children and event dispatch.
+//
+//   The View also uses a simple Box Layout Manager similar to XUL's
+//   SprocketLayout system. Alternative Layout Managers implementing the
+//   LayoutManager interface can be used to lay out children if required.
+//
+//   It is up to the subclass to implement Painting and storage of subclass -
+//   specific properties and functionality.
+//
+/////////////////////////////////////////////////////////////////////////////
+class View : public AcceleratorTarget {
+ public:
+
+  // Used in EnumerateFloatingViews() to specify which floating view to
+  // retrieve.
+  enum FloatingViewPosition {
+    FIRST = 0,
+    NEXT,
+    PREVIOUS,
+    LAST,
+    CURRENT
+  };
+
+  // Used in the versions of GetBounds() and x() that take a transformation
+  // parameter in order to determine whether or not to take into account the
+  // mirroring setting of the View when returning bounds positions.
+  enum PositionMirroringSettings {
+    IGNORE_MIRRORING_TRANSFORMATION = 0,
+    APPLY_MIRRORING_TRANSFORMATION
+  };
+
+  // The view class name.
+  static char kViewClassName[];
+
+  View();
+  virtual ~View();
+
+  // Sizing functions
+
+  // Get the bounds of the View, relative to the parent. Essentially, this
+  // function returns the bounds_ rectangle.
+  //
+  // This is the function subclasses should use whenever they need to obtain
+  // the bounds of one of their child views (for example, when implementing
+  // View::Layout()).
+  // TODO(beng): Convert |bounds_| to a gfx::Rect.
+  gfx::Rect bounds() const { return bounds_; }
+
+  // Get the size of the View.
+  gfx::Size size() const { return bounds_.size(); }
+
+  // Return the bounds of the View, relative to the parent. If
+  // |settings| is IGNORE_MIRRORING_TRANSFORMATION, the function returns the
+  // bounds_ rectangle. If |settings| is APPLY_MIRRORING_SETTINGS AND the
+  // parent View is using a right-to-left UI layout, then the function returns
+  // a shifted version of the bounds_ rectangle that represents the mirrored
+  // View bounds.
+  //
+  // NOTE: in the vast majority of the cases, the mirroring implementation is
+  //       transparent to the View subclasses and therefore you should use the
+  //       version of GetBounds() which does not take a transformation settings
+  //       parameter.
+  gfx::Rect GetBounds(PositionMirroringSettings settings) const;
+
+  // Set the bounds in the parent's coordinate system.
+  void SetBounds(const gfx::Rect& bounds);
+  void SetBounds(int x, int y, int width, int height) {
+    SetBounds(gfx::Rect(x, y, std::max(0, width), std::max(0, height)));
+  }
+  void SetX(int x) { SetBounds(x, y(), width(), height()); }
+  void SetY(int y) { SetBounds(x(), y, width(), height()); }
+
+  // Returns the left coordinate of the View, relative to the parent View,
+  // which is the value of bounds_.x().
+  //
+  // This is the function subclasses should use whenever they need to obtain
+  // the left position of one of their child views (for example, when
+  // implementing View::Layout()).
+  // This is equivalent to GetX(IGNORE_MIRRORING_TRANSFORMATION), but
+  // inlinable.
+  int x() const { return bounds_.x(); }
+  int y() const { return bounds_.y(); }
+  int width() const { return bounds_.width(); }
+  int height() const { return bounds_.height(); }
+
+  // Return the left coordinate of the View, relative to the parent. If
+  // |settings| is IGNORE_MIRRORING_SETTINGS, the function returns the value of
+  // bounds_.x(). If |settings| is APPLY_MIRRORING_SETTINGS AND the parent
+  // View is using a right-to-left UI layout, then the function returns the
+  // mirrored value of bounds_.x().
+  //
+  // NOTE: in the vast majority of the cases, the mirroring implementation is
+  //       transparent to the View subclasses and therefore you should use the
+  //       paremeterless version of x() when you need to get the X
+  //       coordinate of a child View.
+  int GetX(PositionMirroringSettings settings) const;
+
+  // Return this control local bounds. If include_border is true, local bounds
+  // is the rectangle {0, 0, width(), height()}, otherwise, it does not
+  // include the area where the border (if any) is painted.
+  gfx::Rect GetLocalBounds(bool include_border) const;
+
+  // Get the position of the View, relative to the parent.
+  //
+  // Note that if the parent uses right-to-left UI layout, then the mirrored
+  // position of this View is returned. Use x()/y() if you want to ignore
+  // mirroring.
+  gfx::Point GetPosition() const;
+
+  // Get the size the View would like to be, if enough space were available.
+  virtual gfx::Size GetPreferredSize();
+
+  // Convenience method that sizes this view to its preferred size.
+  void SizeToPreferredSize();
+
+  // Gets the minimum size of the view. View's implementation invokes
+  // GetPreferredSize.
+  virtual gfx::Size GetMinimumSize();
+
+  // Return the height necessary to display this view with the provided width.
+  // View's implementation returns the value from getPreferredSize.cy.
+  // Override if your View's preferred height depends upon the width (such
+  // as with Labels).
+  virtual int GetHeightForWidth(int w);
+
+  // This method is invoked when this object size or position changes.
+  // The default implementation does nothing.
+  virtual void DidChangeBounds(const gfx::Rect& previous,
+                               const gfx::Rect& current);
+
+  // Set whether the receiving view is visible. Painting is scheduled as needed
+  virtual void SetVisible(bool flag);
+
+  // Return whether a view is visible
+  virtual bool IsVisible() const { return is_visible_; }
+
+  // Return whether a view and its ancestors are visible. Returns true if the
+  // path from this view to the root view is visible.
+  virtual bool IsVisibleInRootView() const;
+
+  // Set whether this view is enabled. A disabled view does not receive keyboard
+  // or mouse inputs. If flag differs from the current value, SchedulePaint is
+  // invoked.
+  virtual void SetEnabled(bool flag);
+
+  // Returns whether the view is enabled.
+  virtual bool IsEnabled() const;
+
+  // Set whether this view is hottracked. A disabled view cannot be hottracked.
+  // If flag differs from the current value, SchedulePaint is invoked.
+  virtual void SetHotTracked(bool flag);
+
+  // Returns whether the view is hot-tracked.
+  virtual bool IsHotTracked() const { return false; }
+
+  // Returns whether the view is pushed.
+  virtual bool IsPushed() const { return false; }
+
+  // Scrolls the specified region, in this View's coordinate system, to be
+  // visible. View's implementation passes the call onto the parent View (after
+  // adjusting the coordinates). It is up to views that only show a portion of
+  // the child view, such as Viewport, to override appropriately.
+  virtual void ScrollRectToVisible(int x, int y, int width, int height);
+
+  // Layout functions
+
+  // Lay out the child Views (set their bounds based on sizing heuristics
+  // specific to the current Layout Manager)
+  virtual void Layout();
+
+  // Gets/Sets the Layout Manager used by this view to size and place its
+  // children.
+  // The LayoutManager is owned by the View and is deleted when the view is
+  // deleted, or when a new LayoutManager is installed.
+  LayoutManager* GetLayoutManager() const;
+  void SetLayoutManager(LayoutManager* layout);
+
+  // Right-to-left UI layout functions
+
+  // Indicates whether the UI layout for this view is right-to-left. The view
+  // has an RTL UI layout if RTL hasn't been disabled for the view and if the
+  // locale's language is an RTL language.
+  bool UILayoutIsRightToLeft() const;
+
+  // Enables or disables the right-to-left layout for the view. If |enable| is
+  // true, the layout will become right-to-left only if the locale's language
+  // is right-to-left.
+  //
+  // By default, right-to-left UI layout is enabled for the view and therefore
+  // this function must be called (with false as the |enable| parameter) in
+  // order to disable the right-to-left layout property for a specific instance
+  // of the view. Disabling the right-to-left UI layout is necessary in case a
+  // UI element will not appear correctly when mirrored.
+  void EnableUIMirroringForRTLLanguages(bool enable) {
+    ui_mirroring_is_enabled_for_rtl_languages_ = enable;
+  }
+
+  // This method determines whether the ChromeCanvas object passed to
+  // View::Paint() needs to be transformed such that anything drawn on the
+  // canvas object during View::Paint() is flipped horizontally.
+  //
+  // By default, this function returns false (which is the initial value of
+  // |flip_canvas_on_paint_for_rtl_ui_|). View subclasses that need to paint on
+  // a flipped ChromeCanvas when the UI layout is right-to-left need to call
+  // EnableCanvasFlippingForRTLUI().
+  bool FlipCanvasOnPaintForRTLUI() const {
+    return flip_canvas_on_paint_for_rtl_ui_ ? UILayoutIsRightToLeft() : false;
+  }
+
+  // Enables or disables flipping of the ChromeCanvas during View::Paint().
+  // Note that if canvas flipping is enabled, the canvas will be flipped only
+  // if the UI layout is right-to-left; that is, the canvas will be flipped
+  // only if UILayoutIsRightToLeft() returns true.
+  //
+  // Enabling canvas flipping is useful for leaf views that draw a bitmap that
+  // needs to be flipped horizontally when the UI layout is right-to-left
+  // (views::Button, for example). This method is helpful for such classes
+  // because their drawing logic stays the same and they can become agnostic to
+  // the UI directionality.
+  void EnableCanvasFlippingForRTLUI(bool enable) {
+    flip_canvas_on_paint_for_rtl_ui_ = enable;
+  }
+
+  // Returns the mirrored X position for the view, relative to the parent. If
+  // the parent view is not mirrored, this function returns bound_.left.
+  //
+  // UI mirroring is transparent to most View subclasses and therefore there is
+  // no need to call this routine from anywhere within your subclass
+  // implementation.
+  int MirroredX() const;
+
+  // Given a rectangle specified in this View's coordinate system, the function
+  // computes the 'left' value for the mirrored rectangle within this View. If
+  // the View's UI layout is not right-to-left, then bounds.x() is returned.
+  //
+  // UI mirroring is transparent to most View subclasses and therefore there is
+  // no need to call this routine from anywhere within your subclass
+  // implementation.
+  int MirroredLeftPointForRect(const gfx::Rect& rect) const;
+
+  // Given the X coordinate of a point inside the View, this function returns
+  // the mirrored X coordinate of the point if the View's UI layout is
+  // right-to-left. If the layout is left-to-right, the same X coordinate is
+  // returned.
+  //
+  // Following are a few examples of the values returned by this function for
+  // a View with the bounds {0, 0, 100, 100} and a right-to-left layout:
+  //
+  // MirroredXCoordinateInsideView(0) -> 100
+  // MirroredXCoordinateInsideView(20) -> 80
+  // MirroredXCoordinateInsideView(99) -> 1
+  int MirroredXCoordinateInsideView(int x) const {
+    return UILayoutIsRightToLeft() ? width() - x : x;
+  }
+
+  // Painting functions
+
+  // Mark the specified rectangle as dirty (needing repaint). If |urgent| is
+  // true, the view will be repainted when the current event processing is
+  // done. Otherwise, painting will take place as soon as possible.
+  virtual void SchedulePaint(const gfx::Rect& r, bool urgent);
+
+  // Mark the entire View's bounds as dirty. Painting will occur as soon as
+  // possible.
+  virtual void SchedulePaint();
+
+  // Convenience to schedule a paint given some ints. Painting will occur as
+  // soon as possible.
+  virtual void SchedulePaint(int x, int y, int w, int h);
+
+  // Paint the receiving view. g is prepared such as it is in
+  // receiver's coordinate system. g's state is restored after this
+  // call so your implementation can change the graphics configuration
+  //
+  // Default implementation paints the background if it is defined
+  //
+  // Override this method when implementing a new control.
+  virtual void Paint(ChromeCanvas* canvas);
+
+  // Paint the background if any. This method is called by Paint() and
+  // should rarely be invoked directly.
+  virtual void PaintBackground(ChromeCanvas* canvas);
+
+  // Paint the border if any. This method is called by Paint() and
+  // should rarely be invoked directly.
+  virtual void PaintBorder(ChromeCanvas* canvas);
+
+  // Paints the focus border (only if the view has the focus).
+  // This method is called by Paint() and should rarely be invoked directly.
+  // The default implementation paints a gray border around the view. Override
+  // it for custom focus effects.
+  virtual void PaintFocusBorder(ChromeCanvas* canvas);
+
+  // Paint this View immediately.
+  virtual void PaintNow();
+
+  // Paint a view without attaching it to this view hierarchy.
+  // Any view can be painted that way.
+  // This method set bounds, calls layout and handles clipping properly. The
+  // provided view can be attached to a parent. The parent will be saved and
+  // restored. (x, y, width, height) define the floating view bounds
+  void PaintFloatingView(ChromeCanvas* canvas, View* view,
+                         int x, int y, int w, int h);
+
+  // Tree functions
+
+  // Add a child View.
+  void AddChildView(View* v);
+
+  // Adds a child View at the specified position.
+  void AddChildView(int index, View* v);
+
+  // Get the child View at the specified index.
+  View* GetChildViewAt(int index) const;
+
+  // Remove a child view from this view. v's parent will change to NULL
+  void RemoveChildView(View *v);
+
+  // Remove all child view from this view.  If |delete_views| is true, the views
+  // are deleted, unless marked as not parent owned.
+  void RemoveAllChildViews(bool delete_views);
+
+  // Get the number of child Views.
+  int GetChildViewCount() const;
+
+  // Get the child View at the specified point.
+  virtual View* GetViewForPoint(const gfx::Point& point);
+
+  // Get the Widget that hosts this View, if any.
+  virtual Widget* GetWidget() const;
+
+  // Gets the Widget that most closely contains this View, if any.
+  virtual Window* GetWindow() const;
+
+  // Get the containing RootView
+  virtual RootView* GetRootView();
+
+  // Get the parent View
+  View* GetParent() const { return parent_; }
+
+  // Returns the index of the specified |view| in this view's children, or -1
+  // if the specified view is not a child of this view.
+  int GetChildIndex(View* v) const;
+
+  // Returns true if the specified view is a direct or indirect child of this
+  // view.
+  bool IsParentOf(View* v) const;
+
+  // Recursively descends the view tree starting at this view, and returns
+  // the first child that it encounters that has the given ID.
+  // Returns NULL if no matching child view is found.
+  virtual View* GetViewByID(int id) const;
+
+  // Sets and gets the ID for this view.  ID should be unique within the subtree
+  // that you intend to search for it.  0 is the default ID for views.
+  void SetID(int id);
+  int GetID() const;
+
+  // A group id is used to tag views which are part of the same logical group.
+  // Focus can be moved between views with the same group using the arrow keys.
+  // Groups are currently used to implement radio button mutual exclusion.
+  void SetGroup(int gid);
+  int GetGroup() const;
+
+  // If this returns true, the views from the same group can each be focused
+  // when moving focus with the Tab/Shift-Tab key.  If this returns false,
+  // only the selected view from the group (obtained with
+  // GetSelectedViewForGroup()) is focused.
+  virtual bool IsGroupFocusTraversable() const { return true; }
+
+  // Fills the provided vector with all the available views which belong to the
+  // provided group.
+  void GetViewsWithGroup(int group_id, std::vector<View*>* out);
+
+  // Return the View that is currently selected in the specified group.
+  // The default implementation simply returns the first View found for that
+  // group.
+  virtual View* GetSelectedViewForGroup(int group_id);
+
+  // Focus support
+  //
+  // Returns the view that should be selected next when pressing Tab.
+  View* GetNextFocusableView();
+
+  // Returns the view that should be selected next when pressing Shift-Tab.
+  View* GetPreviousFocusableView();
+
+  // Sets the component that should be selected next when pressing Tab, and
+  // makes the current view the precedent view of the specified one.
+  // Note that by default views are linked in the order they have been added to
+  // their container. Use this method if you want to modify the order.
+  // IMPORTANT NOTE: loops in the focus hierarchy are not supported.
+  void SetNextFocusableView(View* view);
+
+  // Return whether this view can accept the focus.
+  virtual bool IsFocusable() const;
+
+  // Sets whether this view can accept the focus.
+  // Note that this is false by default so that a view used as a container does
+  // not get the focus.
+  virtual void SetFocusable(bool focusable);
+
+  // Convenience method to retrieve the FocusManager associated with the
+  // Widget that contains this view.  This can return NULL if this view is not
+  // part of a view hierarchy with a Widget.
+  virtual FocusManager* GetFocusManager();
+
+  // Sets a keyboard accelerator for that view. When the user presses the
+  // accelerator key combination, the AcceleratorPressed method is invoked.
+  // Note that you can set multiple accelerators for a view by invoking this
+  // method several times.
+  virtual void AddAccelerator(const Accelerator& accelerator);
+
+  // Removes the specified accelerator for this view.
+  virtual void RemoveAccelerator(const Accelerator& accelerator);
+
+  // Removes all the keyboard accelerators for this view.
+  virtual void ResetAccelerators();
+
+  // Called when a keyboard accelerator is pressed.
+  // Derived classes should implement desired behavior and return true if they
+  // handled the accelerator.
+  virtual bool AcceleratorPressed(const Accelerator& accelerator) {
+    return false;
+  }
+
+  // Called on a view (if it is has focus) before an Accelerator is processed.
+  // Views that want to override an accelerator should override this method to
+  // perform the required action and return true, to indicate that the
+  // accelerator should not be processed any further.
+  virtual bool OverrideAccelerator(const Accelerator& accelerator) {
+    return false;
+  }
+
+  // Returns whether this view currently has the focus.
+  virtual bool HasFocus();
+
+  // Accessibility support
+  // TODO(klink): Move all this out to a AccessibleInfo wrapper class.
+  //
+  // Returns the MSAA default action of the current view. The string returned
+  // describes the default action that will occur when executing
+  // IAccessible::DoDefaultAction. For instance, default action of a button is
+  // 'Press'. Sets the input string appropriately, and returns true if
+  // successful.
+  virtual bool GetAccessibleDefaultAction(std::wstring* action) {
+    return false;
+  }
+
+  // Returns a string containing the mnemonic, or the keyboard shortcut, for a
+  // given control. Sets the input string appropriately, and returns true if
+  // successful.
+  virtual bool GetAccessibleKeyboardShortcut(std::wstring* shortcut) {
+    return false;
+  }
+
+  // Returns a brief, identifying string, containing a unique, readable name of
+  // a given control. Sets the input string appropriately, and returns true if
+  // successful.
+  virtual bool GetAccessibleName(std::wstring* name) { return false; }
+
+  // Returns the accessibility role of the current view. The role is what
+  // assistive technologies (ATs) use to determine what behavior to expect from
+  // a given control. Sets the input Role appropriately, and returns true if
+  // successful.
+  virtual bool GetAccessibleRole(AccessibilityTypes::Role* role) {
+    return false;
+  }
+
+  // Returns the accessibility state of the current view. Sets the input State
+  // appropriately, and returns true if successful.
+  virtual bool GetAccessibleState(AccessibilityTypes::State* state) {
+    return false;
+  }
+
+  // Assigns a keyboard shortcut string description to the given control. Needed
+  // as a View does not know which shortcut will be associated with it until it
+  // is created to be a certain type.
+  virtual void SetAccessibleKeyboardShortcut(const std::wstring& shortcut) {}
+
+  // Assigns a string name to the given control. Needed as a View does not know
+  // which name will be associated with it until it is created to be a
+  // certain type.
+  virtual void SetAccessibleName(const std::wstring& name) {}
+
+  // Returns an instance of a wrapper class implementing the (platform-specific)
+  // accessibility interface for a given View. If one exists, it will be
+  // re-used, otherwise a new instance will be created.
+  ViewAccessibilityWrapper* GetViewAccessibilityWrapper();
+
+  // Accessor used to determine if a child view (leaf) has accessibility focus.
+  // Returns NULL if there are no children, or if none of the children has
+  // accessibility focus.
+  virtual View* GetAccFocusedChildView() { return NULL; }
+
+  // Floating views
+  //
+  // A floating view is a view that is used to paint a cell within a parent view
+  // Floating Views are painted using PaintFloatingView() above.
+  //
+  // Floating views can also be lazily created and attached to the view
+  // hierarchy to process events. To make this possible, each view is given an
+  // opportunity to create and attach a floating view right before an mouse
+  // event is processed.
+
+  // Retrieves the id for the floating view at the specified coordinates if any.
+  // Derived classes that use floating views should implement this method and
+  // return true if a view has been found and its id set in |id|.
+  virtual bool GetFloatingViewIDForPoint(int x, int y, int* id);
+
+  // Retrieves the ID of the floating view at the specified |position| and sets
+  // it in |id|.
+  // For positions NEXT and PREVIOUS, the specified |starting_id| is used as
+  // the origin, it is ignored for FIRST and LAST.
+  // Returns true if an ID was found, false otherwise.
+  // For CURRENT, the |starting_id| should be set in |id| and true returned if
+  // the |starting_id| is a valid floating view id.
+  // Derived classes that use floating views should implement this method and
+  // return a unique ID for each floating view.
+  // The default implementation always returns false.
+  virtual bool EnumerateFloatingViews(FloatingViewPosition position,
+                                      int starting_id,
+                                      int* id);
+
+  // Creates and attaches the floating view with the specified |id| to this view
+  // hierarchy and returns it.
+  // Derived classes that use floating views should implement this method.
+  //
+  // NOTE: subclasses implementing this should return NULL if passed an invalid
+  // id. An invalid ID may be passed in by the focus manager when attempting
+  // to restore focus.
+  virtual View* ValidateFloatingViewForID(int id);
+
+  // Whether the focus should automatically be restored to the last focused
+  // view. Default implementation returns true.
+  // Derived classes that want to restore focus themselves should override this
+  // method and return false.
+  virtual bool ShouldRestoreFloatingViewFocus();
+
+  // Attach a floating view to the receiving view. The view is inserted
+  // in the child view list and will behave like a normal view. |id| is the
+  // floating view id for that view.
+  void AttachFloatingView(View* v, int id);
+
+  // Return whether a view already has a floating view which bounds intersects
+  // the provided point.
+  //
+  // If the View uses right-to-left UI layout, then the given point is checked
+  // against the mirrored position of each floating View.
+  bool HasFloatingViewForPoint(int x, int y);
+
+  // Detach and delete all floating views. Call this method when your model
+  // or layout changes.
+  void DetachAllFloatingViews();
+
+  // Returns the view with the specified |id|, by calling
+  // ValidateFloatingViewForID if that view has not yet been attached.
+  virtual View* RetrieveFloatingViewForID(int id);
+
+  // Restores the focus to the previously selected floating view.
+  virtual void RestoreFloatingViewFocus();
+
+  // Goes up the parent hierarchy of this view and returns the first floating
+  // view found.  Returns NULL if none were found.
+  View* RetrieveFloatingViewParent();
+
+  // Utility functions
+
+  // Note that the utility coordinate conversions functions always operate on
+  // the mirrored position of the child Views if the parent View uses a
+  // right-to-left UI layout.
+
+  // Convert a point from source coordinate system to dst coordinate system.
+  //
+  // source is a parent or a child of dst, directly or transitively.
+  // If source and dst are not in the same View hierarchy, the result is
+  // undefined.
+  // Source can be NULL in which case it means the screen coordinate system
+  static void ConvertPointToView(const View* src,
+                                 const View* dst,
+                                 gfx::Point* point);
+
+  // Convert a point from the coordinate system of a View to that of the
+  // Widget. This is useful for example when sizing HWND children of the
+  // Widget that don't know about the View hierarchy and need to be placed
+  // relative to the Widget that is their parent.
+  static void ConvertPointToWidget(const View* src, gfx::Point* point);
+
+  // Convert a point from a view Widget to a View dest
+  static void ConvertPointFromWidget(const View* dest, gfx::Point* p);
+
+  // Convert a point from the coordinate system of a View to that of the
+  // screen. This is useful for example when placing popup windows.
+  static void ConvertPointToScreen(const View* src, gfx::Point* point);
+
+  // Event Handlers
+
+  // This method is invoked when the user clicks on this view.
+  // The provided event is in the receiver's coordinate system.
+  //
+  // Return true if you processed the event and want to receive subsequent
+  // MouseDraggged and MouseReleased events.  This also stops the event from
+  // bubbling.  If you return false, the event will bubble through parent
+  // views.
+  //
+  // If you remove yourself from the tree while processing this, event bubbling
+  // stops as if you returned true, but you will not receive future events.
+  // The return value is ignored in this case.
+  //
+  // Default implementation returns true if a ContextMenuController has been
+  // set, false otherwise. Override as needed.
+  //
+  virtual bool OnMousePressed(const MouseEvent& event);
+
+  // This method is invoked when the user clicked on this control.
+  // and is still moving the mouse with a button pressed.
+  // The provided event is in the receiver's coordinate system.
+  //
+  // Return true if you processed the event and want to receive
+  // subsequent MouseDragged and MouseReleased events.
+  //
+  // Default implementation returns true if a ContextMenuController has been
+  // set, false otherwise. Override as needed.
+  //
+  virtual bool OnMouseDragged(const MouseEvent& event);
+
+  // This method is invoked when the user releases the mouse
+  // button. The event is in the receiver's coordinate system.
+  //
+  // If canceled is true it indicates the mouse press/drag was canceled by a
+  // system/user gesture.
+  //
+  // Default implementation notifies the ContextMenuController is appropriate.
+  // Subclasses that wish to honor the ContextMenuController should invoke
+  // super.
+  virtual void OnMouseReleased(const MouseEvent& event, bool canceled);
+
+  // This method is invoked when the mouse is above this control
+  // The event is in the receiver's coordinate system.
+  //
+  // Default implementation does nothing. Override as needed.
+  virtual void OnMouseMoved(const MouseEvent& e);
+
+  // This method is invoked when the mouse enters this control.
+  //
+  // Default implementation does nothing. Override as needed.
+  virtual void OnMouseEntered(const MouseEvent& event);
+
+  // This method is invoked when the mouse exits this control
+  // The provided event location is always (0, 0)
+  // Default implementation does nothing. Override as needed.
+  virtual void OnMouseExited(const MouseEvent& event);
+
+  // Set the MouseHandler for a drag session.
+  //
+  // A drag session is a stream of mouse events starting
+  // with a MousePressed event, followed by several MouseDragged
+  // events and finishing with a MouseReleased event.
+  //
+  // This method should be only invoked while processing a
+  // MouseDragged or MouseReleased event.
+  //
+  // All further mouse dragged and mouse up events will be sent
+  // the MouseHandler, even if it is reparented to another window.
+  //
+  // The MouseHandler is automatically cleared when the control
+  // comes back from processing the MouseReleased event.
+  //
+  // Note: if the mouse handler is no longer connected to a
+  // view hierarchy, events won't be sent.
+  //
+  virtual void SetMouseHandler(View* new_mouse_handler);
+
+  // Request the keyboard focus. The receiving view will become the
+  // focused view.
+  virtual void RequestFocus();
+
+  // Invoked when a view is about to gain focus
+  virtual void WillGainFocus();
+
+  // Invoked when a view just gained focus.
+  virtual void DidGainFocus();
+
+  // Invoked when a view is about lose focus
+  virtual void WillLoseFocus();
+
+  // Invoked when a view is about to be requested for focus due to the focus
+  // traversal. Reverse is this request was generated going backward
+  // (Shift-Tab).
+  virtual void AboutToRequestFocusFromTabTraversal(bool reverse) { }
+
+  // Invoked when a key is pressed or released.
+  // Subclasser should return true if the event has been processed and false
+  // otherwise. If the event has not been processed, the parent will be given a
+  // chance.
+  virtual bool OnKeyPressed(const KeyEvent& e);
+  virtual bool OnKeyReleased(const KeyEvent& e);
+
+  // Whether the view wants to receive Tab and Shift-Tab key events.
+  // If false, Tab and Shift-Tabs key events are used for focus traversal and
+  // are not sent to the view. If true, the events are sent to the view and not
+  // used for focus traversal.
+  // This implementation returns false (so that by default views handle nicely
+  // the keyboard focus traversal).
+  virtual bool CanProcessTabKeyEvents();
+
+  // Invoked when the user uses the mousewheel. Implementors should return true
+  // if the event has been processed and false otherwise. This message is sent
+  // if the view is focused. If the event has not been processed, the parent
+  // will be given a chance.
+  virtual bool OnMouseWheel(const MouseWheelEvent& e);
+
+  // Drag and drop functions.
+
+  // Set/get the DragController. See description of DragController for more
+  // information.
+  void SetDragController(DragController* drag_controller);
+  DragController* GetDragController();
+
+  // During a drag and drop session when the mouse moves the view under the
+  // mouse is queried to see if it should be a target for the drag and drop
+  // session. A view indicates it is a valid target by returning true from
+  // CanDrop. If a view returns true from CanDrop,
+  // OnDragEntered is sent to the view when the mouse first enters the view,
+  // as the mouse moves around within the view OnDragUpdated is invoked.
+  // If the user releases the mouse over the view and OnDragUpdated returns a
+  // valid drop, then OnPerformDrop is invoked. If the mouse moves outside the
+  // view or over another view that wants the drag, OnDragExited is invoked.
+  //
+  // Similar to mouse events, the deepest view under the mouse is first checked
+  // if it supports the drop (Drop). If the deepest view under
+  // the mouse does not support the drop, the ancestors are walked until one
+  // is found that supports the drop.
+
+  // A view that supports drag and drop must override this and return true if
+  // data contains a type that may be dropped on this view.
+  virtual bool CanDrop(const OSExchangeData& data);
+
+  // OnDragEntered is invoked when the mouse enters this view during a drag and
+  // drop session and CanDrop returns true. This is immediately
+  // followed by an invocation of OnDragUpdated, and eventually one of
+  // OnDragExited or OnPerformDrop.
+  virtual void OnDragEntered(const DropTargetEvent& event);
+
+  // Invoked during a drag and drop session while the mouse is over the view.
+  // This should return a bitmask of the DragDropTypes::DragOperation supported
+  // based on the location of the event. Return 0 to indicate the drop should
+  // not be accepted.
+  virtual int OnDragUpdated(const DropTargetEvent& event);
+
+  // Invoked during a drag and drop session when the mouse exits the views, or
+  // when the drag session was canceled and the mouse was over the view.
+  virtual void OnDragExited();
+
+  // Invoked during a drag and drop session when OnDragUpdated returns a valid
+  // operation and the user release the mouse.
+  virtual int OnPerformDrop(const DropTargetEvent& event);
+
+  // Returns true if the mouse was dragged enough to start a drag operation.
+  // delta_x and y are the distance the mouse was dragged.
+  static bool ExceededDragThreshold(int delta_x, int delta_y);
+
+  // This method is the main entry point to process paint for this
+  // view and its children. This method is called by the painting
+  // system. You should call this only if you want to draw a sub tree
+  // inside a custom graphics.
+  // To customize painting override either the Paint or PaintChildren method,
+  // not this one.
+  virtual void ProcessPaint(ChromeCanvas* canvas);
+
+  // Paint the View's child Views, in reverse order.
+  virtual void PaintChildren(ChromeCanvas* canvas);
+
+  // Sets the ContextMenuController. Setting this to non-null makes the View
+  // process mouse events.
+  void SetContextMenuController(ContextMenuController* menu_controller);
+  ContextMenuController* GetContextMenuController() {
+    return context_menu_controller_;
+  }
+
+  // Provides default implementation for context menu handling. The default
+  // implementation calls the ShowContextMenu of the current
+  // ContextMenuController (if it is not NULL). Overridden in subclassed views
+  // to provide right-click menu display triggerd by the keyboard (i.e. for the
+  // Chrome toolbar Back and Forward buttons). No source needs to be specified,
+  // as it is always equal to the current View.
+  virtual void ShowContextMenu(int x,
+                               int y,
+                               bool is_mouse_gesture);
+
+  // The background object is owned by this object and may be NULL.
+  void set_background(Background* b) { background_.reset(b); }
+  const Background* background() const { return background_.get(); }
+
+  // The border object is owned by this object and may be NULL.
+  void set_border(Border* b) { border_.reset(b); }
+  const Border* border() const { return border_.get(); }
+
+  // Returns the insets of the current border. If there is no border an empty
+  // insets is returned.
+  virtual gfx::Insets GetInsets() const;
+
+#if defined(OS_WIN)
+  // TODO(port): Make GetCursorForPoint portable.
+
+  // Return the cursor that should be used for this view or NULL if
+  // the default cursor should be used. The provided point is in the
+  // receiver's coordinate system.
+  virtual HCURSOR GetCursorForPoint(Event::EventType event_type, int x, int y);
+#endif  // defined(OS_WIN)
+
+  // Convenience to test whether a point is within this view's bounds
+  virtual bool HitTest(const gfx::Point& l) const;
+
+  // Gets the tooltip for this View. If the View does not have a tooltip,
+  // return false. If the View does have a tooltip, copy the tooltip into
+  // the supplied string and return true.
+  // Any time the tooltip text that a View is displaying changes, it must
+  // invoke TooltipTextChanged.
+  // The x/y provide the coordinates of the mouse (relative to this view).
+  virtual bool GetTooltipText(int x, int y, std::wstring* tooltip);
+
+  // Returns the location (relative to this View) for the text on the tooltip
+  // to display. If false is returned (the default), the tooltip is placed at
+  // a default position.
+  virtual bool GetTooltipTextOrigin(int x, int y, gfx::Point* loc);
+
+  // Set whether this view is owned by its parent. A view that is owned by its
+  // parent is automatically deleted when the parent is deleted. The default is
+  // true. Set to false if the view is owned by another object and should not
+  // be deleted by its parent.
+  void SetParentOwned(bool f);
+
+  // Return whether a view is owned by its parent. See SetParentOwned()
+  bool IsParentOwned() const;
+
+  // Return the receiving view's class name. A view class is a string which
+  // uniquely identifies the view class. It is intended to be used as a way to
+  // find out during run time if a view can be safely casted to a specific view
+  // subclass. The default implementation returns kViewClassName.
+  virtual std::string GetClassName() const;
+
+  // Returns the first ancestor, starting at this, whose class name is |name|.
+  // Returns null if no ancestor has the class name |name|.
+  View* GetAncestorWithClassName(const std::string& name);
+
+  // Returns the visible bounds of the receiver in the receivers coordinate
+  // system.
+  //
+  // When traversing the View hierarchy in order to compute the bounds, the
+  // function takes into account the mirroring setting for each View and
+  // therefore it will return the mirrored version of the visible bounds if
+  // need be.
+  gfx::Rect GetVisibleBounds();
+
+  // Subclasses that contain traversable children that are not directly
+  // accessible through the children hierarchy should return the associated
+  // FocusTraversable for the focus traversal to work properly.
+  virtual FocusTraversable* GetFocusTraversable() { return NULL; }
+
+#ifndef NDEBUG
+  // Debug method that logs the view hierarchy to the output.
+  void PrintViewHierarchy();
+
+  // Debug method that logs the focus traversal hierarchy to the output.
+  void PrintFocusHierarchy();
+#endif
+
+  // The following methods are used by ScrollView to determine the amount
+  // to scroll relative to the visible bounds of the view. For example, a
+  // return value of 10 indicates the scrollview should scroll 10 pixels in
+  // the appropriate direction.
+  //
+  // Each method takes the following parameters:
+  //
+  // is_horizontal: if true, scrolling is along the horizontal axis, otherwise
+  //                the vertical axis.
+  // is_positive: if true, scrolling is by a positive amount. Along the
+  //              vertical axis scrolling by a positive amount equates to
+  //              scrolling down.
+  //
+  // The return value should always be positive and gives the number of pixels
+  // to scroll. ScrollView interprets a return value of 0 (or negative)
+  // to scroll by a default amount.
+  //
+  // See VariableRowHeightScrollHelper and FixedRowHeightScrollHelper for
+  // implementations of common cases.
+  virtual int GetPageScrollIncrement(ScrollView* scroll_view,
+                                     bool is_horizontal, bool is_positive);
+  virtual int GetLineScrollIncrement(ScrollView* scroll_view,
+                                     bool is_horizontal, bool is_positive);
+
+ protected:
+  // The id of this View. Used to find this View.
+  int id_;
+
+  // The group of this view. Some view subclasses use this id to find other
+  // views of the same group. For example radio button uses this information
+  // to find other radio buttons.
+  int group_;
+
+  // Called when the UI theme has changed, overriding allows individual Views to
+  // do special cleanup and processing (such as dropping resource caches).
+  // Subclasses that override this method must call the base class
+  // implementation to ensure child views are processed.
+  // Can only be called by subclasses. To dispatch a theme changed notification,
+  // call this method on the RootView.
+  virtual void ThemeChanged();
+
+#ifndef NDEBUG
+  // Returns true if the View is currently processing a paint.
+  virtual bool IsProcessingPaint() const;
+#endif
+
+  // Returns the location, in screen coordinates, to show the context menu at
+  // when the context menu is shown from the keyboard. This implementation
+  // returns the middle of the visible region of this view.
+  //
+  // This method is invoked when the context menu is shown by way of the
+  // keyboard.
+  virtual gfx::Point GetKeyboardContextMenuLocation();
+
+  // Called by HitTest to see if this View has a custom hit test mask. If the
+  // return value is true, GetHitTestMask will be called to obtain the mask.
+  // Default value is false, in which case the View will hit-test against its
+  // bounds.
+  virtual bool HasHitTestMask() const;
+
+  // Called by HitTest to retrieve a mask for hit-testing against. Subclasses
+  // override to provide custom shaped hit test regions.
+  virtual void GetHitTestMask(gfx::Path* mask) const;
+
+  // This method is invoked when the tree changes.
+  //
+  // When a view is removed, it is invoked for all children and grand
+  // children. For each of these views, a notification is sent to the
+  // view and all parents.
+  //
+  // When a view is added, a notification is sent to the view, all its
+  // parents, and all its children (and grand children)
+  //
+  // Default implementation does nothing. Override to perform operations
+  // required when a view is added or removed from a view hierarchy
+  //
+  // parent is the new or old parent. Child is the view being added or
+  // removed.
+  //
+  virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child);
+
+  // When SetVisible() changes the visibility of a view, this method is
+  // invoked for that view as well as all the children recursively.
+  virtual void VisibilityChanged(View* starting_from, bool is_visible);
+
+  // Views must invoke this when the tooltip text they are to display changes.
+  void TooltipTextChanged();
+
+  // Actual implementation of GetViewForPoint.
+  virtual View* GetViewForPoint(const gfx::Point& point,
+                                bool can_create_floating);
+
+  // Sets whether this view wants notification when its visible bounds relative
+  // to the root view changes. If true, this view is notified any time the
+  // origin of one its ancestors changes, or the portion of the bounds not
+  // obscured by ancestors changes. The default is false.
+  void SetNotifyWhenVisibleBoundsInRootChanges(bool value);
+  bool GetNotifyWhenVisibleBoundsInRootChanges();
+
+  // Notification that this views visible bounds, relative to the RootView
+  // has changed. The visible bounds corresponds to the region of the
+  // view not obscured by other ancestors.
+  virtual void VisibleBoundsInRootChanged() {}
+
+  // Sets the keyboard focus to this View. The correct way to set the focus is
+  // to call RequestFocus() on the view. This method is called when the focus is
+  // set and gives an opportunity to subclasses to perform any extra focus steps
+  // (for example native component set the native focus on their native
+  // component). The default behavior is to set the native focus on the root
+  // Widget, which is what is appropriate for views that have no native window
+  // associated with them (so the root view gets the keyboard messages).
+  virtual void Focus();
+
+  // Invoked when a key is pressed before the key event is processed by the
+  // focus manager for accelerators.  This gives a chance to the view to
+  // override an accelerator.  Subclasser should return false if they want to
+  // process the key event and not have it translated to an accelerator (if
+  // any).  In that case, OnKeyPressed will subsequently be invoked for that
+  // event.
+  virtual bool ShouldLookupAccelerators(const KeyEvent& e) { return true; }
+
+  // A convenience method for derived classes which have floating views with IDs
+  // that are consecutive numbers in an interval [|low_bound|, |high_bound|[.
+  // They can call this method in their EnumerateFloatingViews implementation.
+  // If |ascending_order| is true, the first id is |low_bound|, the next after
+  // id n is n + 1, and so on.  If |ascending_order| is false, the order is
+  // reversed, first id is |high_bound|, the next id after id n is n -1...
+  static bool EnumerateFloatingViewsForInterval(int low_bound, int high_bound,
+                                                bool ascending_order,
+                                                FloatingViewPosition position,
+                                                int starting_id,
+                                                int* id);
+
+  // These are cover methods that invoke the method of the same name on
+  // the DragController. Subclasses may wish to override rather than install
+  // a DragController.
+  // See DragController for a description of these methods.
+  virtual int GetDragOperations(int press_x, int press_y);
+  virtual void WriteDragData(int press_x, int press_y, OSExchangeData* data);
+
+  // Invoked from DoDrag after the drag completes. This implementation does
+  // nothing, and is intended for subclasses to do cleanup.
+  virtual void OnDragDone();
+
+  // Returns whether we're in the middle of a drag session that was initiated
+  // by us.
+  bool InDrag();
+
+  // Whether this view is enabled.
+  bool enabled_;
+
+  // Whether the view can be focused.
+  bool focusable_;
+
+ private:
+  friend class RootView;
+  friend class FocusManager;
+  friend class ViewStorage;
+
+  // Used to track a drag. RootView passes this into
+  // ProcessMousePressed/Dragged.
+  struct DragInfo {
+    // Sets possible_drag to false and start_x/y to 0. This is invoked by
+    // RootView prior to invoke ProcessMousePressed.
+    void Reset();
+
+    // Sets possible_drag to true and start_x/y to the specified coordinates.
+    // This is invoked by the target view if it detects the press may generate
+    // a drag.
+    void PossibleDrag(int x, int y);
+
+    // Whether the press may generate a drag.
+    bool possible_drag;
+
+    // Coordinates of the mouse press.
+    int start_x;
+    int start_y;
+  };
+
+  // Returns how much the mouse needs to move in one direction to start a
+  // drag. These methods cache in a platform-appropriate way. These values are
+  // used by the public static method ExceededDragThreshold().
+  static int GetHorizontalDragThreshold();
+  static int GetVerticalDragThreshold();
+
+  // RootView invokes these. These in turn invoke the appropriate OnMouseXXX
+  // method. If a drag is detected, DoDrag is invoked.
+  bool ProcessMousePressed(const MouseEvent& e, DragInfo* drop_info);
+  bool ProcessMouseDragged(const MouseEvent& e, DragInfo* drop_info);
+  void ProcessMouseReleased(const MouseEvent& e, bool canceled);
+
+  // Starts a drag and drop operation originating from this view. This invokes
+  // WriteDragData to write the data and GetDragOperations to determine the
+  // supported drag operations. When done, OnDragDone is invoked.
+  void DoDrag(const MouseEvent& e, int press_x, int press_y);
+
+  // Adds a child View at the specified position. |floating_view| should be true
+  // if the |v| is a floating view.
+  void AddChildView(int index, View* v, bool floating_view);
+
+  // Removes |view| from the hierarchy tree.  If |update_focus_cycle| is true,
+  // the next and previous focusable views of views pointing to this view are
+  // updated.  If |update_tool_tip| is true, the tooltip is updated.  If
+  // |delete_removed_view| is true, the view is also deleted (if it is parent
+  // owned).
+  void DoRemoveChildView(View* view,
+                         bool update_focus_cycle,
+                         bool update_tool_tip,
+                         bool delete_removed_view);
+
+  // Sets the parent View. This is called automatically by AddChild and is
+  // thus private.
+  void SetParent(View *parent);
+
+  // Call ViewHierarchyChanged for all child views on all parents
+  void PropagateRemoveNotifications(View* parent);
+
+  // Call ViewHierarchyChanged for all children
+  void PropagateAddNotifications(View* parent, View* child);
+
+  // Call VisibilityChanged() recursively for all children.
+  void PropagateVisibilityNotifications(View* from, bool is_visible);
+
+  // Takes care of registering/unregistering accelerators if
+  // |register_accelerators| true and calls ViewHierarchyChanged().
+  void ViewHierarchyChangedImpl(bool register_accelerators,
+                                bool is_add,
+                                View* parent,
+                                View* child);
+
+  // This is the actual implementation for ConvertPointToView()
+  // Attempts a parent -> child conversion and then a
+  // child -> parent conversion if try_other_direction is true
+  static void ConvertPointToView(const View* src,
+                                 const View* dst,
+                                 gfx::Point* point,
+                                 bool try_other_direction);
+
+  // Propagates UpdateTooltip() to the TooltipManager for the Widget.
+  // This must be invoked any time the View hierarchy changes in such a way
+  // the view under the mouse differs. For example, if the bounds of a View is
+  // changed, this is invoked. Similarly, as Views are added/removed, this
+  // is invoked.
+  void UpdateTooltip();
+
+  // Recursively descends through all descendant views,
+  // registering/unregistering all views that want visible bounds in root
+  // view notification.
+  static void RegisterChildrenForVisibleBoundsNotification(RootView* root,
+                                                           View* view);
+  static void UnregisterChildrenForVisibleBoundsNotification(RootView* root,
+                                                             View* view);
+
+  // Adds/removes view to the list of descendants that are notified any time
+  // this views location and possibly size are changed.
+  void AddDescendantToNotify(View* view);
+  void RemoveDescendantToNotify(View* view);
+
+  // Initialize the previous/next focusable views of the specified view relative
+  // to the view at the specified index.
+  void InitFocusSiblings(View* view, int index);
+
+  // Actual implementation of PrintFocusHierarchy.
+  void PrintViewHierarchyImp(int indent);
+  void PrintFocusHierarchyImp(int indent);
+
+  // Registers/unregister this view's keyboard accelerators with the
+  // FocusManager.
+  void RegisterAccelerators();
+  void UnregisterAccelerators();
+
+  // Returns the number of children that are actually attached floating views.
+  int GetFloatingViewCount() const;
+
+  // Returns the id for this floating view.
+  int GetFloatingViewID();
+
+  // Returns whether this view is a floating view.
+  bool IsFloatingView();
+
+  // Sets in |path| the path in the view hierarchy from |start| to |end| (the
+  // path is the list of indexes in each view's children to get from |start|
+  // to |end|).
+  // Returns true if |start| and |view| are connected and the |path| has been
+  // retrieved succesfully, false otherwise.
+  static bool GetViewPath(View* start, View* end, std::vector<int>* path);
+
+  // Returns the view at the end of the specified |path|, starting at the
+  // |start| view.
+  static View* GetViewForPath(View* start, const std::vector<int>& path);
+
+  // This View's bounds in the parent coordinate system.
+  gfx::Rect bounds_;
+
+  // This view's parent
+  View *parent_;
+
+  // This view's children.
+  typedef std::vector<View*> ViewList;
+  ViewList child_views_;
+
+  // List of floating children. A floating view is always referenced by
+  // child_views_ and will be deleted on destruction just like any other
+  // child view.
+  ViewList floating_views_;
+
+  // Maps a floating view to its floating view id.
+  std::map<View*, int> floating_views_ids_;
+
+  // Whether we want the focus to be restored.  This is used to store/restore
+  // focus for floating views.
+  bool should_restore_focus_;
+
+  // The View's LayoutManager defines the sizing heuristics applied to child
+  // Views. The default is absolute positioning according to bounds_.
+  scoped_ptr<LayoutManager> layout_manager_;
+
+  // Visible state
+  bool is_visible_;
+
+  // Background
+  scoped_ptr<Background> background_;
+
+  // Border.
+  scoped_ptr<Border> border_;
+
+  // Whether this view is owned by its parent.
+  bool is_parent_owned_;
+
+  // See SetNotifyWhenVisibleBoundsInRootChanges.
+  bool notify_when_visible_bounds_in_root_changes_;
+
+  // Whether or not RegisterViewForVisibleBoundsNotification on the RootView
+  // has been invoked.
+  bool registered_for_visible_bounds_notification_;
+
+  // List of descendants wanting notification when their visible bounds change.
+  scoped_ptr<ViewList> descendants_to_notify_;
+
+  // Next view to be focused when the Tab key is pressed.
+  View* next_focusable_view_;
+
+  // Next view to be focused when the Shift-Tab key combination is pressed.
+  View* previous_focusable_view_;
+
+  // The list of accelerators.
+  scoped_ptr<std::vector<Accelerator> > accelerators_;
+
+  // The task used to restore automatically the focus to the last focused
+  // floating view.
+  RestoreFocusTask* restore_focus_view_task_;
+
+  // The menu controller.
+  ContextMenuController* context_menu_controller_;
+
+#if defined(OS_WIN)
+  // The accessibility implementation for this View.
+  scoped_ptr<ViewAccessibilityWrapper> accessibility_;
+#endif
+
+  DragController* drag_controller_;
+
+  // Indicates whether or not the view is going to be mirrored (that is, use a
+  // right-to-left UI layout) if the locale's language is a right-to-left
+  // language like Arabic or Hebrew.
+  bool ui_mirroring_is_enabled_for_rtl_languages_;
+
+  // Indicates whether or not the ChromeCanvas object passed to View::Paint()
+  // is going to be flipped horizontally (using the appropriate transform) on
+  // right-to-left locales for this View.
+  bool flip_canvas_on_paint_for_rtl_ui_;
+
+  DISALLOW_COPY_AND_ASSIGN(View);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_VIEW_H_
diff --git a/views/view_constants.cc b/views/view_constants.cc
new file mode 100644
index 0000000..0e2ed17
--- /dev/null
+++ b/views/view_constants.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2006-2008 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 "views/view_constants.h"
+
+namespace views {
+
+const int kAutoscrollSize = 10;
+const int kAutoscrollRowTimerMS = 200;
+const int kDropBetweenPixels = 5;
+
+}  // namespace views
diff --git a/views/view_constants.h b/views/view_constants.h
new file mode 100644
index 0000000..d36dbb4
--- /dev/null
+++ b/views/view_constants.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2006-2008 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 VIEWS_VIEW_CONSTANTS_H_
+#define VIEWS_VIEW_CONSTANTS_H_
+
+namespace views {
+
+// Size (width or height) within which the user can hold the mouse and the
+// view should scroll.
+extern const int kAutoscrollSize;
+
+// Time in milliseconds to autoscroll by a row. This is used during drag and
+// drop.
+extern const int kAutoscrollRowTimerMS;
+
+// Used to determine whether a drop is on an item or before/after it. If a drop
+// occurs kDropBetweenPixels from the top/bottom it is considered before/after
+// the item, otherwise it is on the item.
+extern const int kDropBetweenPixels;
+
+}  // namespace views
+
+#endif  // VIEWS_VIEW_CONSTANTS_H_
diff --git a/views/view_gtk.cc b/views/view_gtk.cc
new file mode 100644
index 0000000..61ca6ca
--- /dev/null
+++ b/views/view_gtk.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2009 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 "views/view.h"
+
+#include "base/logging.h"
+
+namespace views {
+
+FocusManager* View::GetFocusManager() {
+  NOTIMPLEMENTED();
+  return NULL;
+}
+
+void View::DoDrag(const MouseEvent& e, int press_x, int press_y) {
+  NOTIMPLEMENTED();
+}
+
+ViewAccessibilityWrapper* View::GetViewAccessibilityWrapper() {
+  NOTIMPLEMENTED();
+  return NULL;
+}
+
+bool View::HitTest(const gfx::Point& l) const {
+  if (l.x() >= 0 && l.x() < static_cast<int>(width()) &&
+      l.y() >= 0 && l.y() < static_cast<int>(height())) {
+    if (HasHitTestMask()) {
+      // TODO(port): port the windows hit test code here. Once that's factored
+      // out, we can probably move View::HitTest back into views.cc.
+      NOTIMPLEMENTED();
+    }
+    // No mask, but inside our bounds.
+    return true;
+  }
+  // Outside our bounds.
+  return false;
+}
+
+void View::Focus() {
+  NOTIMPLEMENTED();
+}
+
+int View::GetHorizontalDragThreshold() {
+  static int threshold = -1;
+  NOTIMPLEMENTED();
+  return threshold;
+}
+
+int View::GetVerticalDragThreshold() {
+  static int threshold = -1;
+  NOTIMPLEMENTED();
+  return threshold;
+}
+
+}  // namespace views
diff --git a/views/view_unittest.cc b/views/view_unittest.cc
new file mode 100644
index 0000000..d509940e
--- /dev/null
+++ b/views/view_unittest.cc
@@ -0,0 +1,1009 @@
+// Copyright (c) 2006-2008 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 "app/gfx/chrome_canvas.h"
+#include "app/gfx/path.h"
+#include "base/clipboard.h"
+#include "base/message_loop.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/common/notification_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "views/background.h"
+#include "views/controls/button/checkbox.h"
+#if defined(OS_WIN)
+#include "views/controls/button/native_button_win.h"
+#endif
+#include "views/controls/scroll_view.h"
+#include "views/controls/text_field.h"
+#include "views/event.h"
+#include "views/focus/view_storage.h"
+#include "views/view.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget_win.h"
+#include "views/window/dialog_delegate.h"
+#include "views/window/window.h"
+
+using namespace views;
+
+namespace {
+
+class ViewTest : public testing::Test {
+ public:
+  ViewTest() {
+    OleInitialize(NULL);
+  }
+
+  ~ViewTest() {
+    OleUninitialize();
+  }
+
+ private:
+  MessageLoopForUI message_loop_;
+};
+
+// Paints the RootView.
+void PaintRootView(views::RootView* root, bool empty_paint) {
+  if (!empty_paint) {
+    root->PaintNow();
+  } else {
+    // User isn't logged in, so that PaintNow will generate an empty rectangle.
+    // Invoke paint directly.
+    gfx::Rect paint_rect = root->GetScheduledPaintRect();
+    ChromeCanvas canvas(paint_rect.width(), paint_rect.height(), true);
+    canvas.TranslateInt(-paint_rect.x(), -paint_rect.y());
+    canvas.ClipRectInt(0, 0, paint_rect.width(), paint_rect.height());
+    root->ProcessPaint(&canvas);
+  }
+}
+
+/*
+typedef CWinTraits<WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS> CVTWTraits;
+
+// A trivial window implementation that tracks whether or not it has been
+// painted. This is used by the painting test to determine if paint will result
+// in an empty region.
+class EmptyWindow : public CWindowImpl<EmptyWindow,
+                                       CWindow,
+                                       CVTWTraits> {
+ public:
+  DECLARE_FRAME_WND_CLASS(L"Chrome_ChromeViewsEmptyWindow", 0)
+
+  BEGIN_MSG_MAP_EX(EmptyWindow)
+    MSG_WM_PAINT(OnPaint)
+  END_MSG_MAP()
+
+  EmptyWindow::EmptyWindow(const CRect& bounds) : empty_paint_(false) {
+    Create(NULL, static_cast<RECT>(bounds));
+    ShowWindow(SW_SHOW);
+  }
+
+  EmptyWindow::~EmptyWindow() {
+    ShowWindow(SW_HIDE);
+    DestroyWindow();
+  }
+
+  void EmptyWindow::OnPaint(HDC dc) {
+    PAINTSTRUCT ps;
+    HDC paint_dc = BeginPaint(&ps);
+    if (!empty_paint_ && (ps.rcPaint.top - ps.rcPaint.bottom) == 0 &&
+        (ps.rcPaint.right - ps.rcPaint.left) == 0) {
+      empty_paint_ = true;
+    }
+    EndPaint(&ps);
+  }
+
+  bool empty_paint() {
+    return empty_paint_;
+  }
+
+ private:
+  bool empty_paint_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(EmptyWindow);
+};
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A view subclass for testing purpose
+//
+////////////////////////////////////////////////////////////////////////////////
+class TestView : public View {
+ public:
+   TestView() : View(){
+  }
+
+  virtual ~TestView() {}
+
+  // Reset all test state
+  void Reset() {
+    did_change_bounds_ = false;
+    child_added_ = false;
+    child_removed_ = false;
+    last_mouse_event_type_ = 0;
+    location_.x = 0;
+    location_.y = 0;
+    last_clip_.setEmpty();
+  }
+
+  virtual void DidChangeBounds(const gfx::Rect& previous,
+                               const gfx::Rect& current);
+  virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
+  virtual bool OnMousePressed(const MouseEvent& event);
+  virtual bool OnMouseDragged(const MouseEvent& event);
+  virtual void OnMouseReleased(const MouseEvent& event, bool canceled);
+  virtual void Paint(ChromeCanvas* canvas);
+
+  // DidChangeBounds test
+  bool did_change_bounds_;
+  gfx::Rect previous_bounds_;
+  gfx::Rect new_bounds_;
+
+  // AddRemoveNotifications test
+  bool child_added_;
+  bool child_removed_;
+  View* parent_;
+  View* child_;
+
+  // MouseEvent
+  int last_mouse_event_type_;
+  CPoint location_;
+
+  // Painting
+  SkRect last_clip_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// DidChangeBounds
+////////////////////////////////////////////////////////////////////////////////
+
+void TestView::DidChangeBounds(const gfx::Rect& previous,
+                               const gfx::Rect& current) {
+  did_change_bounds_ = true;
+  previous_bounds_ = previous;
+  new_bounds_ = current;
+}
+
+TEST_F(ViewTest, DidChangeBounds) {
+  TestView* v = new TestView();
+
+  gfx::Rect prev_rect(0, 0, 200, 200);
+  gfx::Rect new_rect(100, 100, 250, 250);
+
+  v->SetBounds(prev_rect);
+  v->Reset();
+
+  v->SetBounds(new_rect);
+  EXPECT_EQ(v->did_change_bounds_, true);
+  EXPECT_EQ(v->previous_bounds_, prev_rect);
+  EXPECT_EQ(v->new_bounds_, new_rect);
+
+  EXPECT_EQ(v->bounds(), gfx::Rect(new_rect));
+  delete v;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// AddRemoveNotifications
+////////////////////////////////////////////////////////////////////////////////
+
+void TestView::ViewHierarchyChanged(bool is_add, View *parent, View *child) {
+  if (is_add) {
+    child_added_ = true;
+  } else {
+    child_removed_ = true;
+  }
+  parent_ = parent;
+  child_ = child;
+}
+
+}
+
+TEST_F(ViewTest, AddRemoveNotifications) {
+  TestView* v1 = new TestView();
+  v1->SetBounds(0, 0, 300, 300);
+
+  TestView* v2 = new TestView();
+  v2->SetBounds(0, 0, 300, 300);
+
+  TestView* v3 = new TestView();
+  v3->SetBounds(0, 0, 300, 300);
+
+  // Add a child. Make sure both v2 and v3 receive the right
+  // notification
+  v2->Reset();
+  v3->Reset();
+  v2->AddChildView(v3);
+  EXPECT_EQ(v2->child_added_, true);
+  EXPECT_EQ(v2->parent_, v2);
+  EXPECT_EQ(v2->child_, v3);
+
+  EXPECT_EQ(v3->child_added_, true);
+  EXPECT_EQ(v3->parent_, v2);
+  EXPECT_EQ(v3->child_, v3);
+
+  // Add v2 and transitively v3 to v1. Make sure that all views
+  // received the right notification
+
+  v1->Reset();
+  v2->Reset();
+  v3->Reset();
+  v1->AddChildView(v2);
+
+  EXPECT_EQ(v1->child_added_, true);
+  EXPECT_EQ(v1->child_, v2);
+  EXPECT_EQ(v1->parent_, v1);
+
+  EXPECT_EQ(v2->child_added_, true);
+  EXPECT_EQ(v2->child_, v2);
+  EXPECT_EQ(v2->parent_, v1);
+
+  EXPECT_EQ(v3->child_added_, true);
+  EXPECT_EQ(v3->child_, v2);
+  EXPECT_EQ(v3->parent_, v1);
+
+  // Remove v2. Make sure all views received the right notification
+  v1->Reset();
+  v2->Reset();
+  v3->Reset();
+  v1->RemoveChildView(v2);
+
+  EXPECT_EQ(v1->child_removed_, true);
+  EXPECT_EQ(v1->parent_, v1);
+  EXPECT_EQ(v1->child_, v2);
+
+  EXPECT_EQ(v2->child_removed_, true);
+  EXPECT_EQ(v2->parent_, v1);
+  EXPECT_EQ(v2->child_, v2);
+
+  EXPECT_EQ(v3->child_removed_, true);
+  EXPECT_EQ(v3->parent_, v1);
+  EXPECT_EQ(v3->child_, v3);
+
+  // Clean-up
+  delete v1;
+  delete v2;  // This also deletes v3 (child of v2).
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// MouseEvent
+////////////////////////////////////////////////////////////////////////////////
+
+bool TestView::OnMousePressed(const MouseEvent& event) {
+  last_mouse_event_type_ = event.GetType();
+  location_.x = event.x();
+  location_.y = event.y();
+  return true;
+}
+
+bool TestView::OnMouseDragged(const MouseEvent& event) {
+  last_mouse_event_type_ = event.GetType();
+  location_.x = event.x();
+  location_.y = event.y();
+  return true;
+}
+
+void TestView::OnMouseReleased(const MouseEvent& event, bool canceled) {
+  last_mouse_event_type_ = event.GetType();
+  location_.x = event.x();
+  location_.y = event.y();
+}
+
+TEST_F(ViewTest, MouseEvent) {
+  TestView* v1 = new TestView();
+  v1->SetBounds(0, 0, 300, 300);
+
+  TestView* v2 = new TestView();
+  v2->SetBounds (100, 100, 100, 100);
+
+  views::WidgetWin window;
+  window.set_delete_on_destroy(false);
+  window.set_window_style(WS_OVERLAPPEDWINDOW);
+  window.Init(NULL, gfx::Rect(50, 50, 650, 650), false);
+  RootView* root = window.GetRootView();
+
+  root->AddChildView(v1);
+  v1->AddChildView(v2);
+
+  v1->Reset();
+  v2->Reset();
+
+  MouseEvent pressed(Event::ET_MOUSE_PRESSED,
+                     110,
+                     120,
+                     Event::EF_LEFT_BUTTON_DOWN);
+  root->OnMousePressed(pressed);
+  EXPECT_EQ(v2->last_mouse_event_type_, Event::ET_MOUSE_PRESSED);
+  EXPECT_EQ(v2->location_.x, 10);
+  EXPECT_EQ(v2->location_.y, 20);
+  // Make sure v1 did not receive the event
+  EXPECT_EQ(v1->last_mouse_event_type_, 0);
+
+  // Drag event out of bounds. Should still go to v2
+  v1->Reset();
+  v2->Reset();
+  MouseEvent dragged(Event::ET_MOUSE_DRAGGED,
+                     50,
+                     40,
+                     Event::EF_LEFT_BUTTON_DOWN);
+  root->OnMouseDragged(dragged);
+  EXPECT_EQ(v2->last_mouse_event_type_, Event::ET_MOUSE_DRAGGED);
+  EXPECT_EQ(v2->location_.x, -50);
+  EXPECT_EQ(v2->location_.y, -60);
+  // Make sure v1 did not receive the event
+  EXPECT_EQ(v1->last_mouse_event_type_, 0);
+
+  // Releasted event out of bounds. Should still go to v2
+  v1->Reset();
+  v2->Reset();
+  MouseEvent released(Event::ET_MOUSE_RELEASED, 0, 0, 0);
+  root->OnMouseDragged(released);
+  EXPECT_EQ(v2->last_mouse_event_type_, Event::ET_MOUSE_RELEASED);
+  EXPECT_EQ(v2->location_.x, -100);
+  EXPECT_EQ(v2->location_.y, -100);
+  // Make sure v1 did not receive the event
+  EXPECT_EQ(v1->last_mouse_event_type_, 0);
+
+  window.CloseNow();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Painting
+////////////////////////////////////////////////////////////////////////////////
+
+void TestView::Paint(ChromeCanvas* canvas) {
+  canvas->getClipBounds(&last_clip_);
+}
+
+void CheckRect(const SkRect& check_rect, const SkRect& target_rect) {
+  EXPECT_EQ(target_rect.fLeft, check_rect.fLeft);
+  EXPECT_EQ(target_rect.fRight, check_rect.fRight);
+  EXPECT_EQ(target_rect.fTop, check_rect.fTop);
+  EXPECT_EQ(target_rect.fBottom, check_rect.fBottom);
+}
+
+/* This test is disabled because it is flakey on some systems.
+TEST_F(ViewTest, DISABLED_Painting) {
+  // Determine if InvalidateRect generates an empty paint rectangle.
+  EmptyWindow paint_window(CRect(50, 50, 650, 650));
+  paint_window.RedrawWindow(CRect(0, 0, 600, 600), NULL,
+                            RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN);
+  bool empty_paint = paint_window.empty_paint();
+
+  views::WidgetWin window;
+  window.set_delete_on_destroy(false);
+  window.set_window_style(WS_OVERLAPPEDWINDOW);
+  window.Init(NULL, gfx::Rect(50, 50, 650, 650), NULL);
+  RootView* root = window.GetRootView();
+
+  TestView* v1 = new TestView();
+  v1->SetBounds(0, 0, 650, 650);
+  root->AddChildView(v1);
+
+  TestView* v2 = new TestView();
+  v2->SetBounds(10, 10, 80, 80);
+  v1->AddChildView(v2);
+
+  TestView* v3 = new TestView();
+  v3->SetBounds(10, 10, 60, 60);
+  v2->AddChildView(v3);
+
+  TestView* v4 = new TestView();
+  v4->SetBounds(10, 200, 100, 100);
+  v1->AddChildView(v4);
+
+  // Make sure to paint current rects
+  PaintRootView(root, empty_paint);
+
+
+  v1->Reset();
+  v2->Reset();
+  v3->Reset();
+  v4->Reset();
+  v3->SchedulePaint(10, 10, 10, 10);
+  PaintRootView(root, empty_paint);
+
+  SkRect tmp_rect;
+
+  tmp_rect.set(SkIntToScalar(10),
+               SkIntToScalar(10),
+               SkIntToScalar(20),
+               SkIntToScalar(20));
+  CheckRect(v3->last_clip_, tmp_rect);
+
+  tmp_rect.set(SkIntToScalar(20),
+               SkIntToScalar(20),
+               SkIntToScalar(30),
+               SkIntToScalar(30));
+  CheckRect(v2->last_clip_, tmp_rect);
+
+  tmp_rect.set(SkIntToScalar(30),
+               SkIntToScalar(30),
+               SkIntToScalar(40),
+               SkIntToScalar(40));
+  CheckRect(v1->last_clip_, tmp_rect);
+
+  // Make sure v4 was not painted
+  tmp_rect.setEmpty();
+  CheckRect(v4->last_clip_, tmp_rect);
+
+  window.DestroyWindow();
+}
+*/
+
+TEST_F(ViewTest, RemoveNotification) {
+  views::ViewStorage* vs = views::ViewStorage::GetSharedInstance();
+  views::WidgetWin* window = new views::WidgetWin;
+  views::RootView* root_view = window->GetRootView();
+
+  View* v1 = new View;
+  int s1 = vs->CreateStorageID();
+  vs->StoreView(s1, v1);
+  root_view->AddChildView(v1);
+  View* v11 = new View;
+  int s11 = vs->CreateStorageID();
+  vs->StoreView(s11, v11);
+  v1->AddChildView(v11);
+  View* v111 = new View;
+  int s111 = vs->CreateStorageID();
+  vs->StoreView(s111, v111);
+  v11->AddChildView(v111);
+  View* v112 = new View;
+  int s112 = vs->CreateStorageID();
+  vs->StoreView(s112, v112);
+  v11->AddChildView(v112);
+  View* v113 = new View;
+  int s113 = vs->CreateStorageID();
+  vs->StoreView(s113, v113);
+  v11->AddChildView(v113);
+  View* v1131 = new View;
+  int s1131 = vs->CreateStorageID();
+  vs->StoreView(s1131, v1131);
+  v113->AddChildView(v1131);
+  View* v12 = new View;
+  int s12 = vs->CreateStorageID();
+  vs->StoreView(s12, v12);
+  v1->AddChildView(v12);
+
+  View* v2 = new View;
+  int s2 = vs->CreateStorageID();
+  vs->StoreView(s2, v2);
+  root_view->AddChildView(v2);
+  View* v21 = new View;
+  int s21 = vs->CreateStorageID();
+  vs->StoreView(s21, v21);
+  v2->AddChildView(v21);
+  View* v211 = new View;
+  int s211 = vs->CreateStorageID();
+  vs->StoreView(s211, v211);
+  v21->AddChildView(v211);
+
+  size_t stored_views = vs->view_count();
+
+  // Try removing a leaf view.
+  v21->RemoveChildView(v211);
+  EXPECT_EQ(stored_views - 1, vs->view_count());
+  EXPECT_EQ(NULL, vs->RetrieveView(s211));
+  delete v211;  // We won't use this one anymore.
+
+  // Now try removing a view with a hierarchy of depth 1.
+  v11->RemoveChildView(v113);
+  EXPECT_EQ(stored_views - 3, vs->view_count());
+  EXPECT_EQ(NULL, vs->RetrieveView(s113));
+  EXPECT_EQ(NULL, vs->RetrieveView(s1131));
+  delete v113;  // We won't use this one anymore.
+
+  // Now remove even more.
+  root_view->RemoveChildView(v1);
+  EXPECT_EQ(stored_views - 8, vs->view_count());
+  EXPECT_EQ(NULL, vs->RetrieveView(s1));
+  EXPECT_EQ(NULL, vs->RetrieveView(s11));
+  EXPECT_EQ(NULL, vs->RetrieveView(s12));
+  EXPECT_EQ(NULL, vs->RetrieveView(s111));
+  EXPECT_EQ(NULL, vs->RetrieveView(s112));
+
+  // Put v1 back for more tests.
+  root_view->AddChildView(v1);
+  vs->StoreView(s1, v1);
+
+  // Now delete the root view (deleting the window will trigger a delete of the
+  // RootView) and make sure we are notified that the views were removed.
+  delete window;
+  EXPECT_EQ(stored_views - 10, vs->view_count());
+  EXPECT_EQ(NULL, vs->RetrieveView(s1));
+  EXPECT_EQ(NULL, vs->RetrieveView(s12));
+  EXPECT_EQ(NULL, vs->RetrieveView(s11));
+  EXPECT_EQ(NULL, vs->RetrieveView(s12));
+  EXPECT_EQ(NULL, vs->RetrieveView(s21));
+  EXPECT_EQ(NULL, vs->RetrieveView(s111));
+  EXPECT_EQ(NULL, vs->RetrieveView(s112));
+}
+
+namespace {
+class HitTestView : public views::View {
+ public:
+  explicit HitTestView(bool has_hittest_mask)
+      : has_hittest_mask_(has_hittest_mask) {
+  }
+  virtual ~HitTestView() {}
+
+ protected:
+  // Overridden from views::View:
+  virtual bool HasHitTestMask() const {
+    return has_hittest_mask_;
+  }
+  virtual void GetHitTestMask(gfx::Path* mask) const {
+    DCHECK(has_hittest_mask_);
+    DCHECK(mask);
+
+    SkScalar w = SkIntToScalar(width());
+    SkScalar h = SkIntToScalar(height());
+
+    // Create a triangular mask within the bounds of this View.
+    mask->moveTo(w / 2, 0);
+    mask->lineTo(w, h);
+    mask->lineTo(0, h);
+    mask->close();
+  }
+
+ private:
+  bool has_hittest_mask_;
+
+  DISALLOW_COPY_AND_ASSIGN(HitTestView);
+};
+
+gfx::Point ConvertPointToView(views::View* view, const gfx::Point& p) {
+  gfx::Point tmp(p);
+  views::View::ConvertPointToView(view->GetRootView(), view, &tmp);
+  return tmp;
+}
+}
+
+TEST_F(ViewTest, HitTestMasks) {
+  views::WidgetWin window;
+  views::RootView* root_view = window.GetRootView();
+  root_view->SetBounds(0, 0, 500, 500);
+
+  gfx::Rect v1_bounds = gfx::Rect(0, 0, 100, 100);
+  HitTestView* v1 = new HitTestView(false);
+  v1->SetBounds(v1_bounds);
+  root_view->AddChildView(v1);
+
+  gfx::Rect v2_bounds = gfx::Rect(105, 0, 100, 100);
+  HitTestView* v2 = new HitTestView(true);
+  v2->SetBounds(v2_bounds);
+  root_view->AddChildView(v2);
+
+  gfx::Point v1_centerpoint = v1_bounds.CenterPoint();
+  gfx::Point v2_centerpoint = v2_bounds.CenterPoint();
+  gfx::Point v1_origin = v1_bounds.origin();
+  gfx::Point v2_origin = v2_bounds.origin();
+
+  // Test HitTest
+  EXPECT_EQ(true, v1->HitTest(ConvertPointToView(v1, v1_centerpoint)));
+  EXPECT_EQ(true, v2->HitTest(ConvertPointToView(v2, v2_centerpoint)));
+
+  EXPECT_EQ(true, v1->HitTest(ConvertPointToView(v1, v1_origin)));
+  EXPECT_EQ(false, v2->HitTest(ConvertPointToView(v2, v2_origin)));
+
+  // Test GetViewForPoint
+  EXPECT_EQ(v1, root_view->GetViewForPoint(v1_centerpoint));
+  EXPECT_EQ(v2, root_view->GetViewForPoint(v2_centerpoint));
+  EXPECT_EQ(v1, root_view->GetViewForPoint(v1_origin));
+  EXPECT_EQ(root_view, root_view->GetViewForPoint(v2_origin));
+}
+
+#if defined(OS_WIN)
+// Tests that the TextField view respond appropiately to cut/copy/paste.
+TEST_F(ViewTest, TextFieldCutCopyPaste) {
+  const std::wstring kNormalText = L"Normal";
+  const std::wstring kReadOnlyText = L"Read only";
+  const std::wstring kPasswordText = L"Password! ** Secret stuff **";
+
+  Clipboard* clipboard = g_browser_process->clipboard();
+
+  WidgetWin* window = new WidgetWin;
+  window->Init(NULL, gfx::Rect(0, 0, 100, 100), true);
+  RootView* root_view = window->GetRootView();
+
+  TextField* normal = new TextField();
+  TextField* read_only = new TextField();
+  read_only->SetReadOnly(true);
+  TextField* password = new TextField(TextField::STYLE_PASSWORD);
+
+  root_view->AddChildView(normal);
+  root_view->AddChildView(read_only);
+  root_view->AddChildView(password);
+
+  normal->SetText(kNormalText);
+  read_only->SetText(kReadOnlyText);
+  password->SetText(kPasswordText);
+
+  //
+  // Test cut.
+  //
+  ASSERT_TRUE(normal->GetNativeComponent());
+  normal->SelectAll();
+  ::SendMessage(normal->GetNativeComponent(), WM_CUT, 0, 0);
+
+  string16 result;
+  clipboard->ReadText(&result);
+  EXPECT_EQ(kNormalText, result);
+  normal->SetText(kNormalText);  // Let's revert to the original content.
+
+  ASSERT_TRUE(read_only->GetNativeComponent());
+  read_only->SelectAll();
+  ::SendMessage(read_only->GetNativeComponent(), WM_CUT, 0, 0);
+  result.clear();
+  clipboard->ReadText(&result);
+  // Cut should have failed, so the clipboard content should not have changed.
+  EXPECT_EQ(kNormalText, result);
+
+  ASSERT_TRUE(password->GetNativeComponent());
+  password->SelectAll();
+  ::SendMessage(password->GetNativeComponent(), WM_CUT, 0, 0);
+  result.clear();
+  clipboard->ReadText(&result);
+  // Cut should have failed, so the clipboard content should not have changed.
+  EXPECT_EQ(kNormalText, result);
+
+  //
+  // Test copy.
+  //
+
+  // Let's start with read_only as the clipboard already contains the content
+  // of normal.
+  read_only->SelectAll();
+  ::SendMessage(read_only->GetNativeComponent(), WM_COPY, 0, 0);
+  result.clear();
+  clipboard->ReadText(&result);
+  EXPECT_EQ(kReadOnlyText, result);
+
+  normal->SelectAll();
+  ::SendMessage(normal->GetNativeComponent(), WM_COPY, 0, 0);
+  result.clear();
+  clipboard->ReadText(&result);
+  EXPECT_EQ(kNormalText, result);
+
+  password->SelectAll();
+  ::SendMessage(password->GetNativeComponent(), WM_COPY, 0, 0);
+  result.clear();
+  clipboard->ReadText(&result);
+  // We don't let you copy from a password field, clipboard should not have
+  // changed.
+  EXPECT_EQ(kNormalText, result);
+
+  //
+  // Test Paste.
+  //
+  // Note that we use GetWindowText instead of TextField::GetText below as the
+  // text in the TextField class is synced to the text of the HWND on
+  // WM_KEYDOWN messages that we are not simulating here.
+
+  // Attempting to copy kNormalText in a read-only text-field should fail.
+  read_only->SelectAll();
+  ::SendMessage(read_only->GetNativeComponent(), WM_KEYDOWN, 0, 0);
+  wchar_t buffer[1024] = { 0 };
+  ::GetWindowText(read_only->GetNativeComponent(), buffer, 1024);
+  EXPECT_EQ(kReadOnlyText, std::wstring(buffer));
+
+  password->SelectAll();
+  ::SendMessage(password->GetNativeComponent(), WM_PASTE, 0, 0);
+  ::GetWindowText(password->GetNativeComponent(), buffer, 1024);
+  EXPECT_EQ(kNormalText, std::wstring(buffer));
+
+  // Copy from read_only so the string we are pasting is not the same as the
+  // current one.
+  read_only->SelectAll();
+  ::SendMessage(read_only->GetNativeComponent(), WM_COPY, 0, 0);
+  normal->SelectAll();
+  ::SendMessage(normal->GetNativeComponent(), WM_PASTE, 0, 0);
+  ::GetWindowText(normal->GetNativeComponent(), buffer, 1024);
+  EXPECT_EQ(kReadOnlyText, std::wstring(buffer));
+}
+#endif
+
+#if defined(OS_WIN)
+////////////////////////////////////////////////////////////////////////////////
+// Mouse-wheel message rerouting
+////////////////////////////////////////////////////////////////////////////////
+class ButtonTest : public NativeButton {
+ public:
+  ButtonTest(ButtonListener* listener, const std::wstring& label)
+      : NativeButton(listener, label) {
+  }
+
+  HWND GetHWND() {
+    return static_cast<NativeButtonWin*>(native_wrapper_)->GetHWND();
+  }
+};
+
+class CheckboxTest : public Checkbox {
+ public:
+  explicit CheckboxTest(const std::wstring& label) : Checkbox(label) {
+  }
+
+  HWND GetHWND() {
+    return static_cast<NativeCheckboxWin*>(native_wrapper_)->GetHWND();
+  }
+};
+
+class ScrollableTestView : public View {
+ public:
+  ScrollableTestView() { }
+
+  virtual gfx::Size GetPreferredSize() {
+    return gfx::Size(100, 10000);
+  }
+
+  virtual void Layout() {
+    SizeToPreferredSize();
+  }
+};
+
+class TestViewWithControls : public View {
+ public:
+  TestViewWithControls() {
+    button_ = new ButtonTest(NULL, L"Button");
+    checkbox_ = new CheckboxTest(L"My checkbox");
+    text_field_ = new TextField();
+    AddChildView(button_);
+    AddChildView(checkbox_);
+    AddChildView(text_field_);
+  }
+
+  ButtonTest* button_;
+  CheckboxTest* checkbox_;
+  TextField* text_field_;
+};
+
+class SimpleWindowDelegate : public WindowDelegate {
+ public:
+  SimpleWindowDelegate(View* contents) : contents_(contents) {  }
+
+  virtual void DeleteDelegate() { delete this; }
+
+  virtual View* GetContentsView() { return contents_; }
+
+ private:
+  View* contents_;
+};
+
+// Tests that the mouse-wheel messages are correctly rerouted to the window
+// under the mouse.
+// TODO(jcampan): http://crbug.com/10572 Disabled as it fails on the Vista build
+//                bot.
+TEST_F(ViewTest, DISABLED_RerouteMouseWheelTest) {
+  TestViewWithControls* view_with_controls = new TestViewWithControls();
+  views::Window* window1 =
+      views::Window::CreateChromeWindow(
+          NULL, gfx::Rect(0, 0, 100, 100),
+          new SimpleWindowDelegate(view_with_controls));
+  window1->Show();
+  ScrollView* scroll_view = new ScrollView();
+  scroll_view->SetContents(new ScrollableTestView());
+  views::Window* window2 =
+      views::Window::CreateChromeWindow(NULL, gfx::Rect(200, 200, 100, 100),
+                                        new SimpleWindowDelegate(scroll_view));
+  window2->Show();
+  EXPECT_EQ(0, scroll_view->GetVisibleRect().y());
+
+  // Make the window1 active, as this is what it would be in real-world.
+  window1->Activate();
+
+  // Let's send a mouse-wheel message to the different controls and check that
+  // it is rerouted to the window under the mouse (effectively scrolling the
+  // scroll-view).
+
+  // First to the Window's HWND.
+  ::SendMessage(view_with_controls->GetWidget()->GetNativeView(),
+                WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250));
+  EXPECT_EQ(20, scroll_view->GetVisibleRect().y());
+
+  // Then the button.
+  ::SendMessage(view_with_controls->button_->GetHWND(),
+                WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250));
+  EXPECT_EQ(40, scroll_view->GetVisibleRect().y());
+
+  // Then the check-box.
+  ::SendMessage(view_with_controls->checkbox_->GetHWND(),
+                WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250));
+  EXPECT_EQ(60, scroll_view->GetVisibleRect().y());
+
+  // Then the text-field.
+  ::SendMessage(view_with_controls->text_field_->GetNativeComponent(),
+                WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250));
+  EXPECT_EQ(80, scroll_view->GetVisibleRect().y());
+
+  // Ensure we don't scroll when the mouse is not over that window.
+  ::SendMessage(view_with_controls->text_field_->GetNativeComponent(),
+                WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(50, 50));
+  EXPECT_EQ(80, scroll_view->GetVisibleRect().y());
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Dialogs' default button
+////////////////////////////////////////////////////////////////////////////////
+
+class TestDialogView : public views::View,
+                       public views::DialogDelegate,
+                       public views::ButtonListener {
+ public:
+  TestDialogView()
+      : last_pressed_button_(NULL),
+        button1_(NULL),
+        button2_(NULL),
+        checkbox_(NULL),
+        canceled_(false),
+        oked_(false) {
+  }
+
+  // views::DialogDelegate implementation:
+  virtual int GetDefaultDialogButton() const {
+    return MessageBoxFlags::DIALOGBUTTON_OK;
+  }
+
+  virtual View* GetContentsView() {
+    views::View* container = new views::View();
+    button1_ = new views::NativeButton(this, L"Button1");
+    button2_ = new views::NativeButton(this, L"Button2");
+    checkbox_ = new views::Checkbox(L"My checkbox");
+    container->AddChildView(button1_);
+    container->AddChildView(button2_);
+    container->AddChildView(checkbox_);
+    return container;
+  }
+
+  // Prevent the dialog from really closing (so we can click the OK/Cancel
+  // buttons to our heart's content).
+  virtual bool Cancel() {
+    canceled_ = true;
+    return false;
+  }
+  virtual bool Accept() {
+    oked_ = true;
+    return false;
+  }
+
+  // views::ButtonListener implementation.
+  virtual void ButtonPressed(Button* sender) {
+    last_pressed_button_ = sender;
+  }
+
+  void ResetStates() {
+    oked_ = false;
+    canceled_ = false;
+    last_pressed_button_ = NULL;
+  }
+
+  views::NativeButton* button1_;
+  views::NativeButton* button2_;
+  views::NativeButton* checkbox_;
+  views::Button* last_pressed_button_;
+
+  bool canceled_;
+  bool oked_;
+};
+
+
+class DefaultButtonTest : public ViewTest {
+ public:
+  enum ButtonID {
+    OK,
+    CANCEL,
+    BUTTON1,
+    BUTTON2
+  };
+
+  DefaultButtonTest()
+      : native_window_(NULL),
+        focus_manager_(NULL),
+        client_view_(NULL),
+        ok_button_(NULL),
+        cancel_button_(NULL) {
+  }
+
+  virtual void SetUp() {
+    dialog_view_ = new TestDialogView();
+    views::Window* window =
+        views::Window::CreateChromeWindow(NULL, gfx::Rect(0, 0, 100, 100),
+                                          dialog_view_);
+    window->Show();
+    native_window_ = window->GetNativeWindow();
+    focus_manager_ = FocusManager::GetFocusManager(native_window_);
+    client_view_ =
+        static_cast<views::DialogClientView*>(window->GetClientView());
+    ok_button_ = client_view_->ok_button();
+    cancel_button_ = client_view_->cancel_button();
+  }
+
+  void SimularePressingEnterAndCheckDefaultButton(ButtonID button_id) {
+#if defined(OS_WIN)
+    focus_manager_->OnKeyDown(native_window_, WM_KEYDOWN, VK_RETURN, 0);
+#else
+    // TODO(platform)
+    return;
+#endif
+    switch (button_id) {
+      case OK:
+        EXPECT_TRUE(dialog_view_->oked_);
+        EXPECT_FALSE(dialog_view_->canceled_);
+        EXPECT_FALSE(dialog_view_->last_pressed_button_);
+        break;
+      case CANCEL:
+        EXPECT_FALSE(dialog_view_->oked_);
+        EXPECT_TRUE(dialog_view_->canceled_);
+        EXPECT_FALSE(dialog_view_->last_pressed_button_);
+        break;
+      case BUTTON1:
+        EXPECT_FALSE(dialog_view_->oked_);
+        EXPECT_FALSE(dialog_view_->canceled_);
+        EXPECT_TRUE(dialog_view_->last_pressed_button_ ==
+            dialog_view_->button1_);
+        break;
+      case BUTTON2:
+        EXPECT_FALSE(dialog_view_->oked_);
+        EXPECT_FALSE(dialog_view_->canceled_);
+        EXPECT_TRUE(dialog_view_->last_pressed_button_ ==
+            dialog_view_->button2_);
+        break;
+    }
+    dialog_view_->ResetStates();
+  }
+
+  gfx::NativeWindow native_window_;
+  views::FocusManager* focus_manager_;
+  TestDialogView* dialog_view_;
+  DialogClientView* client_view_;
+  views::NativeButton* ok_button_;
+  views::NativeButton* cancel_button_;
+};
+
+TEST_F(DefaultButtonTest, DialogDefaultButtonTest) {
+  // Window has just been shown, we expect the default button specified in the
+  // DialogDelegate.
+  EXPECT_TRUE(ok_button_->is_default());
+
+  // Simulate pressing enter, that should trigger the OK button.
+  SimularePressingEnterAndCheckDefaultButton(OK);
+
+  // Simulate focusing another button, it should become the default button.
+  client_view_->FocusWillChange(ok_button_, dialog_view_->button1_);
+  EXPECT_FALSE(ok_button_->is_default());
+  EXPECT_TRUE(dialog_view_->button1_->is_default());
+  // Simulate pressing enter, that should trigger button1.
+  SimularePressingEnterAndCheckDefaultButton(BUTTON1);
+
+  // Now select something that is not a button, the OK should become the default
+  // button again.
+  client_view_->FocusWillChange(dialog_view_->button1_,
+                                dialog_view_->checkbox_);
+  EXPECT_TRUE(ok_button_->is_default());
+  EXPECT_FALSE(dialog_view_->button1_->is_default());
+  SimularePressingEnterAndCheckDefaultButton(OK);
+
+  // Select yet another button.
+  client_view_->FocusWillChange(dialog_view_->checkbox_,
+                                dialog_view_->button2_);
+  EXPECT_FALSE(ok_button_->is_default());
+  EXPECT_FALSE(dialog_view_->button1_->is_default());
+  EXPECT_TRUE(dialog_view_->button2_->is_default());
+  SimularePressingEnterAndCheckDefaultButton(BUTTON2);
+
+  // Focus nothing.
+  client_view_->FocusWillChange(dialog_view_->button2_, NULL);
+  EXPECT_TRUE(ok_button_->is_default());
+  EXPECT_FALSE(dialog_view_->button1_->is_default());
+  EXPECT_FALSE(dialog_view_->button2_->is_default());
+  SimularePressingEnterAndCheckDefaultButton(OK);
+
+  // Focus the cancel button.
+  client_view_->FocusWillChange(NULL, cancel_button_);
+  EXPECT_FALSE(ok_button_->is_default());
+  EXPECT_TRUE(cancel_button_->is_default());
+  EXPECT_FALSE(dialog_view_->button1_->is_default());
+  EXPECT_FALSE(dialog_view_->button2_->is_default());
+  SimularePressingEnterAndCheckDefaultButton(CANCEL);
+}
diff --git a/views/view_win.cc b/views/view_win.cc
new file mode 100644
index 0000000..6dfe183
--- /dev/null
+++ b/views/view_win.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2009 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 "views/view.h"
+
+#include "app/drag_drop_types.h"
+#include "app/gfx/chrome_canvas.h"
+#include "app/gfx/path.h"
+#include "app/os_exchange_data.h"
+#include "base/scoped_handle.h"
+#include "base/string_util.h"
+#include "views/accessibility/view_accessibility_wrapper.h"
+#include "views/border.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+FocusManager* View::GetFocusManager() {
+  Widget* widget = GetWidget();
+  if (!widget)
+    return NULL;
+
+  HWND hwnd = widget->GetNativeView();
+  if (!hwnd)
+    return NULL;
+
+  return FocusManager::GetFocusManager(hwnd);
+}
+
+void View::DoDrag(const MouseEvent& e, int press_x, int press_y) {
+  int drag_operations = GetDragOperations(press_x, press_y);
+  if (drag_operations == DragDropTypes::DRAG_NONE)
+    return;
+
+  scoped_refptr<OSExchangeData> data = new OSExchangeData;
+  WriteDragData(press_x, press_y, data.get());
+
+  // Message the RootView to do the drag and drop. That way if we're removed
+  // the RootView can detect it and avoid calling us back.
+  RootView* root_view = GetRootView();
+  root_view->StartDragForViewFromMouseEvent(this, data, drag_operations);
+}
+
+ViewAccessibilityWrapper* View::GetViewAccessibilityWrapper() {
+  if (accessibility_.get() == NULL) {
+    accessibility_.reset(new ViewAccessibilityWrapper(this));
+  }
+  return accessibility_.get();
+}
+
+bool View::HitTest(const gfx::Point& l) const {
+  if (l.x() >= 0 && l.x() < static_cast<int>(width()) &&
+      l.y() >= 0 && l.y() < static_cast<int>(height())) {
+    if (HasHitTestMask()) {
+      gfx::Path mask;
+      GetHitTestMask(&mask);
+      ScopedHRGN rgn(mask.CreateHRGN());
+      return !!PtInRegion(rgn, l.x(), l.y());
+    }
+    // No mask, but inside our bounds.
+    return true;
+  }
+  // Outside our bounds.
+  return false;
+}
+
+HCURSOR View::GetCursorForPoint(Event::EventType event_type, int x, int y) {
+  return NULL;
+}
+
+void View::Focus() {
+  // Set the native focus to the root view window so it receives the keyboard
+  // messages.
+  FocusManager* focus_manager = GetFocusManager();
+  if (focus_manager)
+    focus_manager->FocusHWND(GetRootView()->GetWidget()->GetNativeView());
+}
+
+int View::GetHorizontalDragThreshold() {
+  static int threshold = -1;
+  if (threshold == -1)
+    threshold = GetSystemMetrics(SM_CXDRAG) / 2;
+  return threshold;
+}
+
+int View::GetVerticalDragThreshold() {
+  static int threshold = -1;
+  if (threshold == -1)
+    threshold = GetSystemMetrics(SM_CYDRAG) / 2;
+  return threshold;
+}
+
+}  // namespace views
diff --git a/views/views.vcproj b/views/views.vcproj
new file mode 100644
index 0000000..c10e68de
--- /dev/null
+++ b/views/views.vcproj
@@ -0,0 +1,869 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="views"
+	ProjectGUID="{6F9258E5-294F-47B2-919D-17FFE7A8B751}"
+	RootNamespace="Views"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="4"
+			InheritedPropertySheets=".\views.vsprops;$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)\tools\build\win\precompiled_wtl.vsprops;..\third_party\icu38\build\using_icu.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="4"
+			InheritedPropertySheets=".\views.vsprops;$(SolutionDir)..\build\release.vsprops;..\third_party\icu38\build\using_icu.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="accessibility"
+			>
+			<File
+				RelativePath=".\accessibility\view_accessibility.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\accessibility\view_accessibility.h"
+				>
+			</File>
+			<File
+				RelativePath=".\accessibility\view_accessibility_wrapper.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\accessibility\view_accessibility_wrapper.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="widget"
+			>
+			<File
+				RelativePath=".\widget\accelerator_handler.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\widget\accelerator_handler.h"
+				>
+			</File>
+			<File
+				RelativePath=".\widget\aero_tooltip_manager.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\widget\aero_tooltip_manager.h"
+				>
+			</File>
+			<File
+				RelativePath=".\widget\root_view.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\widget\root_view.h"
+				>
+			</File>
+			<File
+				RelativePath=".\widget\root_view_drop_target.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\widget\root_view_drop_target.h"
+				>
+			</File>
+			<File
+				RelativePath=".\widget\root_view_win.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\widget\tooltip_manager.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\widget\tooltip_manager.h"
+				>
+			</File>
+			<File
+				RelativePath=".\widget\widget.h"
+				>
+			</File>
+			<File
+				RelativePath=".\widget\widget_win.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						ObjectFile="$(IntDir)\$(InputName)1.obj"
+						XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\widget\widget_win.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="window"
+			>
+			<File
+				RelativePath=".\window\client_view.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\window\client_view.h"
+				>
+			</File>
+			<File
+				RelativePath=".\window\custom_frame_view.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\window\custom_frame_view.h"
+				>
+			</File>
+			<File
+				RelativePath=".\window\dialog_client_view.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\window\dialog_client_view.h"
+				>
+			</File>
+			<File
+				RelativePath=".\window\dialog_delegate.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\window\dialog_delegate.h"
+				>
+			</File>
+			<File
+				RelativePath=".\window\native_frame_view.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\window\native_frame_view.h"
+				>
+			</File>
+			<File
+				RelativePath=".\window\non_client_view.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\window\non_client_view.h"
+				>
+			</File>
+			<File
+				RelativePath=".\window\window.h"
+				>
+			</File>
+			<File
+				RelativePath=".\window\window_delegate.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\window\window_delegate.h"
+				>
+			</File>
+			<File
+				RelativePath=".\window\window_resources.h"
+				>
+			</File>
+			<File
+				RelativePath=".\window\window_win.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\window\window_win.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="focus"
+			>
+			<File
+				RelativePath=".\focus\external_focus_tracker.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\focus\external_focus_tracker.h"
+				>
+			</File>
+			<File
+				RelativePath=".\focus\focus_manager.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\focus\focus_manager.h"
+				>
+			</File>
+			<File
+				RelativePath=".\focus\focus_util_win.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\focus\focus_util_win.h"
+				>
+			</File>
+			<File
+				RelativePath=".\focus\view_storage.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\focus\view_storage.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="controls"
+			>
+			<File
+				RelativePath=".\controls\combo_box.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\combo_box.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\hwnd_view.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\hwnd_view.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\image_view.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\image_view.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\label.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\label.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\link.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\link.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\message_box_view.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\message_box_view.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\native_control.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\native_control.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\native_control_win.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\native_control_win.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\native_view_host.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\native_view_host.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\scroll_view.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\scroll_view.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\separator.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\separator.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\single_split_view.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\single_split_view.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\tabbed_pane.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\tabbed_pane.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\text_field.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\text_field.h"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\throbber.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\controls\throbber.h"
+				>
+			</File>
+			<Filter
+				Name="button"
+				>
+				<File
+					RelativePath=".\controls\button\button.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\button.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\button_dropdown.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\button_dropdown.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\checkbox.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\checkbox.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\custom_button.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\custom_button.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\image_button.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\image_button.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\menu_button.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\menu_button.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\native_button.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\native_button.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\native_button_win.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\native_button_win.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\native_button_wrapper.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\radio_button.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\radio_button.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\text_button.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\button\text_button.h"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="scrollbar"
+				>
+				<File
+					RelativePath=".\controls\scrollbar\bitmap_scroll_bar.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\scrollbar\bitmap_scroll_bar.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\scrollbar\native_scroll_bar.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\scrollbar\native_scroll_bar.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\scrollbar\scroll_bar.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\scrollbar\scroll_bar.h"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="tree"
+				>
+				<File
+					RelativePath=".\controls\tree\tree_model.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\tree\tree_node_iterator.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\tree\tree_node_model.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\tree\tree_view.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\tree\tree_view.h"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="table"
+				>
+				<File
+					RelativePath=".\controls\table\group_table_view.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\table\group_table_view.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\table\table_view.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\table\table_view.h"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="menu"
+				>
+				<File
+					RelativePath=".\controls\menu\chrome_menu.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\menu\chrome_menu.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\menu\controller.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\menu\menu.cc"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\menu\menu.h"
+					>
+				</File>
+				<File
+					RelativePath=".\controls\menu\view_menu_delegate.h"
+					>
+				</File>
+			</Filter>
+		</Filter>
+		<File
+			RelativePath=".\accelerator.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\accelerator.h"
+			>
+		</File>
+		<File
+			RelativePath=".\background.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\background.h"
+			>
+		</File>
+		<File
+			RelativePath=".\border.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\border.h"
+			>
+		</File>
+		<File
+			RelativePath=".\event.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\event.h"
+			>
+		</File>
+		<File
+			RelativePath=".\event_win.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\fill_layout.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\fill_layout.h"
+			>
+		</File>
+		<File
+			RelativePath=".\grid_layout.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\grid_layout.h"
+			>
+		</File>
+		<File
+			RelativePath=".\layout_manager.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\layout_manager.h"
+			>
+		</File>
+		<File
+			RelativePath=".\painter.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\painter.h"
+			>
+		</File>
+		<File
+			RelativePath="$(SolutionDir)\tools\build\win\precompiled_wtl.cc"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="1"
+				/>
+			</FileConfiguration>
+		</File>
+		<File
+			RelativePath="$(SolutionDir)\tools\build\win\precompiled_wtl.h"
+			>
+		</File>
+		<File
+			RelativePath=".\repeat_controller.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\repeat_controller.h"
+			>
+		</File>
+		<File
+			RelativePath=".\view.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\view.h"
+			>
+		</File>
+		<File
+			RelativePath=".\view_constants.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\view_constants.h"
+			>
+		</File>
+		<File
+			RelativePath=".\view_win.cc"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/views/views.vsprops b/views/views.vsprops
new file mode 100644
index 0000000..72a6e0d
--- /dev/null
+++ b/views/views.vsprops
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="views"
+        InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)third_party\wtl\using_wtl.vsprops;$(SolutionDir)..\skia\using_skia.vsprops;$(SolutionDir)..\tools\grit\build\using_generated_resources.vsprops"
+	>
+	<Tool
+		Name="VCCLCompilerTool"
+		AdditionalIncludeDirectories="..\..\;&quot;$(IntDir)\..\generated_resources\&quot;"
+	/>
+</VisualStudioPropertySheet>
diff --git a/views/widget/accelerator_handler.cc b/views/widget/accelerator_handler.cc
new file mode 100644
index 0000000..386357f
--- /dev/null
+++ b/views/widget/accelerator_handler.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2006-2008 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 "views/widget/accelerator_handler.h"
+
+#include "views/focus/focus_manager.h"
+
+namespace views {
+
+AcceleratorHandler::AcceleratorHandler() {
+}
+
+bool AcceleratorHandler::Dispatch(const MSG& msg) {
+  bool process_message = true;
+
+  if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) {
+    FocusManager* focus_manager = FocusManager::GetFocusManager(msg.hwnd);
+    if (focus_manager) {
+      // FocusManager::OnKeyDown and OnKeyUp return false if this message has
+      // been consumed and should not be propagated further.
+      switch (msg.message) {
+        case WM_KEYDOWN:
+        case WM_SYSKEYDOWN:
+          process_message = focus_manager->OnKeyDown(msg.hwnd, msg.message,
+              msg.wParam, msg.lParam);
+          break;
+
+        case WM_KEYUP:
+        case WM_SYSKEYUP:
+          process_message = focus_manager->OnKeyUp(msg.hwnd, msg.message,
+              msg.wParam, msg.lParam);
+          break;
+      }
+    }
+  }
+
+  if (process_message) {
+    TranslateMessage(&msg);
+    DispatchMessage(&msg);
+  }
+
+  return true;
+}
+
+}  // namespace views
diff --git a/views/widget/accelerator_handler.h b/views/widget/accelerator_handler.h
new file mode 100644
index 0000000..5ee896cb
--- /dev/null
+++ b/views/widget/accelerator_handler.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2006-2008 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 VIEWS_WIDGET_ACCELERATOR_HANDLER_H_
+#define VIEWS_WIDGET_ACCELERATOR_HANDLER_H_
+
+#include "base/message_loop.h"
+
+namespace views {
+
+// This class delegates WM_KEYDOWN and WM_SYSKEYDOWN messages to
+// the associated FocusManager class for the window that is receiving
+// these messages for accelerator processing. The BrowserProcess object
+// holds a singleton instance of this class which can be used by other
+// custom message loop dispatcher objects to implement default accelerator
+// handling.
+class AcceleratorHandler : public MessageLoopForUI::Dispatcher {
+ public:
+   AcceleratorHandler();
+  // Dispatcher method. This returns true if an accelerator was
+  // processed by the focus manager
+  virtual bool Dispatch(const MSG& msg);
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(AcceleratorHandler);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_WIDGET_ACCELERATOR_HANDLER_H_
diff --git a/views/widget/aero_tooltip_manager.cc b/views/widget/aero_tooltip_manager.cc
new file mode 100644
index 0000000..ca58c24
--- /dev/null
+++ b/views/widget/aero_tooltip_manager.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2006-2008 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 "views/widget/aero_tooltip_manager.h"
+
+#include <windows.h>
+#include <atlbase.h>
+#include <atlapp.h>  // for GET_X/Y_LPARAM
+#include <commctrl.h>
+#include <shlobj.h>
+
+#include "app/l10n_util_win.h"
+#include "base/message_loop.h"
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+// AeroTooltipManager, public:
+
+AeroTooltipManager::AeroTooltipManager(Widget* widget, HWND parent)
+    : TooltipManager(widget, parent),
+      initial_delay_(0) {
+}
+
+AeroTooltipManager::~AeroTooltipManager() {
+  if (initial_timer_)
+    initial_timer_->Disown();
+}
+
+void AeroTooltipManager::OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param) {
+  if (initial_timer_)
+    initial_timer_->Disown();
+
+  if (u_msg == WM_MOUSEMOVE || u_msg == WM_NCMOUSEMOVE) {
+    int x = GET_X_LPARAM(l_param);
+    int y = GET_Y_LPARAM(l_param);
+    if (last_mouse_x_ != x || last_mouse_y_ != y) {
+      last_mouse_x_ = x;
+      last_mouse_y_ = y;
+      HideKeyboardTooltip();
+      UpdateTooltip(x, y);
+    }
+
+    // Delay opening of the tooltip just in case the user moves their
+    // mouse to another control. We defer this from Init because we get
+    // zero if we query it too soon.
+    if (!initial_delay_) {
+      initial_delay_ = static_cast<int>(
+          ::SendMessage(tooltip_hwnd_, TTM_GETDELAYTIME, TTDT_INITIAL, 0));
+    }
+    initial_timer_ = new InitialTimer(this, initial_delay_);
+  } else {
+    // Hide the tooltip and cancel any timers.
+    ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+    ::SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, false, (LPARAM)&toolinfo_);
+    return;
+  }
+}
+
+void AeroTooltipManager::OnMouseLeave() {
+  last_mouse_x_ = last_mouse_y_ = -1;
+  UpdateTooltip();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// AeroTooltipManager, private:
+
+void AeroTooltipManager::Init() {
+  // Create the tooltip control.
+  tooltip_hwnd_ = CreateWindowEx(
+      WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+      TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0,
+      parent_, NULL, NULL, NULL);
+
+  l10n_util::AdjustUIFontForWindow(tooltip_hwnd_);
+
+  // Add one tool that is used for all tooltips.
+  toolinfo_.cbSize = sizeof(toolinfo_);
+
+  // We use tracking tooltips on Vista to allow us to manually control the
+  // visibility of the tooltip.
+  toolinfo_.uFlags = TTF_TRANSPARENT | TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
+  toolinfo_.hwnd = parent_;
+  toolinfo_.uId = (UINT_PTR)parent_;
+
+  // Setting this tells windows to call parent_ back (using a WM_NOTIFY
+  // message) for the actual tooltip contents.
+  toolinfo_.lpszText = LPSTR_TEXTCALLBACK;
+  SetRectEmpty(&toolinfo_.rect);
+  ::SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, (LPARAM)&toolinfo_);
+}
+
+void AeroTooltipManager::OnTimer() {
+  initial_timer_ = NULL;
+
+  POINT pt;
+  pt.x = last_mouse_x_;
+  pt.y = last_mouse_y_;
+  ::ClientToScreen(parent_, &pt);
+
+  // Set the position and visibility.
+  if (!tooltip_showing_) {
+    ::SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
+    ::SendMessage(tooltip_hwnd_, TTM_TRACKPOSITION, 0, MAKELPARAM(pt.x, pt.y));
+    ::SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, true, (LPARAM)&toolinfo_);
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// AeroTooltipManager::InitialTimer
+
+AeroTooltipManager::InitialTimer::InitialTimer(AeroTooltipManager* manager,
+                                               int time) : manager_(manager) {
+  MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(
+      this, &InitialTimer::Execute), time);
+}
+
+void AeroTooltipManager::InitialTimer::Disown() {
+  manager_ = NULL;
+}
+
+void AeroTooltipManager::InitialTimer::Execute() {
+  if (manager_)
+    manager_->OnTimer();
+}
+
+}  // namespace views
diff --git a/views/widget/aero_tooltip_manager.h b/views/widget/aero_tooltip_manager.h
new file mode 100644
index 0000000..fe5856d
--- /dev/null
+++ b/views/widget/aero_tooltip_manager.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2006-2008 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 VIEWS_WIDGET_AERO_TOOLTIP_MANAGER_H_
+#define VIEWS_WIDGET_AERO_TOOLTIP_MANAGER_H_
+
+#include "base/ref_counted.h"
+#include "base/task.h"
+#include "views/widget/tooltip_manager.h"
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+// AeroTooltipManager
+//
+//  Default Windows tooltips are broken when using our custom window frame
+//  - as soon as the tooltip receives a WM_MOUSEMOVE event, it starts spewing
+//  NCHITTEST messages at its parent window (us). These messages have random
+//  x/y coordinates and can't be ignored, as the DwmDefWindowProc uses
+//  NCHITTEST  messages to determine how to highlight the caption buttons
+//  (the buttons then flicker as the hit tests sent by the user's mouse
+//  trigger different effects to those sent by the tooltip).
+//
+//  So instead, we have to partially implement tooltips ourselves using
+//  TTF_TRACKed tooltips.
+//
+// TODO(glen): Resolve this with Microsoft.
+class AeroTooltipManager : public TooltipManager {
+ public:
+  AeroTooltipManager(Widget* widget, HWND parent);
+  virtual ~AeroTooltipManager();
+
+  virtual void OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param);
+  virtual void OnMouseLeave();
+
+ private:
+  void Init();
+  void OnTimer();
+
+  class InitialTimer : public base::RefCounted<InitialTimer> {
+   public:
+    InitialTimer(AeroTooltipManager* manager, int time);
+    void Disown();
+    void Execute();
+
+   private:
+    AeroTooltipManager* manager_;
+  };
+
+  int initial_delay_;
+  scoped_refptr<InitialTimer> initial_timer_;
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_WIDGET_AERO_TOOLTIP_MANAGER_H_
diff --git a/views/widget/root_view.cc b/views/widget/root_view.cc
new file mode 100644
index 0000000..fd9f1c0
--- /dev/null
+++ b/views/widget/root_view.cc
@@ -0,0 +1,1001 @@
+// Copyright (c) 2006-2008 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 "views/widget/root_view.h"
+
+#include <algorithm>
+
+#include "app/drag_drop_types.h"
+#include "app/gfx/chrome_canvas.h"
+#if defined(OS_WIN)
+#include "base/base_drag_source.h"
+#endif
+#include "base/logging.h"
+#include "base/message_loop.h"
+#if defined(OS_WIN)
+#include "views/focus/view_storage.h"
+#include "views/widget/root_view_drop_target.h"
+#endif
+#include "views/widget/widget.h"
+#include "views/window/window.h"
+
+namespace views {
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// A Task to trigger non urgent painting.
+//
+/////////////////////////////////////////////////////////////////////////////
+class PaintTask : public Task {
+ public:
+  explicit PaintTask(RootView* target) : root_view_(target) {
+  }
+
+  ~PaintTask() {}
+
+  void Cancel() {
+    root_view_ = NULL;
+  }
+
+  void Run() {
+    if (root_view_)
+      root_view_->PaintNow();
+  }
+ private:
+  // The target root view.
+  RootView* root_view_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(PaintTask);
+};
+
+const char RootView::kViewClassName[] = "views/RootView";
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RootView - constructors, destructors, initialization
+//
+/////////////////////////////////////////////////////////////////////////////
+
+RootView::RootView(Widget* widget)
+  : mouse_pressed_handler_(NULL),
+    mouse_move_handler_(NULL),
+    last_click_handler_(NULL),
+    widget_(widget),
+    invalid_rect_urgent_(false),
+    pending_paint_task_(NULL),
+    paint_task_needed_(false),
+    explicit_mouse_handler_(false),
+#if defined(OS_WIN)
+    previous_cursor_(NULL),
+#endif
+    default_keyboard_handler_(NULL),
+    focus_listener_(NULL),
+    focus_on_mouse_pressed_(false),
+    ignore_set_focus_calls_(false),
+    focus_traversable_parent_(NULL),
+    focus_traversable_parent_view_(NULL),
+    drag_view_(NULL)
+#ifndef NDEBUG
+    ,
+    is_processing_paint_(false)
+#endif
+{
+}
+
+RootView::~RootView() {
+  // If we have children remove them explicitly so to make sure a remove
+  // notification is sent for each one of them.
+  if (!child_views_.empty())
+    RemoveAllChildViews(true);
+
+  if (pending_paint_task_)
+    pending_paint_task_->Cancel();  // Ensure we're not called any more.
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RootView - layout, painting
+//
+/////////////////////////////////////////////////////////////////////////////
+
+void RootView::SchedulePaint(const gfx::Rect& r, bool urgent) {
+  // If there is an existing invalid rect, add the union of the scheduled
+  // rect with the invalid rect. This could be optimized further if
+  // necessary.
+  if (invalid_rect_.IsEmpty())
+    invalid_rect_ = r;
+  else
+    invalid_rect_ = invalid_rect_.Union(r);
+
+  if (urgent || invalid_rect_urgent_) {
+    invalid_rect_urgent_ = true;
+  } else {
+    if (!pending_paint_task_) {
+      pending_paint_task_ = new PaintTask(this);
+      MessageLoop::current()->PostTask(FROM_HERE, pending_paint_task_);
+    }
+    paint_task_needed_ = true;
+  }
+}
+
+void RootView::SchedulePaint() {
+  View::SchedulePaint();
+}
+
+void RootView::SchedulePaint(int x, int y, int w, int h) {
+  View::SchedulePaint();
+}
+
+#ifndef NDEBUG
+// Sets the value of RootView's |is_processing_paint_| member to true as long
+// as ProcessPaint is being called. Sets it to |false| when it returns.
+class ScopedProcessingPaint {
+ public:
+  explicit ScopedProcessingPaint(bool* is_processing_paint)
+      : is_processing_paint_(is_processing_paint) {
+    *is_processing_paint_ = true;
+  }
+
+  ~ScopedProcessingPaint() {
+    *is_processing_paint_ = false;
+  }
+ private:
+  bool* is_processing_paint_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ScopedProcessingPaint);
+};
+#endif
+
+void RootView::ProcessPaint(ChromeCanvas* canvas) {
+#ifndef NDEBUG
+  ScopedProcessingPaint processing_paint(&is_processing_paint_);
+#endif
+
+  // Clip the invalid rect to our bounds. If a view is in a scrollview
+  // it could be a lot larger
+  invalid_rect_ = GetScheduledPaintRectConstrainedToSize();
+
+  if (invalid_rect_.IsEmpty())
+    return;
+
+  // Clear the background.
+  canvas->drawColor(SK_ColorBLACK, SkPorterDuff::kClear_Mode);
+
+  // Save the current transforms.
+  canvas->save();
+
+  // Set the clip rect according to the invalid rect.
+  int clip_x = invalid_rect_.x() + x();
+  int clip_y = invalid_rect_.y() + y();
+  canvas->ClipRectInt(clip_x, clip_y, invalid_rect_.width(),
+                      invalid_rect_.height());
+
+  // Paint the tree
+  View::ProcessPaint(canvas);
+
+  // Restore the previous transform
+  canvas->restore();
+
+  ClearPaintRect();
+}
+
+void RootView::PaintNow() {
+  if (pending_paint_task_) {
+    pending_paint_task_->Cancel();
+    pending_paint_task_ = NULL;
+  }
+  if (!paint_task_needed_)
+    return;
+  Widget* widget = GetWidget();
+  if (widget)
+    widget->PaintNow(invalid_rect_);
+}
+
+bool RootView::NeedsPainting(bool urgent) {
+  bool has_invalid_rect = !invalid_rect_.IsEmpty();
+  if (urgent) {
+    if (invalid_rect_urgent_)
+      return has_invalid_rect;
+    else
+      return false;
+  } else {
+    return has_invalid_rect;
+  }
+}
+
+const gfx::Rect& RootView::GetScheduledPaintRect() {
+  return invalid_rect_;
+}
+
+gfx::Rect RootView::GetScheduledPaintRectConstrainedToSize() {
+  if (invalid_rect_.IsEmpty())
+    return invalid_rect_;
+
+  return invalid_rect_.Intersect(GetLocalBounds(true));
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RootView - tree
+//
+/////////////////////////////////////////////////////////////////////////////
+
+Widget* RootView::GetWidget() const {
+  return widget_;
+}
+
+void RootView::ThemeChanged() {
+  View::ThemeChanged();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RootView - event dispatch and propagation
+//
+/////////////////////////////////////////////////////////////////////////////
+
+void RootView::ViewHierarchyChanged(bool is_add, View* parent, View* child) {
+  if (!is_add) {
+    if (!explicit_mouse_handler_ && mouse_pressed_handler_ == child) {
+      mouse_pressed_handler_ = NULL;
+    }
+
+#if defined(OS_WIN)
+    if (drop_target_.get())
+      drop_target_->ResetTargetViewIfEquals(child);
+#else
+    NOTIMPLEMENTED();
+#endif
+
+    if (mouse_move_handler_ == child) {
+      mouse_move_handler_ = NULL;
+    }
+
+    if (GetFocusedView() == child) {
+      FocusView(NULL);
+    }
+
+    if (child == drag_view_)
+      drag_view_ = NULL;
+
+    if (default_keyboard_handler_ == child) {
+      default_keyboard_handler_ = NULL;
+    }
+
+    // For a given widget hierarchy, focus is tracked by a FocusManager attached
+    // to our nearest enclosing Window. <-- Important Assumption!
+    // We may not have access to our window if this function is called as a
+    // result of teardown during the deletion of the RootView and its hierarchy,
+    // so we don't bother notifying the FocusManager in that case because it
+    // will have already been destroyed (the Widget that contains us is
+    // NCDESTROY'ed which in turn destroys the focus manager _before_ the
+    // RootView is deleted.)
+#if defined(OS_WIN)
+    Window* window = GetWindow();
+    if (window) {
+      FocusManager* focus_manager =
+          FocusManager::GetFocusManager(window->GetNativeWindow());
+      focus_manager->ViewRemoved(parent, child);
+    }
+    ViewStorage::GetSharedInstance()->ViewRemoved(parent, child);
+#endif
+  }
+}
+
+void RootView::SetFocusOnMousePressed(bool f) {
+  focus_on_mouse_pressed_ = f;
+}
+
+bool RootView::OnMousePressed(const MouseEvent& e) {
+  // This function does not normally handle non-client messages except for
+  // non-client double-clicks. Actually, all double-clicks are special as the
+  // are formed from a single-click followed by a double-click event. When the
+  // double-click event lands on a different view than its single-click part,
+  // we transform it into a single-click which prevents odd things.
+  if ((e.GetFlags() & MouseEvent::EF_IS_NON_CLIENT) &&
+      !(e.GetFlags() & MouseEvent::EF_IS_DOUBLE_CLICK)) {
+    last_click_handler_ = NULL;
+    return false;
+  }
+
+  UpdateCursor(e);
+  SetMouseLocationAndFlags(e);
+
+  // If mouse_pressed_handler_ is non null, we are currently processing
+  // a pressed -> drag -> released session. In that case we send the
+  // event to mouse_pressed_handler_
+  if (mouse_pressed_handler_) {
+    MouseEvent mouse_pressed_event(e, this, mouse_pressed_handler_);
+    drag_info.Reset();
+    mouse_pressed_handler_->ProcessMousePressed(mouse_pressed_event,
+                                                &drag_info);
+    return true;
+  }
+  DCHECK(!explicit_mouse_handler_);
+
+  bool hit_disabled_view = false;
+  // Walk up the tree until we find a view that wants the mouse event.
+  for (mouse_pressed_handler_ = GetViewForPoint(e.location());
+       mouse_pressed_handler_ && (mouse_pressed_handler_ != this);
+       mouse_pressed_handler_ = mouse_pressed_handler_->GetParent()) {
+    if (!mouse_pressed_handler_->IsEnabled()) {
+      // Disabled views should eat events instead of propagating them upwards.
+      hit_disabled_view = true;
+      break;
+    }
+
+    // See if this view wants to handle the mouse press.
+    MouseEvent mouse_pressed_event(e, this, mouse_pressed_handler_);
+
+    // Remove the double-click flag if the handler is different than the
+    // one which got the first click part of the double-click.
+    if (mouse_pressed_handler_ != last_click_handler_)
+      mouse_pressed_event.set_flags(e.GetFlags() &
+                                    ~MouseEvent::EF_IS_DOUBLE_CLICK);
+
+    drag_info.Reset();
+    bool handled = mouse_pressed_handler_->ProcessMousePressed(
+        mouse_pressed_event, &drag_info);
+
+    // The view could have removed itself from the tree when handling
+    // OnMousePressed().  In this case, the removal notification will have
+    // reset mouse_pressed_handler_ to NULL out from under us.  Detect this
+    // case and stop.  (See comments in view.h.)
+    //
+    // NOTE: Don't return true here, because we don't want the frame to
+    // forward future events to us when there's no handler.
+    if (!mouse_pressed_handler_)
+      break;
+
+    // If the view handled the event, leave mouse_pressed_handler_ set and
+    // return true, which will cause subsequent drag/release events to get
+    // forwarded to that view.
+    if (handled) {
+      last_click_handler_ = mouse_pressed_handler_;
+      return true;
+    }
+  }
+
+  // Reset mouse_pressed_handler_ to indicate that no processing is occurring.
+  mouse_pressed_handler_ = NULL;
+
+  if (focus_on_mouse_pressed_) {
+#if defined(OS_WIN)
+    HWND hwnd = GetWidget()->GetNativeView();
+    if (::GetFocus() != hwnd) {
+      ::SetFocus(hwnd);
+    }
+#else
+    NOTIMPLEMENTED();
+#endif
+  }
+
+  // In the event that a double-click is not handled after traversing the
+  // entire hierarchy (even as a single-click when sent to a different view),
+  // it must be marked as handled to avoid anything happening from default
+  // processing if it the first click-part was handled by us.
+  if (last_click_handler_ && e.GetFlags() & MouseEvent::EF_IS_DOUBLE_CLICK)
+    hit_disabled_view = true;
+
+  last_click_handler_ = NULL;
+  return hit_disabled_view;
+}
+
+bool RootView::ConvertPointToMouseHandler(const gfx::Point& l,
+                                          gfx::Point* p) {
+  //
+  // If the mouse_handler was set explicitly, we need to keep
+  // sending events even if it was reparented in a different
+  // window. (a non explicit mouse handler is automatically
+  // cleared when the control is removed from the hierarchy)
+  if (explicit_mouse_handler_) {
+    if (mouse_pressed_handler_->GetWidget()) {
+      *p = l;
+      ConvertPointToScreen(this, p);
+      ConvertPointToView(NULL, mouse_pressed_handler_, p);
+    } else {
+      // If the mouse_pressed_handler_ is not connected, we send the
+      // event in screen coordinate system
+      *p = l;
+      ConvertPointToScreen(this, p);
+      return true;
+    }
+  } else {
+    *p = l;
+    ConvertPointToView(this, mouse_pressed_handler_, p);
+  }
+  return true;
+}
+
+bool RootView::OnMouseDragged(const MouseEvent& e) {
+  UpdateCursor(e);
+
+  if (mouse_pressed_handler_) {
+    SetMouseLocationAndFlags(e);
+
+    gfx::Point p;
+    ConvertPointToMouseHandler(e.location(), &p);
+    MouseEvent mouse_event(e.GetType(), p.x(), p.y(), e.GetFlags());
+    return mouse_pressed_handler_->ProcessMouseDragged(mouse_event, &drag_info);
+  }
+  return false;
+}
+
+void RootView::OnMouseReleased(const MouseEvent& e, bool canceled) {
+  UpdateCursor(e);
+
+  if (mouse_pressed_handler_) {
+    gfx::Point p;
+    ConvertPointToMouseHandler(e.location(), &p);
+    MouseEvent mouse_released(e.GetType(), p.x(), p.y(), e.GetFlags());
+    // We allow the view to delete us from ProcessMouseReleased. As such,
+    // configure state such that we're done first, then call View.
+    View* mouse_pressed_handler = mouse_pressed_handler_;
+    mouse_pressed_handler_ = NULL;
+    explicit_mouse_handler_ = false;
+    mouse_pressed_handler->ProcessMouseReleased(mouse_released, canceled);
+    // WARNING: we may have been deleted.
+  }
+}
+
+void RootView::OnMouseMoved(const MouseEvent& e) {
+  View* v = GetViewForPoint(e.location());
+  // Find the first enabled view.
+  while (v && !v->IsEnabled())
+    v = v->GetParent();
+  if (v && v != this) {
+    if (v != mouse_move_handler_) {
+      if (mouse_move_handler_ != NULL) {
+        MouseEvent exited_event(Event::ET_MOUSE_EXITED, 0, 0, 0);
+        mouse_move_handler_->OnMouseExited(exited_event);
+      }
+
+      mouse_move_handler_ = v;
+
+      MouseEvent entered_event(Event::ET_MOUSE_ENTERED,
+                               this,
+                               mouse_move_handler_,
+                               e.location(),
+                               0);
+      mouse_move_handler_->OnMouseEntered(entered_event);
+    }
+    MouseEvent moved_event(Event::ET_MOUSE_MOVED,
+                           this,
+                           mouse_move_handler_,
+                           e.location(),
+                           0);
+    mouse_move_handler_->OnMouseMoved(moved_event);
+
+#if defined(OS_WIN)
+    HCURSOR cursor = mouse_move_handler_->GetCursorForPoint(
+        moved_event.GetType(), moved_event.x(), moved_event.y());
+    if (cursor) {
+      previous_cursor_ = ::SetCursor(cursor);
+    } else if (previous_cursor_) {
+      ::SetCursor(previous_cursor_);
+      previous_cursor_ = NULL;
+    }
+#else
+    NOTIMPLEMENTED();
+#endif
+  } else if (mouse_move_handler_ != NULL) {
+    MouseEvent exited_event(Event::ET_MOUSE_EXITED, 0, 0, 0);
+    mouse_move_handler_->OnMouseExited(exited_event);
+#if defined(OS_WIN)
+    if (previous_cursor_) {
+      ::SetCursor(previous_cursor_);
+      previous_cursor_ = NULL;
+    }
+#else
+    NOTIMPLEMENTED();
+#endif
+  }
+}
+
+void RootView::ProcessOnMouseExited() {
+  if (mouse_move_handler_ != NULL) {
+    MouseEvent exited_event(Event::ET_MOUSE_EXITED, 0, 0, 0);
+    mouse_move_handler_->OnMouseExited(exited_event);
+    mouse_move_handler_ = NULL;
+  }
+}
+
+void RootView::SetMouseHandler(View *new_mh) {
+  // If we're clearing the mouse handler, clear explicit_mouse_handler as well.
+  explicit_mouse_handler_ = (new_mh != NULL);
+  mouse_pressed_handler_ = new_mh;
+}
+
+void RootView::OnWidgetCreated() {
+#if defined(OS_WIN)
+  DCHECK(!drop_target_.get());
+  drop_target_ = new RootViewDropTarget(this);
+#else
+  // TODO(port): Port RootViewDropTarget and this goes away.
+  NOTIMPLEMENTED();
+#endif
+}
+
+void RootView::OnWidgetDestroyed() {
+#if defined(OS_WIN)
+  if (drop_target_.get()) {
+    RevokeDragDrop(GetWidget()->GetNativeView());
+    drop_target_ = NULL;
+  }
+#else
+  // TODO(port): Port RootViewDropTarget and this goes away.
+  NOTIMPLEMENTED();
+#endif
+  widget_ = NULL;
+}
+
+void RootView::ProcessMouseDragCanceled() {
+  if (mouse_pressed_handler_) {
+    // Synthesize a release event.
+    MouseEvent release_event(Event::ET_MOUSE_RELEASED, last_mouse_event_x_,
+                             last_mouse_event_y_, last_mouse_event_flags_);
+    OnMouseReleased(release_event, true);
+  }
+}
+
+void RootView::SetFocusListener(FocusListener* listener) {
+  focus_listener_ = listener;
+}
+
+void RootView::FocusView(View* view) {
+  if (view != GetFocusedView()) {
+#if defined(OS_WIN)
+    FocusManager* focus_manager = GetFocusManager();
+    DCHECK(focus_manager) << "No Focus Manager for Window " <<
+        (GetWidget() ? GetWidget()->GetNativeView() : 0);
+    if (!focus_manager)
+      return;
+
+    View* prev_focused_view = focus_manager->GetFocusedView();
+    focus_manager->SetFocusedView(view);
+
+    if (focus_listener_)
+      focus_listener_->FocusChanged(prev_focused_view, view);
+#else
+    // TODO(port): Port the focus manager and this goes away.
+    NOTIMPLEMENTED();
+#endif
+  }
+}
+
+View* RootView::GetFocusedView() {
+  FocusManager* focus_manager = GetFocusManager();
+  if (!focus_manager) {
+    // We may not have a FocusManager when the window that contains us is being
+    // deleted. Sadly we cannot wait for the window to be destroyed before we
+    // remove the FocusManager (see xp_frame.cc for more info).
+    return NULL;
+  }
+
+  // Make sure the focused view belongs to this RootView's view hierarchy.
+  View* view = focus_manager->GetFocusedView();
+  if (view && (view->GetRootView() == this))
+    return view;
+  return NULL;
+}
+
+View* RootView::FindNextFocusableView(View* starting_view,
+                                      bool reverse,
+                                      Direction direction,
+                                      bool dont_loop,
+                                      FocusTraversable** focus_traversable,
+                                      View** focus_traversable_view) {
+  *focus_traversable = NULL;
+  *focus_traversable_view = NULL;
+
+  if (GetChildViewCount() == 0) {
+    NOTREACHED();
+    // Nothing to focus on here.
+    return NULL;
+  }
+
+  bool skip_starting_view = true;
+  if (!starting_view) {
+    // Default to the first/last child
+    starting_view = reverse ? GetChildViewAt(GetChildViewCount() - 1) :
+                              GetChildViewAt(0) ;
+    // If there was no starting view, then the one we select is a potential
+    // focus candidate.
+    skip_starting_view = false;
+  } else {
+    // The starting view should be part of this RootView.
+    DCHECK(IsParentOf(starting_view));
+  }
+
+  View* v = NULL;
+  if (!reverse) {
+    v = FindNextFocusableViewImpl(starting_view, skip_starting_view,
+                                  true,
+                                  (direction == DOWN) ? true : false,
+                                  starting_view->GetGroup());
+  } else {
+    // If the starting view is focusable, we don't want to go down, as we are
+    // traversing the view hierarchy tree bottom-up.
+    bool can_go_down = (direction == DOWN) && !starting_view->IsFocusable();
+    v = FindPreviousFocusableViewImpl(starting_view, true,
+                                      true,
+                                      can_go_down,
+                                      starting_view->GetGroup());
+  }
+  if (v) {
+    if (v->IsFocusable())
+      return v;
+    *focus_traversable = v->GetFocusTraversable();
+    DCHECK(*focus_traversable);
+    *focus_traversable_view = v;
+    return NULL;
+  }
+  // Nothing found.
+  return NULL;
+}
+
+// Strategy for finding the next focusable view:
+// - keep going down the first child, stop when you find a focusable view or
+//   a focus traversable view (in that case return it) or when you reach a view
+//   with no children.
+// - go to the right sibling and start the search from there (by invoking
+//   FindNextFocusableViewImpl on that view).
+// - if the view has no right sibling, go up the parents until you find a parent
+//   with a right sibling and start the search from there.
+View* RootView::FindNextFocusableViewImpl(View* starting_view,
+                                          bool skip_starting_view,
+                                          bool can_go_up,
+                                          bool can_go_down,
+                                          int skip_group_id) {
+  if (!skip_starting_view) {
+    if (IsViewFocusableCandidate(starting_view, skip_group_id))
+      return FindSelectedViewForGroup(starting_view);
+    if (starting_view->GetFocusTraversable())
+      return starting_view;
+  }
+
+  // First let's try the left child.
+  if (can_go_down) {
+    View* v = NULL;
+    if (starting_view->GetChildViewCount() > 0) {
+      // We are only interested in non floating-views, as attached floating
+      // views order is variable (depending on mouse moves).
+      for (int i = 0; i < starting_view->GetChildViewCount(); i++) {
+        View* child = starting_view->GetChildViewAt(i);
+        if (!child->IsFloatingView()) {
+          v = FindNextFocusableViewImpl(child, false, false, true,
+                                        skip_group_id);
+          break;
+        }
+      }
+    }
+    if (v == NULL) {
+      // Try the floating views.
+      int id = 0;
+      if (starting_view->EnumerateFloatingViews(View::FIRST, 0, &id)) {
+        View* child = starting_view->RetrieveFloatingViewForID(id);
+        DCHECK(child);
+        v = FindNextFocusableViewImpl(child, false, false, true, skip_group_id);
+      }
+    }
+    if (v)
+      return v;
+  }
+
+  // Then try the right sibling.
+  View* sibling = NULL;
+  if (starting_view->IsFloatingView()) {
+    int id = 0;
+    if (starting_view->GetParent()->EnumerateFloatingViews(
+        View::NEXT, starting_view->GetFloatingViewID(), &id)) {
+      sibling = starting_view->GetParent()->RetrieveFloatingViewForID(id);
+      DCHECK(sibling);
+    }
+  } else {
+    sibling = starting_view->GetNextFocusableView();
+    if (!sibling) {
+      // Let's try floating views.
+      int id = 0;
+      if (starting_view->GetParent()->EnumerateFloatingViews(View::FIRST,
+                                                             0, &id)) {
+        sibling = starting_view->GetParent()->RetrieveFloatingViewForID(id);
+        DCHECK(sibling);
+      }
+    }
+  }
+  if (sibling) {
+    View* v =
+        FindNextFocusableViewImpl(sibling, false, false, true, skip_group_id);
+    if (v)
+      return v;
+  }
+
+  // Then go up to the parent sibling.
+  if (can_go_up) {
+    View* parent = starting_view->GetParent();
+    while (parent) {
+      int id = 0;
+      if (parent->IsFloatingView() &&
+          parent->GetParent()->EnumerateFloatingViews(
+                View::NEXT, parent->GetFloatingViewID(), &id)) {
+        sibling = parent->GetParent()->RetrieveFloatingViewForID(id);
+        DCHECK(sibling);
+      } else {
+        sibling = parent->GetNextFocusableView();
+      }
+      if (sibling) {
+        return FindNextFocusableViewImpl(sibling,
+                                         false, true, true,
+                                         skip_group_id);
+      }
+      parent = parent->GetParent();
+    }
+  }
+
+  // We found nothing.
+  return NULL;
+}
+
+// Strategy for finding the previous focusable view:
+// - keep going down on the right until you reach a view with no children, if it
+//   it is a good candidate return it.
+// - start the search on the left sibling.
+// - if there are no left sibling, start the search on the parent (without going
+//   down).
+View* RootView::FindPreviousFocusableViewImpl(View* starting_view,
+                                              bool skip_starting_view,
+                                              bool can_go_up,
+                                              bool can_go_down,
+                                              int skip_group_id) {
+  // Let's go down and right as much as we can.
+  if (can_go_down) {
+    View* v = NULL;
+    if (starting_view->GetChildViewCount() -
+        starting_view->GetFloatingViewCount() > 0) {
+      View* view =
+          starting_view->GetChildViewAt(starting_view->GetChildViewCount() - 1);
+      v = FindPreviousFocusableViewImpl(view, false, false, true,
+                                        skip_group_id);
+    } else {
+      // Let's try floating views.
+      int id = 0;
+      if (starting_view->EnumerateFloatingViews(View::LAST, 0, &id)) {
+        View* child = starting_view->RetrieveFloatingViewForID(id);
+        DCHECK(child);
+        v = FindNextFocusableViewImpl(child, false, false, true, skip_group_id);
+      }
+    }
+    if (v)
+      return v;
+  }
+
+  if (!skip_starting_view) {
+    if (IsViewFocusableCandidate(starting_view, skip_group_id))
+      return FindSelectedViewForGroup(starting_view);
+    if (starting_view->GetFocusTraversable())
+      return starting_view;
+  }
+
+  // Then try the left sibling.
+  View* sibling = NULL;
+  if (starting_view->IsFloatingView()) {
+    int id = 0;
+    if (starting_view->GetParent()->EnumerateFloatingViews(
+        View::PREVIOUS, starting_view->GetFloatingViewID(), &id)) {
+      sibling = starting_view->GetParent()->RetrieveFloatingViewForID(id);
+      DCHECK(sibling);
+    }
+    if (!sibling) {
+      // No more floating views, try regular views, starting at the last one.
+      View* parent = starting_view->GetParent();
+      for (int i = parent->GetChildViewCount() - 1; i >= 0; i--) {
+        View* v = parent->GetChildViewAt(i);
+        if (!v->IsFloatingView()) {
+          sibling = v;
+          break;
+        }
+      }
+    }
+  } else {
+    sibling = starting_view->GetPreviousFocusableView();
+  }
+  if (sibling) {
+    return FindPreviousFocusableViewImpl(sibling,
+                                         false, true, true,
+                                         skip_group_id);
+  }
+
+  // Then go up the parent.
+  if (can_go_up) {
+    View* parent = starting_view->GetParent();
+    if (parent)
+      return FindPreviousFocusableViewImpl(parent,
+                                           false, true, false,
+                                           skip_group_id);
+  }
+
+  // We found nothing.
+  return NULL;
+}
+
+FocusTraversable* RootView::GetFocusTraversableParent() {
+  return focus_traversable_parent_;
+}
+
+void RootView::SetFocusTraversableParent(FocusTraversable* focus_traversable) {
+  DCHECK(focus_traversable != this);
+  focus_traversable_parent_ = focus_traversable;
+}
+
+View* RootView::GetFocusTraversableParentView() {
+  return focus_traversable_parent_view_;
+}
+
+void RootView::SetFocusTraversableParentView(View* view) {
+  focus_traversable_parent_view_ = view;
+}
+
+// static
+View* RootView::FindSelectedViewForGroup(View* view) {
+  if (view->IsGroupFocusTraversable() ||
+      view->GetGroup() == -1)  // No group for that view.
+    return view;
+
+  View* selected_view = view->GetSelectedViewForGroup(view->GetGroup());
+  if (selected_view)
+    return selected_view;
+
+  // No view selected for that group, default to the specified view.
+  return view;
+}
+
+// static
+bool RootView::IsViewFocusableCandidate(View* v, int skip_group_id) {
+  return v->IsFocusable() &&
+      (v->IsGroupFocusTraversable() || skip_group_id == -1 ||
+       v->GetGroup() != skip_group_id);
+}
+
+bool RootView::ProcessKeyEvent(const KeyEvent& event) {
+  bool consumed = false;
+
+  View* v = GetFocusedView();
+#if defined(OS_WIN)
+  // Special case to handle right-click context menus triggered by the
+  // keyboard.
+  if (v && v->IsEnabled() && ((event.GetCharacter() == VK_APPS) ||
+      (event.GetCharacter() == VK_F10 && event.IsShiftDown()))) {
+    gfx::Point screen_loc = v->GetKeyboardContextMenuLocation();
+    v->ShowContextMenu(screen_loc.x(), screen_loc.y(), false);
+    return true;
+  }
+#else
+  // TODO(port): The above block needs the VK_* refactored out.
+  NOTIMPLEMENTED();
+#endif
+
+  for (; v && v != this && !consumed; v = v->GetParent()) {
+    consumed = (event.GetType() == Event::ET_KEY_PRESSED) ?
+        v->OnKeyPressed(event) : v->OnKeyReleased(event);
+  }
+
+  if (!consumed && default_keyboard_handler_) {
+    consumed = (event.GetType() == Event::ET_KEY_PRESSED) ?
+        default_keyboard_handler_->OnKeyPressed(event) :
+        default_keyboard_handler_->OnKeyReleased(event);
+  }
+
+  return consumed;
+}
+
+bool RootView::ProcessMouseWheelEvent(const MouseWheelEvent& e) {
+  View* v;
+  bool consumed = false;
+  if (GetFocusedView()) {
+    for (v = GetFocusedView();
+         v && v != this && !consumed; v = v->GetParent()) {
+      consumed = v->OnMouseWheel(e);
+    }
+  }
+
+  if (!consumed && default_keyboard_handler_) {
+    consumed = default_keyboard_handler_->OnMouseWheel(e);
+  }
+  return consumed;
+}
+
+void RootView::SetDefaultKeyboardHandler(View* v) {
+  default_keyboard_handler_ = v;
+}
+
+bool RootView::IsVisibleInRootView() const {
+  return IsVisible();
+}
+
+void RootView::ViewBoundsChanged(View* view, bool size_changed,
+                                 bool position_changed) {
+  DCHECK(view && (size_changed || position_changed));
+  if (!view->descendants_to_notify_.get())
+    return;
+
+  for (std::vector<View*>::iterator i = view->descendants_to_notify_->begin();
+       i != view->descendants_to_notify_->end(); ++i) {
+    (*i)->VisibleBoundsInRootChanged();
+  }
+}
+
+void RootView::RegisterViewForVisibleBoundsNotification(View* view) {
+  DCHECK(view);
+  if (view->registered_for_visible_bounds_notification_)
+    return;
+  view->registered_for_visible_bounds_notification_ = true;
+  View* ancestor = view->GetParent();
+  while (ancestor) {
+    ancestor->AddDescendantToNotify(view);
+    ancestor = ancestor->GetParent();
+  }
+}
+
+void RootView::UnregisterViewForVisibleBoundsNotification(View* view) {
+  DCHECK(view);
+  if (!view->registered_for_visible_bounds_notification_)
+    return;
+  view->registered_for_visible_bounds_notification_ = false;
+  View* ancestor = view->GetParent();
+  while (ancestor) {
+    ancestor->RemoveDescendantToNotify(view);
+    ancestor = ancestor->GetParent();
+  }
+}
+
+void RootView::SetMouseLocationAndFlags(const MouseEvent& e) {
+  last_mouse_event_flags_ = e.GetFlags();
+  last_mouse_event_x_ = e.x();
+  last_mouse_event_y_ = e.y();
+}
+
+std::string RootView::GetClassName() const {
+  return kViewClassName;
+}
+
+void RootView::ClearPaintRect() {
+  invalid_rect_.SetRect(0, 0, 0, 0);
+
+  // This painting has been done. Reset the urgent flag.
+  invalid_rect_urgent_ = false;
+
+  // If a pending_paint_task_ does Run(), we don't need to do anything.
+  paint_task_needed_ = false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RootView - accessibility
+//
+/////////////////////////////////////////////////////////////////////////////
+
+bool RootView::GetAccessibleRole(AccessibilityTypes::Role* role) {
+  DCHECK(role);
+
+  *role = AccessibilityTypes::ROLE_APPLICATION;
+  return true;
+}
+
+bool RootView::GetAccessibleName(std::wstring* name) {
+  if (!accessible_name_.empty()) {
+    *name = accessible_name_;
+    return true;
+  }
+  return false;
+}
+
+void RootView::SetAccessibleName(const std::wstring& name) {
+  accessible_name_.assign(name);
+}
+
+View* RootView::GetDragView() {
+  return drag_view_;
+}
+
+}  // namespace views
diff --git a/views/widget/root_view.h b/views/widget/root_view.h
new file mode 100644
index 0000000..d775ac15
--- /dev/null
+++ b/views/widget/root_view.h
@@ -0,0 +1,363 @@
+// Copyright (c) 2009 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 VIEWS_WIDGET_ROOT_VIEW_H_
+#define VIEWS_WIDGET_ROOT_VIEW_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_LINUX)
+#include <gtk/gtk.h>
+#endif
+
+#if defined(OS_WIN)
+#include "base/ref_counted.h"
+#endif
+
+#include "views/focus/focus_manager.h"
+#include "views/view.h"
+
+namespace views {
+
+class PaintTask;
+class RootViewDropTarget;
+class Widget;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// FocusListener Interface
+//
+////////////////////////////////////////////////////////////////////////////////
+class FocusListener {
+ public:
+  virtual void FocusChanged(View* lost_focus, View* got_focus) = 0;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RootView class
+//
+//   The RootView is the root of a View hierarchy. A RootView is always the
+//   first and only child of a Widget.
+//
+//   The RootView manages the View hierarchy's interface with the Widget
+//   and also maintains the current invalid rect - the region that needs
+//   repainting.
+//
+/////////////////////////////////////////////////////////////////////////////
+class RootView : public View,
+                 public FocusTraversable {
+ public:
+  static const char kViewClassName[];
+
+  explicit RootView(Widget* widget);
+
+  virtual ~RootView();
+
+  // Layout and Painting functions
+
+  // Overridden from View to implement paint scheduling.
+  virtual void SchedulePaint(const gfx::Rect& r, bool urgent);
+
+  // Convenience to schedule the whole view
+  virtual void SchedulePaint();
+
+  // Convenience to schedule a paint given some ints
+  virtual void SchedulePaint(int x, int y, int w, int h);
+
+  // Paint this RootView and its child Views.
+  virtual void ProcessPaint(ChromeCanvas* canvas);
+
+  // If the invalid rect is non-empty and there is a pending paint the RootView
+  // is painted immediately. This is internally invoked as the result of
+  // invoking SchedulePaint.
+  virtual void PaintNow();
+
+  // Whether or not this View needs repainting. If |urgent| is true, this method
+  // returns whether this root view needs to paint as soon as possible.
+  virtual bool NeedsPainting(bool urgent);
+
+  // Invoked by the Widget to discover what rectangle should be painted.
+  const gfx::Rect& GetScheduledPaintRect();
+
+  // Returns the region scheduled to paint clipped to the RootViews bounds.
+  gfx::Rect GetScheduledPaintRectConstrainedToSize();
+
+  // Tree functions
+
+  // Get the Widget that hosts this View.
+  virtual Widget* GetWidget() const;
+
+  // Public API for broadcasting theme change notifications to this View
+  // hierarchy.
+  virtual void ThemeChanged();
+
+  // The following event methods are overridden to propagate event to the
+  // control tree
+  virtual bool OnMousePressed(const MouseEvent& e);
+  virtual bool OnMouseDragged(const MouseEvent& e);
+  virtual void OnMouseReleased(const MouseEvent& e, bool canceled);
+  virtual void OnMouseMoved(const MouseEvent& e);
+  virtual void SetMouseHandler(View* new_mouse_handler);
+
+  // Invoked when the Widget has been fully initialized.
+  // At the time the constructor is invoked the Widget may not be completely
+  // initialized, when this method is invoked, it is.
+  void OnWidgetCreated();
+
+  // Invoked prior to the Widget being destroyed.
+  void OnWidgetDestroyed();
+
+  // Invoked By the Widget if the mouse drag is interrupted by
+  // the system. Invokes OnMouseReleased with a value of true for canceled.
+  void ProcessMouseDragCanceled();
+
+  // Invoked by the Widget instance when the mouse moves outside of the Widget
+  // bounds.
+  virtual void ProcessOnMouseExited();
+
+  // Make the provided view focused. Also make sure that our Widget is focused.
+  void FocusView(View* view);
+
+  // Check whether the provided view is in the focus path. The focus path is the
+  // path between the focused view (included) to the root view.
+  bool IsInFocusPath(View* view);
+
+  // Returns the View in this RootView hierarchy that has the focus, or NULL if
+  // no View currently has the focus.
+  View* GetFocusedView();
+
+  // Process a key event. Send the event to the focused view and up the focus
+  // path, and finally to the default keyboard handler, until someone consumes
+  // it.  Returns whether anyone consumed the event.
+  bool ProcessKeyEvent(const KeyEvent& event);
+
+  // Set the default keyboard handler. The default keyboard handler is
+  // a view that will get an opportunity to process key events when all
+  // views in the focus path did not process an event.
+  //
+  // Note: this is a single view at this point. We may want to make
+  // this a list if needed.
+  void SetDefaultKeyboardHandler(View* v);
+
+  // Set whether this root view should focus the corresponding hwnd
+  // when an unprocessed mouse event occurs.
+  void SetFocusOnMousePressed(bool f);
+
+  // Process a mousewheel event. Return true if the event was processed
+  // and false otherwise.
+  // MouseWheel events are sent on the focus path.
+  virtual bool ProcessMouseWheelEvent(const MouseWheelEvent& e);
+
+  // Overridden to handle special root view case.
+  virtual bool IsVisibleInRootView() const;
+
+  // Sets a listener that receives focus changes events.
+  void SetFocusListener(FocusListener* listener);
+
+  // FocusTraversable implementation.
+  virtual View* FindNextFocusableView(View* starting_view,
+                                      bool reverse,
+                                      Direction direction,
+                                      bool dont_loop,
+                                      FocusTraversable** focus_traversable,
+                                      View** focus_traversable_view);
+  virtual FocusTraversable* GetFocusTraversableParent();
+  virtual View* GetFocusTraversableParentView();
+
+  // Used to set the FocusTraversable parent after the view has been created
+  // (typically when the hierarchy changes and this RootView is added/removed).
+  virtual void SetFocusTraversableParent(FocusTraversable* focus_traversable);
+
+  // Used to set the View parent after the view has been created.
+  virtual void SetFocusTraversableParentView(View* view);
+
+  // Returns the name of this class: views/RootView
+  virtual std::string GetClassName() const;
+
+  // Clears the region that is schedule to be painted. You nearly never need
+  // to invoke this. This is primarily intended for Widgets.
+  void ClearPaintRect();
+
+#if defined(OS_WIN)
+  // Invoked from the Widget to service a WM_PAINT call.
+  void OnPaint(HWND hwnd);
+#elif defined(OS_LINUX)
+  void OnPaint(GdkEventExpose* event);
+#endif
+
+  // Accessibility accessors/mutators, overridden from View.
+  virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+  virtual bool GetAccessibleName(std::wstring* name);
+  virtual void SetAccessibleName(const std::wstring& name);
+
+ protected:
+
+  // Overridden to properly reset our event propagation member
+  // variables when a child is removed
+  virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
+
+#ifndef NDEBUG
+  virtual bool IsProcessingPaint() const { return is_processing_paint_; }
+#endif
+
+ private:
+  friend class View;
+  friend class PaintTask;
+
+  RootView();
+  DISALLOW_EVIL_CONSTRUCTORS(RootView);
+
+  // Convert a point to our current mouse handler. Returns false if the
+  // mouse handler is not connected to a Widget. In that case, the
+  // conversion cannot take place and *p is unchanged
+  bool ConvertPointToMouseHandler(const gfx::Point& l, gfx::Point *p);
+
+  // Update the cursor given a mouse event. This is called by non mouse_move
+  // event handlers to honor the cursor desired by views located under the
+  // cursor during drag operations.
+  void UpdateCursor(const MouseEvent& e);
+
+  // Notification that size and/or position of a view has changed. This
+  // notifies the appropriate views.
+  void ViewBoundsChanged(View* view, bool size_changed, bool position_changed);
+
+  // Registers a view for notification when the visible bounds relative to the
+  // root of a view changes.
+  void RegisterViewForVisibleBoundsNotification(View* view);
+  void UnregisterViewForVisibleBoundsNotification(View* view);
+
+  // Returns the next focusable view or view containing a FocusTraversable (NULL
+  // if none was found), starting at the starting_view.
+  // skip_starting_view, can_go_up and can_go_down controls the traversal of
+  // the views hierarchy.
+  // skip_group_id specifies a group_id, -1 means no group. All views from a
+  // group are traversed in one pass.
+  View* FindNextFocusableViewImpl(View* starting_view,
+                                  bool skip_starting_view,
+                                  bool can_go_up,
+                                  bool can_go_down,
+                                  int skip_group_id);
+
+  // Same as FindNextFocusableViewImpl but returns the previous focusable view.
+  View* FindPreviousFocusableViewImpl(View* starting_view,
+                                      bool skip_starting_view,
+                                      bool can_go_up,
+                                      bool can_go_down,
+                                      int skip_group_id);
+
+  // Convenience method that returns true if a view is focusable and does not
+  // belong to the specified group.
+  bool IsViewFocusableCandidate(View* v, int skip_group_id);
+
+  // Returns the view selected for the group of the selected view. If the view
+  // does not belong to a group or if no view is selected in the group, the
+  // specified view is returned.
+  static View* FindSelectedViewForGroup(View* view);
+
+  // Updates the last_mouse_* fields from e.
+  void SetMouseLocationAndFlags(const MouseEvent& e);
+
+#if defined(OS_WIN)
+  // Starts a drag operation for the specified view. This blocks until done.
+  // If the view has not been deleted during the drag, OnDragDone is invoked
+  // on the view.
+  void StartDragForViewFromMouseEvent(View* view,
+                                      IDataObject* data,
+                                      int operation);
+#endif
+
+  // If a view is dragging, this returns it. Otherwise returns NULL.
+  View* GetDragView();
+
+  // The view currently handing down - drag - up
+  View* mouse_pressed_handler_;
+
+  // The view currently handling enter / exit
+  View* mouse_move_handler_;
+
+  // The last view to handle a mouse click, so that we can determine if
+  // a double-click lands on the same view as its single-click part.
+  View* last_click_handler_;
+
+  // The host Widget
+  Widget* widget_;
+
+  // The rectangle that should be painted
+  gfx::Rect invalid_rect_;
+
+  // Whether the current invalid rect should be painted urgently.
+  bool invalid_rect_urgent_;
+
+  // The task that we are using to trigger some non urgent painting or NULL
+  // if no painting has been scheduled yet.
+  PaintTask* pending_paint_task_;
+
+  // Indicate if, when the pending_paint_task_ is run, actual painting is still
+  // required.
+  bool paint_task_needed_;
+
+  // true if mouse_handler_ has been explicitly set
+  bool explicit_mouse_handler_;
+
+#if defined(OS_WIN)
+  // Previous cursor
+  HCURSOR previous_cursor_;
+#endif
+
+  // Default keyboard handler
+  View* default_keyboard_handler_;
+
+  // The listener that gets focus change notifications.
+  FocusListener* focus_listener_;
+
+  // Whether this root view should make our hwnd focused
+  // when an unprocessed mouse press event occurs
+  bool focus_on_mouse_pressed_;
+
+  // Flag used to ignore focus events when we focus the native window associated
+  // with a view.
+  bool ignore_set_focus_calls_;
+
+  // Whether this root view belongs to the current active window.
+  // bool activated_;
+
+  // Last position/flag of a mouse press/drag. Used if capture stops and we need
+  // to synthesize a release.
+  int last_mouse_event_flags_;
+  int last_mouse_event_x_;
+  int last_mouse_event_y_;
+
+  // The parent FocusTraversable, used for focus traversal.
+  FocusTraversable* focus_traversable_parent_;
+
+  // The View that contains this RootView. This is used when we have RootView
+  // wrapped inside native components, and is used for the focus traversal.
+  View* focus_traversable_parent_view_;
+
+#if defined(OS_WIN)
+  // Handles dnd for us.
+  scoped_refptr<RootViewDropTarget> drop_target_;
+#endif
+
+  // Storage of strings needed for accessibility.
+  std::wstring accessible_name_;
+
+  // Tracks drag state for a view.
+  View::DragInfo drag_info;
+
+  // Valid for the lifetime of StartDragForViewFromMouseEvent, indicates the
+  // view the drag started from.
+  View* drag_view_;
+
+#ifndef NDEBUG
+  // True if we're currently processing paint.
+  bool is_processing_paint_;
+#endif
+};
+
+}  // namespace views
+
+#endif // VIEWS_WIDGET_ROOT_VIEW_H_
diff --git a/views/widget/root_view_drop_target.cc b/views/widget/root_view_drop_target.cc
new file mode 100644
index 0000000..9c1f087
--- /dev/null
+++ b/views/widget/root_view_drop_target.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2006-2008 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 "views/widget/root_view_drop_target.h"
+
+#include "app/drag_drop_types.h"
+#include "base/gfx/point.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+RootViewDropTarget::RootViewDropTarget(RootView* root_view)
+    : BaseDropTarget(root_view->GetWidget()->GetNativeView()),
+      root_view_(root_view),
+      target_view_(NULL),
+      deepest_view_(NULL) {
+}
+
+RootViewDropTarget::~RootViewDropTarget() {
+}
+
+void RootViewDropTarget::ResetTargetViewIfEquals(View* view) {
+  if (target_view_ == view)
+    target_view_ = NULL;
+  if (deepest_view_ == view)
+    deepest_view_ = NULL;
+}
+
+DWORD RootViewDropTarget::OnDragOver(IDataObject* data_object,
+                                     DWORD key_state,
+                                     POINT cursor_position,
+                                     DWORD effect) {
+  const OSExchangeData data(data_object);
+  gfx::Point root_view_location(cursor_position.x, cursor_position.y);
+  View::ConvertPointToView(NULL, root_view_, &root_view_location);
+  View* view = CalculateTargetView(root_view_location, data);
+
+  if (view != target_view_) {
+    // Target changed notify old drag exited, then new drag entered.
+    if (target_view_)
+      target_view_->OnDragExited();
+    target_view_ = view;
+    if (target_view_) {
+      gfx::Point target_view_location(root_view_location);
+      View::ConvertPointToView(root_view_, target_view_, &target_view_location);
+      DropTargetEvent enter_event(data,
+          target_view_location.x(),
+          target_view_location.y(),
+          DragDropTypes::DropEffectToDragOperation(effect));
+      target_view_->OnDragEntered(enter_event);
+    }
+  }
+
+  if (target_view_) {
+    gfx::Point target_view_location(root_view_location);
+    View::ConvertPointToView(root_view_, target_view_, &target_view_location);
+    DropTargetEvent enter_event(data,
+        target_view_location.x(),
+        target_view_location.y(),
+        DragDropTypes::DropEffectToDragOperation(effect));
+    int result_operation = target_view_->OnDragUpdated(enter_event);
+    return DragDropTypes::DragOperationToDropEffect(result_operation);
+  } else {
+    return DROPEFFECT_NONE;
+  }
+}
+
+void RootViewDropTarget::OnDragLeave(IDataObject* data_object) {
+  if (target_view_)
+    target_view_->OnDragExited();
+  deepest_view_ = target_view_ = NULL;
+}
+
+DWORD RootViewDropTarget::OnDrop(IDataObject* data_object,
+                                 DWORD key_state,
+                                 POINT cursor_position,
+                                 DWORD effect) {
+  const OSExchangeData data(data_object);
+  DWORD drop_effect = OnDragOver(data_object, key_state, cursor_position,
+                                 effect);
+  View* drop_view = target_view_;
+  deepest_view_ = target_view_ = NULL;
+  if (drop_effect != DROPEFFECT_NONE) {
+    gfx::Point view_location(cursor_position.x, cursor_position.y);
+    View::ConvertPointToView(NULL, drop_view, &view_location);
+    DropTargetEvent drop_event(data, view_location.x(), view_location.y(),
+        DragDropTypes::DropEffectToDragOperation(effect));
+    return DragDropTypes::DragOperationToDropEffect(
+        drop_view->OnPerformDrop(drop_event));
+  } else {
+    if (drop_view)
+      drop_view->OnDragExited();
+    return DROPEFFECT_NONE;
+  }
+}
+
+View* RootViewDropTarget::CalculateTargetView(
+    const gfx::Point& root_view_location,
+    const OSExchangeData& data) {
+  View* view = root_view_->GetViewForPoint(root_view_location);
+  if (view == deepest_view_) {
+    // The view the mouse is over hasn't changed; reuse the target.
+    return target_view_;
+  }
+  // View under mouse changed, which means a new view may want the drop.
+  // Walk the tree, stopping at target_view_ as we know it'll accept the
+  // drop.
+  deepest_view_ = view;
+  while (view && view != target_view_ &&
+         (!view->IsEnabled() || !view->CanDrop(data))) {
+    view = view->GetParent();
+  }
+  return view;
+}
+
+}  // namespace views
diff --git a/views/widget/root_view_drop_target.h b/views/widget/root_view_drop_target.h
new file mode 100644
index 0000000..a3c3afd
--- /dev/null
+++ b/views/widget/root_view_drop_target.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2006-2008 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 VIEWS_WIDGET_ROOT_VIEW_DROP_TARGET_H_
+#define VIEWS_WIDGET_ROOT_VIEW_DROP_TARGET_H_
+
+#include <atlbase.h>
+#include <atlapp.h>
+#include <atlmisc.h>
+
+#include "app/os_exchange_data.h"
+#include "base/base_drop_target.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace views {
+
+class RootView;
+class View;
+
+// RootViewDropTarget takes care of managing drag and drop for the RootView and
+// converts Windows OLE drop messages into Views drop messages.
+//
+// RootViewDropTarget is responsible for determining the appropriate View to
+// use during a drag and drop session, and forwarding events to it.
+class RootViewDropTarget : public BaseDropTarget {
+ public:
+  explicit RootViewDropTarget(RootView* root_view);
+  virtual ~RootViewDropTarget();
+
+  // If a drag and drop is underway and view is the current drop target, the
+  // drop target is set to null.
+  // This is invoked when a View is removed from the RootView to make sure
+  // we don't target a view that was removed during dnd.
+  void ResetTargetViewIfEquals(View* view);
+
+ protected:
+  virtual DWORD OnDragOver(IDataObject* data_object,
+                           DWORD key_state,
+                           POINT cursor_position,
+                           DWORD effect);
+
+  virtual void OnDragLeave(IDataObject* data_object);
+
+  virtual DWORD OnDrop(IDataObject* data_object,
+                       DWORD key_state,
+                       POINT cursor_position,
+                       DWORD effect);
+
+ private:
+  // Calculates the target view for a drop given the specified location in
+  // the coordinate system of the rootview. This tries to avoid continually
+  // querying CanDrop by returning target_view_ if the mouse is still over
+  // target_view_.
+  View* CalculateTargetView(const gfx::Point& root_view_location,
+                            const OSExchangeData& data);
+
+  // RootView we were created for.
+  RootView* root_view_;
+
+  // View we're targeting events at.
+  View* target_view_;
+
+  // The deepest view under the current drop coordinate.
+  View* deepest_view_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(RootViewDropTarget);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_WIDGET_ROOT_VIEW_DROP_TARGET_H_
diff --git a/views/widget/root_view_gtk.cc b/views/widget/root_view_gtk.cc
new file mode 100644
index 0000000..428c695b
--- /dev/null
+++ b/views/widget/root_view_gtk.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2006-2008 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 "views/widget/root_view.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "base/logging.h"
+#include "skia/include/SkColor.h"
+
+namespace views {
+
+void RootView::UpdateCursor(const MouseEvent& e) {
+  NOTIMPLEMENTED();
+}
+
+void RootView::OnPaint(GdkEventExpose* event) {
+  ChromeCanvasPaint canvas(event);
+
+  if (!canvas.isEmpty()) {
+    SchedulePaint(gfx::Rect(canvas.rectangle()), false);
+    if (NeedsPainting(false)) {
+      ProcessPaint(&canvas);
+    }
+  }
+}
+
+}
diff --git a/views/widget/root_view_win.cc b/views/widget/root_view_win.cc
new file mode 100644
index 0000000..ac4a50d7
--- /dev/null
+++ b/views/widget/root_view_win.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2006-2008 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 "views/widget/root_view.h"
+
+#include "app/drag_drop_types.h"
+#include "app/gfx/chrome_canvas.h"
+#include "base/base_drag_source.h"
+#include "base/logging.h"
+#include "views/widget/root_view_drop_target.h"
+
+namespace views {
+
+void RootView::UpdateCursor(const MouseEvent& e) {
+  View *v = GetViewForPoint(e.location());
+
+  if (v && v != this) {
+    gfx::Point l(e.location());
+    View::ConvertPointToView(this, v, &l);
+    HCURSOR cursor = v->GetCursorForPoint(e.GetType(), l.x(), l.y());
+    if (cursor) {
+      ::SetCursor(cursor);
+      return;
+    }
+  }
+  if (previous_cursor_) {
+    SetCursor(previous_cursor_);
+  }
+}
+
+void RootView::OnPaint(HWND hwnd) {
+  gfx::Rect original_dirty_region = GetScheduledPaintRectConstrainedToSize();
+  if (!original_dirty_region.IsEmpty()) {
+    // Invoke InvalidateRect so that the dirty region of the window includes the
+    // region we need to paint. If we didn't do this and the region didn't
+    // include the dirty region, ProcessPaint would incorrectly mark everything
+    // as clean. This can happen if a WM_PAINT is generated by the system before
+    // the InvokeLater schedule by RootView is processed.
+    RECT win_version = original_dirty_region.ToRECT();
+    InvalidateRect(hwnd, &win_version, FALSE);
+  }
+  ChromeCanvasPaint canvas(hwnd);
+  if (!canvas.isEmpty()) {
+    const PAINTSTRUCT& ps = canvas.paintStruct();
+    SchedulePaint(gfx::Rect(ps.rcPaint), false);
+    if (NeedsPainting(false))
+      ProcessPaint(&canvas);
+  }
+}
+
+void RootView::StartDragForViewFromMouseEvent(
+    View* view,
+    IDataObject* data,
+    int operation) {
+  drag_view_ = view;
+  scoped_refptr<BaseDragSource> drag_source(new BaseDragSource);
+  DWORD effects;
+  DoDragDrop(data, drag_source,
+             DragDropTypes::DragOperationToDropEffect(operation), &effects);
+  // If the view is removed during the drag operation, drag_view_ is set to
+  // NULL.
+  if (drag_view_ == view) {
+    View* drag_view = drag_view_;
+    drag_view_ = NULL;
+    drag_view->OnDragDone();
+  }
+}
+
+}
diff --git a/views/widget/tooltip_manager.cc b/views/widget/tooltip_manager.cc
new file mode 100644
index 0000000..18faf4a5
--- /dev/null
+++ b/views/widget/tooltip_manager.cc
@@ -0,0 +1,447 @@
+// Copyright (c) 2006-2008 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 "views/widget/tooltip_manager.h"
+
+#include <limits>
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_win.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "chrome/common/gfx/text_elider.h"
+#include "chrome/common/win_util.h"
+#include "views/view.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+//static
+int TooltipManager::tooltip_height_ = 0;
+
+// Default timeout for the tooltip displayed using keyboard.
+// Timeout is mentioned in milliseconds.
+static const int kDefaultTimeout = 4000;
+
+// Maximum number of lines we allow in the tooltip.
+static const int kMaxLines = 6;
+
+// Maximum number of characters we allow in a tooltip.
+static const int kMaxTooltipLength = 1024;
+
+// Breaks |text| along line boundaries, placing each line of text into lines.
+static void SplitTooltipString(const std::wstring& text,
+                               std::vector<std::wstring>* lines) {
+  size_t index = 0;
+  size_t next_index;
+  while ((next_index = text.find(TooltipManager::GetLineSeparator(), index))
+         != std::wstring::npos && lines->size() < kMaxLines) {
+    lines->push_back(text.substr(index, next_index - index));
+    index = next_index + TooltipManager::GetLineSeparator().size();
+  }
+  if (next_index != text.size() && lines->size() < kMaxLines)
+    lines->push_back(text.substr(index, text.size() - index));
+}
+
+// static
+int TooltipManager::GetTooltipHeight() {
+  DCHECK(tooltip_height_ > 0);
+  return tooltip_height_;
+}
+
+static ChromeFont DetermineDefaultFont() {
+  HWND window = CreateWindowEx(
+      WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+      TOOLTIPS_CLASS, NULL, 0 , 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+  HFONT hfont = reinterpret_cast<HFONT>(SendMessage(window, WM_GETFONT, 0, 0));
+  ChromeFont font = hfont ? ChromeFont::CreateFont(hfont) : ChromeFont();
+  DestroyWindow(window);
+  return font;
+}
+
+// static
+ChromeFont TooltipManager::GetDefaultFont() {
+  static ChromeFont* font = NULL;
+  if (!font)
+    font = new ChromeFont(DetermineDefaultFont());
+  return *font;
+}
+
+// static
+const std::wstring& TooltipManager::GetLineSeparator() {
+  static const std::wstring* separator = NULL;
+  if (!separator)
+    separator = new std::wstring(L"\r\n");
+  return *separator;
+}
+
+TooltipManager::TooltipManager(Widget* widget, HWND parent)
+    : widget_(widget),
+      parent_(parent),
+      last_mouse_x_(-1),
+      last_mouse_y_(-1),
+      tooltip_showing_(false),
+      last_tooltip_view_(NULL),
+      last_view_out_of_sync_(false),
+      tooltip_width_(0),
+      keyboard_tooltip_hwnd_(NULL),
+#pragma warning(suppress: 4355)
+      keyboard_tooltip_factory_(this) {
+  DCHECK(widget && parent);
+  Init();
+}
+
+TooltipManager::~TooltipManager() {
+  if (tooltip_hwnd_)
+    DestroyWindow(tooltip_hwnd_);
+  if (keyboard_tooltip_hwnd_)
+    DestroyWindow(keyboard_tooltip_hwnd_);
+}
+
+void TooltipManager::Init() {
+  // Create the tooltip control.
+  tooltip_hwnd_ = CreateWindowEx(
+      WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+      TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0,
+      parent_, NULL, NULL, NULL);
+
+  l10n_util::AdjustUIFontForWindow(tooltip_hwnd_);
+
+  // This effectively turns off clipping of tooltips. We need this otherwise
+  // multi-line text (\r\n) won't work right. The size doesn't really matter
+  // (just as long as its bigger than the monitor's width) as we clip to the
+  // screen size before rendering.
+  SendMessage(tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
+              std::numeric_limits<short>::max());
+
+  // Add one tool that is used for all tooltips.
+  toolinfo_.cbSize = sizeof(toolinfo_);
+  toolinfo_.uFlags = TTF_TRANSPARENT | TTF_IDISHWND;
+  toolinfo_.hwnd = parent_;
+  toolinfo_.uId = reinterpret_cast<UINT_PTR>(parent_);
+  // Setting this tells windows to call parent_ back (using a WM_NOTIFY
+  // message) for the actual tooltip contents.
+  toolinfo_.lpszText = LPSTR_TEXTCALLBACK;
+  SetRectEmpty(&toolinfo_.rect);
+  SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, (LPARAM)&toolinfo_);
+}
+
+void TooltipManager::UpdateTooltip() {
+  // Set last_view_out_of_sync_ to indicate the view is currently out of sync.
+  // This doesn't update the view under the mouse immediately as it may cause
+  // timing problems.
+  last_view_out_of_sync_ = true;
+  last_tooltip_view_ = NULL;
+  // Hide the tooltip.
+  SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+}
+
+void TooltipManager::TooltipTextChanged(View* view) {
+  if (view == last_tooltip_view_)
+    UpdateTooltip(last_mouse_x_, last_mouse_y_);
+}
+
+LRESULT TooltipManager::OnNotify(int w_param, NMHDR* l_param, bool* handled) {
+  *handled = false;
+  if (l_param->hwndFrom == tooltip_hwnd_ && keyboard_tooltip_hwnd_ == NULL) {
+    switch (l_param->code) {
+      case TTN_GETDISPINFO: {
+        if (last_view_out_of_sync_) {
+          // View under the mouse is out of sync, determine it now.
+          RootView* root_view = widget_->GetRootView();
+          last_tooltip_view_ = root_view->GetViewForPoint(
+              gfx::Point(last_mouse_x_, last_mouse_y_));
+          last_view_out_of_sync_ = false;
+        }
+        // Tooltip control is asking for the tooltip to display.
+        NMTTDISPINFOW* tooltip_info =
+            reinterpret_cast<NMTTDISPINFOW*>(l_param);
+        // Initialize the string, if we have a valid tooltip the string will
+        // get reset below.
+        tooltip_info->szText[0] = TEXT('\0');
+        tooltip_text_.clear();
+        tooltip_info->lpszText = NULL;
+        clipped_text_.clear();
+        if (last_tooltip_view_ != NULL) {
+          tooltip_text_.clear();
+          // Mouse is over a View, ask the View for it's tooltip.
+          gfx::Point view_loc(last_mouse_x_, last_mouse_y_);
+          View::ConvertPointToView(widget_->GetRootView(),
+                                   last_tooltip_view_, &view_loc);
+          if (last_tooltip_view_->GetTooltipText(view_loc.x(), view_loc.y(),
+                                                 &tooltip_text_) &&
+              !tooltip_text_.empty()) {
+            // View has a valid tip, copy it into TOOLTIPINFO.
+            clipped_text_ = tooltip_text_;
+            TrimTooltipToFit(&clipped_text_, &tooltip_width_, &line_count_,
+                             last_mouse_x_, last_mouse_y_, tooltip_hwnd_);
+            // Adjust the clipped tooltip text for locale direction.
+            l10n_util::AdjustStringForLocaleDirection(clipped_text_,
+                                                      &clipped_text_);
+            tooltip_info->lpszText = const_cast<WCHAR*>(clipped_text_.c_str());
+          } else {
+            tooltip_text_.clear();
+          }
+        }
+        *handled = true;
+        return 0;
+      }
+      case TTN_POP:
+        tooltip_showing_ = false;
+        *handled = true;
+        return 0;
+      case TTN_SHOW: {
+        *handled = true;
+        tooltip_showing_ = true;
+        // The tooltip is about to show, allow the view to position it
+        gfx::Point text_origin;
+        if (tooltip_height_ == 0)
+          tooltip_height_ = CalcTooltipHeight();
+        gfx::Point view_loc(last_mouse_x_, last_mouse_y_);
+        View::ConvertPointToView(widget_->GetRootView(),
+                                 last_tooltip_view_, &view_loc);
+        if (last_tooltip_view_->GetTooltipTextOrigin(
+              view_loc.x(), view_loc.y(), &text_origin) &&
+            SetTooltipPosition(text_origin.x(), text_origin.y())) {
+          // Return true, otherwise the rectangle we specified is ignored.
+          return TRUE;
+        }
+        return 0;
+      }
+      default:
+        // Fall through.
+        break;
+    }
+  }
+  return 0;
+}
+
+bool TooltipManager::SetTooltipPosition(int text_x, int text_y) {
+  // NOTE: this really only tests that the y location fits on screen, but that
+  // is good enough for our usage.
+
+  // Calculate the bounds the tooltip will get.
+  gfx::Point view_loc;
+  View::ConvertPointToScreen(last_tooltip_view_, &view_loc);
+  RECT bounds = { view_loc.x() + text_x,
+                  view_loc.y() + text_y,
+                  view_loc.x() + text_x + tooltip_width_,
+                  view_loc.y() + line_count_ * GetTooltipHeight() };
+  SendMessage(tooltip_hwnd_, TTM_ADJUSTRECT, TRUE, (LPARAM)&bounds);
+
+  // Make sure the rectangle completely fits on the current monitor. If it
+  // doesn't, return false so that windows positions the tooltip at the
+  // default location.
+  gfx::Rect monitor_bounds =
+      win_util::GetMonitorBoundsForRect(gfx::Rect(bounds.left,bounds.right,
+                                                  0, 0));
+  if (!monitor_bounds.Contains(gfx::Rect(bounds))) {
+    return false;
+  }
+
+  ::SetWindowPos(tooltip_hwnd_, NULL, bounds.left, bounds.top, 0, 0,
+                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
+  return true;
+}
+
+int TooltipManager::CalcTooltipHeight() {
+  // Ask the tooltip for it's font.
+  int height;
+  HFONT hfont = reinterpret_cast<HFONT>(
+      SendMessage(tooltip_hwnd_, WM_GETFONT, 0, 0));
+  if (hfont != NULL) {
+    HDC dc = GetDC(tooltip_hwnd_);
+    HFONT previous_font = static_cast<HFONT>(SelectObject(dc, hfont));
+    int last_map_mode = SetMapMode(dc, MM_TEXT);
+    TEXTMETRIC font_metrics;
+    GetTextMetrics(dc, &font_metrics);
+    height = font_metrics.tmHeight;
+    // To avoid the DC referencing font_handle_, select the previous font.
+    SelectObject(dc, previous_font);
+    SetMapMode(dc, last_map_mode);
+    ReleaseDC(NULL, dc);
+  } else {
+    // Tooltip is using the system font. Use ChromeFont, which should pick
+    // up the system font.
+    height = ChromeFont().height();
+  }
+  // Get the margins from the tooltip
+  RECT tooltip_margin;
+  SendMessage(tooltip_hwnd_, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin);
+  return height + tooltip_margin.top + tooltip_margin.bottom;
+}
+
+void TooltipManager::TrimTooltipToFit(std::wstring* text,
+                                      int* max_width,
+                                      int* line_count,
+                                      int position_x,
+                                      int position_y,
+                                      HWND window) {
+  *max_width = 0;
+  *line_count = 0;
+
+  // Clamp the tooltip length to kMaxTooltipLength so that we don't
+  // accidentally DOS the user with a mega tooltip (since Windows doesn't seem
+  // to do this itself).
+  if (text->length() > kMaxTooltipLength)
+    *text = text->substr(0, kMaxTooltipLength);
+
+  // Determine the available width for the tooltip.
+  gfx::Point screen_loc(position_x, position_y);
+  View::ConvertPointToScreen(widget_->GetRootView(), &screen_loc);
+  gfx::Rect monitor_bounds =
+      win_util::GetMonitorBoundsForRect(gfx::Rect(screen_loc.x(),
+                                                  screen_loc.y(),
+                                                  0, 0));
+  RECT tooltip_margin;
+  SendMessage(window, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin);
+  const int available_width = monitor_bounds.width() - tooltip_margin.left -
+      tooltip_margin.right;
+  if (available_width <= 0)
+    return;
+
+  // Split the string.
+  std::vector<std::wstring> lines;
+  SplitTooltipString(*text, &lines);
+  *line_count = static_cast<int>(lines.size());
+
+  // Format each line to fit.
+  ChromeFont font = GetDefaultFont();
+  std::wstring result;
+  for (std::vector<std::wstring>::iterator i = lines.begin(); i != lines.end();
+       ++i) {
+    std::wstring elided_text = gfx::ElideText(*i, font, available_width);
+    *max_width = std::max(*max_width, font.GetStringWidth(elided_text));
+    if (i == lines.begin() && i + 1 == lines.end()) {
+      *text = elided_text;
+      return;
+    }
+    if (!result.empty())
+      result.append(GetLineSeparator());
+    result.append(elided_text);
+  }
+  *text = result;
+}
+
+void TooltipManager::UpdateTooltip(int x, int y) {
+  RootView* root_view = widget_->GetRootView();
+  View* view = root_view->GetViewForPoint(gfx::Point(x, y));
+  if (view != last_tooltip_view_) {
+    // NOTE: This *must* be sent regardless of the visibility of the tooltip.
+    // It triggers Windows to ask for the tooltip again.
+    SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+    last_tooltip_view_ = view;
+  } else if (last_tooltip_view_ != NULL) {
+    // Tooltip is showing, and mouse is over the same view. See if the tooltip
+    // text has changed.
+    gfx::Point view_point(x, y);
+    View::ConvertPointToView(root_view, last_tooltip_view_, &view_point);
+    std::wstring new_tooltip_text;
+    if (last_tooltip_view_->GetTooltipText(view_point.x(), view_point.y(),
+                                           &new_tooltip_text) &&
+        new_tooltip_text != tooltip_text_) {
+      // The text has changed, hide the popup.
+      SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+      if (!new_tooltip_text.empty() && tooltip_showing_) {
+        // New text is valid, show the popup.
+        SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
+      }
+    }
+  }
+}
+
+void TooltipManager::OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param) {
+  int x = GET_X_LPARAM(l_param);
+  int y = GET_Y_LPARAM(l_param);
+
+  if (u_msg >= WM_NCMOUSEMOVE && u_msg <= WM_NCXBUTTONDBLCLK) {
+    // NC message coordinates are in screen coordinates.
+    gfx::Rect frame_bounds;
+    widget_->GetBounds(&frame_bounds, true);
+    x -= frame_bounds.x();
+    y -= frame_bounds.y();
+  }
+
+  if (u_msg != WM_MOUSEMOVE || last_mouse_x_ != x || last_mouse_y_ != y) {
+    last_mouse_x_ = x;
+    last_mouse_y_ = y;
+    HideKeyboardTooltip();
+    UpdateTooltip(x, y);
+  }
+  // Forward the message onto the tooltip.
+  MSG msg;
+  msg.hwnd = parent_;
+  msg.message = u_msg;
+  msg.wParam = w_param;
+  msg.lParam = l_param;
+  SendMessage(tooltip_hwnd_, TTM_RELAYEVENT, 0, (LPARAM)&msg);
+}
+
+void TooltipManager::ShowKeyboardTooltip(View* focused_view) {
+  if (tooltip_showing_) {
+    SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+    tooltip_text_.clear();
+  }
+  HideKeyboardTooltip();
+  std::wstring tooltip_text;
+  if (!focused_view->GetTooltipText(0, 0, &tooltip_text))
+    return;
+  gfx::Rect focused_bounds = focused_view->bounds();
+  gfx::Point screen_point;
+  focused_view->ConvertPointToScreen(focused_view, &screen_point);
+  gfx::Point relative_point_coordinates;
+  focused_view->ConvertPointToWidget(focused_view, &relative_point_coordinates);
+  keyboard_tooltip_hwnd_ = CreateWindowEx(
+      WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+      TOOLTIPS_CLASS, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+  SendMessage(keyboard_tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
+              std::numeric_limits<short>::max());
+  int tooltip_width;
+  int line_count;
+  TrimTooltipToFit(&tooltip_text, &tooltip_width, &line_count,
+                   relative_point_coordinates.x(),
+                   relative_point_coordinates.y(), keyboard_tooltip_hwnd_);
+  TOOLINFO keyboard_toolinfo;
+  memset(&keyboard_toolinfo, 0, sizeof(keyboard_toolinfo));
+  keyboard_toolinfo.cbSize = sizeof(keyboard_toolinfo);
+  keyboard_toolinfo.hwnd = parent_;
+  keyboard_toolinfo.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_IDISHWND ;
+  keyboard_toolinfo.lpszText = const_cast<WCHAR*>(tooltip_text.c_str());
+  SendMessage(keyboard_tooltip_hwnd_, TTM_ADDTOOL, 0,
+              reinterpret_cast<LPARAM>(&keyboard_toolinfo));
+  SendMessage(keyboard_tooltip_hwnd_, TTM_TRACKACTIVATE,  TRUE,
+              reinterpret_cast<LPARAM>(&keyboard_toolinfo));
+  if (!tooltip_height_)
+    tooltip_height_ = CalcTooltipHeight();
+  RECT rect_bounds = {screen_point.x(),
+                      screen_point.y() + focused_bounds.height(),
+                      screen_point.x() + tooltip_width,
+                      screen_point.y() + focused_bounds.height() +
+                      line_count * tooltip_height_ };
+  gfx::Rect monitor_bounds =
+      win_util::GetMonitorBoundsForRect(gfx::Rect(rect_bounds));
+  rect_bounds = gfx::Rect(rect_bounds).AdjustToFit(monitor_bounds).ToRECT();
+  ::SetWindowPos(keyboard_tooltip_hwnd_, NULL, rect_bounds.left,
+                 rect_bounds.top, 0, 0,
+                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
+  MessageLoop::current()->PostDelayedTask(FROM_HERE,
+      keyboard_tooltip_factory_.NewRunnableMethod(
+      &TooltipManager::DestroyKeyboardTooltipWindow, keyboard_tooltip_hwnd_),
+      kDefaultTimeout);
+}
+
+void TooltipManager::HideKeyboardTooltip() {
+  if (keyboard_tooltip_hwnd_ != NULL) {
+    SendMessage(keyboard_tooltip_hwnd_, WM_CLOSE, 0, 0);
+    keyboard_tooltip_hwnd_ = NULL;
+  }
+}
+
+void TooltipManager::DestroyKeyboardTooltipWindow(HWND window_to_destroy) {
+  if (keyboard_tooltip_hwnd_ == window_to_destroy)
+    HideKeyboardTooltip();
+}
+
+}  // namespace views
diff --git a/views/widget/tooltip_manager.h b/views/widget/tooltip_manager.h
new file mode 100644
index 0000000..3d5620d
--- /dev/null
+++ b/views/widget/tooltip_manager.h
@@ -0,0 +1,168 @@
+// Copyright (c) 2006-2008 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 VIEWS_WIDGET_TOOLTIP_MANAGER_H_
+#define VIEWS_WIDGET_TOOLTIP_MANAGER_H_
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <string>
+#include "base/basictypes.h"
+#include "base/task.h"
+
+class ChromeFont;
+
+namespace views {
+
+class View;
+class Widget;
+
+// TooltipManager takes care of the wiring to support tooltips for Views.
+// This class is intended to be used by Widgets. To use this, you must
+// do the following:
+// Add the following to your MSG_MAP:
+//
+//   MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
+//   MESSAGE_RANGE_HANDLER(WM_NCMOUSEMOVE, WM_NCMOUSEMOVE, OnMouseRange)
+//   MSG_WM_NOTIFY(OnNotify)
+//
+// With the following implementations:
+//   LRESULT XXX::OnMouseRange(UINT u_msg, WPARAM w_param, LPARAM l_param,
+//                             BOOL& handled) {
+//     tooltip_manager_->OnMouse(u_msg, w_param, l_param);
+//     handled = FALSE;
+//     return 0;
+//   }
+//
+//   LRESULT XXX::OnNotify(int w_param, NMHDR* l_param) {
+//     bool handled;
+//     LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled);
+//     SetMsgHandled(handled);
+//     return result;
+//   }
+//
+// And of course you'll need to create the TooltipManager!
+//
+// Lastly, you'll need to override GetTooltipManager.
+//
+// See XPFrame for an example of this in action.
+class TooltipManager {
+ public:
+  // Returns the height of tooltips. This should only be invoked from within
+  // GetTooltipTextOrigin.
+  static int GetTooltipHeight();
+
+  // Returns the default font used by tooltips.
+  static ChromeFont GetDefaultFont();
+
+  // Returns the separator for lines of text in a tooltip.
+  static const std::wstring& GetLineSeparator();
+
+  // Creates a TooltipManager for the specified Widget and parent window.
+  TooltipManager(Widget* widget, HWND parent);
+  virtual ~TooltipManager();
+
+  // Notification that the view hierarchy has changed in some way.
+  void UpdateTooltip();
+
+  // Invoked when the tooltip text changes for the specified views.
+  void TooltipTextChanged(View* view);
+
+  // Invoked when toolbar icon gets focus.
+  void ShowKeyboardTooltip(View* view);
+
+  // Invoked when toolbar loses focus.
+  void HideKeyboardTooltip();
+
+  // Message handlers. These forward to the tooltip control.
+  virtual void OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param);
+  LRESULT OnNotify(int w_param, NMHDR* l_param, bool* handled);
+  // Not used directly by TooltipManager, but provided for AeroTooltipManager.
+  virtual void OnMouseLeave() {}
+
+ protected:
+  virtual void Init();
+
+  // Updates the tooltip for the specified location.
+  void UpdateTooltip(int x, int y);
+
+  // Parent window the tooltip is added to.
+  HWND parent_;
+
+  // Tooltip control window.
+  HWND tooltip_hwnd_;
+
+  // Tooltip information.
+  TOOLINFO toolinfo_;
+
+  // Last location of the mouse. This is in the coordinates of the rootview.
+  int last_mouse_x_;
+  int last_mouse_y_;
+
+  // Whether or not the tooltip is showing.
+  bool tooltip_showing_;
+
+ private:
+  // Sets the tooltip position based on the x/y position of the text. If the
+  // tooltip fits, true is returned.
+  bool SetTooltipPosition(int text_x, int text_y);
+
+  // Calculates the preferred height for tooltips. This always returns a
+  // positive value.
+  int CalcTooltipHeight();
+
+  // Trims the tooltip to fit, setting text to the clipped result, width to the
+  // width (in pixels) of the clipped text and line_count to the number of lines
+  // of text in the tooltip.
+  void TrimTooltipToFit(std::wstring* text,
+                        int* width,
+                        int* line_count,
+                        int position_x,
+                        int position_y,
+                        HWND window);
+
+  // Invoked when the timer elapses and tooltip has to be destroyed.
+  void DestroyKeyboardTooltipWindow(HWND window_to_destroy);
+
+  // Hosting Widget.
+  Widget* widget_;
+
+  // The View the mouse is under. This is null if the mouse isn't under a
+  // View.
+  View* last_tooltip_view_;
+
+  // Whether or not the view under the mouse needs to be refreshed. If this
+  // is true, when the tooltip is asked for the view under the mouse is
+  // refreshed.
+  bool last_view_out_of_sync_;
+
+  // Text for tooltip from the view.
+  std::wstring tooltip_text_;
+
+  // The clipped tooltip.
+  std::wstring clipped_text_;
+
+  // Number of lines in the tooltip.
+  int line_count_;
+
+  // Width of the last tooltip.
+  int tooltip_width_;
+
+  // Height for a tooltip; lazily calculated.
+  static int tooltip_height_;
+
+  // control window for tooltip displayed using keyboard.
+  HWND keyboard_tooltip_hwnd_;
+
+  // Used to register DestroyTooltipWindow function with PostDelayedTask
+  // function.
+  ScopedRunnableMethodFactory<TooltipManager> keyboard_tooltip_factory_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(TooltipManager);
+};
+
+}  // namespace views
+
+#endif // VIEWS_WIDGET_TOOLTIP_MANAGER_H_
diff --git a/views/widget/widget.h b/views/widget/widget.h
new file mode 100644
index 0000000..8dd3f2e
--- /dev/null
+++ b/views/widget/widget.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2006-2008 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 VIEWS_WIDGET_WIDGET_H_
+#define VIEWS_WIDGET_WIDGET_H_
+
+#include "base/gfx/native_widget_types.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace views {
+
+class Accelerator;
+class RootView;
+class TooltipManager;
+class Window;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Widget interface
+//
+//   Widget is an abstract class that defines the API that should be implemented
+//   by a native window in order to host a view hierarchy.
+//
+//   Widget wraps a hierarchy of View objects (see view.h) that implement
+//   painting and flexible layout within the bounds of the Widget's window.
+//
+//   The Widget is responsible for handling various system events and forwarding
+//   them to the appropriate view.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+class Widget {
+ public:
+  virtual ~Widget() { }
+
+  // Returns the bounds of this Widget in the screen coordinate system.
+  // If the receiving Widget is a frame which is larger than its client area,
+  // this method returns the client area if including_frame is false and the
+  // frame bounds otherwise. If the receiving Widget is not a frame,
+  // including_frame is ignored.
+  virtual void GetBounds(gfx::Rect* out, bool including_frame) const = 0;
+
+  // Returns the gfx::NativeView associated with this Widget.
+  virtual gfx::NativeView GetNativeView() const = 0;
+
+  // Forces a paint of a specified rectangle immediately.
+  virtual void PaintNow(const gfx::Rect& update_rect) = 0;
+
+  // Returns the RootView contained by this Widget.
+  virtual RootView* GetRootView() = 0;
+
+  // Returns whether the Widget is visible to the user.
+  virtual bool IsVisible() const = 0;
+
+  // Returns whether the Widget is the currently active window.
+  virtual bool IsActive() const = 0;
+
+  // Returns the TooltipManager for this Widget. If this Widget does not support
+  // tooltips, NULL is returned.
+  virtual TooltipManager* GetTooltipManager() {
+    return NULL;
+  }
+
+  // Returns the accelerator given a command id. Returns false if there is
+  // no accelerator associated with a given id, which is a common condition.
+  virtual bool GetAccelerator(int cmd_id,
+                              Accelerator* accelerator) = 0;
+
+  // Returns the Window containing this Widget, or NULL if not contained in a
+  // window.
+  virtual Window* GetWindow() { return NULL; }
+  virtual const Window* GetWindow() const { return NULL; }
+};
+
+}  // namespace views
+
+#endif // VIEWS_WIDGET_WIDGET_H_
diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc
new file mode 100644
index 0000000..25869f6
--- /dev/null
+++ b/views/widget/widget_gtk.cc
@@ -0,0 +1,386 @@
+// Copyright (c) 2009 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 "views/widget/widget_gtk.h"
+
+#include "views/fill_layout.h"
+#include "views/widget/root_view.h"
+
+namespace views {
+
+WidgetGtk::WidgetGtk()
+    : widget_(NULL),
+      is_mouse_down_(false),
+      last_mouse_event_was_move_(false) {
+}
+
+WidgetGtk::~WidgetGtk() {
+  gtk_widget_unref(widget_);
+
+  // MessageLoopForUI::current()->RemoveObserver(this);
+}
+
+void WidgetGtk::Init(const gfx::Rect& bounds,
+                     bool has_own_focus_manager) {
+
+  // Force creation of the RootView if it hasn't been created yet.
+  GetRootView();
+
+  // Make container here.
+  widget_ = gtk_drawing_area_new();
+  gtk_drawing_area_size(GTK_DRAWING_AREA(widget_), 100, 100);
+  gtk_widget_show(widget_);
+
+  // Make sure we receive our motion events.
+  gtk_widget_set_events(widget_,
+                        gtk_widget_get_events(widget_) |
+                        GDK_ENTER_NOTIFY_MASK |
+                        GDK_LEAVE_NOTIFY_MASK |
+                        GDK_BUTTON_PRESS_MASK |
+                        GDK_BUTTON_RELEASE_MASK |
+                        GDK_POINTER_MOTION_MASK |
+                        GDK_KEY_PRESS_MASK |
+                        GDK_KEY_RELEASE_MASK);
+
+  root_view_->OnWidgetCreated();
+
+  // TODO(port): if(has_own_focus_manager) block
+
+  SetViewForNative(widget_, this);
+  SetRootViewForWidget(widget_, root_view_.get());
+
+  // MessageLoopForUI::current()->AddObserver(this);
+
+  g_signal_connect_after(G_OBJECT(widget_), "size_allocate",
+                         G_CALLBACK(CallSizeAllocate), NULL);
+  g_signal_connect(G_OBJECT(widget_), "expose_event",
+                   G_CALLBACK(CallPaint), NULL);
+  g_signal_connect(G_OBJECT(widget_), "enter_notify_event",
+                   G_CALLBACK(CallEnterNotify), NULL);
+  g_signal_connect(G_OBJECT(widget_), "leave_notify_event",
+                   G_CALLBACK(CallLeaveNotify), NULL);
+  g_signal_connect(G_OBJECT(widget_), "motion_notify_event",
+                   G_CALLBACK(CallMotionNotify), NULL);
+  g_signal_connect(G_OBJECT(widget_), "button_press_event",
+                   G_CALLBACK(CallButtonPress), NULL);
+  g_signal_connect(G_OBJECT(widget_), "button_release_event",
+                   G_CALLBACK(CallButtonRelease), NULL);
+  g_signal_connect(G_OBJECT(widget_), "focus_in_event",
+                   G_CALLBACK(CallFocusIn), NULL);
+  g_signal_connect(G_OBJECT(widget_), "focus_out_event",
+                   G_CALLBACK(CallFocusOut), NULL);
+  g_signal_connect(G_OBJECT(widget_), "key_press_event",
+                   G_CALLBACK(CallKeyPress), NULL);
+  g_signal_connect(G_OBJECT(widget_), "key_release_event",
+                   G_CALLBACK(CallKeyRelease), NULL);
+  g_signal_connect(G_OBJECT(widget_), "scroll_event",
+                   G_CALLBACK(CallScroll), NULL);
+  g_signal_connect(G_OBJECT(widget_), "visibility_notify_event",
+                   G_CALLBACK(CallVisibilityNotify), NULL);
+
+  // TODO(erg): Ignore these signals for now because they're such a drag.
+  //
+  // g_signal_connect(G_OBJECT(widget_), "drag_motion",
+  //                  G_CALLBACK(drag_motion_event_cb), NULL);
+  // g_signal_connect(G_OBJECT(widget_), "drag_leave",
+  //                  G_CALLBACK(drag_leave_event_cb), NULL);
+  // g_signal_connect(G_OBJECT(widget_), "drag_drop",
+  //                  G_CALLBACK(drag_drop_event_cb), NULL);
+  // g_signal_connect(G_OBJECT(widget_), "drag_data_received",
+  //                  G_CALLBACK(drag_data_received_event_cb), NULL);
+}
+
+void WidgetGtk::SetContentsView(View* view) {
+  DCHECK(view && widget_) << "Can't be called until after the HWND is created!";
+  // The ContentsView must be set up _after_ the window is created so that its
+  // Widget pointer is valid.
+  root_view_->SetLayoutManager(new FillLayout);
+  if (root_view_->GetChildViewCount() != 0)
+    root_view_->RemoveAllChildViews(true);
+  root_view_->AddChildView(view);
+
+  // TODO(erg): Terrible hack to work around lack of real sizing mechanics for
+  // now.
+  root_view_->SetBounds(0, 0, 100, 100);
+  root_view_->Layout();
+  root_view_->SchedulePaint();
+  NOTIMPLEMENTED();
+}
+
+void WidgetGtk::GetBounds(gfx::Rect* out, bool including_frame) const {
+  if (including_frame) {
+    NOTIMPLEMENTED();
+    *out = gfx::Rect();
+    return;
+  }
+
+  // TODO(erg): Not sure how to implement this. gtk_widget_size_request()
+  // returns a widget's requested size--not it's actual size. The system of
+  // containers and such do auto sizing tricks to make everything work within
+  // the constraints and requested sizes...
+  NOTIMPLEMENTED();
+}
+
+gfx::NativeView WidgetGtk::GetNativeView() const {
+  return widget_;
+}
+
+void WidgetGtk::PaintNow(const gfx::Rect& update_rect) {
+  // TODO(erg): This is woefully incomplete and is a straw man implementation.
+  gtk_widget_queue_draw_area(widget_, update_rect.x(), update_rect.y(),
+                             update_rect.width(), update_rect.height());
+}
+
+RootView* WidgetGtk::GetRootView() {
+  if (!root_view_.get()) {
+    // First time the root view is being asked for, create it now.
+    root_view_.reset(CreateRootView());
+  }
+  return root_view_.get();
+}
+
+bool WidgetGtk::IsVisible() const {
+  return GTK_WIDGET_VISIBLE(widget_);
+}
+
+bool WidgetGtk::IsActive() const {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+TooltipManager* WidgetGtk::GetTooltipManager() {
+  NOTIMPLEMENTED();
+  return NULL;
+}
+
+bool WidgetGtk::GetAccelerator(int cmd_id, Accelerator* accelerator) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+gboolean WidgetGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event) {
+  gfx::Point screen_loc(event->x_root, event->y_root);
+  if (last_mouse_event_was_move_ && last_mouse_move_x_ == screen_loc.x() &&
+      last_mouse_move_y_ == screen_loc.y()) {
+    // Don't generate a mouse event for the same location as the last.
+    return false;
+  }
+  last_mouse_move_x_ = screen_loc.x();
+  last_mouse_move_y_ = screen_loc.y();
+  last_mouse_event_was_move_ = true;
+  MouseEvent mouse_move(Event::ET_MOUSE_MOVED,
+                        event->x,
+                        event->y,
+                        Event::GetFlagsFromGdkState(event->state));
+  root_view_->OnMouseMoved(mouse_move);
+  return true;
+}
+
+gboolean WidgetGtk::OnButtonPress(GtkWidget* widget, GdkEventButton* event) {
+  return ProcessMousePressed(event);
+}
+
+gboolean WidgetGtk::OnButtonRelease(GtkWidget* widget, GdkEventButton* event) {
+  ProcessMouseReleased(event);
+  return true;
+}
+
+gboolean WidgetGtk::OnPaint(GtkWidget* widget, GdkEventExpose* event) {
+  root_view_->OnPaint(event);
+  return true;
+}
+
+gboolean WidgetGtk::OnEnterNotify(GtkWidget* widget, GdkEventCrossing* event) {
+  // TODO(port): We may not actually need this message; it looks like
+  // OnNotificationNotify() takes care of this case...
+  return false;
+}
+
+gboolean WidgetGtk::OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event) {
+  last_mouse_event_was_move_ = false;
+  root_view_->ProcessOnMouseExited();
+  return true;
+}
+
+gboolean WidgetGtk::OnKeyPress(GtkWidget* widget, GdkEventKey* event) {
+  KeyEvent key_event(event);
+  return root_view_->ProcessKeyEvent(key_event);
+}
+
+gboolean WidgetGtk::OnKeyRelease(GtkWidget* widget, GdkEventKey* event) {
+  KeyEvent key_event(event);
+  return root_view_->ProcessKeyEvent(key_event);
+}
+
+RootView* WidgetGtk::CreateRootView() {
+  return new RootView(this);
+}
+
+bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) {
+  last_mouse_event_was_move_ = false;
+  MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED,
+                           event->x, event->y,
+//                         (dbl_click ? MouseEvent::EF_IS_DOUBLE_CLICK : 0) |
+                           Event::GetFlagsFromGdkState(event->state));
+  if (root_view_->OnMousePressed(mouse_pressed)) {
+    is_mouse_down_ = true;
+    // TODO(port): Enable this once I figure out what capture is.
+    // if (!has_capture_) {
+    //   SetCapture();
+    //   has_capture_ = true;
+    //   current_action_ = FA_FORWARDING;
+    // }
+    return true;
+  }
+
+  return false;
+}
+
+void WidgetGtk::ProcessMouseReleased(GdkEventButton* event) {
+  last_mouse_event_was_move_ = false;
+  MouseEvent mouse_up(Event::ET_MOUSE_RELEASED,
+                      event->x, event->y,
+                      Event::GetFlagsFromGdkState(event->state));
+  // Release the capture first, that way we don't get confused if
+  // OnMouseReleased blocks.
+  //
+  // TODO(port): Enable this once I figure out what capture is.
+  // if (has_capture_ && ReleaseCaptureOnMouseReleased()) {
+  //   has_capture_ = false;
+  //   current_action_ = FA_NONE;
+  //   ReleaseCapture();
+  // }
+  is_mouse_down_ = false;
+  root_view_->OnMouseReleased(mouse_up, false);
+}
+
+// static
+WidgetGtk* WidgetGtk::GetViewForNative(GtkWidget* widget) {
+  gpointer user_data = g_object_get_data(G_OBJECT(widget), "chrome-views");
+  return static_cast<WidgetGtk*>(user_data);
+}
+
+// static
+void WidgetGtk::SetViewForNative(GtkWidget* widget, WidgetGtk* view) {
+  g_object_set_data(G_OBJECT(widget), "chrome-views", view);
+}
+
+// static
+RootView* WidgetGtk::GetRootViewForWidget(GtkWidget* widget) {
+  gpointer user_data = g_object_get_data(G_OBJECT(widget), "root-view");
+  return static_cast<RootView*>(user_data);
+}
+
+// static
+void WidgetGtk::SetRootViewForWidget(GtkWidget* widget, RootView* root_view) {
+  g_object_set_data(G_OBJECT(widget), "root-view", root_view);
+}
+
+// static
+void WidgetGtk::CallSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return;
+
+  widget_gtk->OnSizeAllocate(widget, allocation);
+}
+
+gboolean WidgetGtk::CallPaint(GtkWidget* widget, GdkEventExpose* event) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return false;
+
+  return widget_gtk->OnPaint(widget, event);
+}
+
+gboolean WidgetGtk::CallEnterNotify(GtkWidget* widget, GdkEventCrossing* event) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return false;
+
+  return widget_gtk->OnEnterNotify(widget, event);
+}
+
+gboolean WidgetGtk::CallLeaveNotify(GtkWidget* widget, GdkEventCrossing* event) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return false;
+
+  return widget_gtk->OnLeaveNotify(widget, event);
+}
+
+gboolean WidgetGtk::CallMotionNotify(GtkWidget* widget, GdkEventMotion* event) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return false;
+
+  return widget_gtk->OnMotionNotify(widget, event);
+}
+
+gboolean WidgetGtk::CallButtonPress(GtkWidget* widget, GdkEventButton* event) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return false;
+
+  return widget_gtk->OnButtonPress(widget, event);
+}
+
+gboolean WidgetGtk::CallButtonRelease(GtkWidget* widget, GdkEventButton* event) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return false;
+
+  return widget_gtk->OnButtonRelease(widget, event);
+}
+
+gboolean WidgetGtk::CallFocusIn(GtkWidget* widget, GdkEventFocus* event) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return false;
+
+  return widget_gtk->OnFocusIn(widget, event);
+}
+
+gboolean WidgetGtk::CallFocusOut(GtkWidget* widget, GdkEventFocus* event) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return false;
+
+  return widget_gtk->OnFocusOut(widget, event);
+}
+
+gboolean WidgetGtk::CallKeyPress(GtkWidget* widget, GdkEventKey* event) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return false;
+
+  return widget_gtk->OnKeyPress(widget, event);
+}
+
+gboolean WidgetGtk::CallKeyRelease(GtkWidget* widget, GdkEventKey* event) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return false;
+
+  return widget_gtk->OnKeyRelease(widget, event);
+}
+
+gboolean WidgetGtk::CallScroll(GtkWidget* widget, GdkEventScroll* event) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return false;
+
+  return widget_gtk->OnScroll(widget, event);
+}
+
+gboolean WidgetGtk::CallVisibilityNotify(GtkWidget* widget,
+                                         GdkEventVisibility* event) {
+  WidgetGtk* widget_gtk = GetViewForNative(widget);
+  if (!widget_gtk)
+    return false;
+
+  return widget_gtk->OnVisibilityNotify(widget, event);
+}
+
+}
diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h
new file mode 100644
index 0000000..4bbc0dd0
--- /dev/null
+++ b/views/widget/widget_gtk.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2009 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 VIEWS_WIDGET_WIDGET_GTK_H_
+#define VIEWS_WIDGET_WIDGET_GTK_H_
+
+#include <gtk/gtk.h>
+
+#include "base/message_loop.h"
+#include "views/widget/widget.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace views {
+
+class View;
+
+class WidgetGtk : public Widget {
+ public:
+  static WidgetGtk* Construct() {
+    // This isn't used, but exists to force WidgetGtk to be instantiable.
+    return new WidgetGtk;
+  }
+
+  WidgetGtk();
+  virtual ~WidgetGtk();
+
+  // Initializes this widget and returns the gtk drawing area for the caller to
+  // add to its hierarchy. (We can't pass in the parent to this method because
+  // there are no standard adding semantics in gtk...)
+  void Init(const gfx::Rect& bounds, bool has_own_focus_manager);
+
+  virtual void SetContentsView(View* view);
+
+  // Overridden from Widget:
+  virtual void GetBounds(gfx::Rect* out, bool including_frame) const;
+  virtual gfx::NativeView GetNativeView() const;
+  virtual void PaintNow(const gfx::Rect& update_rect);
+  virtual RootView* GetRootView();
+  virtual bool IsVisible() const;
+  virtual bool IsActive() const;
+  virtual TooltipManager* GetTooltipManager();
+  virtual bool GetAccelerator(int cmd_id, Accelerator* accelerator);
+
+ protected:
+  virtual void OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) {}
+  virtual gboolean OnPaint(GtkWidget* widget, GdkEventExpose* event);
+  virtual gboolean OnEnterNotify(GtkWidget* widget, GdkEventCrossing* event);
+  virtual gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event);
+  virtual gboolean OnMotionNotify(GtkWidget* widget, GdkEventMotion* event);
+  virtual gboolean OnButtonPress(GtkWidget* widget, GdkEventButton* event);
+  virtual gboolean OnButtonRelease(GtkWidget* widget, GdkEventButton* event);
+  virtual gboolean OnFocusIn(GtkWidget* widget, GdkEventFocus* event) {
+    return false;
+  }
+  virtual gboolean OnFocusOut(GtkWidget* widget, GdkEventFocus* event) {
+    return false;
+  }
+  virtual gboolean OnKeyPress(GtkWidget* widget, GdkEventKey* event);
+  virtual gboolean OnKeyRelease(GtkWidget* widget, GdkEventKey* event);
+  virtual gboolean OnScroll(GtkWidget* widget, GdkEventScroll* event) {
+    return false;
+  }
+  virtual gboolean OnVisibilityNotify(GtkWidget* widget,
+                                      GdkEventVisibility* event) {
+    return false;
+  }
+
+ private:
+  virtual RootView* CreateRootView();
+
+  // Process a mouse click
+  bool ProcessMousePressed(GdkEventButton* event);
+  void ProcessMouseReleased(GdkEventButton* event);
+
+  // Sets and retrieves the WidgetGtk in the userdata section of the widget.
+  static WidgetGtk* GetViewForNative(GtkWidget* widget);
+  static void SetViewForNative(GtkWidget* widget, WidgetGtk* view);
+
+  static RootView* GetRootViewForWidget(GtkWidget* widget);
+  static void SetRootViewForWidget(GtkWidget* widget, RootView* root_view);
+
+  // A set of static signal handlers that bridge
+  static void CallSizeAllocate(GtkWidget* widget, GtkAllocation* allocation);
+  static gboolean CallPaint(GtkWidget* widget, GdkEventExpose* event);
+  static gboolean CallEnterNotify(GtkWidget* widget, GdkEventCrossing* event);
+  static gboolean CallLeaveNotify(GtkWidget* widget, GdkEventCrossing* event);
+  static gboolean CallMotionNotify(GtkWidget* widget, GdkEventMotion* event);
+  static gboolean CallButtonPress(GtkWidget* widget, GdkEventButton* event);
+  static gboolean CallButtonRelease(GtkWidget* widget, GdkEventButton* event);
+  static gboolean CallFocusIn(GtkWidget* widget, GdkEventFocus* event);
+  static gboolean CallFocusOut(GtkWidget* widget, GdkEventFocus* event);
+  static gboolean CallKeyPress(GtkWidget* widget, GdkEventKey* event);
+  static gboolean CallKeyRelease(GtkWidget* widget, GdkEventKey* event);
+  static gboolean CallScroll(GtkWidget* widget, GdkEventScroll* event);
+  static gboolean CallVisibilityNotify(GtkWidget* widget,
+                                       GdkEventVisibility* event);
+
+  // Our native view.
+  GtkWidget* widget_;
+
+  // The root of the View hierarchy attached to this window.
+  scoped_ptr<RootView> root_view_;
+
+  // If true, the mouse is currently down.
+  bool is_mouse_down_;
+
+  // The following are used to detect duplicate mouse move events and not
+  // deliver them. Displaying a window may result in the system generating
+  // duplicate move events even though the mouse hasn't moved.
+
+  // If true, the last event was a mouse move event.
+  bool last_mouse_event_was_move_;
+
+  // Coordinates of the last mouse move event, in screen coordinates.
+  int last_mouse_move_x_;
+  int last_mouse_move_y_;
+};
+
+}  // namespace views
+
+#endif  // VIEWS_WIDGET_WIDGET_GTK_H_
diff --git a/views/widget/widget_win.cc b/views/widget/widget_win.cc
new file mode 100644
index 0000000..2bc9b0c
--- /dev/null
+++ b/views/widget/widget_win.cc
@@ -0,0 +1,999 @@
+// Copyright (c) 2006-2008 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 "views/widget/widget_win.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "base/gfx/native_theme.h"
+#include "base/string_util.h"
+#include "base/win_util.h"
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/common/win_util.h"
+#include "views/accessibility/view_accessibility.h"
+#include "views/controls/native_control_win.h"
+#include "views/fill_layout.h"
+#include "views/focus/focus_util_win.h"
+#include "views/widget/aero_tooltip_manager.h"
+#include "views/widget/root_view.h"
+#include "views/window/window_win.h"
+
+namespace views {
+
+static const DWORD kWindowDefaultChildStyle =
+    WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+static const DWORD kWindowDefaultStyle = WS_OVERLAPPEDWINDOW;
+static const DWORD kWindowDefaultExStyle = 0;
+
+// Property used to link the HWND to its RootView.
+static const wchar_t* const kRootViewWindowProperty = L"__ROOT_VIEW__";
+
+bool SetRootViewForHWND(HWND hwnd, RootView* root_view) {
+  return ::SetProp(hwnd, kRootViewWindowProperty, root_view) ? true : false;
+}
+
+RootView* GetRootViewForHWND(HWND hwnd) {
+  return reinterpret_cast<RootView*>(::GetProp(hwnd, kRootViewWindowProperty));
+}
+
+NativeControlWin* GetNativeControlWinForHWND(HWND hwnd) {
+  return reinterpret_cast<NativeControlWin*>(
+      ::GetProp(hwnd, NativeControlWin::kNativeControlWinKey));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Window class tracking.
+
+// static
+const wchar_t* const WidgetWin::kBaseClassName =
+    L"Chrome_WidgetWin_";
+
+// Window class information used for registering unique windows.
+struct ClassInfo {
+  UINT style;
+  HBRUSH background;
+
+  explicit ClassInfo(int style)
+      : style(style),
+        background(NULL) {}
+
+  // Compares two ClassInfos. Returns true if all members match.
+  bool Equals(const ClassInfo& other) const {
+    return (other.style == style && other.background == background);
+  }
+};
+
+class ClassRegistrar {
+ public:
+  ~ClassRegistrar() {
+    for (RegisteredClasses::iterator i = registered_classes_.begin();
+         i != registered_classes_.end(); ++i) {
+      UnregisterClass(i->name.c_str(), NULL);
+    }
+  }
+
+  // Puts the name for the class matching |class_info| in |class_name|, creating
+  // a new name if the class is not yet known.
+  // Returns true if this class was already known, false otherwise.
+  bool RetrieveClassName(const ClassInfo& class_info, std::wstring* name) {
+    for (RegisteredClasses::const_iterator i = registered_classes_.begin();
+         i != registered_classes_.end(); ++i) {
+      if (class_info.Equals(i->info)) {
+        name->assign(i->name);
+        return true;
+      }
+    }
+
+    name->assign(std::wstring(WidgetWin::kBaseClassName) +
+        IntToWString(registered_count_++));
+    return false;
+  }
+
+  void RegisterClass(const ClassInfo& class_info,
+                     const std::wstring& name,
+                     ATOM atom) {
+    registered_classes_.push_back(RegisteredClass(class_info, name, atom));
+  }
+
+ private:
+  // Represents a registered window class.
+  struct RegisteredClass {
+    RegisteredClass(const ClassInfo& info,
+                    const std::wstring& name,
+                    ATOM atom)
+        : info(info),
+          name(name),
+          atom(atom) {
+    }
+
+    // Info used to create the class.
+    ClassInfo info;
+
+    // The name given to the window.
+    std::wstring name;
+
+    // The ATOM returned from creating the window.
+    ATOM atom;
+  };
+
+  ClassRegistrar() : registered_count_(0) { }
+  friend struct DefaultSingletonTraits<ClassRegistrar>;
+
+  typedef std::list<RegisteredClass> RegisteredClasses;
+  RegisteredClasses registered_classes_;
+
+  // Counter of how many classes have ben registered so far.
+  int registered_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClassRegistrar);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// WidgetWin, public
+
+WidgetWin::WidgetWin()
+    : close_widget_factory_(this),
+      active_mouse_tracking_flags_(0),
+      has_capture_(false),
+      current_action_(FA_NONE),
+      window_style_(0),
+      window_ex_style_(kWindowDefaultExStyle),
+      use_layered_buffer_(true),
+      layered_alpha_(255),
+      delete_on_destroy_(true),
+      can_update_layered_window_(true),
+      last_mouse_event_was_move_(false),
+      is_mouse_down_(false),
+      is_window_(false),
+      class_style_(CS_DBLCLKS),
+      hwnd_(NULL) {
+}
+
+WidgetWin::~WidgetWin() {
+  MessageLoopForUI::current()->RemoveObserver(this);
+}
+
+void WidgetWin::Init(HWND parent, const gfx::Rect& bounds,
+                     bool has_own_focus_manager) {
+  if (window_style_ == 0)
+    window_style_ = parent ? kWindowDefaultChildStyle : kWindowDefaultStyle;
+
+  // See if the style has been overridden.
+  opaque_ = !(window_ex_style_ & WS_EX_TRANSPARENT);
+  use_layered_buffer_ = (use_layered_buffer_ &&
+                         !!(window_ex_style_ & WS_EX_LAYERED));
+
+  // Force creation of the RootView if it hasn't been created yet.
+  GetRootView();
+
+  // Ensures the parent we have been passed is valid, otherwise CreateWindowEx
+  // will fail.
+  if (parent && !::IsWindow(parent)) {
+    NOTREACHED() << "invalid parent window specified.";
+    parent = NULL;
+  }
+
+  hwnd_ = CreateWindowEx(window_ex_style_, GetWindowClassName().c_str(), L"",
+                         window_style_, bounds.x(), bounds.y(), bounds.width(),
+                         bounds.height(), parent, NULL, NULL, this);
+  DCHECK(hwnd_);
+  TRACK_HWND_CREATION(hwnd_);
+  SetWindowSupportsRerouteMouseWheel(hwnd_);
+
+  // The window procedure should have set the data for us.
+  DCHECK(win_util::GetWindowUserData(hwnd_) == this);
+
+  root_view_->OnWidgetCreated();
+
+  if (has_own_focus_manager) {
+    FocusManager::CreateFocusManager(hwnd_, GetRootView());
+  } else {
+    // Subclass the window so we get the tab key messages when a view with no
+    // associated native window is focused.
+    FocusManager::InstallFocusSubclass(hwnd_, NULL);
+  }
+
+  // Sets the RootView as a property, so the automation can introspect windows.
+  SetRootViewForHWND(hwnd_, root_view_.get());
+
+  MessageLoopForUI::current()->AddObserver(this);
+
+  // Windows special DWM window frame requires a special tooltip manager so
+  // that window controls in Chrome windows don't flicker when you move your
+  // mouse over them. See comment in aero_tooltip_manager.h.
+  if (win_util::ShouldUseVistaFrame()) {
+    tooltip_manager_.reset(new AeroTooltipManager(this, GetNativeView()));
+  } else {
+    tooltip_manager_.reset(new TooltipManager(this, GetNativeView()));
+  }
+
+  // This message initializes the window so that focus border are shown for
+  // windows.
+  ::SendMessage(GetNativeView(),
+                WM_CHANGEUISTATE,
+                MAKELPARAM(UIS_CLEAR, UISF_HIDEFOCUS),
+                0);
+
+  // Bug 964884: detach the IME attached to this window.
+  // We should attach IMEs only when we need to input CJK strings.
+  ::ImmAssociateContextEx(GetNativeView(), NULL, 0);
+}
+
+void WidgetWin::SetContentsView(View* view) {
+  DCHECK(view && hwnd_) << "Can't be called until after the HWND is created!";
+  // The ContentsView must be set up _after_ the window is created so that its
+  // Widget pointer is valid.
+  root_view_->SetLayoutManager(new FillLayout);
+  if (root_view_->GetChildViewCount() != 0)
+    root_view_->RemoveAllChildViews(true);
+  root_view_->AddChildView(view);
+
+  // Manually size the window here to ensure the root view is laid out.
+  RECT wr;
+  GetWindowRect(&wr);
+  ChangeSize(0, CSize(wr.right - wr.left, wr.bottom - wr.top));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Widget implementation:
+
+void WidgetWin::GetBounds(gfx::Rect* out, bool including_frame) const {
+  CRect crect;
+  if (including_frame) {
+    GetWindowRect(&crect);
+    *out = gfx::Rect(crect);
+    return;
+  }
+
+  GetClientRect(&crect);
+  POINT p = {0, 0};
+  ::ClientToScreen(hwnd_, &p);
+  out->SetRect(crect.left + p.x, crect.top + p.y,
+               crect.Width(), crect.Height());
+}
+
+gfx::NativeView WidgetWin::GetNativeView() const {
+  return hwnd_;
+}
+
+void WidgetWin::PaintNow(const gfx::Rect& update_rect) {
+  if (use_layered_buffer_) {
+    PaintLayeredWindow();
+  } else if (root_view_->NeedsPainting(false) && IsWindow()) {
+    if (!opaque_ && GetParent()) {
+      // We're transparent. Need to force painting to occur from our parent.
+      CRect parent_update_rect = update_rect.ToRECT();
+      POINT location_in_parent = { 0, 0 };
+      ClientToScreen(hwnd_, &location_in_parent);
+      ::ScreenToClient(GetParent(), &location_in_parent);
+      parent_update_rect.OffsetRect(location_in_parent);
+      ::RedrawWindow(GetParent(), parent_update_rect, NULL,
+                     RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN);
+    } else {
+      RECT native_update_rect = update_rect.ToRECT();
+      RedrawWindow(hwnd_, &native_update_rect, NULL,
+                   RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN);
+    }
+    // As we were created with a style of WS_CLIPCHILDREN redraw requests may
+    // result in an empty paint rect in WM_PAINT (this'll happen if a
+    // child HWND completely contains the update _rect). In such a scenario
+    // RootView would never get a ProcessPaint and always think it needs to
+    // be painted (leading to a steady stream of RedrawWindow requests on every
+    // event). For this reason we tell RootView it doesn't need to paint
+    // here.
+    root_view_->ClearPaintRect();
+  }
+}
+
+RootView* WidgetWin::GetRootView() {
+  if (!root_view_.get()) {
+    // First time the root view is being asked for, create it now.
+    root_view_.reset(CreateRootView());
+  }
+  return root_view_.get();
+}
+
+bool WidgetWin::IsVisible() const {
+  return !!::IsWindowVisible(GetNativeView());
+}
+
+bool WidgetWin::IsActive() const {
+  return win_util::IsWindowActive(GetNativeView());
+}
+
+TooltipManager* WidgetWin::GetTooltipManager() {
+  return tooltip_manager_.get();
+}
+
+Window* WidgetWin::GetWindow() {
+  return GetWindowImpl(hwnd_);
+}
+
+const Window* WidgetWin::GetWindow() const {
+  return GetWindowImpl(hwnd_);
+}
+
+void WidgetWin::SetLayeredAlpha(BYTE layered_alpha) {
+  layered_alpha_ = layered_alpha;
+
+//  if (hwnd_)
+//    UpdateWindowFromContents(contents_->getTopPlatformDevice().getBitmapDC());
+}
+
+void WidgetWin::SetUseLayeredBuffer(bool use_layered_buffer) {
+  if (use_layered_buffer_ == use_layered_buffer)
+    return;
+
+  use_layered_buffer_ = use_layered_buffer;
+  if (!hwnd_)
+    return;
+
+  if (use_layered_buffer_) {
+    // Force creation of the buffer at the right size.
+    RECT wr;
+    GetWindowRect(&wr);
+    ChangeSize(0, CSize(wr.right - wr.left, wr.bottom - wr.top));
+  } else {
+    contents_.reset(NULL);
+  }
+}
+
+static BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM l_param) {
+  RootView* root_view =
+    reinterpret_cast<RootView*>(GetProp(hwnd, kRootViewWindowProperty));
+  if (root_view) {
+    *reinterpret_cast<RootView**>(l_param) = root_view;
+    return FALSE;  // Stop enumerating.
+  }
+  return TRUE;  // Keep enumerating.
+}
+
+// static
+RootView* WidgetWin::FindRootView(HWND hwnd) {
+  RootView* root_view =
+    reinterpret_cast<RootView*>(GetProp(hwnd, kRootViewWindowProperty));
+  if (root_view)
+    return root_view;
+
+  // Enumerate all children and check if they have a RootView.
+  EnumChildWindows(hwnd, EnumChildProc, reinterpret_cast<LPARAM>(&root_view));
+
+  return root_view;
+}
+
+void WidgetWin::Close() {
+  if (!IsWindow())
+    return;  // No need to do anything.
+
+  // Let's hide ourselves right away.
+  Hide();
+  if (close_widget_factory_.empty()) {
+    // And we delay the close so that if we are called from an ATL callback,
+    // we don't destroy the window before the callback returned (as the caller
+    // may delete ourselves on destroy and the ATL callback would still
+    // dereference us when the callback returns).
+    MessageLoop::current()->PostTask(FROM_HERE,
+        close_widget_factory_.NewRunnableMethod(
+            &WidgetWin::CloseNow));
+  }
+}
+
+void WidgetWin::Hide() {
+  if (IsWindow()) {
+    // NOTE: Be careful not to activate any windows here (for example, calling
+    // ShowWindow(SW_HIDE) will automatically activate another window).  This
+    // code can be called while a window is being deactivated, and activating
+    // another window will screw up the activation that is already in progress.
+    SetWindowPos(NULL, 0, 0, 0, 0,
+                 SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE |
+                 SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
+  }
+}
+
+void WidgetWin::Show() {
+  if (IsWindow())
+    ShowWindow(SW_SHOWNOACTIVATE);
+}
+
+void WidgetWin::CloseNow() {
+  // We may already have been destroyed if the selection resulted in a tab
+  // switch which will have reactivated the browser window and closed us, so
+  // we need to check to see if we're still a window before trying to destroy
+  // ourself.
+  if (IsWindow())
+    DestroyWindow();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MessageLoop::Observer
+
+void WidgetWin::WillProcessMessage(const MSG& msg) {
+}
+
+void WidgetWin::DidProcessMessage(const MSG& msg) {
+  if (root_view_->NeedsPainting(true)) {
+    PaintNow(root_view_->GetScheduledPaintRect());
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// FocusTraversable
+
+View* WidgetWin::FindNextFocusableView(
+    View* starting_view, bool reverse, Direction direction, bool dont_loop,
+    FocusTraversable** focus_traversable, View** focus_traversable_view) {
+  return root_view_->FindNextFocusableView(starting_view,
+                                           reverse,
+                                           direction,
+                                           dont_loop,
+                                           focus_traversable,
+                                           focus_traversable_view);
+}
+
+FocusTraversable* WidgetWin::GetFocusTraversableParent() {
+  // We are a proxy to the root view, so we should be bypassed when traversing
+  // up and as a result this should not be called.
+  NOTREACHED();
+  return NULL;
+}
+
+void WidgetWin::SetFocusTraversableParent(FocusTraversable* parent) {
+  root_view_->SetFocusTraversableParent(parent);
+}
+
+View* WidgetWin::GetFocusTraversableParentView() {
+  // We are a proxy to the root view, so we should be bypassed when traversing
+  // up and as a result this should not be called.
+  NOTREACHED();
+  return NULL;
+}
+
+void WidgetWin::SetFocusTraversableParentView(View* parent_view) {
+  root_view_->SetFocusTraversableParentView(parent_view);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Message handlers
+
+void WidgetWin::OnCaptureChanged(HWND hwnd) {
+  if (has_capture_) {
+    if (is_mouse_down_)
+      root_view_->ProcessMouseDragCanceled();
+    is_mouse_down_ = false;
+    has_capture_ = false;
+  }
+}
+
+void WidgetWin::OnClose() {
+  Close();
+}
+
+void WidgetWin::OnDestroy() {
+  root_view_->OnWidgetDestroyed();
+
+  RemoveProp(hwnd_, kRootViewWindowProperty);
+}
+
+LRESULT WidgetWin::OnEraseBkgnd(HDC dc) {
+  // This is needed for magical win32 flicker ju-ju
+  return 1;
+}
+
+LRESULT WidgetWin::OnGetObject(UINT uMsg, WPARAM w_param, LPARAM l_param) {
+  LRESULT reference_result = static_cast<LRESULT>(0L);
+
+  // Accessibility readers will send an OBJID_CLIENT message
+  if (OBJID_CLIENT == l_param) {
+    // If our MSAA root is already created, reuse that pointer. Otherwise,
+    // create a new one.
+    if (!accessibility_root_) {
+      CComObject<ViewAccessibility>* instance = NULL;
+
+      HRESULT hr = CComObject<ViewAccessibility>::CreateInstance(&instance);
+      DCHECK(SUCCEEDED(hr));
+
+      if (!instance) {
+        // Return with failure.
+        return static_cast<LRESULT>(0L);
+      }
+
+      CComPtr<IAccessible> accessibility_instance(instance);
+
+      if (!SUCCEEDED(instance->Initialize(root_view_.get()))) {
+        // Return with failure.
+        return static_cast<LRESULT>(0L);
+      }
+
+      // All is well, assign the temp instance to the class smart pointer
+      accessibility_root_.Attach(accessibility_instance.Detach());
+
+      if (!accessibility_root_) {
+        // Return with failure.
+        return static_cast<LRESULT>(0L);
+      }
+
+      // Notify that an instance of IAccessible was allocated for m_hWnd
+      ::NotifyWinEvent(EVENT_OBJECT_CREATE, GetNativeView(), OBJID_CLIENT,
+                       CHILDID_SELF);
+    }
+
+    // Create a reference to ViewAccessibility that MSAA will marshall
+    // to the client.
+    reference_result = LresultFromObject(IID_IAccessible, w_param,
+        static_cast<IAccessible*>(accessibility_root_));
+  }
+  return reference_result;
+}
+
+void WidgetWin::OnKeyDown(TCHAR c, UINT rep_cnt, UINT flags) {
+  KeyEvent event(Event::ET_KEY_PRESSED, c, rep_cnt, flags);
+  SetMsgHandled(root_view_->ProcessKeyEvent(event));
+}
+
+void WidgetWin::OnKeyUp(TCHAR c, UINT rep_cnt, UINT flags) {
+  KeyEvent event(Event::ET_KEY_RELEASED, c, rep_cnt, flags);
+  SetMsgHandled(root_view_->ProcessKeyEvent(event));
+}
+
+void WidgetWin::OnLButtonDown(UINT flags, const CPoint& point) {
+  ProcessMousePressed(point, flags | MK_LBUTTON, false, false);
+}
+
+void WidgetWin::OnLButtonUp(UINT flags, const CPoint& point) {
+  ProcessMouseReleased(point, flags | MK_LBUTTON);
+}
+
+void WidgetWin::OnLButtonDblClk(UINT flags, const CPoint& point) {
+  ProcessMousePressed(point, flags | MK_LBUTTON, true, false);
+}
+
+void WidgetWin::OnMButtonDown(UINT flags, const CPoint& point) {
+  ProcessMousePressed(point, flags | MK_MBUTTON, false, false);
+}
+
+void WidgetWin::OnMButtonUp(UINT flags, const CPoint& point) {
+  ProcessMouseReleased(point, flags | MK_MBUTTON);
+}
+
+void WidgetWin::OnMButtonDblClk(UINT flags, const CPoint& point) {
+  ProcessMousePressed(point, flags | MK_MBUTTON, true, false);
+}
+
+LRESULT WidgetWin::OnMouseActivate(HWND window, UINT hittest_code,
+                                   UINT message) {
+  SetMsgHandled(FALSE);
+  return MA_ACTIVATE;
+}
+
+void WidgetWin::OnMouseMove(UINT flags, const CPoint& point) {
+  ProcessMouseMoved(point, flags, false);
+}
+
+LRESULT WidgetWin::OnMouseLeave(UINT message, WPARAM w_param, LPARAM l_param) {
+  tooltip_manager_->OnMouseLeave();
+  ProcessMouseExited();
+  return 0;
+}
+
+LRESULT WidgetWin::OnMouseWheel(UINT message, WPARAM w_param, LPARAM l_param) {
+  // Reroute the mouse-wheel to the window under the mouse pointer if
+  // applicable.
+  if (message == WM_MOUSEWHEEL &&
+      views::RerouteMouseWheel(hwnd_, w_param, l_param)) {
+    return 0;
+  }
+
+  int flags = GET_KEYSTATE_WPARAM(w_param);
+  short distance = GET_WHEEL_DELTA_WPARAM(w_param);
+  int x = GET_X_LPARAM(l_param);
+  int y = GET_Y_LPARAM(l_param);
+  MouseWheelEvent e(distance, x, y, Event::ConvertWindowsFlags(flags));
+  return root_view_->ProcessMouseWheelEvent(e) ? 0 : 1;
+}
+
+LRESULT WidgetWin::OnMouseRange(UINT msg, WPARAM w_param, LPARAM l_param) {
+  tooltip_manager_->OnMouse(msg, w_param, l_param);
+  SetMsgHandled(FALSE);
+  return 0;
+}
+
+void WidgetWin::OnNCLButtonDblClk(UINT flags, const CPoint& point) {
+  SetMsgHandled(ProcessMousePressed(point, flags | MK_LBUTTON, true, true));
+}
+
+void WidgetWin::OnNCLButtonDown(UINT flags, const CPoint& point) {
+  SetMsgHandled(ProcessMousePressed(point, flags | MK_LBUTTON, false, true));
+}
+
+void WidgetWin::OnNCLButtonUp(UINT flags, const CPoint& point) {
+  SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnNCMButtonDblClk(UINT flags, const CPoint& point) {
+  SetMsgHandled(ProcessMousePressed(point, flags | MK_MBUTTON, true, true));
+}
+
+void WidgetWin::OnNCMButtonDown(UINT flags, const CPoint& point) {
+  SetMsgHandled(ProcessMousePressed(point, flags | MK_MBUTTON, false, true));
+}
+
+void WidgetWin::OnNCMButtonUp(UINT flags, const CPoint& point) {
+  SetMsgHandled(FALSE);
+}
+
+LRESULT WidgetWin::OnNCMouseLeave(UINT uMsg, WPARAM w_param, LPARAM l_param) {
+  ProcessMouseExited();
+  return 0;
+}
+
+LRESULT WidgetWin::OnNCMouseMove(UINT flags, const CPoint& point) {
+  // NC points are in screen coordinates.
+  CPoint temp = point;
+  MapWindowPoints(HWND_DESKTOP, GetNativeView(), &temp, 1);
+  ProcessMouseMoved(temp, 0, true);
+
+  // We need to process this message to stop Windows from drawing the window
+  // controls as the mouse moves over the title bar area when the window is
+  // maximized.
+  return 0;
+}
+
+void WidgetWin::OnNCRButtonDblClk(UINT flags, const CPoint& point) {
+  SetMsgHandled(ProcessMousePressed(point, flags | MK_RBUTTON, true, true));
+}
+
+void WidgetWin::OnNCRButtonDown(UINT flags, const CPoint& point) {
+  SetMsgHandled(ProcessMousePressed(point, flags | MK_RBUTTON, false, true));
+}
+
+void WidgetWin::OnNCRButtonUp(UINT flags, const CPoint& point) {
+  SetMsgHandled(FALSE);
+}
+
+LRESULT WidgetWin::OnNotify(int w_param, NMHDR* l_param) {
+  // We can be sent this message before the tooltip manager is created, if a
+  // subclass overrides OnCreate and creates some kind of Windows control there
+  // that sends WM_NOTIFY messages.
+  if (tooltip_manager_.get()) {
+    bool handled;
+    LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled);
+    SetMsgHandled(handled);
+    return result;
+  }
+  SetMsgHandled(FALSE);
+  return 0;
+}
+
+void WidgetWin::OnPaint(HDC dc) {
+  root_view_->OnPaint(GetNativeView());
+}
+
+void WidgetWin::OnRButtonDown(UINT flags, const CPoint& point) {
+  ProcessMousePressed(point, flags | MK_RBUTTON, false, false);
+}
+
+void WidgetWin::OnRButtonUp(UINT flags, const CPoint& point) {
+  ProcessMouseReleased(point, flags | MK_RBUTTON);
+}
+
+void WidgetWin::OnRButtonDblClk(UINT flags, const CPoint& point) {
+  ProcessMousePressed(point, flags | MK_RBUTTON, true, false);
+}
+
+void WidgetWin::OnSize(UINT param, const CSize& size) {
+  ChangeSize(param, size);
+}
+
+void WidgetWin::OnThemeChanged() {
+  // Notify NativeTheme.
+  gfx::NativeTheme::instance()->CloseHandles();
+}
+
+void WidgetWin::OnFinalMessage(HWND window) {
+  if (delete_on_destroy_)
+    delete this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WidgetWin, protected:
+
+void WidgetWin::TrackMouseEvents(DWORD mouse_tracking_flags) {
+  // Begin tracking mouse events for this HWND so that we get WM_MOUSELEAVE
+  // when the user moves the mouse outside this HWND's bounds.
+  if (active_mouse_tracking_flags_ == 0 || mouse_tracking_flags & TME_CANCEL) {
+    if (mouse_tracking_flags & TME_CANCEL) {
+      // We're about to cancel active mouse tracking, so empty out the stored
+      // state.
+      active_mouse_tracking_flags_ = 0;
+    } else {
+      active_mouse_tracking_flags_ = mouse_tracking_flags;
+    }
+
+    TRACKMOUSEEVENT tme;
+    tme.cbSize = sizeof(tme);
+    tme.dwFlags = mouse_tracking_flags;
+    tme.hwndTrack = GetNativeView();
+    tme.dwHoverTime = 0;
+    TrackMouseEvent(&tme);
+  } else if (mouse_tracking_flags != active_mouse_tracking_flags_) {
+    TrackMouseEvents(active_mouse_tracking_flags_ | TME_CANCEL);
+    TrackMouseEvents(mouse_tracking_flags);
+  }
+}
+
+bool WidgetWin::ProcessMousePressed(const CPoint& point,
+                                    UINT flags,
+                                    bool dbl_click,
+                                    bool non_client) {
+  last_mouse_event_was_move_ = false;
+  // Windows gives screen coordinates for nonclient events, while the RootView
+  // expects window coordinates; convert if necessary.
+  gfx::Point converted_point(point);
+  if (non_client)
+    View::ConvertPointToView(NULL, root_view_.get(), &converted_point);
+  MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED,
+                           converted_point.x(),
+                           converted_point.y(),
+                           (dbl_click ? MouseEvent::EF_IS_DOUBLE_CLICK : 0) |
+                           (non_client ? MouseEvent::EF_IS_NON_CLIENT : 0) |
+                           Event::ConvertWindowsFlags(flags));
+  if (root_view_->OnMousePressed(mouse_pressed)) {
+    is_mouse_down_ = true;
+    if (!has_capture_) {
+      SetCapture();
+      has_capture_ = true;
+      current_action_ = FA_FORWARDING;
+    }
+    return true;
+  }
+  return false;
+}
+
+void WidgetWin::ProcessMouseDragged(const CPoint& point, UINT flags) {
+  last_mouse_event_was_move_ = false;
+  MouseEvent mouse_drag(Event::ET_MOUSE_DRAGGED,
+                        point.x,
+                        point.y,
+                        Event::ConvertWindowsFlags(flags));
+  root_view_->OnMouseDragged(mouse_drag);
+}
+
+void WidgetWin::ProcessMouseReleased(const CPoint& point, UINT flags) {
+  last_mouse_event_was_move_ = false;
+  MouseEvent mouse_up(Event::ET_MOUSE_RELEASED,
+                      point.x,
+                      point.y,
+                      Event::ConvertWindowsFlags(flags));
+  // Release the capture first, that way we don't get confused if
+  // OnMouseReleased blocks.
+  if (has_capture_ && ReleaseCaptureOnMouseReleased()) {
+    has_capture_ = false;
+    current_action_ = FA_NONE;
+    ReleaseCapture();
+  }
+  is_mouse_down_ = false;
+  root_view_->OnMouseReleased(mouse_up, false);
+}
+
+void WidgetWin::ProcessMouseMoved(const CPoint &point, UINT flags,
+                                  bool is_nonclient) {
+  // Windows only fires WM_MOUSELEAVE events if the application begins
+  // "tracking" mouse events for a given HWND during WM_MOUSEMOVE events.
+  // We need to call |TrackMouseEvents| to listen for WM_MOUSELEAVE.
+  if (!has_capture_)
+    TrackMouseEvents(is_nonclient ? TME_NONCLIENT | TME_LEAVE : TME_LEAVE);
+  if (has_capture_ && is_mouse_down_) {
+    ProcessMouseDragged(point, flags);
+  } else {
+    gfx::Point screen_loc(point);
+    View::ConvertPointToScreen(root_view_.get(), &screen_loc);
+    if (last_mouse_event_was_move_ && last_mouse_move_x_ == screen_loc.x() &&
+        last_mouse_move_y_ == screen_loc.y()) {
+      // Don't generate a mouse event for the same location as the last.
+      return;
+    }
+    last_mouse_move_x_ = screen_loc.x();
+    last_mouse_move_y_ = screen_loc.y();
+    last_mouse_event_was_move_ = true;
+    MouseEvent mouse_move(Event::ET_MOUSE_MOVED,
+                          point.x,
+                          point.y,
+                          Event::ConvertWindowsFlags(flags));
+    root_view_->OnMouseMoved(mouse_move);
+  }
+}
+
+void WidgetWin::ProcessMouseExited() {
+  last_mouse_event_was_move_ = false;
+  root_view_->ProcessOnMouseExited();
+  // Reset our tracking flag so that future mouse movement over this WidgetWin
+  // results in a new tracking session.
+  active_mouse_tracking_flags_ = 0;
+}
+
+void WidgetWin::ChangeSize(UINT size_param, const CSize& size) {
+  CRect rect;
+  if (use_layered_buffer_) {
+    GetWindowRect(&rect);
+    SizeContents(rect);
+  } else {
+    GetClientRect(&rect);
+  }
+
+  // Resizing changes the size of the view hierarchy and thus forces a
+  // complete relayout.
+  root_view_->SetBounds(0, 0, rect.Width(), rect.Height());
+  root_view_->Layout();
+  root_view_->SchedulePaint();
+
+  if (use_layered_buffer_)
+    PaintNow(gfx::Rect(rect));
+}
+
+RootView* WidgetWin::CreateRootView() {
+  return new RootView(this);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WidgetWin, private:
+
+// static
+Window* WidgetWin::GetWindowImpl(HWND hwnd) {
+  // NOTE: we can't use GetAncestor here as constrained windows are a Window,
+  // but not a top level window.
+  HWND parent = hwnd;
+  while (parent) {
+    WidgetWin* widget =
+        reinterpret_cast<WidgetWin*>(win_util::GetWindowUserData(parent));
+    if (widget && widget->is_window_)
+      return static_cast<WindowWin*>(widget);
+    parent = ::GetParent(parent);
+  }
+  return NULL;
+}
+
+void WidgetWin::SizeContents(const CRect& window_rect) {
+  contents_.reset(new ChromeCanvas(window_rect.Width(),
+                                   window_rect.Height(),
+                                   false));
+}
+
+void WidgetWin::PaintLayeredWindow() {
+  // Painting monkeys with our cliprect, so we need to save it so that the
+  // call to UpdateLayeredWindow updates the entire window, not just the
+  // cliprect.
+  contents_->save(SkCanvas::kClip_SaveFlag);
+  gfx::Rect dirty_rect = root_view_->GetScheduledPaintRect();
+  contents_->ClipRectInt(dirty_rect.x(), dirty_rect.y(), dirty_rect.width(),
+                         dirty_rect.height());
+  root_view_->ProcessPaint(contents_.get());
+  contents_->restore();
+
+  UpdateWindowFromContents(contents_->getTopPlatformDevice().getBitmapDC());
+}
+
+void WidgetWin::UpdateWindowFromContents(HDC dib_dc) {
+  DCHECK(use_layered_buffer_);
+  if (can_update_layered_window_) {
+    CRect wr;
+    GetWindowRect(&wr);
+    CSize size(wr.right - wr.left, wr.bottom - wr.top);
+    CPoint zero_origin(0, 0);
+    CPoint window_position = wr.TopLeft();
+
+    BLENDFUNCTION blend = {AC_SRC_OVER, 0, layered_alpha_, AC_SRC_ALPHA};
+    ::UpdateLayeredWindow(
+        hwnd_, NULL, &window_position, &size, dib_dc, &zero_origin,
+        RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
+  }
+}
+
+std::wstring WidgetWin::GetWindowClassName() {
+  ClassInfo class_info(initial_class_style());
+  std::wstring name;
+  if (Singleton<ClassRegistrar>()->RetrieveClassName(class_info, &name))
+    return name;
+
+  // No class found, need to register one.
+  WNDCLASSEX class_ex;
+  class_ex.cbSize = sizeof(WNDCLASSEX);
+  class_ex.style = class_info.style;
+  class_ex.lpfnWndProc = &WidgetWin::WndProc;
+  class_ex.cbClsExtra = 0;
+  class_ex.cbWndExtra = 0;
+  class_ex.hInstance = NULL;
+  class_ex.hIcon = LoadIcon(GetModuleHandle(L"chrome.dll"),
+                            MAKEINTRESOURCE(IDR_MAINFRAME));
+  class_ex.hCursor = LoadCursor(NULL, IDC_ARROW);
+  class_ex.hbrBackground = reinterpret_cast<HBRUSH>(class_info.background + 1);
+  class_ex.lpszMenuName = NULL;
+  class_ex.lpszClassName = name.c_str();
+  class_ex.hIconSm = class_ex.hIcon;
+  ATOM atom = RegisterClassEx(&class_ex);
+  DCHECK(atom);
+
+  Singleton<ClassRegistrar>()->RegisterClass(class_info, name, atom);
+
+  return name;
+}
+
+// Get the source HWND of the specified message. Depending on the message, the
+// source HWND is encoded in either the WPARAM or the LPARAM value.
+HWND GetControlHWNDForMessage(UINT message, WPARAM w_param, LPARAM l_param) {
+  // Each of the following messages can be sent by a child HWND and must be
+  // forwarded to its associated NativeControlWin for handling.
+  switch (message) {
+    case WM_NOTIFY:
+      return reinterpret_cast<NMHDR*>(l_param)->hwndFrom;
+    case WM_COMMAND:
+      return reinterpret_cast<HWND>(l_param);
+    case WM_CONTEXTMENU:
+      return reinterpret_cast<HWND>(w_param);
+    case WM_CTLCOLORBTN:
+    case WM_CTLCOLORSTATIC:
+      return reinterpret_cast<HWND>(l_param);
+  }
+  return NULL;
+}
+
+// Some messages may be sent to us by a child HWND managed by
+// NativeControlWin. If this is the case, this function will forward those
+// messages on to the object associated with the source HWND and return true,
+// in which case the window procedure must not do any further processing of
+// the message. If there is no associated NativeControlWin, the return value
+// will be false and the WndProc can continue processing the message normally.
+// |l_result| contains the result of the message processing by the control and
+// must be returned by the WndProc if the return value is true.
+bool ProcessNativeControlMessage(UINT message,
+                                 WPARAM w_param,
+                                 LPARAM l_param,
+                                 LRESULT* l_result) {
+  *l_result = 0;
+
+  HWND control_hwnd = GetControlHWNDForMessage(message, w_param, l_param);
+  if (IsWindow(control_hwnd)) {
+    NativeControlWin* wrapper = GetNativeControlWinForHWND(control_hwnd);
+    if (wrapper)
+      return wrapper->ProcessMessage(message, w_param, l_param, l_result);
+  }
+
+  return false;
+}
+
+// static
+LRESULT CALLBACK WidgetWin::WndProc(HWND window, UINT message,
+                                    WPARAM w_param, LPARAM l_param) {
+  if (message == WM_NCCREATE) {
+    CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(l_param);
+    WidgetWin* widget = reinterpret_cast<WidgetWin*>(cs->lpCreateParams);
+    DCHECK(widget);
+    win_util::SetWindowUserData(window, widget);
+    widget->hwnd_ = window;
+    return TRUE;
+  }
+
+  WidgetWin* widget = reinterpret_cast<WidgetWin*>(
+      win_util::GetWindowUserData(window));
+  if (!widget)
+    return 0;
+
+  LRESULT result = 0;
+
+  // First allow messages sent by child controls to be processed directly by
+  // their associated views. If such a view is present, it will handle the
+  // message *instead of* this WidgetWin.
+  if (ProcessNativeControlMessage(message, w_param, l_param, &result))
+    return result;
+
+  // Otherwise we handle everything else.
+  if (!widget->ProcessWindowMessage(window, message, w_param, l_param, result))
+    result = DefWindowProc(window, message, w_param, l_param);
+  if (message == WM_NCDESTROY) {
+    TRACK_HWND_DESTRUCTION(window);
+    widget->hwnd_ = NULL;
+    widget->OnFinalMessage(window);
+  }
+  return result;
+}
+
+}  // namespace views
diff --git a/views/widget/widget_win.h b/views/widget/widget_win.h
new file mode 100644
index 0000000..09efa21
--- /dev/null
+++ b/views/widget/widget_win.h
@@ -0,0 +1,636 @@
+// Copyright (c) 2006-2008 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 VIEWS_WIDGET_WIDGET_WIN_H_
+#define VIEWS_WIDGET_WIDGET_WIN_H_
+
+#include <atlbase.h>
+#include <atlcrack.h>
+
+#include "base/message_loop.h"
+#include "base/system_monitor.h"
+#include "views/focus/focus_manager.h"
+#include "views/layout_manager.h"
+#include "views/widget/widget.h"
+
+class ChromeCanvas;
+
+namespace gfx {
+class Rect;
+}
+
+namespace views {
+
+class RootView;
+class TooltipManager;
+class Window;
+
+bool SetRootViewForHWND(HWND hwnd, RootView* root_view);
+RootView* GetRootViewForHWND(HWND hwnd);
+
+// A Windows message reflected from other windows. This message is sent
+// with the following arguments:
+// hWnd - Target window
+// uMsg - kReflectedMessage
+// wParam - Should be 0
+// lParam - Pointer to MSG struct containing the original message.
+static const int kReflectedMessage = WM_APP + 3;
+
+// These two messages aren't defined in winuser.h, but they are sent to windows
+// with captions. They appear to paint the window caption and frame.
+// Unfortunately if you override the standard non-client rendering as we do
+// with CustomFrameWindow, sometimes Windows (not deterministically
+// reproducibly but definitely frequently) will send these messages to the
+// window and paint the standard caption/title over the top of the custom one.
+// So we need to handle these messages in CustomFrameWindow to prevent this
+// from happening.
+static const int WM_NCUAHDRAWCAPTION = 0xAE;
+static const int WM_NCUAHDRAWFRAME = 0xAF;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// WidgetWin
+//  A Widget for a views hierarchy used to represent anything that can be
+//  contained within an HWND, e.g. a control, a window, etc. Specializations
+//  suitable for specific tasks, e.g. top level window, are derived from this.
+//
+//  This Widget contains a RootView which owns the hierarchy of views within it.
+//  As long as views are part of this tree, they will be deleted automatically
+//  when the RootView is destroyed. If you remove a view from the tree, you are
+//  then responsible for cleaning up after it.
+//
+///////////////////////////////////////////////////////////////////////////////
+class WidgetWin : public Widget,
+                  public MessageLoopForUI::Observer,
+                  public FocusTraversable,
+                  public AcceleratorTarget {
+ public:
+  WidgetWin();
+  virtual ~WidgetWin();
+
+  // Initialize the Widget with a parent and an initial desired size.
+  // |contents_view| is the view that will be the single child of RootView
+  // within this Widget. As contents_view is inserted into RootView's tree,
+  // RootView assumes ownership of this view and cleaning it up. If you remove
+  // this view, you are responsible for its destruction. If this value is NULL,
+  // the caller is responsible for populating the RootView, and sizing its
+  // contents as the window is sized.
+  // If |has_own_focus_manager| is true, the focus traversal stay confined to
+  // the window.
+  void Init(HWND parent,
+            const gfx::Rect& bounds,
+            bool has_own_focus_manager);
+
+  // Sets the specified view as the contents of this Widget. There can only
+  // be one contnets view child of this Widget's RootView. This view is sized to
+  // fit the entire size of the RootView. The RootView takes ownership of this
+  // View, unless it is set as not being parent-owned.
+  virtual void SetContentsView(View* view);
+
+  // Sets the window styles. This is ONLY used when the window is created.
+  // In other words, if you invoke this after invoking Init, nothing happens.
+  void set_window_style(DWORD style) { window_style_ = style; }
+  DWORD window_style() const { return window_style_; }
+
+  // Sets the extended window styles. See comment about |set_window_style|.
+  void set_window_ex_style(DWORD style) { window_ex_style_ = style; }
+  DWORD window_ex_style() const { return window_ex_style_; };
+
+  // Sets the class style to use. The default is CS_DBLCLKS.
+  void set_initial_class_style(UINT class_style) {
+    // We dynamically generate the class name, so don't register it globally!
+    DCHECK((class_style & CS_GLOBALCLASS) == 0);
+    class_style_ = class_style;
+  }
+  UINT initial_class_style() { return class_style_; }
+
+  void set_delete_on_destroy(bool delete_on_destroy) {
+    delete_on_destroy_ = delete_on_destroy;
+  }
+
+  // Sets the initial opacity of a layered window, or updates the window's
+  // opacity if it is on the screen.
+  void SetLayeredAlpha(BYTE layered_alpha);
+
+  // See description of use_layered_buffer_ for details.
+  void SetUseLayeredBuffer(bool use_layered_buffer);
+
+  // Disable Layered Window updates by setting to false.
+  void set_can_update_layered_window(bool can_update_layered_window) {
+    can_update_layered_window_ = can_update_layered_window;
+  }
+
+  // Returns the RootView associated with the specified HWND (if any).
+  static RootView* FindRootView(HWND hwnd);
+
+  // Closes the window asynchronously by scheduling a task for it.  The window
+  // is destroyed as a result.
+  // This invokes Hide to hide the window, and schedules a task that
+  // invokes CloseNow.
+  virtual void Close();
+
+  // Hides the window. This does NOT delete the window, it just hides it.
+  virtual void Hide();
+
+  // Shows the window without changing size/position/activation state.
+  virtual void Show();
+
+  // Closes the window synchronously.  Note that this should not be called from
+  // an ATL message callback as it deletes the WidgetWin and ATL will
+  // dereference it after the callback is processed.
+  void CloseNow();
+
+  // All classes registered by WidgetWin start with this name.
+  static const wchar_t* const kBaseClassName;
+
+  BEGIN_MSG_MAP_EX(0)
+    // Range handlers must go first!
+    MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
+    MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCMOUSEMOVE, OnMouseRange)
+
+    // Reflected message handler
+    MESSAGE_HANDLER_EX(kReflectedMessage, OnReflectedMessage)
+
+    // CustomFrameWindow hacks
+    MESSAGE_HANDLER_EX(WM_NCUAHDRAWCAPTION, OnNCUAHDrawCaption)
+    MESSAGE_HANDLER_EX(WM_NCUAHDRAWFRAME, OnNCUAHDrawFrame)
+
+    // Vista and newer
+    MESSAGE_HANDLER_EX(WM_DWMCOMPOSITIONCHANGED, OnDwmCompositionChanged)
+
+    // Non-atlcrack.h handlers
+    MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
+    MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnNCMouseLeave)
+    MESSAGE_HANDLER_EX(WM_MOUSELEAVE, OnMouseLeave)
+    MESSAGE_HANDLER_EX(WM_MOUSEWHEEL, OnMouseWheel)
+
+    // This list is in _ALPHABETICAL_ order! OR I WILL HURT YOU.
+    MSG_WM_ACTIVATE(OnActivate)
+    MSG_WM_ACTIVATEAPP(OnActivateApp)
+    MSG_WM_APPCOMMAND(OnAppCommand)
+    MSG_WM_CANCELMODE(OnCancelMode)
+    MSG_WM_CAPTURECHANGED(OnCaptureChanged)
+    MSG_WM_CLOSE(OnClose)
+    MSG_WM_COMMAND(OnCommand)
+    MSG_WM_CREATE(OnCreate)
+    MSG_WM_DESTROY(OnDestroy)
+    MSG_WM_ERASEBKGND(OnEraseBkgnd)
+    MSG_WM_ENDSESSION(OnEndSession)
+    MSG_WM_ENTERSIZEMOVE(OnEnterSizeMove)
+    MSG_WM_EXITMENULOOP(OnExitMenuLoop)
+    MSG_WM_GETMINMAXINFO(OnGetMinMaxInfo)
+    MSG_WM_HSCROLL(OnHScroll)
+    MSG_WM_INITMENU(OnInitMenu)
+    MSG_WM_INITMENUPOPUP(OnInitMenuPopup)
+    MSG_WM_KEYDOWN(OnKeyDown)
+    MSG_WM_KEYUP(OnKeyUp)
+    MSG_WM_SYSKEYDOWN(OnKeyDown)
+    MSG_WM_SYSKEYUP(OnKeyUp)
+    MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
+    MSG_WM_LBUTTONDOWN(OnLButtonDown)
+    MSG_WM_LBUTTONUP(OnLButtonUp)
+    MSG_WM_MBUTTONDOWN(OnMButtonDown)
+    MSG_WM_MBUTTONUP(OnMButtonUp)
+    MSG_WM_MBUTTONDBLCLK(OnMButtonDblClk)
+    MSG_WM_MOUSEACTIVATE(OnMouseActivate)
+    MSG_WM_MOUSEMOVE(OnMouseMove)
+    MSG_WM_MOVE(OnMove)
+    MSG_WM_MOVING(OnMoving)
+    MSG_WM_NCACTIVATE(OnNCActivate)
+    MSG_WM_NCCALCSIZE(OnNCCalcSize)
+    MSG_WM_NCHITTEST(OnNCHitTest)
+    MSG_WM_NCMOUSEMOVE(OnNCMouseMove)
+    MSG_WM_NCLBUTTONDBLCLK(OnNCLButtonDblClk)
+    MSG_WM_NCLBUTTONDOWN(OnNCLButtonDown)
+    MSG_WM_NCLBUTTONUP(OnNCLButtonUp)
+    MSG_WM_NCMBUTTONDBLCLK(OnNCMButtonDblClk)
+    MSG_WM_NCMBUTTONDOWN(OnNCMButtonDown)
+    MSG_WM_NCMBUTTONUP(OnNCMButtonUp)
+    MSG_WM_NCPAINT(OnNCPaint)
+    MSG_WM_NCRBUTTONDBLCLK(OnNCRButtonDblClk)
+    MSG_WM_NCRBUTTONDOWN(OnNCRButtonDown)
+    MSG_WM_NCRBUTTONUP(OnNCRButtonUp)
+    MSG_WM_NOTIFY(OnNotify)
+    MSG_WM_PAINT(OnPaint)
+    MSG_WM_POWERBROADCAST(OnPowerBroadcast)
+    MSG_WM_RBUTTONDBLCLK(OnRButtonDblClk)
+    MSG_WM_RBUTTONDOWN(OnRButtonDown)
+    MSG_WM_RBUTTONUP(OnRButtonUp)
+    MSG_WM_SETCURSOR(OnSetCursor)
+    MSG_WM_SETFOCUS(OnSetFocus)
+    MSG_WM_SETICON(OnSetIcon)
+    MSG_WM_SETTEXT(OnSetText)
+    MSG_WM_SETTINGCHANGE(OnSettingChange)
+    MSG_WM_SIZE(OnSize)
+    MSG_WM_SYSCOMMAND(OnSysCommand)
+    MSG_WM_THEMECHANGED(OnThemeChanged)
+    MSG_WM_VSCROLL(OnVScroll)
+    MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging)
+    MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged)
+  END_MSG_MAP()
+
+  // Overridden from Widget:
+  virtual void GetBounds(gfx::Rect* out, bool including_frame) const;
+  virtual gfx::NativeView GetNativeView() const;
+  virtual void PaintNow(const gfx::Rect& update_rect);
+  virtual RootView* GetRootView();
+  virtual bool IsVisible() const;
+  virtual bool IsActive() const;
+  virtual TooltipManager* GetTooltipManager();
+  virtual Window* GetWindow();
+  virtual const Window* GetWindow() const;
+
+  // Overridden from MessageLoop::Observer:
+  void WillProcessMessage(const MSG& msg);
+  virtual void DidProcessMessage(const MSG& msg);
+
+  // Overridden from FocusTraversable:
+  virtual View* FindNextFocusableView(View* starting_view,
+                                      bool reverse,
+                                      Direction direction,
+                                      bool dont_loop,
+                                      FocusTraversable** focus_traversable,
+                                      View** focus_traversable_view);
+  virtual FocusTraversable* GetFocusTraversableParent();
+  virtual View* GetFocusTraversableParentView();
+
+  // Overridden from AcceleratorTarget:
+  virtual bool AcceleratorPressed(const Accelerator& accelerator) {
+    return false;
+  }
+
+  void SetFocusTraversableParent(FocusTraversable* parent);
+  void SetFocusTraversableParentView(View* parent_view);
+
+  virtual bool GetAccelerator(int cmd_id, Accelerator* accelerator) {
+    return false;
+  }
+
+  BOOL IsWindow() const {
+    return ::IsWindow(GetNativeView());
+  }
+
+  BOOL ShowWindow(int command) {
+    DCHECK(::IsWindow(GetNativeView()));
+    return ::ShowWindow(GetNativeView(), command);
+  }
+
+  HWND SetCapture() {
+    DCHECK(::IsWindow(GetNativeView()));
+    return ::SetCapture(GetNativeView());
+  }
+
+  HWND GetParent() const {
+    return ::GetParent(GetNativeView());
+  }
+
+  LONG GetWindowLong(int index) {
+    DCHECK(::IsWindow(GetNativeView()));
+    return ::GetWindowLong(GetNativeView(), index);
+  }
+
+  BOOL GetWindowRect(RECT* rect) const {
+    return ::GetWindowRect(GetNativeView(), rect);
+  }
+
+  LONG SetWindowLong(int index, LONG new_long) {
+    DCHECK(::IsWindow(GetNativeView()));
+    return ::SetWindowLong(GetNativeView(), index, new_long);
+  }
+
+  BOOL SetWindowPos(HWND hwnd_after, int x, int y, int cx, int cy, UINT flags) {
+    DCHECK(::IsWindow(GetNativeView()));
+    return ::SetWindowPos(GetNativeView(), hwnd_after, x, y, cx, cy, flags);
+  }
+
+  BOOL IsZoomed() const {
+    DCHECK(::IsWindow(GetNativeView()));
+    return ::IsZoomed(GetNativeView());
+  }
+
+  BOOL MoveWindow(int x, int y, int width, int height) {
+    return MoveWindow(x, y, width, height, TRUE);
+  }
+
+  BOOL MoveWindow(int x, int y, int width, int height, BOOL repaint) {
+    DCHECK(::IsWindow(GetNativeView()));
+    return ::MoveWindow(GetNativeView(), x, y, width, height, repaint);
+  }
+
+  int SetWindowRgn(HRGN region, BOOL redraw) {
+    DCHECK(::IsWindow(GetNativeView()));
+    return ::SetWindowRgn(GetNativeView(), region, redraw);
+  }
+
+  BOOL GetClientRect(RECT* rect) const {
+    DCHECK(::IsWindow(GetNativeView()));
+    return ::GetClientRect(GetNativeView(), rect);
+  }
+
+ protected:
+
+  // Call close instead of this to Destroy the window.
+  BOOL DestroyWindow() {
+    DCHECK(::IsWindow(GetNativeView()));
+    return ::DestroyWindow(GetNativeView());
+  }
+
+  // Message Handlers
+  // These are all virtual so that specialized Widgets can modify or augment
+  // processing.
+  // This list is in _ALPHABETICAL_ order!
+  // Note: in the base class these functions must do nothing but convert point
+  //       coordinates to client coordinates (if necessary) and forward the
+  //       handling to the appropriate Process* function. This is so that
+  //       subclasses can easily override these methods to do different things
+  //       and have a convenient function to call to get the default behavior.
+  virtual void OnActivate(UINT action, BOOL minimized, HWND window) {
+    SetMsgHandled(FALSE);
+  }
+  virtual void OnActivateApp(BOOL active, DWORD thread_id) {
+    SetMsgHandled(FALSE);
+  }
+  virtual LRESULT OnAppCommand(HWND window, short app_command, WORD device,
+                               int keystate) {
+    SetMsgHandled(FALSE);
+    return 0;
+  }
+  virtual void OnCancelMode() {}
+  virtual void OnCaptureChanged(HWND hwnd);
+  virtual void OnClose();
+  virtual void OnCommand(UINT notification_code, int command_id, HWND window) {
+    SetMsgHandled(FALSE);
+  }
+  virtual LRESULT OnCreate(LPCREATESTRUCT create_struct) { return 0; }
+  // WARNING: If you override this be sure and invoke super, otherwise we'll
+  // leak a few things.
+  virtual void OnDestroy();
+  virtual LRESULT OnDwmCompositionChanged(UINT msg,
+                                          WPARAM w_param,
+                                          LPARAM l_param) {
+    SetMsgHandled(FALSE);
+    return 0;
+  }
+  virtual void OnEndSession(BOOL ending, UINT logoff) { SetMsgHandled(FALSE); }
+  virtual void OnEnterSizeMove() { SetMsgHandled(FALSE); }
+  virtual void OnExitMenuLoop(BOOL is_track_popup_menu) {
+    SetMsgHandled(FALSE);
+  }
+  virtual LRESULT OnEraseBkgnd(HDC dc);
+  virtual LRESULT OnGetObject(UINT uMsg, WPARAM w_param, LPARAM l_param);
+  virtual void OnGetMinMaxInfo(MINMAXINFO* minmax_info) {
+    SetMsgHandled(FALSE);
+  }
+  virtual void OnHScroll(int scroll_type, short position, HWND scrollbar) {
+    SetMsgHandled(FALSE);
+  }
+  virtual void OnInitMenu(HMENU menu) { SetMsgHandled(FALSE); }
+  virtual void OnInitMenuPopup(HMENU menu, UINT position, BOOL is_system_menu) {
+    SetMsgHandled(FALSE);
+  }
+  virtual void OnKeyDown(TCHAR c, UINT rep_cnt, UINT flags);
+  virtual void OnKeyUp(TCHAR c, UINT rep_cnt, UINT flags);
+  virtual void OnLButtonDblClk(UINT flags, const CPoint& point);
+  virtual void OnLButtonDown(UINT flags, const CPoint& point);
+  virtual void OnLButtonUp(UINT flags, const CPoint& point);
+  virtual void OnMButtonDblClk(UINT flags, const CPoint& point);
+  virtual void OnMButtonDown(UINT flags, const CPoint& point);
+  virtual void OnMButtonUp(UINT flags, const CPoint& point);
+  virtual LRESULT OnMouseActivate(HWND window, UINT hittest_code, UINT message);
+  virtual void OnMouseMove(UINT flags, const CPoint& point);
+  virtual LRESULT OnMouseLeave(UINT message, WPARAM w_param, LPARAM l_param);
+  virtual LRESULT OnMouseWheel(UINT message, WPARAM w_param, LPARAM l_param);
+  virtual void OnMove(const CPoint& point) { SetMsgHandled(FALSE); }
+  virtual void OnMoving(UINT param, const LPRECT new_bounds) { }
+  virtual LRESULT OnMouseRange(UINT msg, WPARAM w_param, LPARAM l_param);
+  virtual LRESULT OnNCActivate(BOOL active) { SetMsgHandled(FALSE); return 0; }
+  virtual LRESULT OnNCCalcSize(BOOL w_param, LPARAM l_param) {
+    SetMsgHandled(FALSE);
+    return 0;
+  }
+  virtual LRESULT OnNCHitTest(const CPoint& pt) {
+    SetMsgHandled(FALSE);
+    return 0;
+  }
+  virtual void OnNCLButtonDblClk(UINT flags, const CPoint& point);
+  virtual void OnNCLButtonDown(UINT flags, const CPoint& point);
+  virtual void OnNCLButtonUp(UINT flags, const CPoint& point);
+  virtual void OnNCMButtonDblClk(UINT flags, const CPoint& point);
+  virtual void OnNCMButtonDown(UINT flags, const CPoint& point);
+  virtual void OnNCMButtonUp(UINT flags, const CPoint& point);
+  virtual LRESULT OnNCMouseLeave(UINT uMsg, WPARAM w_param, LPARAM l_param);
+  virtual LRESULT OnNCMouseMove(UINT flags, const CPoint& point);
+  virtual void OnNCPaint(HRGN rgn) { SetMsgHandled(FALSE); }
+  virtual void OnNCRButtonDblClk(UINT flags, const CPoint& point);
+  virtual void OnNCRButtonDown(UINT flags, const CPoint& point);
+  virtual void OnNCRButtonUp(UINT flags, const CPoint& point);
+  virtual LRESULT OnNCUAHDrawCaption(UINT msg,
+                                     WPARAM w_param,
+                                     LPARAM l_param) {
+    SetMsgHandled(FALSE);
+    return 0;
+  }
+  virtual LRESULT OnNCUAHDrawFrame(UINT msg, WPARAM w_param, LPARAM l_param) {
+    SetMsgHandled(FALSE);
+    return 0;
+  }
+  virtual LRESULT OnNotify(int w_param, NMHDR* l_param);
+  virtual void OnPaint(HDC dc);
+  virtual LRESULT OnPowerBroadcast(DWORD power_event, DWORD data) {
+    base::SystemMonitor* monitor = base::SystemMonitor::Get();
+    if (monitor)
+      monitor->ProcessWmPowerBroadcastMessage(power_event);
+    SetMsgHandled(FALSE);
+    return 0;
+  }
+  virtual void OnRButtonDblClk(UINT flags, const CPoint& point);
+  virtual void OnRButtonDown(UINT flags, const CPoint& point);
+  virtual void OnRButtonUp(UINT flags, const CPoint& point);
+  virtual LRESULT OnReflectedMessage(UINT msg, WPARAM w_param, LPARAM l_param) {
+    SetMsgHandled(FALSE);
+    return 0;
+  }
+  virtual LRESULT OnSetCursor(HWND window, UINT hittest_code, UINT message) {
+    SetMsgHandled(FALSE);
+    return 0;
+  }
+  virtual void OnSetFocus(HWND focused_window) {
+    SetMsgHandled(FALSE);
+  }
+  virtual LRESULT OnSetIcon(UINT size_type, HICON new_icon) {
+    SetMsgHandled(FALSE);
+    return 0;
+  }
+  virtual LRESULT OnSetText(const wchar_t* text) {
+    SetMsgHandled(FALSE);
+    return 0;
+  }
+  virtual void OnSettingChange(UINT flags, const wchar_t* section) {
+    SetMsgHandled(FALSE);
+  }
+  virtual void OnSize(UINT param, const CSize& size);
+  virtual void OnSysCommand(UINT notification_code, CPoint click) { }
+  virtual void OnThemeChanged();
+  virtual void OnVScroll(int scroll_type, short position, HWND scrollbar) {
+    SetMsgHandled(FALSE);
+  }
+  virtual void OnWindowPosChanging(WINDOWPOS* window_pos) {
+    SetMsgHandled(FALSE);
+  }
+  virtual void OnWindowPosChanged(WINDOWPOS* window_pos) {
+    SetMsgHandled(FALSE);
+  }
+
+  // deletes this window as it is destroyed, override to provide different
+  // behavior.
+  virtual void OnFinalMessage(HWND window);
+
+  // Start tracking all mouse events so that this window gets sent mouse leave
+  // messages too. |is_nonclient| is true when we should track WM_NCMOUSELEAVE
+  // messages instead of WM_MOUSELEAVE ones.
+  void TrackMouseEvents(DWORD mouse_tracking_flags);
+
+  // Actually handle mouse events. These functions are called by subclasses who
+  // override the message handlers above to do the actual real work of handling
+  // the event in the View system.
+  bool ProcessMousePressed(const CPoint& point,
+                           UINT flags,
+                           bool dbl_click,
+                           bool non_client);
+  void ProcessMouseDragged(const CPoint& point, UINT flags);
+  void ProcessMouseReleased(const CPoint& point, UINT flags);
+  void ProcessMouseMoved(const CPoint& point, UINT flags, bool is_nonclient);
+  void ProcessMouseExited();
+
+  // Handles re-laying out content in response to a window size change.
+  virtual void ChangeSize(UINT size_param, const CSize& size);
+
+  // Returns whether capture should be released on mouse release. The default
+  // is true.
+  virtual bool ReleaseCaptureOnMouseReleased() { return true; }
+
+  enum FrameAction {FA_NONE = 0, FA_RESIZING, FA_MOVING, FA_FORWARDING};
+
+  virtual RootView* CreateRootView();
+
+  // Returns true if this WidgetWin is opaque.
+  bool opaque() const { return opaque_; }
+
+  // The root of the View hierarchy attached to this window.
+  scoped_ptr<RootView> root_view_;
+
+  // Current frame ui action
+  FrameAction current_action_;
+
+  // Whether or not we have capture the mouse.
+  bool has_capture_;
+
+  // If true, the mouse is currently down.
+  bool is_mouse_down_;
+
+  scoped_ptr<TooltipManager> tooltip_manager_;
+
+  // Are a subclass of WindowWin?
+  bool is_window_;
+
+ private:
+  // Implementation of GetWindow. Ascends the parents of |hwnd| returning the
+  // first ancestor that is a Window.
+  static Window* GetWindowImpl(HWND hwnd);
+
+  // Resize the bitmap used to contain the contents of the layered window. This
+  // recreates the entire bitmap.
+  void SizeContents(const CRect& window_rect);
+
+  // Paint into a DIB and then update the layered window with its contents.
+  void PaintLayeredWindow();
+
+  // In layered mode, update the layered window. |dib_dc| represents a handle
+  // to a device context that contains the contents of the window.
+  void UpdateWindowFromContents(HDC dib_dc);
+
+  // Invoked from WM_DESTROY. Does appropriate cleanup and invokes OnDestroy
+  // so that subclasses can do any cleanup they need to.
+  void OnDestroyImpl();
+
+  // The windows procedure used by all WidgetWins.
+  static LRESULT CALLBACK WndProc(HWND window,
+                                  UINT message,
+                                  WPARAM w_param,
+                                  LPARAM l_param);
+
+  // Gets the window class name to use when creating the corresponding HWND.
+  // If necessary, this registers the window class.
+  std::wstring GetWindowClassName();
+
+  // The following factory is used for calls to close the WidgetWin
+  // instance.
+  ScopedRunnableMethodFactory<WidgetWin> close_widget_factory_;
+
+  // The flags currently being used with TrackMouseEvent to track mouse
+  // messages. 0 if there is no active tracking. The value of this member is
+  // used when tracking is canceled.
+  DWORD active_mouse_tracking_flags_;
+
+  bool opaque_;
+
+  // Window Styles used when creating the window.
+  DWORD window_style_;
+
+  // Window Extended Styles used when creating the window.
+  DWORD window_ex_style_;
+
+  // Style of the class to use.
+  UINT class_style_;
+
+  // Should we keep an offscreen buffer? This is initially true and if the
+  // window has WS_EX_LAYERED then it remains true. You can set this to false
+  // at any time to ditch the buffer, and similarly set back to true to force
+  // creation of the buffer.
+  //
+  // NOTE: this is intended to be used with a layered window (a window with an
+  // extended window style of WS_EX_LAYERED). If you are using a layered window
+  // and NOT changing the layered alpha or anything else, then leave this value
+  // alone. OTOH if you are invoking SetLayeredWindowAttributes then you'll
+  // must likely want to set this to false, or after changing the alpha toggle
+  // the extended style bit to false than back to true. See MSDN for more
+  // details.
+  bool use_layered_buffer_;
+
+  // The default alpha to be applied to the layered window.
+  BYTE layered_alpha_;
+
+  // A canvas that contains the window contents in the case of a layered
+  // window.
+  scoped_ptr<ChromeCanvas> contents_;
+
+  // Whether or not the window should delete itself when it is destroyed.
+  // Set this to false via its setter for stack allocated instances.
+  bool delete_on_destroy_;
+
+  // True if we are allowed to update the layered window from the DIB backing
+  // store if necessary.
+  bool can_update_layered_window_;
+
+  // The following are used to detect duplicate mouse move events and not
+  // deliver them. Displaying a window may result in the system generating
+  // duplicate move events even though the mouse hasn't moved.
+
+  // If true, the last event was a mouse move event.
+  bool last_mouse_event_was_move_;
+
+  // Coordinates of the last mouse move event, in screen coordinates.
+  int last_mouse_move_x_;
+  int last_mouse_move_y_;
+
+  // Instance of accessibility information and handling for MSAA root
+  CComPtr<IAccessible> accessibility_root_;
+
+  // Our hwnd.
+  HWND hwnd_;
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_WIDGET_WIDGET_WIN_H_
diff --git a/views/window/client_view.cc b/views/window/client_view.cc
new file mode 100644
index 0000000..5b5afb19f
--- /dev/null
+++ b/views/window/client_view.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2006-2008 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 "views/window/client_view.h"
+#include "views/window/window.h"
+#include "views/window/window_delegate.h"
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+// ClientView, public:
+
+ClientView::ClientView(Window* window, View* contents_view)
+    : window_(window),
+      contents_view_(contents_view) {
+}
+
+int ClientView::NonClientHitTest(const gfx::Point& point) {
+  return bounds().Contains(point) ? HTCLIENT : HTNOWHERE;
+}
+
+void ClientView::WindowClosing() {
+  window_->GetDelegate()->WindowClosing();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ClientView, View overrides:
+
+gfx::Size ClientView::GetPreferredSize() {
+  // |contents_view_| is allowed to be NULL up until the point where this view
+  // is attached to a Container.
+  if (contents_view_)
+    return contents_view_->GetPreferredSize();
+  return gfx::Size();
+}
+
+void ClientView::Layout() {
+  // |contents_view_| is allowed to be NULL up until the point where this view
+  // is attached to a Container.
+  if (contents_view_)
+    contents_view_->SetBounds(0, 0, width(), height());
+}
+
+void ClientView::ViewHierarchyChanged(bool is_add, View* parent, View* child) {
+  if (is_add && child == this) {
+    DCHECK(GetWidget());
+    DCHECK(contents_view_); // |contents_view_| must be valid now!
+    AddChildView(contents_view_);
+  }
+}
+
+void ClientView::DidChangeBounds(const gfx::Rect& previous,
+                                 const gfx::Rect& current) {
+  // Overridden to do nothing. The NonClientView manually calls Layout on the
+  // ClientView when it is itself laid out, see comment in
+  // NonClientView::Layout.
+}
+
+}  // namespace views
diff --git a/views/window/client_view.h b/views/window/client_view.h
new file mode 100644
index 0000000..b56fcfd
--- /dev/null
+++ b/views/window/client_view.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2006-2008 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 VIEWS_WINDOW_CLIENT_VIEW_H_
+#define VIEWS_WINDOW_CLIENT_VIEW_H_
+
+#include "views/view.h"
+
+namespace views {
+
+class DialogClientView;
+class Window;
+
+///////////////////////////////////////////////////////////////////////////////
+// ClientView
+//
+//  A ClientView is a View subclass that is used to occupy the "client area"
+//  of a window. It provides basic information to the window that contains it
+//  such as non-client hit testing information, sizing etc. Sub-classes of
+//  ClientView are used to create more elaborate contents, e.g.
+//  "DialogClientView".
+class ClientView : public View {
+ public:
+  // Constructs a ClientView object for the specified window with the specified
+  // contents. Since this object is created during the process of creating
+  // |window|, |contents_view| must be valid if you want the initial size of
+  // the window to be based on |contents_view|'s preferred size.
+  ClientView(Window* window, View* contents_view);
+  virtual ~ClientView() {}
+
+  // Manual RTTI ftw.
+  virtual DialogClientView* AsDialogClientView() { return NULL; }
+
+  // Returns true to signal that the Window can be closed. Specialized
+  // ClientView subclasses can override this default behavior to allow the
+  // close to be blocked until the user corrects mistakes, accepts a warning
+  // dialog, etc.
+  virtual bool CanClose() const { return true; }
+
+  // Notification that the window is closing.  The default implementation
+  // forwards the notification to the delegate.
+  virtual void WindowClosing();
+
+  // Tests to see if the specified point (in view coordinates) is within the
+  // bounds of this view. If so, it returns HTCLIENT in this default
+  // implementation. If it is outside the bounds of this view, this must return
+  // HTNOWHERE to tell the caller to do further processing to determine where
+  // in the non-client area it is (if it is).
+  // Subclasses of ClientView can extend this logic by overriding this method
+  // to detect if regions within the client area count as parts of the "non-
+  // client" area. A good example of this is the size box at the bottom right
+  // corner of resizable dialog boxes.
+  virtual int NonClientHitTest(const gfx::Point& point);
+
+  // Overridden from View:
+  virtual gfx::Size GetPreferredSize();
+  virtual void Layout();
+
+ protected:
+  // Overridden from View:
+  virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child);
+  virtual void DidChangeBounds(const gfx::Rect& previous,
+                               const gfx::Rect& current);
+
+  // Accessors for private data members.
+  Window* window() const { return window_; }
+  void set_window(Window* window) { window_ = window; }
+  View* contents_view() const { return contents_view_; }
+  void set_contents_view(View* contents_view) {
+    contents_view_ = contents_view;
+  }
+
+ private:
+  // The Window that hosts this ClientView.
+  Window* window_;
+
+  // The View that this ClientView contains.
+  View* contents_view_;
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_WINDOW_CLIENT_VIEW_H_
diff --git a/views/window/custom_frame_view.cc b/views/window/custom_frame_view.cc
new file mode 100644
index 0000000..cf8173f
--- /dev/null
+++ b/views/window/custom_frame_view.cc
@@ -0,0 +1,695 @@
+// Copyright (c) 2009 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 "views/window/custom_frame_view.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/gfx/chrome_font.h"
+#include "app/gfx/path.h"
+#include "app/resource_bundle.h"
+#include "base/win_util.h"
+#include "chrome/common/win_util.h"
+#include "grit/theme_resources.h"
+#include "views/window/client_view.h"
+#include "views/window/window_delegate.h"
+
+namespace views {
+
+// An enumeration of bitmap resources used by this window.
+enum {
+  FRAME_PART_BITMAP_FIRST = 0,  // Must be first.
+
+  // Window Controls.
+  FRAME_CLOSE_BUTTON_ICON,
+  FRAME_CLOSE_BUTTON_ICON_H,
+  FRAME_CLOSE_BUTTON_ICON_P,
+  FRAME_CLOSE_BUTTON_ICON_SA,
+  FRAME_CLOSE_BUTTON_ICON_SA_H,
+  FRAME_CLOSE_BUTTON_ICON_SA_P,
+  FRAME_RESTORE_BUTTON_ICON,
+  FRAME_RESTORE_BUTTON_ICON_H,
+  FRAME_RESTORE_BUTTON_ICON_P,
+  FRAME_MAXIMIZE_BUTTON_ICON,
+  FRAME_MAXIMIZE_BUTTON_ICON_H,
+  FRAME_MAXIMIZE_BUTTON_ICON_P,
+  FRAME_MINIMIZE_BUTTON_ICON,
+  FRAME_MINIMIZE_BUTTON_ICON_H,
+  FRAME_MINIMIZE_BUTTON_ICON_P,
+
+  // Window Frame Border.
+  FRAME_BOTTOM_EDGE,
+  FRAME_BOTTOM_LEFT_CORNER,
+  FRAME_BOTTOM_RIGHT_CORNER,
+  FRAME_LEFT_EDGE,
+  FRAME_RIGHT_EDGE,
+  FRAME_TOP_EDGE,
+  FRAME_TOP_LEFT_CORNER,
+  FRAME_TOP_RIGHT_CORNER,
+
+  // Client Edge Border.
+  FRAME_CLIENT_EDGE_TOP_LEFT,
+  FRAME_CLIENT_EDGE_TOP,
+  FRAME_CLIENT_EDGE_TOP_RIGHT,
+  FRAME_CLIENT_EDGE_RIGHT,
+  FRAME_CLIENT_EDGE_BOTTOM_RIGHT,
+  FRAME_CLIENT_EDGE_BOTTOM,
+  FRAME_CLIENT_EDGE_BOTTOM_LEFT,
+  FRAME_CLIENT_EDGE_LEFT,
+
+  FRAME_PART_BITMAP_COUNT  // Must be last.
+};
+
+class ActiveWindowResources : public WindowResources {
+ public:
+  ActiveWindowResources() {
+    InitClass();
+  }
+  virtual ~ActiveWindowResources() {
+  }
+
+  // WindowResources implementation:
+  virtual SkBitmap* GetPartBitmap(FramePartBitmap part) const {
+    return standard_frame_bitmaps_[part];
+  }
+
+ private:
+  static void InitClass() {
+    static bool initialized = false;
+    if (!initialized) {
+      static const int kFramePartBitmapIds[] = {
+        0,
+        IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P,
+        IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P,
+        IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P,
+        IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P,
+        IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P,
+        IDR_WINDOW_BOTTOM_CENTER, IDR_WINDOW_BOTTOM_LEFT_CORNER,
+            IDR_WINDOW_BOTTOM_RIGHT_CORNER, IDR_WINDOW_LEFT_SIDE,
+            IDR_WINDOW_RIGHT_SIDE, IDR_WINDOW_TOP_CENTER,
+            IDR_WINDOW_TOP_LEFT_CORNER, IDR_WINDOW_TOP_RIGHT_CORNER,
+        IDR_APP_TOP_LEFT, IDR_APP_TOP_CENTER, IDR_APP_TOP_RIGHT,
+            IDR_CONTENT_RIGHT_SIDE, IDR_CONTENT_BOTTOM_RIGHT_CORNER,
+            IDR_CONTENT_BOTTOM_CENTER, IDR_CONTENT_BOTTOM_LEFT_CORNER,
+            IDR_CONTENT_LEFT_SIDE,
+        0
+      };
+
+      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+      for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) {
+        int id = kFramePartBitmapIds[i];
+        if (id != 0)
+          standard_frame_bitmaps_[i] = rb.GetBitmapNamed(id);
+      }
+      initialized = true;
+    }
+  }
+
+  static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT];
+
+  DISALLOW_EVIL_CONSTRUCTORS(ActiveWindowResources);
+};
+
+class InactiveWindowResources : public WindowResources {
+ public:
+  InactiveWindowResources() {
+    InitClass();
+  }
+  virtual ~InactiveWindowResources() {
+  }
+
+  // WindowResources implementation:
+  virtual SkBitmap* GetPartBitmap(FramePartBitmap part) const {
+    return standard_frame_bitmaps_[part];
+  }
+
+ private:
+  static void InitClass() {
+    static bool initialized = false;
+    if (!initialized) {
+      static const int kFramePartBitmapIds[] = {
+        0,
+        IDR_CLOSE, IDR_CLOSE_H, IDR_CLOSE_P,
+        IDR_CLOSE_SA, IDR_CLOSE_SA_H, IDR_CLOSE_SA_P,
+        IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P,
+        IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P,
+        IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P,
+        IDR_DEWINDOW_BOTTOM_CENTER, IDR_DEWINDOW_BOTTOM_LEFT_CORNER,
+            IDR_DEWINDOW_BOTTOM_RIGHT_CORNER, IDR_DEWINDOW_LEFT_SIDE,
+            IDR_DEWINDOW_RIGHT_SIDE, IDR_DEWINDOW_TOP_CENTER,
+            IDR_DEWINDOW_TOP_LEFT_CORNER, IDR_DEWINDOW_TOP_RIGHT_CORNER,
+        IDR_APP_TOP_LEFT, IDR_APP_TOP_CENTER, IDR_APP_TOP_RIGHT,
+            IDR_CONTENT_RIGHT_SIDE, IDR_CONTENT_BOTTOM_RIGHT_CORNER,
+            IDR_CONTENT_BOTTOM_CENTER, IDR_CONTENT_BOTTOM_LEFT_CORNER,
+            IDR_CONTENT_LEFT_SIDE,
+        0
+      };
+
+      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+      for (int i = 0; i < FRAME_PART_BITMAP_COUNT; ++i) {
+        int id = kFramePartBitmapIds[i];
+        if (id != 0)
+          standard_frame_bitmaps_[i] = rb.GetBitmapNamed(id);
+      }
+      initialized = true;
+    }
+  }
+
+  static SkBitmap* standard_frame_bitmaps_[FRAME_PART_BITMAP_COUNT];
+
+  DISALLOW_EVIL_CONSTRUCTORS(InactiveWindowResources);
+};
+
+// static
+SkBitmap* ActiveWindowResources::standard_frame_bitmaps_[];
+SkBitmap* InactiveWindowResources::standard_frame_bitmaps_[];
+
+// static
+WindowResources* CustomFrameView::active_resources_ = NULL;
+WindowResources* CustomFrameView::inactive_resources_ = NULL;
+ChromeFont* CustomFrameView::title_font_ = NULL;
+
+namespace {
+// The frame border is only visible in restored mode and is hardcoded to 4 px on
+// each side regardless of the system window border size.
+const int kFrameBorderThickness = 4;
+// Various edges of the frame border have a 1 px shadow along their edges; in a
+// few cases we shift elements based on this amount for visual appeal.
+const int kFrameShadowThickness = 1;
+// While resize areas on Windows are normally the same size as the window
+// borders, our top area is shrunk by 1 px to make it easier to move the window
+// around with our thinner top grabbable strip.  (Incidentally, our side and
+// bottom resize areas don't match the frame border thickness either -- they
+// span the whole nonclient area, so there's no "dead zone" for the mouse.)
+const int kTopResizeAdjust = 1;
+// In the window corners, the resize areas don't actually expand bigger, but the
+// 16 px at the end of each edge triggers diagonal resizing.
+const int kResizeAreaCornerSize = 16;
+// The titlebar never shrinks to less than 18 px tall, plus the height of the
+// frame border and any bottom edge.
+const int kTitlebarMinimumHeight = 18;
+// The icon is inset 2 px from the left frame border.
+const int kIconLeftSpacing = 2;
+// The icon takes up 16/25th of the available titlebar height.  (This is
+// expressed as two ints to avoid precision losses leading to off-by-one pixel
+// errors.)
+const int kIconHeightFractionNumerator = 16;
+const int kIconHeightFractionDenominator = 25;
+// The icon never shrinks below 16 px on a side.
+const int kIconMinimumSize = 16;
+// Because our frame border has a different "3D look" than Windows', with a less
+// cluttered top edge, we need to shift the icon up by 1 px in restored mode so
+// it looks more centered.
+const int kIconRestoredAdjust = 1;
+// There is a 4 px gap between the icon and the title text.
+const int kIconTitleSpacing = 4;
+// The title text starts 2 px below the bottom of the top frame border.
+const int kTitleTopSpacing = 2;
+// There is a 5 px gap between the title text and the caption buttons.
+const int kTitleCaptionSpacing = 5;
+// The caption buttons are always drawn 1 px down from the visible top of the
+// window (the true top in restored mode, or the top of the screen in maximized
+// mode).
+const int kCaptionTopSpacing = 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CustomFrameView, public:
+
+CustomFrameView::CustomFrameView(Window* frame)
+    : NonClientFrameView(),
+      close_button_(new ImageButton(this)),
+      restore_button_(new ImageButton(this)),
+      maximize_button_(new ImageButton(this)),
+      minimize_button_(new ImageButton(this)),
+      system_menu_button_(new ImageButton(this)),
+      should_show_minmax_buttons_(false),
+      frame_(frame) {
+  InitClass();
+  WindowResources* resources = active_resources_;
+
+  // Close button images will be set in LayoutWindowControls().
+  AddChildView(close_button_);
+
+  restore_button_->SetImage(CustomButton::BS_NORMAL,
+      resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON));
+  restore_button_->SetImage(CustomButton::BS_HOT,
+      resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON_H));
+  restore_button_->SetImage(CustomButton::BS_PUSHED,
+      resources->GetPartBitmap(FRAME_RESTORE_BUTTON_ICON_P));
+  AddChildView(restore_button_);
+
+  maximize_button_->SetImage(CustomButton::BS_NORMAL,
+      resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON));
+  maximize_button_->SetImage(CustomButton::BS_HOT,
+      resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON_H));
+  maximize_button_->SetImage(CustomButton::BS_PUSHED,
+      resources->GetPartBitmap(FRAME_MAXIMIZE_BUTTON_ICON_P));
+  AddChildView(maximize_button_);
+
+  minimize_button_->SetImage(CustomButton::BS_NORMAL,
+      resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON));
+  minimize_button_->SetImage(CustomButton::BS_HOT,
+      resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON_H));
+  minimize_button_->SetImage(CustomButton::BS_PUSHED,
+      resources->GetPartBitmap(FRAME_MINIMIZE_BUTTON_ICON_P));
+  AddChildView(minimize_button_);
+
+  should_show_minmax_buttons_ = frame_->GetDelegate()->CanMaximize();
+
+  AddChildView(system_menu_button_);
+}
+
+CustomFrameView::~CustomFrameView() {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CustomFrameView, NonClientFrameView implementation:
+
+gfx::Rect CustomFrameView::GetBoundsForClientView() const {
+  return client_view_bounds_;
+}
+
+gfx::Rect CustomFrameView::GetWindowBoundsForClientBounds(
+    const gfx::Rect& client_bounds) const {
+  int top_height = NonClientTopBorderHeight();
+  int border_thickness = NonClientBorderThickness();
+  return gfx::Rect(std::max(0, client_bounds.x() - border_thickness),
+                   std::max(0, client_bounds.y() - top_height),
+                   client_bounds.width() + (2 * border_thickness),
+                   client_bounds.height() + top_height + border_thickness);
+}
+
+gfx::Point CustomFrameView::GetSystemMenuPoint() const {
+  gfx::Point system_menu_point(
+      MirroredXCoordinateInsideView(FrameBorderThickness()),
+      NonClientTopBorderHeight() - BottomEdgeThicknessWithinNonClientHeight());
+  ConvertPointToScreen(this, &system_menu_point);
+  return system_menu_point;
+}
+
+int CustomFrameView::NonClientHitTest(const gfx::Point& point) {
+  // Then see if the point is within any of the window controls.
+  if (close_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(point))
+    return HTCLOSE;
+  if (restore_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(
+      point))
+    return HTMAXBUTTON;
+  if (maximize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(
+      point))
+    return HTMAXBUTTON;
+  if (minimize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(
+      point))
+    return HTMINBUTTON;
+  if (system_menu_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(
+      point))
+    return HTSYSMENU;
+
+  int window_component = GetHTComponentForFrame(point, FrameBorderThickness(),
+      NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize,
+      frame_->GetDelegate()->CanResize());
+  // Fall back to the caption if no other component matches.
+  return (window_component == HTNOWHERE) ? HTCAPTION : window_component;
+}
+
+void CustomFrameView::GetWindowMask(const gfx::Size& size,
+                                    gfx::Path* window_mask) {
+  DCHECK(window_mask);
+
+  if (frame_->IsMaximized())
+    return;
+
+  // Redefine the window visible region for the new size.
+  window_mask->moveTo(0, 3);
+  window_mask->lineTo(1, 2);
+  window_mask->lineTo(1, 1);
+  window_mask->lineTo(2, 1);
+  window_mask->lineTo(3, 0);
+
+  window_mask->lineTo(SkIntToScalar(size.width() - 3), 0);
+  window_mask->lineTo(SkIntToScalar(size.width() - 2), 1);
+  window_mask->lineTo(SkIntToScalar(size.width() - 1), 1);
+  window_mask->lineTo(SkIntToScalar(size.width() - 1), 2);
+  window_mask->lineTo(SkIntToScalar(size.width()), 3);
+
+  window_mask->lineTo(SkIntToScalar(size.width()),
+                      SkIntToScalar(size.height()));
+  window_mask->lineTo(0, SkIntToScalar(size.height()));
+  window_mask->close();
+}
+
+void CustomFrameView::EnableClose(bool enable) {
+  close_button_->SetEnabled(enable);
+}
+
+void CustomFrameView::ResetWindowControls() {
+  restore_button_->SetState(CustomButton::BS_NORMAL);
+  minimize_button_->SetState(CustomButton::BS_NORMAL);
+  maximize_button_->SetState(CustomButton::BS_NORMAL);
+  // The close button isn't affected by this constraint.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CustomFrameView, View overrides:
+
+void CustomFrameView::Paint(ChromeCanvas* canvas) {
+  if (frame_->IsMaximized())
+    PaintMaximizedFrameBorder(canvas);
+  else
+    PaintRestoredFrameBorder(canvas);
+  PaintTitleBar(canvas);
+  if (!frame_->IsMaximized())
+    PaintRestoredClientEdge(canvas);
+}
+
+void CustomFrameView::Layout() {
+  LayoutWindowControls();
+  LayoutTitleBar();
+  LayoutClientView();
+}
+
+gfx::Size CustomFrameView::GetPreferredSize() {
+  gfx::Size pref = frame_->GetClientView()->GetPreferredSize();
+  gfx::Rect bounds(0, 0, pref.width(), pref.height());
+  return frame_->GetNonClientView()->GetWindowBoundsForClientBounds(
+      bounds).size();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CustomFrameView, ButtonListener implementation:
+
+void CustomFrameView::ButtonPressed(Button* sender) {
+  if (sender == close_button_)
+    frame_->Close();
+  else if (sender == minimize_button_)
+    frame_->Minimize();
+  else if (sender == maximize_button_)
+    frame_->Maximize();
+  else if (sender == restore_button_)
+    frame_->Restore();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CustomFrameView, private:
+
+int CustomFrameView::FrameBorderThickness() const {
+  return frame_->IsMaximized() ? 0 : kFrameBorderThickness;
+}
+
+int CustomFrameView::NonClientBorderThickness() const {
+  // In maximized mode, we don't show a client edge.
+  return FrameBorderThickness() +
+      (frame_->IsMaximized() ? 0 : kClientEdgeThickness);
+}
+
+int CustomFrameView::NonClientTopBorderHeight() const {
+  int title_top_spacing, title_thickness;
+  return TitleCoordinates(&title_top_spacing, &title_thickness);
+}
+
+int CustomFrameView::BottomEdgeThicknessWithinNonClientHeight() const {
+  return kFrameShadowThickness +
+      (frame_->IsMaximized() ? 0 : kClientEdgeThickness);
+}
+
+int CustomFrameView::TitleCoordinates(int* title_top_spacing,
+                                      int* title_thickness) const {
+  int frame_thickness = FrameBorderThickness();
+  int min_titlebar_height = kTitlebarMinimumHeight + frame_thickness;
+  *title_top_spacing = frame_thickness + kTitleTopSpacing;
+  // The bottom spacing should be the same apparent height as the top spacing.
+  // Because the actual top spacing height varies based on the system border
+  // thickness, we calculate this based on the restored top spacing and then
+  // adjust for maximized mode.  We also don't include the frame shadow here,
+  // since while it's part of the bottom spacing it will be added in at the end.
+  int title_bottom_spacing =
+      kFrameBorderThickness + kTitleTopSpacing - kFrameShadowThickness;
+  if (frame_->IsMaximized()) {
+    // When we maximize, the top border appears to be chopped off; shift the
+    // title down to stay centered within the remaining space.
+    int title_adjust = (kFrameBorderThickness / 2);
+    *title_top_spacing += title_adjust;
+    title_bottom_spacing -= title_adjust;
+  }
+  *title_thickness = std::max(title_font_->height(),
+      min_titlebar_height - *title_top_spacing - title_bottom_spacing);
+  return *title_top_spacing + *title_thickness + title_bottom_spacing +
+      BottomEdgeThicknessWithinNonClientHeight();
+}
+
+void CustomFrameView::PaintRestoredFrameBorder(ChromeCanvas* canvas) {
+  SkBitmap* top_left_corner = resources()->GetPartBitmap(FRAME_TOP_LEFT_CORNER);
+  SkBitmap* top_right_corner =
+      resources()->GetPartBitmap(FRAME_TOP_RIGHT_CORNER);
+  SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE);
+  SkBitmap* right_edge = resources()->GetPartBitmap(FRAME_RIGHT_EDGE);
+  SkBitmap* left_edge = resources()->GetPartBitmap(FRAME_LEFT_EDGE);
+  SkBitmap* bottom_left_corner =
+      resources()->GetPartBitmap(FRAME_BOTTOM_LEFT_CORNER);
+  SkBitmap* bottom_right_corner =
+    resources()->GetPartBitmap(FRAME_BOTTOM_RIGHT_CORNER);
+  SkBitmap* bottom_edge = resources()->GetPartBitmap(FRAME_BOTTOM_EDGE);
+
+  // Top.
+  canvas->DrawBitmapInt(*top_left_corner, 0, 0);
+  canvas->TileImageInt(*top_edge, top_left_corner->width(), 0,
+                       width() - top_right_corner->width(), top_edge->height());
+  canvas->DrawBitmapInt(*top_right_corner,
+                        width() - top_right_corner->width(), 0);
+
+  // Right.
+  canvas->TileImageInt(*right_edge, width() - right_edge->width(),
+                       top_right_corner->height(), right_edge->width(),
+                       height() - top_right_corner->height() -
+                           bottom_right_corner->height());
+
+  // Bottom.
+  canvas->DrawBitmapInt(*bottom_right_corner,
+                        width() - bottom_right_corner->width(),
+                        height() - bottom_right_corner->height());
+  canvas->TileImageInt(*bottom_edge, bottom_left_corner->width(),
+                       height() - bottom_edge->height(),
+                       width() - bottom_left_corner->width() -
+                           bottom_right_corner->width(),
+                       bottom_edge->height());
+  canvas->DrawBitmapInt(*bottom_left_corner, 0,
+                        height() - bottom_left_corner->height());
+
+  // Left.
+  canvas->TileImageInt(*left_edge, 0, top_left_corner->height(),
+      left_edge->width(),
+      height() - top_left_corner->height() - bottom_left_corner->height());
+}
+
+void CustomFrameView::PaintMaximizedFrameBorder(
+    ChromeCanvas* canvas) {
+  SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE);
+  canvas->TileImageInt(*top_edge, 0, FrameBorderThickness(), width(),
+                       top_edge->height());
+
+  // The bottom of the titlebar actually comes from the top of the Client Edge
+  // graphic, with the actual client edge clipped off the bottom.
+  SkBitmap* titlebar_bottom = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP);
+  int edge_height = titlebar_bottom->height() - kClientEdgeThickness;
+  canvas->TileImageInt(*titlebar_bottom, 0,
+      frame_->GetClientView()->y() - edge_height, width(), edge_height);
+}
+
+void CustomFrameView::PaintTitleBar(ChromeCanvas* canvas) {
+  WindowDelegate* d = frame_->GetDelegate();
+
+  // It seems like in some conditions we can be asked to paint after the window
+  // that contains us is WM_DESTROYed. At this point, our delegate is NULL. The
+  // correct long term fix may be to shut down the RootView in WM_DESTROY.
+  if (!d)
+    return;
+
+  canvas->DrawStringInt(d->GetWindowTitle(), *title_font_, SK_ColorWHITE,
+      MirroredLeftPointForRect(title_bounds_), title_bounds_.y(),
+      title_bounds_.width(), title_bounds_.height());
+}
+
+void CustomFrameView::PaintRestoredClientEdge(ChromeCanvas* canvas) {
+  gfx::Rect client_area_bounds = frame_->GetClientView()->bounds();
+  int client_area_top = client_area_bounds.y();
+
+  SkBitmap* top_left = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_LEFT);
+  SkBitmap* top = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP);
+  SkBitmap* top_right = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_RIGHT);
+  SkBitmap* right = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_RIGHT);
+  SkBitmap* bottom_right =
+      resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_RIGHT);
+  SkBitmap* bottom = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM);
+  SkBitmap* bottom_left =
+      resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_LEFT);
+  SkBitmap* left = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_LEFT);
+
+  // Top.
+  // This next calculation is necessary because the top center bitmap is shorter
+  // than the top left and right bitmaps.  We need their top edges to line up,
+  // and we need the left and right edges to start below the corners' bottoms.
+  int top_edge_y = client_area_top - top->height();
+  client_area_top = top_edge_y + top_left->height();
+  canvas->DrawBitmapInt(*top_left, client_area_bounds.x() - top_left->width(),
+                        top_edge_y);
+  canvas->TileImageInt(*top, client_area_bounds.x(), top_edge_y,
+                       client_area_bounds.width(), top->height());
+  canvas->DrawBitmapInt(*top_right, client_area_bounds.right(), top_edge_y);
+
+  // Right.
+  int client_area_bottom =
+      std::max(client_area_top, client_area_bounds.bottom());
+  int client_area_height = client_area_bottom - client_area_top;
+  canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top,
+                       right->width(), client_area_height);
+
+  // Bottom.
+  canvas->DrawBitmapInt(*bottom_right, client_area_bounds.right(),
+                        client_area_bottom);
+  canvas->TileImageInt(*bottom, client_area_bounds.x(), client_area_bottom,
+                       client_area_bounds.width(), bottom_right->height());
+  canvas->DrawBitmapInt(*bottom_left,
+      client_area_bounds.x() - bottom_left->width(), client_area_bottom);
+
+  // Left.
+  canvas->TileImageInt(*left, client_area_bounds.x() - left->width(),
+      client_area_top, left->width(), client_area_height);
+}
+
+void CustomFrameView::LayoutWindowControls() {
+  close_button_->SetImageAlignment(ImageButton::ALIGN_LEFT,
+                                   ImageButton::ALIGN_BOTTOM);
+  // Maximized buttons start at window top so that even if their images aren't
+  // drawn flush with the screen edge, they still obey Fitts' Law.
+  bool is_maximized = frame_->IsMaximized();
+  int frame_thickness = FrameBorderThickness();
+  int caption_y = is_maximized ? frame_thickness : kCaptionTopSpacing;
+  int top_extra_height = is_maximized ? kCaptionTopSpacing : 0;
+  // There should always be the same number of non-shadow pixels visible to the
+  // side of the caption buttons.  In maximized mode we extend the rightmost
+  // button to the screen corner to obey Fitts' Law.
+  int right_extra_width = is_maximized ?
+      (kFrameBorderThickness - kFrameShadowThickness) : 0;
+  gfx::Size close_button_size = close_button_->GetPreferredSize();
+  close_button_->SetBounds(width() - close_button_size.width() -
+      right_extra_width - frame_thickness, caption_y,
+      close_button_size.width() + right_extra_width,
+      close_button_size.height() + top_extra_height);
+
+  // When the window is restored, we show a maximized button; otherwise, we show
+  // a restore button.
+  bool is_restored = !is_maximized && !frame_->IsMinimized();
+  views::ImageButton* invisible_button = is_restored ?
+      restore_button_ : maximize_button_;
+  invisible_button->SetVisible(false);
+
+  views::ImageButton* visible_button = is_restored ?
+      maximize_button_ : restore_button_;
+  FramePartBitmap normal_part, hot_part, pushed_part;
+  if (should_show_minmax_buttons_) {
+    visible_button->SetVisible(true);
+    visible_button->SetImageAlignment(ImageButton::ALIGN_LEFT,
+                                      ImageButton::ALIGN_BOTTOM);
+    gfx::Size visible_button_size = visible_button->GetPreferredSize();
+    visible_button->SetBounds(close_button_->x() - visible_button_size.width(),
+                              caption_y, visible_button_size.width(),
+                              visible_button_size.height() + top_extra_height);
+
+    minimize_button_->SetVisible(true);
+    minimize_button_->SetImageAlignment(ImageButton::ALIGN_LEFT,
+                                        ImageButton::ALIGN_BOTTOM);
+    gfx::Size minimize_button_size = minimize_button_->GetPreferredSize();
+    minimize_button_->SetBounds(
+        visible_button->x() - minimize_button_size.width(), caption_y,
+        minimize_button_size.width(),
+        minimize_button_size.height() + top_extra_height);
+
+    normal_part = FRAME_CLOSE_BUTTON_ICON;
+    hot_part = FRAME_CLOSE_BUTTON_ICON_H;
+    pushed_part = FRAME_CLOSE_BUTTON_ICON_P;
+  } else {
+    visible_button->SetVisible(false);
+    minimize_button_->SetVisible(false);
+
+    normal_part = FRAME_CLOSE_BUTTON_ICON_SA;
+    hot_part = FRAME_CLOSE_BUTTON_ICON_SA_H;
+    pushed_part = FRAME_CLOSE_BUTTON_ICON_SA_P;
+  }
+
+  close_button_->SetImage(CustomButton::BS_NORMAL,
+                          active_resources_->GetPartBitmap(normal_part));
+  close_button_->SetImage(CustomButton::BS_HOT,
+                          active_resources_->GetPartBitmap(hot_part));
+  close_button_->SetImage(CustomButton::BS_PUSHED,
+                          active_resources_->GetPartBitmap(pushed_part));
+}
+
+void CustomFrameView::LayoutTitleBar() {
+  // Always lay out the icon, even when it's not present, so we can lay out the
+  // window title based on its position.
+  int frame_thickness = FrameBorderThickness();
+  int icon_x = frame_thickness + kIconLeftSpacing;
+
+  // The usable height of the titlebar area is the total height minus the top
+  // resize border and any edge area we draw at its bottom.
+  int title_top_spacing, title_thickness;
+  int top_height = TitleCoordinates(&title_top_spacing, &title_thickness);
+  int available_height = top_height - frame_thickness -
+      BottomEdgeThicknessWithinNonClientHeight();
+
+  // The icon takes up a constant fraction of the available height, down to a
+  // minimum size, and is always an even number of pixels on a side (presumably
+  // to make scaled icons look better).  It's centered within the usable height.
+  int icon_size = std::max((available_height * kIconHeightFractionNumerator /
+      kIconHeightFractionDenominator) / 2 * 2, kIconMinimumSize);
+  int icon_y = ((available_height - icon_size) / 2) + frame_thickness;
+
+  // Hack: Our frame border has a different "3D look" than Windows'.  Theirs has
+  // a more complex gradient on the top that they push their icon/title below;
+  // then the maximized window cuts this off and the icon/title are centered in
+  // the remaining space.  Because the apparent shape of our border is simpler,
+  // using the same positioning makes things look slightly uncentered with
+  // restored windows, so we come up to compensate.
+  if (!frame_->IsMaximized())
+    icon_y -= kIconRestoredAdjust;
+
+  views::WindowDelegate* d = frame_->GetDelegate();
+  if (!d->ShouldShowWindowIcon())
+    icon_size = 0;
+  system_menu_button_->SetBounds(icon_x, icon_y, icon_size, icon_size);
+
+  // Size the title.
+  int icon_right = icon_x + icon_size;
+  int title_x =
+      icon_right + (d->ShouldShowWindowIcon() ? kIconTitleSpacing : 0);
+  int title_right = (should_show_minmax_buttons_ ?
+      minimize_button_->x() : close_button_->x()) - kTitleCaptionSpacing;
+  title_bounds_.SetRect(title_x,
+      title_top_spacing + ((title_thickness - title_font_->height()) / 2),
+      std::max(0, title_right - title_x), title_font_->height());
+}
+
+void CustomFrameView::LayoutClientView() {
+  int top_height = NonClientTopBorderHeight();
+  int border_thickness = NonClientBorderThickness();
+  client_view_bounds_.SetRect(
+      border_thickness,
+      top_height,
+      std::max(0, width() - (2 * border_thickness)),
+      std::max(0, height() - top_height - border_thickness));
+}
+
+// static
+void CustomFrameView::InitClass() {
+  static bool initialized = false;
+  if (!initialized) {
+    active_resources_ = new ActiveWindowResources;
+    inactive_resources_ = new InactiveWindowResources;
+
+    title_font_ = new ChromeFont(win_util::GetWindowTitleFont());
+
+    initialized = true;
+  }
+}
+
+}  // namespace views
diff --git a/views/window/custom_frame_view.h b/views/window/custom_frame_view.h
new file mode 100644
index 0000000..f0716924
--- /dev/null
+++ b/views/window/custom_frame_view.h
@@ -0,0 +1,122 @@
+// Copyright (c) 2009 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 VIEWS_WINDOW_CUSTOM_FRAME_VIEW_H_
+#define VIEWS_WINDOW_CUSTOM_FRAME_VIEW_H_
+
+#include "views/controls/button/image_button.h"
+#include "views/window/non_client_view.h"
+#include "views/window/window.h"
+#include "views/window/window_resources.h"
+
+namespace gfx{
+class Size;
+class Path;
+class Point;
+}
+class ChromeCanvas;
+class ChromeFont;
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// CustomFrameView
+//
+//  A ChromeView that provides the non client frame for Windows. This means
+//  rendering the non-standard window caption, border, and controls.
+//
+////////////////////////////////////////////////////////////////////////////////
+class CustomFrameView : public NonClientFrameView,
+                        public ButtonListener {
+ public:
+  explicit CustomFrameView(Window* frame);
+  virtual ~CustomFrameView();
+
+  // Overridden from views::NonClientFrameView:
+  virtual gfx::Rect GetBoundsForClientView() const;
+  virtual gfx::Rect GetWindowBoundsForClientBounds(
+      const gfx::Rect& client_bounds) const;
+  virtual gfx::Point GetSystemMenuPoint() const;
+  virtual int NonClientHitTest(const gfx::Point& point);
+  virtual void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask);
+  virtual void EnableClose(bool enable);
+  virtual void ResetWindowControls();
+
+  // View overrides:
+  virtual void Paint(ChromeCanvas* canvas);
+  virtual void Layout();
+  virtual gfx::Size GetPreferredSize();
+
+  // ButtonListener implementation:
+  virtual void ButtonPressed(Button* sender);
+
+ private:
+  // Returns the thickness of the border that makes up the window frame edges.
+  // This does not include any client edge.
+  int FrameBorderThickness() const;
+
+  // Returns the thickness of the entire nonclient left, right, and bottom
+  // borders, including both the window frame and any client edge.
+  int NonClientBorderThickness() const;
+
+  // Returns the height of the entire nonclient top border, including the window
+  // frame, any title area, and any connected client edge.
+  int NonClientTopBorderHeight() const;
+
+  // A bottom border, and, in restored mode, a client edge are drawn at the
+  // bottom of the titlebar.  This returns the total height drawn.
+  int BottomEdgeThicknessWithinNonClientHeight() const;
+
+  // Calculates multiple values related to title layout.  Returns the height of
+  // the entire titlebar including any connected client edge.
+  int TitleCoordinates(int* title_top_spacing,
+                       int* title_thickness) const;
+
+  // Paint various sub-components of this view.
+  void PaintRestoredFrameBorder(ChromeCanvas* canvas);
+  void PaintMaximizedFrameBorder(ChromeCanvas* canvas);
+  void PaintTitleBar(ChromeCanvas* canvas);
+  void PaintRestoredClientEdge(ChromeCanvas* canvas);
+
+  // Layout various sub-components of this view.
+  void LayoutWindowControls();
+  void LayoutTitleBar();
+  void LayoutClientView();
+
+  // Returns the resource collection to be used when rendering the window.
+  WindowResources* resources() const {
+    return frame_->IsActive() || paint_as_active() ? active_resources_
+                                                   : inactive_resources_;
+  }
+
+  // The bounds of the client view, in this view's coordinates.
+  gfx::Rect client_view_bounds_;
+
+  // The layout rect of the title, if visible.
+  gfx::Rect title_bounds_;
+
+  // Window controls.
+  ImageButton* close_button_;
+  ImageButton* restore_button_;
+  ImageButton* maximize_button_;
+  ImageButton* minimize_button_;
+  ImageButton* system_menu_button_;  // Uses the window icon if visible.
+  bool should_show_minmax_buttons_;
+
+  // The window that owns this view.
+  Window* frame_;
+
+  // Initialize various static resources.
+  static void InitClass();
+  static WindowResources* active_resources_;
+  static WindowResources* inactive_resources_;
+  static ChromeFont* title_font_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(CustomFrameView);
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_WINDOW_CUSTOM_FRAME_VIEW_H_
diff --git a/views/window/dialog_client_view.cc b/views/window/dialog_client_view.cc
new file mode 100644
index 0000000..b7989ac
--- /dev/null
+++ b/views/window/dialog_client_view.cc
@@ -0,0 +1,440 @@
+// Copyright (c) 2006-2008 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 "views/window/dialog_client_view.h"
+
+#include <windows.h>
+#include <uxtheme.h>
+#include <vsstyle.h>
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/gfx/chrome_font.h"
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/gfx/native_theme.h"
+#include "chrome/browser/views/standard_layout.h"
+#include "grit/generated_resources.h"
+#include "views/controls/button/native_button.h"
+#include "views/window/dialog_delegate.h"
+#include "views/window/window.h"
+
+namespace views {
+
+namespace {
+
+// Updates any of the standard buttons according to the delegate.
+void UpdateButtonHelper(NativeButton* button_view,
+                        DialogDelegate* delegate,
+                        MessageBoxFlags::DialogButton button) {
+  std::wstring label = delegate->GetDialogButtonLabel(button);
+  if (!label.empty())
+    button_view->SetLabel(label);
+  button_view->SetEnabled(delegate->IsDialogButtonEnabled(button));
+  button_view->SetVisible(delegate->IsDialogButtonVisible(button));
+}
+
+void FillViewWithSysColor(ChromeCanvas* canvas, View* view, COLORREF color) {
+  SkColor sk_color =
+      SkColorSetRGB(GetRValue(color), GetGValue(color), GetBValue(color));
+  canvas->FillRectInt(sk_color, 0, 0, view->width(), view->height());
+}
+
+// DialogButton ----------------------------------------------------------------
+
+// DialogButtons is used for the ok/cancel buttons of the window. DialogButton
+// forwards AcceleratorPressed to the delegate.
+
+class DialogButton : public NativeButton {
+ public:
+  DialogButton(ButtonListener* listener,
+               Window* owner,
+               MessageBoxFlags::DialogButton type,
+               const std::wstring& title,
+               bool is_default)
+      : NativeButton(listener, title),
+        owner_(owner),
+        type_(type) {
+    SetIsDefault(is_default);
+  }
+
+  // Overridden to forward to the delegate.
+  virtual bool AcceleratorPressed(const Accelerator& accelerator) {
+    if (!owner_->GetDelegate()->AsDialogDelegate()->
+        AreAcceleratorsEnabled(type_)) {
+      return false;
+    }
+    return NativeButton::AcceleratorPressed(accelerator);
+  }
+
+ private:
+  Window* owner_;
+  const MessageBoxFlags::DialogButton type_;
+
+  DISALLOW_COPY_AND_ASSIGN(DialogButton);
+};
+
+}  // namespace
+
+// static
+ChromeFont* DialogClientView::dialog_button_font_ = NULL;
+static const int kDialogMinButtonWidth = 75;
+static const int kDialogButtonLabelSpacing = 16;
+static const int kDialogButtonContentSpacing = 5;
+
+// The group used by the buttons.  This name is chosen voluntarily big not to
+// conflict with other groups that could be in the dialog content.
+static const int kButtonGroup = 6666;
+
+///////////////////////////////////////////////////////////////////////////////
+// DialogClientView, public:
+
+DialogClientView::DialogClientView(Window* owner, View* contents_view)
+    : ClientView(owner, contents_view),
+      ok_button_(NULL),
+      cancel_button_(NULL),
+      extra_view_(NULL),
+      accepted_(false),
+      default_button_(NULL) {
+  InitClass();
+}
+
+DialogClientView::~DialogClientView() {
+}
+
+void DialogClientView::ShowDialogButtons() {
+  DialogDelegate* dd = GetDialogDelegate();
+  int buttons = dd->GetDialogButtons();
+  if (buttons & MessageBoxFlags::DIALOGBUTTON_OK && !ok_button_) {
+    std::wstring label =
+        dd->GetDialogButtonLabel(MessageBoxFlags::DIALOGBUTTON_OK);
+    if (label.empty())
+      label = l10n_util::GetString(IDS_OK);
+    bool is_default_button =
+        (dd->GetDefaultDialogButton() & MessageBoxFlags::DIALOGBUTTON_OK) != 0;
+    ok_button_ = new DialogButton(this, window(),
+                                  MessageBoxFlags::DIALOGBUTTON_OK, label,
+                                  is_default_button);
+    ok_button_->SetGroup(kButtonGroup);
+    if (is_default_button)
+      default_button_ = ok_button_;
+    if (!(buttons & MessageBoxFlags::DIALOGBUTTON_CANCEL))
+      ok_button_->AddAccelerator(Accelerator(VK_ESCAPE, false, false, false));
+    AddChildView(ok_button_);
+  }
+  if (buttons & MessageBoxFlags::DIALOGBUTTON_CANCEL && !cancel_button_) {
+    std::wstring label =
+        dd->GetDialogButtonLabel(MessageBoxFlags::DIALOGBUTTON_CANCEL);
+    if (label.empty()) {
+      if (buttons & MessageBoxFlags::DIALOGBUTTON_OK) {
+        label = l10n_util::GetString(IDS_CANCEL);
+      } else {
+        label = l10n_util::GetString(IDS_CLOSE);
+      }
+    }
+    bool is_default_button =
+        (dd->GetDefaultDialogButton() & MessageBoxFlags::DIALOGBUTTON_CANCEL)
+        != 0;
+    cancel_button_ = new DialogButton(this, window(),
+                                      MessageBoxFlags::DIALOGBUTTON_CANCEL,
+                                      label, is_default_button);
+    cancel_button_->SetGroup(kButtonGroup);
+    cancel_button_->AddAccelerator(Accelerator(VK_ESCAPE, false, false, false));
+    if (is_default_button)
+      default_button_ = ok_button_;
+    AddChildView(cancel_button_);
+  }
+  if (!buttons) {
+    // Register the escape key as an accelerator which will close the window
+    // if there are no dialog buttons.
+    AddAccelerator(Accelerator(VK_ESCAPE, false, false, false));
+  }
+}
+
+void DialogClientView::SetDefaultButton(NativeButton* new_default_button) {
+  if (default_button_ && default_button_ != new_default_button) {
+    default_button_->SetIsDefault(false);
+    default_button_ = NULL;
+  }
+
+  if (new_default_button) {
+    default_button_ = new_default_button;
+    default_button_->SetIsDefault(true);
+  }
+}
+
+void DialogClientView::FocusWillChange(View* focused_before,
+                                       View* focused_now) {
+  NativeButton* new_default_button = NULL;
+  if (focused_now &&
+      focused_now->GetClassName() == NativeButton::kViewClassName) {
+    new_default_button = static_cast<NativeButton*>(focused_now);
+  } else {
+    // The focused view is not a button, get the default button from the
+    // delegate.
+    DialogDelegate* dd = GetDialogDelegate();
+    if ((dd->GetDefaultDialogButton() & MessageBoxFlags::DIALOGBUTTON_OK) != 0)
+      new_default_button = ok_button_;
+    if ((dd->GetDefaultDialogButton() & MessageBoxFlags::DIALOGBUTTON_CANCEL)
+        != 0)
+      new_default_button = cancel_button_;
+  }
+  SetDefaultButton(new_default_button);
+}
+
+// Changing dialog labels will change button widths.
+void DialogClientView::UpdateDialogButtons() {
+  DialogDelegate* dd = GetDialogDelegate();
+  int buttons = dd->GetDialogButtons();
+
+  if (buttons & MessageBoxFlags::DIALOGBUTTON_OK)
+    UpdateButtonHelper(ok_button_, dd, MessageBoxFlags::DIALOGBUTTON_OK);
+
+  if (buttons & MessageBoxFlags::DIALOGBUTTON_CANCEL) {
+    UpdateButtonHelper(cancel_button_, dd,
+                       MessageBoxFlags::DIALOGBUTTON_CANCEL);
+  }
+
+  LayoutDialogButtons();
+  SchedulePaint();
+}
+
+void DialogClientView::AcceptWindow() {
+  if (accepted_) {
+    // We should only get into AcceptWindow once.
+    NOTREACHED();
+    return;
+  }
+  if (GetDialogDelegate()->Accept(false)) {
+    accepted_ = true;
+    window()->Close();
+  }
+}
+
+void DialogClientView::CancelWindow() {
+  // Call the standard Close handler, which checks with the delegate before
+  // proceeding. This checking _isn't_ done here, but in the WM_CLOSE handler,
+  // so that the close box on the window also shares this code path.
+  window()->Close();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// DialogClientView, ClientView overrides:
+
+bool DialogClientView::CanClose() const {
+  if (!accepted_) {
+    DialogDelegate* dd = GetDialogDelegate();
+    int buttons = dd->GetDialogButtons();
+    if (buttons & MessageBoxFlags::DIALOGBUTTON_CANCEL)
+      return dd->Cancel();
+    if (buttons & MessageBoxFlags::DIALOGBUTTON_OK)
+      return dd->Accept(true);
+  }
+  return true;
+}
+
+void DialogClientView::WindowClosing() {
+  FocusManager* focus_manager = GetFocusManager();
+  DCHECK(focus_manager);
+  if (focus_manager)
+     focus_manager->RemoveFocusChangeListener(this);
+  ClientView::WindowClosing();
+}
+
+int DialogClientView::NonClientHitTest(const gfx::Point& point) {
+  if (size_box_bounds_.Contains(point.x() - x(), point.y() - y()))
+    return HTBOTTOMRIGHT;
+  return ClientView::NonClientHitTest(point);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DialogClientView, View overrides:
+
+void DialogClientView::Paint(ChromeCanvas* canvas) {
+  FillViewWithSysColor(canvas, this, GetSysColor(COLOR_3DFACE));
+}
+
+void DialogClientView::PaintChildren(ChromeCanvas* canvas) {
+  View::PaintChildren(canvas);
+  if (!window()->IsMaximized() && !window()->IsMinimized())
+    PaintSizeBox(canvas);
+}
+
+void DialogClientView::Layout() {
+  if (has_dialog_buttons())
+    LayoutDialogButtons();
+  LayoutContentsView();
+}
+
+void DialogClientView::ViewHierarchyChanged(bool is_add, View* parent,
+                                            View* child) {
+  if (is_add && child == this) {
+    // Can only add and update the dialog buttons _after_ they are added to the
+    // view hierarchy since they are native controls and require the
+    // Container's HWND.
+    ShowDialogButtons();
+    ClientView::ViewHierarchyChanged(is_add, parent, child);
+
+    FocusManager* focus_manager = GetFocusManager();
+    // Listen for focus change events so we can update the default button.
+    DCHECK(focus_manager);  // bug #1291225: crash reports seem to indicate it
+                            // can be NULL.
+    if (focus_manager)
+      focus_manager->AddFocusChangeListener(this);
+
+    // The "extra view" must be created and installed after the contents view
+    // has been inserted into the view hierarchy.
+    CreateExtraView();
+    UpdateDialogButtons();
+    Layout();
+  }
+}
+
+gfx::Size DialogClientView::GetPreferredSize() {
+  gfx::Size prefsize = contents_view()->GetPreferredSize();
+  int button_height = 0;
+  if (has_dialog_buttons()) {
+    if (cancel_button_)
+      button_height = cancel_button_->height();
+    else
+      button_height = ok_button_->height();
+    // Account for padding above and below the button.
+    button_height += kDialogButtonContentSpacing + kButtonVEdgeMargin;
+  }
+  prefsize.Enlarge(0, button_height);
+  return prefsize;
+}
+
+bool DialogClientView::AcceleratorPressed(const Accelerator& accelerator) {
+  DCHECK(accelerator.GetKeyCode() == VK_ESCAPE);  // We only expect Escape key.
+  window()->Close();
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DialogClientView, ButtonListener implementation:
+
+void DialogClientView::ButtonPressed(Button* sender) {
+  if (sender == ok_button_) {
+    AcceptWindow();
+  } else if (sender == cancel_button_) {
+    CancelWindow();
+  } else {
+    NOTREACHED();
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DialogClientView, private:
+
+void DialogClientView::PaintSizeBox(ChromeCanvas* canvas) {
+  if (window()->GetDelegate()->CanResize() ||
+      window()->GetDelegate()->CanMaximize()) {
+    HDC dc = canvas->beginPlatformPaint();
+    SIZE gripper_size = { 0, 0 };
+    gfx::NativeTheme::instance()->GetThemePartSize(
+        gfx::NativeTheme::STATUS, dc, SP_GRIPPER, 1, NULL, TS_TRUE,
+        &gripper_size);
+
+    // TODO(beng): (http://b/1085509) In "classic" rendering mode, there isn't
+    //             a theme-supplied gripper. We should probably improvise
+    //             something, which would also require changing |gripper_size|
+    //             to have different default values, too...
+    size_box_bounds_ = GetLocalBounds(false);
+    size_box_bounds_.set_x(size_box_bounds_.right() - gripper_size.cx);
+    size_box_bounds_.set_y(size_box_bounds_.bottom() - gripper_size.cy);
+    RECT native_bounds = size_box_bounds_.ToRECT();
+    gfx::NativeTheme::instance()->PaintStatusGripper(
+        dc, SP_PANE, 1, 0, &native_bounds);
+    canvas->endPlatformPaint();
+  }
+}
+
+int DialogClientView::GetButtonWidth(int button) const {
+  DialogDelegate* dd = GetDialogDelegate();
+  std::wstring button_label = dd->GetDialogButtonLabel(
+      static_cast<MessageBoxFlags::DialogButton>(button));
+  int string_width = dialog_button_font_->GetStringWidth(button_label);
+  return std::max(string_width + kDialogButtonLabelSpacing,
+                  kDialogMinButtonWidth);
+}
+
+int DialogClientView::GetButtonsHeight() const {
+  if (has_dialog_buttons()) {
+    if (cancel_button_)
+      return cancel_button_->height() + kDialogButtonContentSpacing;
+    return ok_button_->height() + kDialogButtonContentSpacing;
+  }
+  return 0;
+}
+
+void DialogClientView::LayoutDialogButtons() {
+  gfx::Rect extra_bounds;
+  if (cancel_button_) {
+    gfx::Size ps = cancel_button_->GetPreferredSize();
+    gfx::Rect lb = GetLocalBounds(false);
+    int button_width = GetButtonWidth(MessageBoxFlags::DIALOGBUTTON_CANCEL);
+    int button_x = lb.right() - button_width - kButtonHEdgeMargin;
+    int button_y = lb.bottom() - ps.height() - kButtonVEdgeMargin;
+    cancel_button_->SetBounds(button_x, button_y, button_width, ps.height());
+    // The extra view bounds are dependent on this button.
+    extra_bounds.set_width(std::max(0, cancel_button_->x()));
+    extra_bounds.set_y(cancel_button_->y());
+  }
+  if (ok_button_) {
+    gfx::Size ps = ok_button_->GetPreferredSize();
+    gfx::Rect lb = GetLocalBounds(false);
+    int button_width = GetButtonWidth(MessageBoxFlags::DIALOGBUTTON_OK);
+    int ok_button_right = lb.right() - kButtonHEdgeMargin;
+    if (cancel_button_)
+      ok_button_right = cancel_button_->x() - kRelatedButtonHSpacing;
+    int button_x = ok_button_right - button_width;
+    int button_y = lb.bottom() - ps.height() - kButtonVEdgeMargin;
+    ok_button_->SetBounds(button_x, button_y, ok_button_right - button_x,
+                          ps.height());
+    // The extra view bounds are dependent on this button.
+    extra_bounds.set_width(std::max(0, ok_button_->x()));
+    extra_bounds.set_y(ok_button_->y());
+  }
+  if (extra_view_) {
+    gfx::Size ps = extra_view_->GetPreferredSize();
+    gfx::Rect lb = GetLocalBounds(false);
+    extra_bounds.set_x(lb.x() + kButtonHEdgeMargin);
+    extra_bounds.set_height(ps.height());
+    extra_view_->SetBounds(extra_bounds);
+  }
+}
+
+void DialogClientView::LayoutContentsView() {
+  gfx::Rect lb = GetLocalBounds(false);
+  lb.set_height(std::max(0, lb.height() - GetButtonsHeight()));
+  contents_view()->SetBounds(lb);
+  contents_view()->Layout();
+}
+
+void DialogClientView::CreateExtraView() {
+  View* extra_view = GetDialogDelegate()->GetExtraView();
+  if (extra_view && !extra_view_) {
+    extra_view_ = extra_view;
+    extra_view_->SetGroup(kButtonGroup);
+    AddChildView(extra_view_);
+  }
+}
+
+DialogDelegate* DialogClientView::GetDialogDelegate() const {
+  DialogDelegate* dd = window()->GetDelegate()->AsDialogDelegate();
+  DCHECK(dd);
+  return dd;
+}
+
+// static
+void DialogClientView::InitClass() {
+  static bool initialized = false;
+  if (!initialized) {
+    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+    dialog_button_font_ = new ChromeFont(rb.GetFont(ResourceBundle::BaseFont));
+    initialized = true;
+  }
+}
+
+}  // namespace views
diff --git a/views/window/dialog_client_view.h b/views/window/dialog_client_view.h
new file mode 100644
index 0000000..347b61c
--- /dev/null
+++ b/views/window/dialog_client_view.h
@@ -0,0 +1,123 @@
+// Copyright (c) 2006-2008 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 VIEWS_WINDOW_DIALOG_CLIENT_VIEW_H_
+#define VIEWS_WINDOW_DIALOG_CLIENT_VIEW_H_
+
+#include "app/gfx/chrome_font.h"
+#include "views/focus/focus_manager.h"
+#include "views/controls/button/button.h"
+#include "views/window/client_view.h"
+
+namespace views {
+
+class DialogDelegate;
+class NativeButton;
+class Window;
+
+///////////////////////////////////////////////////////////////////////////////
+// DialogClientView
+//
+//  This ClientView subclass provides the content of a typical dialog box,
+//  including a strip of buttons at the bottom right of the window, default
+//  accelerator handlers for accept and cancel, and the ability for the
+//  embedded contents view to provide extra UI to be shown in the row of
+//  buttons.
+//
+class DialogClientView : public ClientView,
+                         public ButtonListener,
+                         public FocusChangeListener {
+ public:
+  DialogClientView(Window* window, View* contents_view);
+  virtual ~DialogClientView();
+
+  // Adds the dialog buttons required by the supplied WindowDelegate to the
+  // view.
+  void ShowDialogButtons();
+
+  // Updates the enabled state and label of the buttons required by the
+  // supplied WindowDelegate
+  void UpdateDialogButtons();
+
+  // Accept the changes made in the window that contains this ClientView.
+  void AcceptWindow();
+
+  // Cancel the changes made in the window that contains this ClientView.
+  void CancelWindow();
+
+  // Accessors in case the user wishes to adjust these buttons.
+  NativeButton* ok_button() const { return ok_button_; }
+  NativeButton* cancel_button() const { return cancel_button_; }
+
+  // Overridden from ClientView:
+  virtual bool CanClose() const;
+  virtual void WindowClosing();
+  virtual int NonClientHitTest(const gfx::Point& point);
+  virtual DialogClientView* AsDialogClientView() { return this; }
+
+  // FocusChangeListener implementation:
+  virtual void FocusWillChange(View* focused_before, View* focused_now);
+
+ protected:
+  // View overrides:
+  virtual void Paint(ChromeCanvas* canvas);
+  virtual void PaintChildren(ChromeCanvas* canvas);
+  virtual void Layout();
+  virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child);
+  virtual gfx::Size GetPreferredSize();
+  virtual bool AcceleratorPressed(const Accelerator& accelerator);
+
+  // ButtonListener implementation:
+  virtual void ButtonPressed(Button* sender);
+
+ private:
+  // Paint the size box in the bottom right corner of the window if it is
+  // resizable.
+  void PaintSizeBox(ChromeCanvas* canvas);
+
+  // Returns the width of the specified dialog button using the correct font.
+  int GetButtonWidth(int button) const;
+  int GetButtonsHeight() const;
+
+  // Position and size various sub-views.
+  void LayoutDialogButtons();
+  void LayoutContentsView();
+
+  // Makes the specified button the default button.
+  void SetDefaultButton(NativeButton* button);
+
+  bool has_dialog_buttons() const { return ok_button_ || cancel_button_; }
+
+  // Create and add the extra view, if supplied by the delegate.
+  void CreateExtraView();
+
+  // Returns the DialogDelegate for the window.
+  DialogDelegate* GetDialogDelegate() const;
+
+  // The dialog buttons.
+  NativeButton* ok_button_;
+  NativeButton* cancel_button_;
+
+  // The button that is currently the default button if any.
+  NativeButton* default_button_;
+
+  // The button-level extra view, NULL unless the dialog delegate supplies one.
+  View* extra_view_;
+
+  // The layout rect of the size box, when visible.
+  gfx::Rect size_box_bounds_;
+
+  // True if the window was Accepted by the user using the OK button.
+  bool accepted_;
+
+  // Static resource initialization
+  static void InitClass();
+  static ChromeFont* dialog_button_font_;
+
+  DISALLOW_COPY_AND_ASSIGN(DialogClientView);
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_WINDOW_DIALOG_CLIENT_VIEW_H_
diff --git a/views/window/dialog_delegate.cc b/views/window/dialog_delegate.cc
new file mode 100644
index 0000000..4ae9a91
--- /dev/null
+++ b/views/window/dialog_delegate.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2006-2008 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 "views/window/dialog_delegate.h"
+
+#include "base/logging.h"
+#include "views/controls/button/native_button.h"
+#include "views/window/window.h"
+
+namespace views {
+
+// Overridden from WindowDelegate:
+
+int DialogDelegate::GetDefaultDialogButton() const {
+  if (GetDialogButtons() & MessageBoxFlags::DIALOGBUTTON_OK)
+    return MessageBoxFlags::DIALOGBUTTON_OK;
+  if (GetDialogButtons() & MessageBoxFlags::DIALOGBUTTON_CANCEL)
+    return MessageBoxFlags::DIALOGBUTTON_CANCEL;
+  return MessageBoxFlags::DIALOGBUTTON_NONE;
+}
+
+View* DialogDelegate::GetInitiallyFocusedView() {
+  // Focus the default button if any.
+  DialogClientView* dcv = GetDialogClientView();
+  int default_button = GetDefaultDialogButton();
+  if (default_button == MessageBoxFlags::DIALOGBUTTON_NONE)
+    return NULL;
+
+  if ((default_button & GetDialogButtons()) == 0) {
+    // The default button is a button we don't have.
+    NOTREACHED();
+    return NULL;
+  }
+
+  if (default_button & MessageBoxFlags::DIALOGBUTTON_OK)
+    return dcv->ok_button();
+  if (default_button & MessageBoxFlags::DIALOGBUTTON_CANCEL)
+    return dcv->cancel_button();
+  return NULL;
+}
+
+ClientView* DialogDelegate::CreateClientView(Window* window) {
+  return new DialogClientView(window, GetContentsView());
+}
+
+DialogClientView* DialogDelegate::GetDialogClientView() const {
+  ClientView* client_view = window()->GetClientView();
+  DialogClientView* dialog_client_view = client_view->AsDialogClientView();
+  DCHECK(dialog_client_view);
+  return dialog_client_view;
+}
+
+}  // namespace views
diff --git a/views/window/dialog_delegate.h b/views/window/dialog_delegate.h
new file mode 100644
index 0000000..4418e61f
--- /dev/null
+++ b/views/window/dialog_delegate.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2006-2008 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 VIEWS_WINDOW_DIALOG_DELEGATE_H_
+#define VIEWS_WINDOW_DIALOG_DELEGATE_H_
+
+#include "app/message_box_flags.h"
+#include "views/window/dialog_client_view.h"
+#include "views/window/window_delegate.h"
+
+namespace views {
+
+class View;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// DialogDelegate
+//
+//  DialogDelegate is an interface implemented by objects that wish to show a
+//  dialog box Window. The window that is displayed uses this interface to
+//  determine how it should be displayed and notify the delegate object of
+//  certain events.
+//
+///////////////////////////////////////////////////////////////////////////////
+class DialogDelegate : public WindowDelegate {
+ public:
+  virtual DialogDelegate* AsDialogDelegate() { return this; }
+
+  // Returns a mask specifying which of the available DialogButtons are visible
+  // for the dialog. Note: If an OK button is provided, you should provide a
+  // CANCEL button. A dialog box with just an OK button is frowned upon and
+  // considered a very special case, so if you're planning on including one,
+  // you should reconsider, or beng says there will be stabbings.
+  //
+  // To use the extra button you need to override GetDialogButtons()
+  virtual int GetDialogButtons() const {
+    return MessageBoxFlags::DIALOGBUTTON_OK |
+        MessageBoxFlags::DIALOGBUTTON_CANCEL;
+  }
+
+  // Returns whether accelerators are enabled on the button. This is invoked
+  // when an accelerator is pressed, not at construction time. This
+  // returns true.
+  virtual bool AreAcceleratorsEnabled(MessageBoxFlags::DialogButton button) {
+    return true;
+  }
+
+  // Returns the label of the specified DialogButton.
+  virtual std::wstring GetDialogButtonLabel(
+      MessageBoxFlags::DialogButton button) const {
+    // empty string results in defaults for MessageBoxFlags::DIALOGBUTTON_OK,
+    // MessageBoxFlags::DIALOGBUTTON_CANCEL.
+    return L"";
+  }
+
+  // Override this function if with a view which will be shown in the same
+  // row as the OK and CANCEL buttons but flush to the left and extending
+  // up to the buttons.
+  virtual View* GetExtraView() { return NULL; }
+
+  // Returns the default dialog button. This should not be a mask as only
+  // one button should ever be the default button.  Return
+  // MessageBoxFlags::DIALOGBUTTON_NONE if there is no default.  Default
+  // behavior is to return MessageBoxFlags::DIALOGBUTTON_OK or
+  // MessageBoxFlags::DIALOGBUTTON_CANCEL (in that order) if they are
+  // present, MessageBoxFlags::DIALOGBUTTON_NONE otherwise.
+  virtual int GetDefaultDialogButton() const;
+
+  // Returns whether the specified dialog button is enabled.
+  virtual bool IsDialogButtonEnabled(
+      MessageBoxFlags::DialogButton button) const {
+    return true;
+  }
+
+  // Returns whether the specified dialog button is visible.
+  virtual bool IsDialogButtonVisible(
+      MessageBoxFlags::DialogButton button) const {
+    return true;
+  }
+
+  // For Dialog boxes, if there is a "Cancel" button, this is called when the
+  // user presses the "Cancel" button or the Close button on the window or
+  // in the system menu, or presses the Esc key. This function should return
+  // true if the window can be closed after it returns, or false if it must
+  // remain open.
+  virtual bool Cancel() { return true; }
+
+  // For Dialog boxes, this is called when the user presses the "OK" button,
+  // or the Enter key.  Can also be called on Esc key or close button
+  // presses if there is no "Cancel" button.  This function should return
+  // true if the window can be closed after the window can be closed after
+  // it returns, or false if it must remain open.  If |window_closing| is
+  // true, it means that this handler is being called because the window is
+  // being closed (e.g.  by Window::Close) and there is no Cancel handler,
+  // so Accept is being called instead.
+  virtual bool Accept(bool window_closing) { return Accept(); }
+  virtual bool Accept() { return true; }
+
+  // Overridden from WindowDelegate:
+  virtual View* GetInitiallyFocusedView();
+
+  // Overridden from WindowDelegate:
+  virtual ClientView* CreateClientView(Window* window);
+
+  // A helper for accessing the DialogClientView object contained by this
+  // delegate's Window.
+  DialogClientView* GetDialogClientView() const;
+};
+
+}  // namespace views
+
+#endif  // VIEWS_WINDOW_DIALOG_DELEGATE_H_
diff --git a/views/window/native_frame_view.cc b/views/window/native_frame_view.cc
new file mode 100644
index 0000000..05a8dcb0
--- /dev/null
+++ b/views/window/native_frame_view.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2009 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 "views/window/native_frame_view.h"
+
+#include "views/window/window_win.h"
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeFrameView, public:
+
+NativeFrameView::NativeFrameView(WindowWin* frame)
+    : NonClientFrameView(),
+      frame_(frame) {
+}
+
+NativeFrameView::~NativeFrameView() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NativeFrameView, NonClientFrameView overrides:
+
+gfx::Rect NativeFrameView::GetBoundsForClientView() const {
+  return gfx::Rect(0, 0, width(), height());
+}
+
+gfx::Rect NativeFrameView::GetWindowBoundsForClientBounds(
+    const gfx::Rect& client_bounds) const {
+  RECT rect = client_bounds.ToRECT();
+  AdjustWindowRectEx(&rect, frame_->window_style(), FALSE,
+                     frame_->window_ex_style());
+  return gfx::Rect(rect);
+}
+
+gfx::Point NativeFrameView::GetSystemMenuPoint() const {
+  POINT temp = {0, -kFrameShadowThickness };
+  MapWindowPoints(frame_->GetNativeView(), HWND_DESKTOP, &temp, 1);
+  return gfx::Point(temp);
+}
+
+int NativeFrameView::NonClientHitTest(const gfx::Point& point) {
+  return HTNOWHERE;
+}
+
+void NativeFrameView::GetWindowMask(const gfx::Size& size,
+                                    gfx::Path* window_mask) {
+  // Nothing to do, we use the default window mask.
+}
+
+void NativeFrameView::EnableClose(bool enable) {
+  // Nothing to do, handled automatically by Window.
+}
+
+void NativeFrameView::ResetWindowControls() {
+  // Nothing to do.
+}
+
+}  // namespace views
diff --git a/views/window/native_frame_view.h b/views/window/native_frame_view.h
new file mode 100644
index 0000000..e2efa9d
--- /dev/null
+++ b/views/window/native_frame_view.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2009 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 VIEWS_WINDOW_NATIVE_FRAME_VIEW_H_
+#define VIEWS_WINDOW_NATIVE_FRAME_VIEW_H_
+
+#include "views/window/non_client_view.h"
+
+namespace views {
+
+class WindowWin;
+
+class NativeFrameView : public NonClientFrameView {
+ public:
+  explicit NativeFrameView(WindowWin* frame);
+  virtual ~NativeFrameView();
+
+  // NonClientFrameView overrides:
+  virtual gfx::Rect GetBoundsForClientView() const;
+  virtual gfx::Rect GetWindowBoundsForClientBounds(
+      const gfx::Rect& client_bounds) const;
+  virtual gfx::Point GetSystemMenuPoint() const;
+  virtual int NonClientHitTest(const gfx::Point& point);
+  virtual void GetWindowMask(const gfx::Size& size,
+                             gfx::Path* window_mask);
+  virtual void EnableClose(bool enable);
+  virtual void ResetWindowControls();
+
+ private:
+  // Our containing frame.
+  WindowWin* frame_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeFrameView);
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_WINDOW_NATIVE_FRAME_VIEW_H_
diff --git a/views/window/non_client_view.cc b/views/window/non_client_view.cc
new file mode 100644
index 0000000..9a06cfc9
--- /dev/null
+++ b/views/window/non_client_view.cc
@@ -0,0 +1,255 @@
+// Copyright (c) 2006-2008 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 "views/window/non_client_view.h"
+
+#include "chrome/common/win_util.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+#include "views/window/window.h"
+
+namespace views {
+
+const int NonClientFrameView::kFrameShadowThickness = 1;
+const int NonClientFrameView::kClientEdgeThickness = 1;
+
+// The frame view and the client view are always at these specific indices,
+// because the RootView message dispatch sends messages to items higher in the
+// z-order first and we always want the client view to have first crack at
+// handling mouse messages.
+static const int kFrameViewIndex = 0;
+static const int kClientViewIndex = 1;
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientView, public:
+
+NonClientView::NonClientView(Window* frame)
+    : frame_(frame),
+      client_view_(NULL),
+      use_native_frame_(win_util::ShouldUseVistaFrame()) {
+}
+
+NonClientView::~NonClientView() {
+  // This value may have been reset before the window hierarchy shuts down,
+  // so we need to manually remove it.
+  RemoveChildView(frame_view_.get());
+}
+
+void NonClientView::SetFrameView(NonClientFrameView* frame_view) {
+  // See comment in header about ownership.
+  frame_view->SetParentOwned(false);
+  if (frame_view_.get())
+    RemoveChildView(frame_view_.get());
+  frame_view_.reset(frame_view);
+  if (GetParent())
+    AddChildView(kFrameViewIndex, frame_view_.get());
+}
+
+bool NonClientView::CanClose() const {
+  return client_view_->CanClose();
+}
+
+void NonClientView::WindowClosing() {
+  client_view_->WindowClosing();
+}
+
+void NonClientView::SetUseNativeFrame(bool use_native_frame) {
+  use_native_frame_ = use_native_frame;
+  SetFrameView(frame_->CreateFrameViewForWindow());
+  GetRootView()->ThemeChanged();
+  Layout();
+  SchedulePaint();
+  frame_->UpdateFrameAfterFrameChange();
+}
+
+bool NonClientView::UseNativeFrame() const {
+  // The frame view may always require a custom frame, e.g. Constrained Windows.
+  bool always_use_custom_frame =
+      frame_view_.get() && frame_view_->AlwaysUseCustomFrame();
+  return !always_use_custom_frame && use_native_frame_;
+}
+
+void NonClientView::DisableInactiveRendering(bool disable) {
+  frame_view_->DisableInactiveRendering(disable);
+}
+
+gfx::Rect NonClientView::GetWindowBoundsForClientBounds(
+    const gfx::Rect client_bounds) const {
+  return frame_view_->GetWindowBoundsForClientBounds(client_bounds);
+}
+
+gfx::Point NonClientView::GetSystemMenuPoint() const {
+  return frame_view_->GetSystemMenuPoint();
+}
+
+int NonClientView::NonClientHitTest(const gfx::Point& point) {
+  // Sanity check.
+  if (!bounds().Contains(point))
+    return HTNOWHERE;
+
+  // The ClientView gets first crack, since it overlays the NonClientFrameView
+  // in the display stack.
+  int frame_component = client_view_->NonClientHitTest(point);
+  if (frame_component != HTNOWHERE)
+    return frame_component;
+
+  // Finally ask the NonClientFrameView. It's at the back of the display stack
+  // so it gets asked last.
+  return frame_view_->NonClientHitTest(point);
+}
+
+void NonClientView::GetWindowMask(const gfx::Size& size,
+                                  gfx::Path* window_mask) {
+  frame_view_->GetWindowMask(size, window_mask);
+}
+
+void NonClientView::EnableClose(bool enable) {
+  frame_view_->EnableClose(enable);
+}
+
+void NonClientView::ResetWindowControls() {
+  frame_view_->ResetWindowControls();
+}
+
+void NonClientView::LayoutFrameView() {
+  // First layout the NonClientFrameView, which determines the size of the
+  // ClientView...
+  frame_view_->SetBounds(0, 0, width(), height());
+
+  // We need to manually call Layout here because layout for the frame view can
+  // change independently of the bounds changing - e.g. after the initial
+  // display of the window the metrics of the native window controls can change,
+  // which does not change the bounds of the window but requires a re-layout to
+  // trigger a repaint. We override DidChangeBounds for the NonClientFrameView
+  // to do nothing so that SetBounds above doesn't cause Layout to be called
+  // twice.
+  frame_view_->Layout();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientView, View overrides:
+
+gfx::Size NonClientView::GetPreferredSize() {
+  // TODO(pkasting): This should probably be made to look similar to
+  // GetMinimumSize() below.  This will require implementing GetPreferredSize()
+  // better in the various frame views.
+  gfx::Rect client_bounds(gfx::Point(), client_view_->GetPreferredSize());
+  return GetWindowBoundsForClientBounds(client_bounds).size();
+}
+
+gfx::Size NonClientView::GetMinimumSize() {
+  return frame_view_->GetMinimumSize();
+}
+
+void NonClientView::Layout() {
+  LayoutFrameView();
+
+  // Then layout the ClientView, using those bounds.
+  client_view_->SetBounds(frame_view_->GetBoundsForClientView());
+
+  // We need to manually call Layout on the ClientView as well for the same
+  // reason as above.
+  client_view_->Layout();
+}
+
+void NonClientView::ViewHierarchyChanged(bool is_add, View* parent,
+                                         View* child) {
+  // Add our two child views here as we are added to the Widget so that if we
+  // are subsequently resized all the parent-child relationships are
+  // established.
+  if (is_add && GetWidget() && child == this) {
+    AddChildView(kFrameViewIndex, frame_view_.get());
+    AddChildView(kClientViewIndex, client_view_);
+  }
+}
+
+views::View* NonClientView::GetViewForPoint(const gfx::Point& point) {
+  return GetViewForPoint(point, false);
+}
+
+views::View* NonClientView::GetViewForPoint(const gfx::Point& point,
+                                            bool can_create_floating) {
+  // Because of the z-ordering of our child views (the client view is positioned
+  // over the non-client frame view, if the client view ever overlaps the frame
+  // view visually (as it does for the browser window), then it will eat mouse
+  // events for the window controls. We override this method here so that we can
+  // detect this condition and re-route the events to the non-client frame view.
+  // The assumption is that the frame view's implementation of HitTest will only
+  // return true for area not occupied by the client view.
+  gfx::Point point_in_child_coords(point);
+  View::ConvertPointToView(this, frame_view_.get(), &point_in_child_coords);
+  if (frame_view_->HitTest(point_in_child_coords))
+    return frame_view_->GetViewForPoint(point);
+
+  return View::GetViewForPoint(point, can_create_floating);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientFrameView, View overrides:
+
+bool NonClientFrameView::HitTest(const gfx::Point& l) const {
+  // For the default case, we assume the non-client frame view never overlaps
+  // the client view.
+  return !GetWindow()->GetClientView()->bounds().Contains(l);
+}
+
+void NonClientFrameView::DidChangeBounds(const gfx::Rect& previous,
+                                         const gfx::Rect& current) {
+  // Overridden to do nothing. The NonClientView manually calls Layout on the
+  // FrameView when it is itself laid out, see comment in NonClientView::Layout.
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientFrameView, protected:
+
+int NonClientFrameView::GetHTComponentForFrame(const gfx::Point& point,
+                                               int top_resize_border_height,
+                                               int resize_border_thickness,
+                                               int top_resize_corner_height,
+                                               int resize_corner_width,
+                                               bool can_resize) {
+  // Tricky: In XP, native behavior is to return HTTOPLEFT and HTTOPRIGHT for
+  // a |resize_corner_size|-length strip of both the side and top borders, but
+  // only to return HTBOTTOMLEFT/HTBOTTOMRIGHT along the bottom border + corner
+  // (not the side border).  Vista goes further and doesn't return these on any
+  // of the side borders.  We allow callers to match either behavior.
+  int component;
+  if (point.x() < resize_border_thickness) {
+    if (point.y() < top_resize_corner_height)
+      component = HTTOPLEFT;
+    else if (point.y() >= (height() - resize_border_thickness))
+      component = HTBOTTOMLEFT;
+    else
+      component = HTLEFT;
+  } else if (point.x() >= (width() - resize_border_thickness)) {
+    if (point.y() < top_resize_corner_height)
+      component = HTTOPRIGHT;
+    else if (point.y() >= (height() - resize_border_thickness))
+      component = HTBOTTOMRIGHT;
+    else
+      component = HTRIGHT;
+  } else if (point.y() < top_resize_border_height) {
+    if (point.x() < resize_corner_width)
+      component = HTTOPLEFT;
+    else if (point.x() >= (width() - resize_corner_width))
+      component = HTTOPRIGHT;
+    else
+      component = HTTOP;
+  } else if (point.y() >= (height() - resize_border_thickness)) {
+    if (point.x() < resize_corner_width)
+      component = HTBOTTOMLEFT;
+    else if (point.x() >= (width() - resize_corner_width))
+      component = HTBOTTOMRIGHT;
+    else
+      component = HTBOTTOM;
+  } else {
+    return HTNOWHERE;
+  }
+
+  // If the window can't be resized, there are no resize boundaries, just
+  // window borders.
+  return can_resize ? component : HTBORDER;
+}
+
+}  // namespace views
diff --git a/views/window/non_client_view.h b/views/window/non_client_view.h
new file mode 100644
index 0000000..d93f423
--- /dev/null
+++ b/views/window/non_client_view.h
@@ -0,0 +1,227 @@
+// Copyright (c) 2006-2008 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 VIEWS_WINDOW_NON_CLIENT_VIEW_H_
+#define VIEWS_WINDOW_NON_CLIENT_VIEW_H_
+
+#include "base/task.h"
+#include "views/view.h"
+#include "views/window/client_view.h"
+
+namespace gfx {
+class Path;
+}
+
+namespace views {
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientFrameView
+//
+//  An object that subclasses NonClientFrameView is a View that renders and
+//  responds to events within the frame portions of the non-client area of a
+//  window. This view does _not_ contain the ClientView, but rather is a sibling
+//  of it.
+class NonClientFrameView : public View {
+ public:
+  // Various edges of the frame border have a 1 px shadow along their edges; in
+  // a few cases we shift elements based on this amount for visual appeal.
+  static const int kFrameShadowThickness;
+  // In restored mode, we draw a 1 px edge around the content area inside the
+  // frame border.
+  static const int kClientEdgeThickness;
+
+  void DisableInactiveRendering(bool disable) {
+    paint_as_active_ = disable;
+    if (!paint_as_active_)
+      SchedulePaint();
+  }
+
+  // Returns the bounds (in this View's parent's coordinates) that the client
+  // view should be laid out within.
+  virtual gfx::Rect GetBoundsForClientView() const = 0;
+
+  // Returns true if this FrameView should always use the custom frame,
+  // regardless of the system settings. An example is the Constrained Window,
+  // which is a child window and must always provide its own frame.
+  virtual bool AlwaysUseCustomFrame() const { return false; }
+
+  virtual gfx::Rect GetWindowBoundsForClientBounds(
+      const gfx::Rect& client_bounds) const = 0;
+  virtual gfx::Point GetSystemMenuPoint() const = 0;
+  virtual int NonClientHitTest(const gfx::Point& point) = 0;
+  virtual void GetWindowMask(const gfx::Size& size,
+                             gfx::Path* window_mask) = 0;
+  virtual void EnableClose(bool enable) = 0;
+  virtual void ResetWindowControls() = 0;
+
+  // Overridden from View:
+  virtual bool HitTest(const gfx::Point& l) const;
+
+ protected:
+  virtual void DidChangeBounds(const gfx::Rect& previous,
+                               const gfx::Rect& current);
+
+  NonClientFrameView() : paint_as_active_(false) {}
+
+
+  // Helper for non-client view implementations to determine which area of the
+  // window border the specified |point| falls within. The other parameters are
+  // the size of the sizing edges, and whether or not the window can be
+  // resized.
+  int GetHTComponentForFrame(const gfx::Point& point,
+                             int top_resize_border_height,
+                             int resize_border_thickness,
+                             int top_resize_corner_height,
+                             int resize_corner_width,
+                             bool can_resize);
+
+  // Accessor for paint_as_active_.
+  bool paint_as_active() const { return paint_as_active_; }
+
+ private:
+  // True when the non-client view should always be rendered as if the window
+  // were active, regardless of whether or not the top level window actually
+  // is active.
+  bool paint_as_active_;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// NonClientView
+//
+//  The NonClientView is the logical root of all Views contained within a
+//  Window, except for the RootView which is its parent and of which it is the
+//  sole child. The NonClientView has two children, the NonClientFrameView which
+//  is responsible for painting and responding to events from the non-client
+//  portions of the window, and the ClientView, which is responsible for the
+//  same for the client area of the window:
+//
+//  +- views::Window ------------------------------------+
+//  | +- views::RootView ------------------------------+ |
+//  | | +- views::NonClientView ---------------------+ | |
+//  | | | +- views::NonClientView subclass      ---+ | | |
+//  | | | |                                        | | | |
+//  | | | | << all painting and event receiving >> | | | |
+//  | | | | << of the non-client areas of a     >> | | | |
+//  | | | | << views::Window.                   >> | | | |
+//  | | | |                                        | | | |
+//  | | | +----------------------------------------+ | | |
+//  | | | +- views::ClientView or subclass --------+ | | |
+//  | | | |                                        | | | |
+//  | | | | << all painting and event receiving >> | | | |
+//  | | | | << of the client areas of a         >> | | | |
+//  | | | | << views::Window.                   >> | | | |
+//  | | | |                                        | | | |
+//  | | | +----------------------------------------+ | | |
+//  | | +--------------------------------------------+ | |
+//  | +------------------------------------------------+ |
+//  +----------------------------------------------------+
+//
+// The NonClientFrameView and ClientView are siblings because due to theme
+// changes the NonClientFrameView may be replaced with different
+// implementations (e.g. during the switch from DWM/Aero-Glass to Vista Basic/
+// Classic rendering).
+//
+class NonClientView : public View {
+ public:
+  explicit NonClientView(Window* frame);
+  virtual ~NonClientView();
+
+  // Replaces the current NonClientFrameView (if any) with the specified one.
+  void SetFrameView(NonClientFrameView* frame_view);
+
+  // Returns true if the ClientView determines that the containing window can be
+  // closed, false otherwise.
+  bool CanClose() const;
+
+  // Called by the containing Window when it is closed.
+  void WindowClosing();
+
+  // Changes the frame from native to custom depending on the value of
+  // |use_native_frame|.
+  void SetUseNativeFrame(bool use_native_frame);
+
+  // Returns true if the native window frame should be used, false if the
+  // NonClientView provides its own frame implementation.
+  bool UseNativeFrame() const;
+
+  // Prevents the window from being rendered as deactivated when |disable| is
+  // true, until called with |disable| false. Used when a sub-window is to be
+  // shown that shouldn't visually de-activate the window.
+  // Subclasses can override this to perform additional actions when this value
+  // changes.
+  void DisableInactiveRendering(bool disable);
+
+  // Returns the bounds of the window required to display the content area at
+  // the specified bounds.
+  gfx::Rect GetWindowBoundsForClientBounds(const gfx::Rect client_bounds) const;
+
+  // Returns the point, in screen coordinates, where the system menu should
+  // be shown so it shows up anchored to the system menu icon.
+  gfx::Point GetSystemMenuPoint() const;
+
+  // Determines the windows HT* code when the mouse cursor is at the
+  // specified point, in window coordinates.
+  int NonClientHitTest(const gfx::Point& point);
+
+  // Returns a mask to be used to clip the top level window for the given
+  // size. This is used to create the non-rectangular window shape.
+  void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask);
+
+  // Toggles the enable state for the Close button (and the Close menu item in
+  // the system menu).
+  void EnableClose(bool enable);
+
+  // Tells the window controls as rendered by the NonClientView to reset
+  // themselves to a normal state. This happens in situations where the
+  // containing window does not receive a normal sequences of messages that
+  // would lead to the controls returning to this normal state naturally, e.g.
+  // when the window is maximized, minimized or restored.
+  void ResetWindowControls();
+
+  // Get/Set client_view property.
+  ClientView* client_view() const { return client_view_; }
+  void set_client_view(ClientView* client_view) {
+    client_view_ = client_view;
+  }
+
+  // Layout just the frame view. This is necessary on Windows when non-client
+  // metrics such as the position of the window controls changes independently
+  // of a window resize message.
+  void LayoutFrameView();
+
+  // NonClientView, View overrides:
+  virtual gfx::Size GetPreferredSize();
+  virtual gfx::Size GetMinimumSize();
+  virtual void Layout();
+
+ protected:
+  // NonClientView, View overrides:
+  virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child);
+  virtual views::View* GetViewForPoint(const gfx::Point& point);
+  virtual views::View* GetViewForPoint(const gfx::Point& point,
+                                       bool can_create_floating);
+
+ private:
+  // The frame that hosts this NonClientView.
+  Window* frame_;
+
+  // A ClientView object or subclass, responsible for sizing the contents view
+  // of the window, hit testing and perhaps other tasks depending on the
+  // implementation.
+  ClientView* client_view_;
+
+  // The NonClientFrameView that renders the non-client portions of the window.
+  // This object is not owned by the view hierarchy because it can be replaced
+  // dynamically as the system settings change.
+  scoped_ptr<NonClientFrameView> frame_view_;
+
+  // Whether or not we should use the native frame.
+  bool use_native_frame_;
+
+  DISALLOW_COPY_AND_ASSIGN(NonClientView);
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_WINDOW_NON_CLIENT_VIEW_H_
diff --git a/views/window/window.h b/views/window/window.h
new file mode 100644
index 0000000..17a2ff5
--- /dev/null
+++ b/views/window/window.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2009 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 VIEWS_WINDOW_WINDOW_H_
+#define VIEWS_WINDOW_WINDOW_H_
+
+#include "base/gfx/native_widget_types.h"
+
+namespace gfx {
+class Rect;
+class Size;
+}
+
+namespace views {
+
+class ClientView;
+class NonClientFrameView;
+class NonClientView;
+class WindowDelegate;
+
+// An interface implemented by an object that provides a top level window.
+class Window {
+ public:
+  virtual ~Window() {}
+
+  // Creates an instance of an object implementing this interface.
+  static Window* CreateChromeWindow(gfx::NativeWindow parent,
+                                    const gfx::Rect& bounds,
+                                    WindowDelegate* window_delegate);
+
+  // Returns the preferred size of the contents view of this window based on
+  // its localized size data. The width in cols is held in a localized string
+  // resource identified by |col_resource_id|, the height in the same fashion.
+  // TODO(beng): This should eventually live somewhere else, probably closer to
+  //             ClientView.
+  static int GetLocalizedContentsWidth(int col_resource_id);
+  static int GetLocalizedContentsHeight(int row_resource_id);
+  static gfx::Size GetLocalizedContentsSize(int col_resource_id,
+                                            int row_resource_id);
+
+  // Closes all windows that aren't identified as "app windows" via
+  // IsAppWindow. Called during application shutdown when the last "app window"
+  // is closed.
+  static void CloseAllSecondaryWindows();
+
+  // Retrieves the window's bounds, including its frame.
+  virtual gfx::Rect GetBounds() const = 0;
+
+  // Retrieves the restored bounds for the window.
+  virtual gfx::Rect GetNormalBounds() const = 0;
+
+  // Sizes and/or places the window to the specified bounds, size or position.
+  virtual void SetBounds(const gfx::Rect& bounds) = 0;
+
+  // As above, except the window is inserted after |other_window| in the window
+  // Z-order. If this window is not yet visible, other_window's monitor  is used
+  // as the constraining rectangle, rather than this window's monitor.
+  virtual void SetBounds(const gfx::Rect& bounds,
+                         gfx::NativeWindow other_window) = 0;
+
+  // Makes the window visible.
+  virtual void Show() = 0;
+
+  // Activate the window, assuming it already exists and is visible.
+  virtual void Activate() = 0;
+
+  // Closes the window, ultimately destroying it. This isn't immediate (it
+  // occurs after a return to the message loop. Implementors must also make sure
+  // that invoking Close multiple times doesn't cause bad things to happen,
+  // since it can happen.
+  virtual void Close() = 0;
+
+  // Maximizes/minimizes/restores the window.
+  virtual void Maximize() = 0;
+  virtual void Minimize() = 0;
+  virtual void Restore() = 0;
+
+  // Whether or not the window is currently active.
+  virtual bool IsActive() const = 0;
+
+  // Whether or not the window is currently visible.
+  virtual bool IsVisible() const = 0;
+
+  // Whether or not the window is maximized or minimized.
+  virtual bool IsMaximized() const = 0;
+  virtual bool IsMinimized() const = 0;
+
+  // Accessors for fullscreen state.
+  virtual void SetFullscreen(bool fullscreen) = 0;
+  virtual bool IsFullscreen() const = 0;
+
+  // Returns true if the Window is considered to be an "app window" - i.e.
+  // any window which when it is the last of its type closed causes the
+  // application to exit.
+  virtual bool IsAppWindow() const { return false; }
+
+  // Toggles the enable state for the Close button (and the Close menu item in
+  // the system menu).
+  virtual void EnableClose(bool enable) = 0;
+
+  // Prevents the window from being rendered as deactivated the next time it is.
+  // This state is reset automatically as soon as the window becomes activated
+  // again. There is no ability to control the state through this API as this
+  // leads to sync problems.
+  virtual void DisableInactiveRendering() = 0;
+
+  // Tell the window to update its title from the delegate.
+  virtual void UpdateWindowTitle() = 0;
+
+  // Tell the window to update its icon from the delegate.
+  virtual void UpdateWindowIcon() = 0;
+
+  // Creates an appropriate NonClientFrameView for this window.
+  virtual NonClientFrameView* CreateFrameViewForWindow() = 0;
+
+  // Updates the frame after an event caused it to be changed.
+  virtual void UpdateFrameAfterFrameChange() = 0;
+
+  // Retrieves the Window's delegate.
+  virtual WindowDelegate* GetDelegate() const = 0;
+
+  // Retrieves the Window's non-client view.
+  virtual NonClientView* GetNonClientView() const = 0;
+
+  // Retrieves the Window's client view.
+  virtual ClientView* GetClientView() const = 0;
+
+  // Retrieves the Window's native window handle.
+  virtual gfx::NativeWindow GetNativeWindow() const = 0;
+};
+
+}  // namespace views
+
+#endif  // #ifndef VIEWS_WINDOW_WINDOW_H_
diff --git a/views/window/window_delegate.cc b/views/window/window_delegate.cc
new file mode 100644
index 0000000..7b5f251
--- /dev/null
+++ b/views/window/window_delegate.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2006-2008 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 "views/window/window_delegate.h"
+
+// TODO(beng): hrmp. Fix this in http://crbug.com/4406
+#include "chrome/browser/browser_process.h"
+#include "chrome/common/pref_service.h"
+#include "views/window/client_view.h"
+#include "views/window/window.h"
+#include "skia/include/SkBitmap.h"
+
+namespace views {
+
+WindowDelegate::WindowDelegate() {
+}
+
+WindowDelegate::~WindowDelegate() {
+  ReleaseWindow();
+}
+
+// Returns the icon to be displayed in the window.
+SkBitmap WindowDelegate::GetWindowIcon() {
+  return SkBitmap();
+}
+
+void WindowDelegate::SaveWindowPlacement(const gfx::Rect& bounds,
+                                         bool maximized,
+                                         bool always_on_top) {
+  std::wstring window_name = GetWindowName();
+  if (window_name.empty() || !g_browser_process->local_state())
+    return;
+
+  DictionaryValue* window_preferences =
+      g_browser_process->local_state()->GetMutableDictionary(
+          window_name.c_str());
+  window_preferences->SetInteger(L"left", bounds.x());
+  window_preferences->SetInteger(L"top", bounds.y());
+  window_preferences->SetInteger(L"right", bounds.right());
+  window_preferences->SetInteger(L"bottom", bounds.bottom());
+  window_preferences->SetBoolean(L"maximized", maximized);
+  window_preferences->SetBoolean(L"always_on_top", always_on_top);
+}
+
+bool WindowDelegate::GetSavedWindowBounds(gfx::Rect* bounds) const {
+  std::wstring window_name = GetWindowName();
+  if (window_name.empty())
+    return false;
+
+  const DictionaryValue* dictionary =
+      g_browser_process->local_state()->GetDictionary(window_name.c_str());
+  int left, top, right, bottom;
+  if (!dictionary || !dictionary->GetInteger(L"left", &left) ||
+      !dictionary->GetInteger(L"top", &top) ||
+      !dictionary->GetInteger(L"right", &right) ||
+      !dictionary->GetInteger(L"bottom", &bottom))
+    return false;
+
+  bounds->SetRect(left, top, right - left, bottom - top);
+  return true;
+}
+
+bool WindowDelegate::GetSavedMaximizedState(bool* maximized) const {
+  std::wstring window_name = GetWindowName();
+  if (window_name.empty())
+    return false;
+
+  const DictionaryValue* dictionary =
+      g_browser_process->local_state()->GetDictionary(window_name.c_str());
+  return dictionary && dictionary->GetBoolean(L"maximized", maximized);
+}
+
+bool WindowDelegate::GetSavedAlwaysOnTopState(bool* always_on_top) const {
+  if (!g_browser_process->local_state())
+    return false;
+
+  std::wstring window_name = GetWindowName();
+  if (window_name.empty())
+    return false;
+
+  const DictionaryValue* dictionary =
+      g_browser_process->local_state()->GetDictionary(window_name.c_str());
+  return dictionary && dictionary->GetBoolean(L"always_on_top", always_on_top);
+}
+
+
+ClientView* WindowDelegate::CreateClientView(Window* window) {
+  return new ClientView(window, GetContentsView());
+}
+
+void WindowDelegate::ReleaseWindow() {
+  window_.release();
+}
+
+}  // namespace views
diff --git a/views/window/window_delegate.h b/views/window/window_delegate.h
new file mode 100644
index 0000000..af8285c
--- /dev/null
+++ b/views/window/window_delegate.h
@@ -0,0 +1,162 @@
+// Copyright (c) 2006-2008 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 VIEWS_WINDOW_WINDOW_DELEGATE_H_
+#define VIEWS_WINDOW_WINDOW_DELEGATE_H_
+
+#include <string>
+
+#include "base/scoped_ptr.h"
+
+class SkBitmap;
+
+namespace gfx {
+class Rect;
+}
+// TODO(maruel):  Remove once gfx::Rect is used instead.
+namespace WTL {
+class CRect;
+}
+using WTL::CRect;
+
+namespace views {
+
+class ClientView;
+class DialogDelegate;
+class View;
+class Window;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// WindowDelegate
+//
+//  WindowDelegate is an interface implemented by objects that wish to show a
+//  Window. The window that is displayed uses this interface to determine how
+//  it should be displayed and notify the delegate object of certain events.
+//
+///////////////////////////////////////////////////////////////////////////////
+class WindowDelegate {
+ public:
+  WindowDelegate();
+  virtual ~WindowDelegate();
+
+  virtual DialogDelegate* AsDialogDelegate() { return NULL; }
+
+  // Returns true if the window can ever be resized.
+  virtual bool CanResize() const {
+    return false;
+  }
+
+  // Returns true if the window can ever be maximized.
+  virtual bool CanMaximize() const {
+    return false;
+  }
+
+  // Returns true if the window should be placed on top of all other windows on
+  // the system, even when it is not active. If HasAlwaysOnTopMenu() returns
+  // true, then this method is only used the first time the window is opened, it
+  // is stored in the preferences for next runs.
+  virtual bool IsAlwaysOnTop() const {
+    return false;
+  }
+
+  // Returns whether an "always on top" menu should be added to the system menu
+  // of the window.
+  virtual bool HasAlwaysOnTopMenu() const {
+    return false;
+  }
+
+  // Returns true if the dialog should be displayed modally to the window that
+  // opened it. Only windows with WindowType == DIALOG can be modal.
+  virtual bool IsModal() const {
+    return false;
+  }
+
+  // Returns the text to be displayed in the window title.
+  virtual std::wstring GetWindowTitle() const {
+    return L"";
+  }
+
+  // Returns the view that should have the focus when the dialog is opened.  If
+  // NULL no view is focused.
+  virtual View* GetInitiallyFocusedView() { return NULL; }
+
+  // Returns true if the window should show a title in the title bar.
+  virtual bool ShouldShowWindowTitle() const {
+    return true;
+  }
+
+  // Returns the icon to be displayed in the window.
+  virtual SkBitmap GetWindowIcon();
+
+  // Returns true if a window icon should be shown.
+  virtual bool ShouldShowWindowIcon() const {
+    return false;
+  }
+
+  // Execute a command in the window's controller. Returns true if the command
+  // was handled, false if it was not.
+  virtual bool ExecuteWindowsCommand(int command_id) { return false; }
+
+  // Returns the window's name identifier. Used to identify this window for
+  // state restoration.
+  virtual std::wstring GetWindowName() const {
+    return std::wstring();
+  }
+
+  // Saves the window's bounds, maximized and always-on-top states. By default
+  // this uses the process' local state keyed by window name (See GetWindowName
+  // above). This behavior can be overridden to provide additional
+  // functionality.
+  virtual void SaveWindowPlacement(const gfx::Rect& bounds,
+                                   bool maximized,
+                                   bool always_on_top);
+
+  // Retrieves the window's bounds, maximized and always-on-top states. By
+  // default, this uses the process' local state keyed by window name (See
+  // GetWindowName above). This behavior can be overridden to provide
+  // additional functionality.
+  virtual bool GetSavedWindowBounds(gfx::Rect* bounds) const;
+  virtual bool GetSavedMaximizedState(bool* maximized) const;
+  virtual bool GetSavedAlwaysOnTopState(bool* always_on_top) const;
+
+  // Called when the window closes.
+  virtual void WindowClosing() { }
+
+  // Called when the window is destroyed. No events must be sent or received
+  // after this point. The delegate can use this opportunity to delete itself at
+  // this time if necessary.
+  virtual void DeleteDelegate() { }
+
+  // Returns the View that is contained within this Window.
+  virtual View* GetContentsView() {
+    return NULL;
+  }
+
+  // Called by the Window to create the Client View used to host the contents
+  // of the window.
+  virtual ClientView* CreateClientView(Window* window);
+
+  // An accessor to the Window this delegate is bound to.
+  Window* window() const { return window_.get(); }
+
+ protected:
+  // Releases the Window* we maintain. This should be done by a delegate in its
+  // WindowClosing handler if it intends to be re-cycled to be used on a
+  // different Window.
+  void ReleaseWindow();
+
+ private:
+  friend class WindowWin;
+  // This is a little unusual. We use a scoped_ptr here because it's
+  // initialized to NULL automatically. We do this because we want to allow
+  // people using this helper to not have to call a ctor on this object.
+  // Instead we just release the owning ref this pointer has when we are
+  // destroyed.
+  scoped_ptr<Window> window_;
+};
+
+}  // namespace views
+
+#endif  // VIEWS_WINDOW_WINDOW_DELEGATE_H_
diff --git a/views/window/window_resources.h b/views/window/window_resources.h
new file mode 100644
index 0000000..e79476ed8
--- /dev/null
+++ b/views/window/window_resources.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2006-2008 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 VIEWS_WINDOW_WINDOW_RESOURCES_H_
+#define VIEWS_WINDOW_WINDOW_RESOURCES_H_
+
+class SkBitmap;
+
+namespace views {
+
+typedef int FramePartBitmap;
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowResources
+//
+//  An interface implemented by an object providing bitmaps to render the
+//  contents of a window frame. The Window may swap in different
+//  implementations of this interface to render different modes. The definition
+//  of FramePartBitmap depends on the implementation.
+//
+class WindowResources {
+ public:
+  virtual ~WindowResources() { }
+  virtual SkBitmap* GetPartBitmap(FramePartBitmap part) const = 0;
+};
+
+}  // namespace views
+
+#endif  // VIEWS_WINDOW_WINDOW_RESOURCES_H_
diff --git a/views/window/window_win.cc b/views/window/window_win.cc
new file mode 100644
index 0000000..f41ef18
--- /dev/null
+++ b/views/window/window_win.cc
@@ -0,0 +1,1446 @@
+// Copyright (c) 2006-2008 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 "views/window/window_win.h"
+
+#include <shellapi.h>
+
+#include "app/gfx/chrome_canvas.h"
+#include "app/gfx/chrome_font.h"
+#include "app/gfx/icon_util.h"
+#include "app/gfx/path.h"
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/win_util.h"
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/common/win_util.h"
+#include "grit/generated_resources.h"
+#include "views/widget/root_view.h"
+#include "views/window/client_view.h"
+#include "views/window/custom_frame_view.h"
+#include "views/window/native_frame_view.h"
+#include "views/window/non_client_view.h"
+#include "views/window/window_delegate.h"
+
+namespace {
+
+bool GetMonitorAndRects(const RECT& rect,
+                        HMONITOR* monitor,
+                        gfx::Rect* monitor_rect,
+                        gfx::Rect* work_area) {
+  DCHECK(monitor);
+  DCHECK(monitor_rect);
+  DCHECK(work_area);
+  *monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONULL);
+  if (!*monitor)
+    return false;
+  MONITORINFO monitor_info = { 0 };
+  monitor_info.cbSize = sizeof(monitor_info);
+  GetMonitorInfo(*monitor, &monitor_info);
+  *monitor_rect = monitor_info.rcMonitor;
+  *work_area = monitor_info.rcWork;
+  return true;
+}
+
+}  // namespace
+
+namespace views {
+
+// A scoping class that prevents a window from being able to redraw in response
+// to invalidations that may occur within it for the lifetime of the object.
+//
+// Why would we want such a thing? Well, it turns out Windows has some
+// "unorthodox" behavior when it comes to painting its non-client areas.
+// Occasionally, Windows will paint portions of the default non-client area
+// right over the top of the custom frame. This is not simply fixed by handling
+// WM_NCPAINT/WM_PAINT, with some investigation it turns out that this
+// rendering is being done *inside* the default implementation of some message
+// handlers and functions:
+//  . WM_SETTEXT
+//  . WM_SETICON
+//  . WM_NCLBUTTONDOWN
+//  . EnableMenuItem, called from our WM_INITMENU handler
+// The solution is to handle these messages and call DefWindowProc ourselves,
+// but prevent the window from being able to update itself for the duration of
+// the call. We do this with this class, which automatically calls its
+// associated Window's lock and unlock functions as it is created and destroyed.
+// See documentation in those methods for the technique used.
+//
+// IMPORTANT: Do not use this scoping object for large scopes or periods of
+//            time! IT WILL PREVENT THE WINDOW FROM BEING REDRAWN! (duh).
+//
+// I would love to hear Raymond Chen's explanation for all this. And maybe a
+// list of other messages that this applies to ;-)
+class WindowWin::ScopedRedrawLock {
+ public:
+  explicit ScopedRedrawLock(WindowWin* window) : window_(window) {
+    window_->LockUpdates();
+  }
+
+  ~ScopedRedrawLock() {
+    window_->UnlockUpdates();
+  }
+
+ private:
+  // The window having its style changed.
+  WindowWin* window_;
+};
+
+HCURSOR WindowWin::resize_cursors_[6];
+
+// If the hung renderer warning doesn't fit on screen, the amount of padding to
+// be left between the edge of the window and the edge of the nearest monitor,
+// after the window is nudged back on screen. Pixels.
+static const int kMonitorEdgePadding = 10;
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowWin, public:
+
+WindowWin::~WindowWin() {
+}
+
+// static
+Window* Window::CreateChromeWindow(gfx::NativeWindow parent,
+                                   const gfx::Rect& bounds,
+                                   WindowDelegate* window_delegate) {
+  WindowWin* window = new WindowWin(window_delegate);
+  window->GetNonClientView()->SetFrameView(window->CreateFrameViewForWindow());
+  window->Init(parent, bounds);
+  return window;
+}
+
+gfx::Rect WindowWin::GetBounds() const {
+  gfx::Rect bounds;
+  WidgetWin::GetBounds(&bounds, true);
+  return bounds;
+}
+
+gfx::Rect WindowWin::GetNormalBounds() const {
+  // If we're in fullscreen mode, we've changed the normal bounds to the monitor
+  // rect, so return the saved bounds instead.
+  if (IsFullscreen())
+    return gfx::Rect(saved_window_info_.window_rect);
+
+  WINDOWPLACEMENT wp;
+  wp.length = sizeof(wp);
+  const bool ret = !!GetWindowPlacement(GetNativeView(), &wp);
+  DCHECK(ret);
+  return gfx::Rect(wp.rcNormalPosition);
+}
+
+void WindowWin::SetBounds(const gfx::Rect& bounds) {
+  SetBounds(bounds, NULL);
+}
+
+void WindowWin::SetBounds(const gfx::Rect& bounds,
+                          gfx::NativeWindow other_window) {
+  win_util::SetChildBounds(GetNativeView(), GetParent(), other_window, bounds,
+                           kMonitorEdgePadding, 0);
+}
+
+void WindowWin::Show(int show_state) {
+  ShowWindow(show_state);
+  // When launched from certain programs like bash and Windows Live Messenger,
+  // show_state is set to SW_HIDE, so we need to correct that condition. We
+  // don't just change show_state to SW_SHOWNORMAL because MSDN says we must
+  // always first call ShowWindow with the specified value from STARTUPINFO,
+  // otherwise all future ShowWindow calls will be ignored (!!#@@#!). Instead,
+  // we call ShowWindow again in this case.
+  if (show_state == SW_HIDE) {
+    show_state = SW_SHOWNORMAL;
+    ShowWindow(show_state);
+  }
+
+  // We need to explicitly activate the window if we've been shown with a state
+  // that should activate, because if we're opened from a desktop shortcut while
+  // an existing window is already running it doesn't seem to be enough to use
+  // one of these flags to activate the window.
+  if (show_state == SW_SHOWNORMAL)
+    Activate();
+
+  SetInitialFocus();
+}
+
+int WindowWin::GetShowState() const {
+  return SW_SHOWNORMAL;
+}
+
+void WindowWin::ExecuteSystemMenuCommand(int command) {
+  if (command)
+    SendMessage(GetNativeView(), WM_SYSCOMMAND, command, 0);
+}
+
+void WindowWin::PushForceHidden() {
+  if (force_hidden_count_++ == 0)
+    Hide();
+}
+
+void WindowWin::PopForceHidden() {
+  if (--force_hidden_count_ <= 0) {
+    force_hidden_count_ = 0;
+    ShowWindow(SW_SHOW);
+  }
+}
+
+// static
+int Window::GetLocalizedContentsWidth(int col_resource_id) {
+  double chars = _wtof(l10n_util::GetString(col_resource_id).c_str());
+  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+  ChromeFont font = rb.GetFont(ResourceBundle::BaseFont);
+  int width = font.GetExpectedTextWidth(static_cast<int>(chars));
+  DCHECK(width > 0);
+  return width;
+}
+
+// static
+int Window::GetLocalizedContentsHeight(int row_resource_id) {
+  double lines = _wtof(l10n_util::GetString(row_resource_id).c_str());
+  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+  ChromeFont font = rb.GetFont(ResourceBundle::BaseFont);
+  int height = static_cast<int>(font.height() * lines);
+  DCHECK(height > 0);
+  return height;
+}
+
+// static
+gfx::Size Window::GetLocalizedContentsSize(int col_resource_id,
+                                           int row_resource_id) {
+  return gfx::Size(GetLocalizedContentsWidth(col_resource_id),
+                   GetLocalizedContentsHeight(row_resource_id));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowWin, Window implementation:
+
+void WindowWin::Show() {
+  int show_state = GetShowState();
+  if (saved_maximized_state_)
+    show_state = SW_SHOWMAXIMIZED;
+  Show(show_state);
+}
+
+void WindowWin::Activate() {
+  if (IsMinimized())
+    ::ShowWindow(GetNativeView(), SW_RESTORE);
+  ::SetWindowPos(GetNativeView(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+  SetForegroundWindow(GetNativeView());
+}
+
+void WindowWin::Close() {
+  if (window_closed_) {
+    // It appears we can hit this code path if you close a modal dialog then
+    // close the last browser before the destructor is hit, which triggers
+    // invoking Close again. I'm short circuiting this code path to avoid
+    // calling into the delegate twice, which is problematic.
+    return;
+  }
+
+  if (non_client_view_->CanClose()) {
+    SaveWindowPosition();
+    RestoreEnabledIfNecessary();
+    WidgetWin::Close();
+    // If the user activates another app after opening us, then comes back and
+    // closes us, we want our owner to gain activation.  But only if the owner
+    // is visible. If we don't manually force that here, the other app will
+    // regain activation instead.
+    if (owning_hwnd_ && GetNativeView() == GetForegroundWindow() &&
+        IsWindowVisible(owning_hwnd_)) {
+      SetForegroundWindow(owning_hwnd_);
+    }
+    window_closed_ = true;
+  }
+}
+
+void WindowWin::Maximize() {
+  ExecuteSystemMenuCommand(SC_MAXIMIZE);
+}
+
+void WindowWin::Minimize() {
+  ExecuteSystemMenuCommand(SC_MINIMIZE);
+}
+
+void WindowWin::Restore() {
+  ExecuteSystemMenuCommand(SC_RESTORE);
+}
+
+bool WindowWin::IsActive() const {
+  return is_active_;
+}
+
+bool WindowWin::IsVisible() const {
+  return !!::IsWindowVisible(GetNativeView());
+}
+
+bool WindowWin::IsMaximized() const {
+  return !!::IsZoomed(GetNativeView());
+}
+
+bool WindowWin::IsMinimized() const {
+  return !!::IsIconic(GetNativeView());
+}
+
+void WindowWin::SetFullscreen(bool fullscreen) {
+  if (fullscreen_ == fullscreen)
+    return;  // Nothing to do.
+
+  // Reduce jankiness during the following position changes by hiding the window
+  // until it's in the final position.
+  PushForceHidden();
+
+  // Size/position/style window appropriately.
+  if (!fullscreen_) {
+    // Save current window information.  We force the window into restored mode
+    // before going fullscreen because Windows doesn't seem to hide the
+    // taskbar if the window is in the maximized state.
+    saved_window_info_.maximized = IsMaximized();
+    if (saved_window_info_.maximized)
+      Restore();
+    saved_window_info_.style = GetWindowLong(GWL_STYLE);
+    saved_window_info_.ex_style = GetWindowLong(GWL_EXSTYLE);
+    GetWindowRect(&saved_window_info_.window_rect);
+  }
+
+  // Toggle fullscreen mode.
+  fullscreen_ = fullscreen;
+
+  if (fullscreen_) {
+    // Set new window style and size.
+    MONITORINFO monitor_info;
+    monitor_info.cbSize = sizeof(monitor_info);
+    GetMonitorInfo(MonitorFromWindow(GetNativeView(), MONITOR_DEFAULTTONEAREST),
+                   &monitor_info);
+    gfx::Rect monitor_rect(monitor_info.rcMonitor);
+    SetWindowLong(GWL_STYLE,
+                  saved_window_info_.style & ~(WS_CAPTION | WS_THICKFRAME));
+    SetWindowLong(GWL_EXSTYLE,
+                  saved_window_info_.ex_style & ~(WS_EX_DLGMODALFRAME |
+                  WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
+    SetWindowPos(NULL, monitor_rect.x(), monitor_rect.y(),
+                 monitor_rect.width(), monitor_rect.height(),
+                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
+  } else {
+    // Reset original window style and size.  The multiple window size/moves
+    // here are ugly, but if SetWindowPos() doesn't redraw, the taskbar won't be
+    // repainted.  Better-looking methods welcome.
+    gfx::Rect new_rect(saved_window_info_.window_rect);
+    SetWindowLong(GWL_STYLE, saved_window_info_.style);
+    SetWindowLong(GWL_EXSTYLE, saved_window_info_.ex_style);
+    SetWindowPos(NULL, new_rect.x(), new_rect.y(), new_rect.width(),
+                 new_rect.height(),
+                 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
+    if (saved_window_info_.maximized)
+      Maximize();
+  }
+
+  // Undo our anti-jankiness hacks.
+  PopForceHidden();
+}
+
+bool WindowWin::IsFullscreen() const {
+  return fullscreen_;
+}
+
+void WindowWin::EnableClose(bool enable) {
+  // If the native frame is rendering its own close button, ask it to disable.
+  non_client_view_->EnableClose(enable);
+
+  // Disable the native frame's close button regardless of whether or not the
+  // native frame is in use, since this also affects the system menu.
+  EnableMenuItem(GetSystemMenu(GetNativeView(), false),
+                 SC_CLOSE, enable ? MF_ENABLED : MF_GRAYED);
+
+  // Let the window know the frame changed.
+  SetWindowPos(NULL, 0, 0, 0, 0,
+               SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOCOPYBITS |
+                   SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREPOSITION |
+                   SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER);
+}
+
+void WindowWin::DisableInactiveRendering() {
+  disable_inactive_rendering_ = true;
+  non_client_view_->DisableInactiveRendering(disable_inactive_rendering_);
+}
+
+void WindowWin::UpdateWindowTitle() {
+  // If the non-client view is rendering its own title, it'll need to relayout
+  // now.
+  non_client_view_->Layout();
+
+  // Update the native frame's text. We do this regardless of whether or not
+  // the native frame is being used, since this also updates the taskbar, etc.
+  std::wstring window_title = window_delegate_->GetWindowTitle();
+  std::wstring localized_text;
+  if (l10n_util::AdjustStringForLocaleDirection(window_title, &localized_text))
+    window_title.assign(localized_text);
+  SetWindowText(GetNativeView(), window_title.c_str());
+}
+
+void WindowWin::UpdateWindowIcon() {
+  // If the non-client view is rendering its own icon, we need to tell it to
+  // repaint.
+  non_client_view_->SchedulePaint();
+
+  // Update the native frame's icon. We do this regardless of whether or not
+  // the native frame is being used, since this also updates the taskbar, etc.
+  SkBitmap icon = window_delegate_->GetWindowIcon();
+  if (!icon.isNull()) {
+    HICON windows_icon = IconUtil::CreateHICONFromSkBitmap(icon);
+    // We need to make sure to destroy the previous icon, otherwise we'll leak
+    // these GDI objects until we crash!
+    HICON old_icon = reinterpret_cast<HICON>(
+        SendMessage(GetNativeView(), WM_SETICON, ICON_SMALL,
+                    reinterpret_cast<LPARAM>(windows_icon)));
+    if (old_icon)
+      DestroyIcon(old_icon);
+    old_icon = reinterpret_cast<HICON>(
+        SendMessage(GetNativeView(), WM_SETICON, ICON_BIG,
+                    reinterpret_cast<LPARAM>(windows_icon)));
+    if (old_icon)
+      DestroyIcon(old_icon);
+  }
+}
+
+NonClientFrameView* WindowWin::CreateFrameViewForWindow() {
+  if (non_client_view_->UseNativeFrame())
+    return new NativeFrameView(this);
+  return new CustomFrameView(this);
+}
+
+void WindowWin::UpdateFrameAfterFrameChange() {
+  // We've either gained or lost a custom window region, so reset it now.
+  ResetWindowRegion(true);
+}
+
+WindowDelegate* WindowWin::GetDelegate() const {
+  return window_delegate_;
+}
+
+NonClientView* WindowWin::GetNonClientView() const {
+  return non_client_view_;
+}
+
+ClientView* WindowWin::GetClientView() const {
+  return non_client_view_->client_view();
+}
+
+gfx::NativeWindow WindowWin::GetNativeWindow() const {
+  return GetNativeView();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowWin, protected:
+
+WindowWin::WindowWin(WindowDelegate* window_delegate)
+    : WidgetWin(),
+      focus_on_creation_(true),
+      window_delegate_(window_delegate),
+      non_client_view_(new NonClientView(this)),
+      owning_hwnd_(NULL),
+      minimum_size_(100, 100),
+      is_modal_(false),
+      restored_enabled_(false),
+      is_always_on_top_(false),
+      fullscreen_(false),
+      window_closed_(false),
+      disable_inactive_rendering_(false),
+      is_active_(false),
+      lock_updates_(false),
+      saved_window_style_(0),
+      saved_maximized_state_(0),
+      ignore_window_pos_changes_(false),
+      ignore_pos_changes_factory_(this),
+      force_hidden_count_(0),
+      last_monitor_(NULL) {
+  is_window_ = true;
+  InitClass();
+  DCHECK(window_delegate_);
+  window_delegate_->window_.reset(this);
+  // Initialize these values to 0 so that subclasses can override the default
+  // behavior before calling Init.
+  set_window_style(0);
+  set_window_ex_style(0);
+}
+
+void WindowWin::Init(HWND parent, const gfx::Rect& bounds) {
+  // We need to save the parent window, since later calls to GetParent() will
+  // return NULL.
+  owning_hwnd_ = parent;
+  // We call this after initializing our members since our implementations of
+  // assorted WidgetWin functions may be called during initialization.
+  is_modal_ = window_delegate_->IsModal();
+  if (is_modal_)
+    BecomeModal();
+  is_always_on_top_ = window_delegate_->IsAlwaysOnTop();
+
+  if (window_style() == 0)
+    set_window_style(CalculateWindowStyle());
+  if (window_ex_style() == 0)
+    set_window_ex_style(CalculateWindowExStyle());
+
+  WidgetWin::Init(parent, bounds, true);
+  win_util::SetWindowUserData(GetNativeView(), this);
+
+  // Create the ClientView, add it to the NonClientView and add the
+  // NonClientView to the RootView. This will cause everything to be parented.
+  non_client_view_->set_client_view(window_delegate_->CreateClientView(this));
+  WidgetWin::SetContentsView(non_client_view_);
+
+  UpdateWindowTitle();
+
+  SetInitialBounds(bounds);
+  InitAlwaysOnTopState();
+
+  GetMonitorAndRects(bounds.ToRECT(), &last_monitor_, &last_monitor_rect_,
+                     &last_work_area_);
+  ResetWindowRegion(false);
+}
+
+void WindowWin::SizeWindowToDefault() {
+  win_util::CenterAndSizeWindow(owning_window(), GetNativeView(),
+                                non_client_view_->GetPreferredSize().ToSIZE(),
+                                false);
+}
+
+void WindowWin::RunSystemMenu(const gfx::Point& point) {
+  // We need to reset and clean up any currently created system menu objects.
+  // We need to call this otherwise there's a small chance that we aren't going
+  // to get a system menu. We also can't take the return value of this
+  // function. We need to call it *again* to get a valid HMENU.
+  //::GetSystemMenu(GetNativeView(), TRUE);
+  UINT flags = TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD;
+  if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
+    flags |= TPM_RIGHTALIGN;
+  HMENU system_menu = ::GetSystemMenu(GetNativeView(), FALSE);
+  int id = ::TrackPopupMenu(system_menu, flags,
+                            point.x(), point.y(), 0, GetNativeView(), NULL);
+  ExecuteSystemMenuCommand(id);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WindowWin, WidgetWin overrides:
+
+void WindowWin::OnActivate(UINT action, BOOL minimized, HWND window) {
+  if (action == WA_INACTIVE)
+    SaveWindowPosition();
+}
+
+void WindowWin::OnActivateApp(BOOL active, DWORD thread_id) {
+  if (!active && thread_id != GetCurrentThreadId()) {
+    // Another application was activated, we should reset any state that
+    // disables inactive rendering now.
+    disable_inactive_rendering_ = false;
+    non_client_view_->DisableInactiveRendering(false);
+    // Update the native frame too, since it could be rendering the non-client
+    // area.
+    CallDefaultNCActivateHandler(FALSE);
+  }
+}
+
+LRESULT WindowWin::OnAppCommand(HWND window, short app_command, WORD device,
+                                int keystate) {
+  // We treat APPCOMMAND ids as an extension of our command namespace, and just
+  // let the delegate figure out what to do...
+  if (!window_delegate_->ExecuteWindowsCommand(app_command))
+    return WidgetWin::OnAppCommand(window, app_command, device, keystate);
+  return 0;
+}
+
+void WindowWin::OnCommand(UINT notification_code, int command_id, HWND window) {
+  // If the notification code is > 1 it means it is control specific and we
+  // should ignore it.
+  if (notification_code > 1 ||
+      window_delegate_->ExecuteWindowsCommand(command_id)) {
+    WidgetWin::OnCommand(notification_code, command_id, window);
+  }
+}
+
+void WindowWin::OnDestroy() {
+  non_client_view_->WindowClosing();
+  RestoreEnabledIfNecessary();
+  WidgetWin::OnDestroy();
+}
+
+namespace {
+static BOOL CALLBACK SendDwmCompositionChanged(HWND window, LPARAM param) {
+  SendMessage(window, WM_DWMCOMPOSITIONCHANGED, 0, 0);
+  return TRUE;
+}
+}  // namespace
+
+LRESULT WindowWin::OnDwmCompositionChanged(UINT msg, WPARAM w_param,
+                                           LPARAM l_param) {
+  // The window may try to paint in SetUseNativeFrame, and as a result it can
+  // get into a state where it is very unhappy with itself - rendering black
+  // behind the entire client area. This is because for some reason the
+  // SkPorterDuff::kClear_mode erase done in the RootView thinks the window is
+  // still opaque. So, to work around this we hide the window as soon as we can
+  // (now), saving off its placement so it can be properly restored once
+  // everything has settled down.
+  WINDOWPLACEMENT saved_window_placement;
+  saved_window_placement.length = sizeof(WINDOWPLACEMENT);
+  GetWindowPlacement(GetNativeView(), &saved_window_placement);
+  Hide();
+
+  // Important step: restore the window first, since our hiding hack doesn't
+  // work for maximized windows! We tell the frame not to allow itself to be
+  // made visible though, which removes the brief flicker.
+  ++force_hidden_count_;
+  ::ShowWindow(GetNativeView(), SW_RESTORE);
+  --force_hidden_count_;
+
+  // We respond to this in response to WM_DWMCOMPOSITIONCHANGED since that is
+  // the only thing we care about - we don't actually respond to WM_THEMECHANGED
+  // messages.
+  non_client_view_->SetUseNativeFrame(win_util::ShouldUseVistaFrame());
+
+  // Now that we've updated the frame, we'll want to restore our saved placement
+  // since the display should have settled down and we can be properly rendered.
+  SetWindowPlacement(GetNativeView(), &saved_window_placement);
+
+  // WM_DWMCOMPOSITIONCHANGED is only sent to top level windows, however we want
+  // to notify our children too, since we can have MDI child windows who need to
+  // update their appearance.
+  EnumChildWindows(GetNativeView(), &SendDwmCompositionChanged, NULL);
+  return 0;
+}
+
+void WindowWin::OnFinalMessage(HWND window) {
+  // Delete and NULL the delegate here once we're guaranteed to get no more
+  // messages.
+  window_delegate_->DeleteDelegate();
+  window_delegate_ = NULL;
+  WidgetWin::OnFinalMessage(window);
+}
+
+void WindowWin::OnGetMinMaxInfo(MINMAXINFO* minmax_info) {
+  gfx::Size min_window_size(GetNonClientView()->GetMinimumSize());
+  minmax_info->ptMinTrackSize.x = min_window_size.width();
+  minmax_info->ptMinTrackSize.y = min_window_size.height();
+  WidgetWin::OnGetMinMaxInfo(minmax_info);
+}
+
+namespace {
+static void EnableMenuItem(HMENU menu, UINT command, bool enabled) {
+  UINT flags = MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
+  EnableMenuItem(menu, command, flags);
+}
+}  // namespace
+
+void WindowWin::OnInitMenu(HMENU menu) {
+  // We only need to manually enable the system menu if we're not using a native
+  // frame.
+  if (non_client_view_->UseNativeFrame())
+    WidgetWin::OnInitMenu(menu);
+
+  bool is_fullscreen = IsFullscreen();
+  bool is_minimized = IsMinimized();
+  bool is_maximized = IsMaximized();
+  bool is_restored = !is_fullscreen && !is_minimized && !is_maximized;
+
+  ScopedRedrawLock lock(this);
+  EnableMenuItem(menu, SC_RESTORE, is_minimized || is_maximized);
+  EnableMenuItem(menu, SC_MOVE, is_restored);
+  EnableMenuItem(menu, SC_SIZE, window_delegate_->CanResize() && is_restored);
+  EnableMenuItem(menu, SC_MAXIMIZE,
+      window_delegate_->CanMaximize() && !is_fullscreen && !is_maximized);
+  EnableMenuItem(menu, SC_MINIMIZE,
+      window_delegate_->CanMaximize() && !is_minimized);
+}
+
+void WindowWin::OnMouseLeave() {
+  // We only need to manually track WM_MOUSELEAVE messages between the client
+  // and non-client area when we're not using the native frame.
+  if (non_client_view_->UseNativeFrame()) {
+    SetMsgHandled(FALSE);
+    return;
+  }
+
+  bool process_mouse_exited = true;
+  POINT pt;
+  if (GetCursorPos(&pt)) {
+    LRESULT ht_component =
+        ::SendMessage(GetNativeView(), WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y));
+    if (ht_component != HTNOWHERE) {
+      // If the mouse moved into a part of the window's non-client area, then
+      // don't send a mouse exited event since the mouse is still within the
+      // bounds of the ChromeView that's rendering the frame. Note that we do
+      // _NOT_ do this for windows with native frames, since in that case the
+      // mouse really will have left the bounds of the RootView.
+      process_mouse_exited = false;
+    }
+  }
+
+  if (process_mouse_exited)
+    ProcessMouseExited();
+}
+
+LRESULT WindowWin::OnNCActivate(BOOL active) {
+  is_active_ = !!active;
+
+  // If we're not using the native frame, we need to force a synchronous repaint
+  // otherwise we'll be left in the wrong activation state until something else
+  // causes a repaint later.
+  if (!non_client_view_->UseNativeFrame()) {
+    // We can get WM_NCACTIVATE before we're actually visible. If we're not
+    // visible, no need to paint.
+    if (IsWindowVisible(GetNativeView())) {
+      non_client_view_->SchedulePaint();
+      // We need to force a paint now, as a user dragging a window will block
+      // painting operations while the move is in progress.
+      PaintNow(root_view_->GetScheduledPaintRect());
+    }
+  }
+
+  // If we're active again, we should be allowed to render as inactive, so
+  // tell the non-client view. This must be done independently of the check for
+  // disable_inactive_rendering_ since that check is valid even if the frame
+  // is not active, but this can only be done if we've become active.
+  if (IsActive())
+    non_client_view_->DisableInactiveRendering(false);
+
+  // Reset the disable inactive rendering state since activation has changed.
+  if (disable_inactive_rendering_) {
+    disable_inactive_rendering_ = false;
+    return CallDefaultNCActivateHandler(TRUE);
+  }
+  return CallDefaultNCActivateHandler(active);
+}
+
+LRESULT WindowWin::OnNCCalcSize(BOOL mode, LPARAM l_param) {
+  // We only need to adjust the client size/paint handling when we're not using
+  // the native frame.
+  if (non_client_view_->UseNativeFrame())
+    return WidgetWin::OnNCCalcSize(mode, l_param);
+
+  RECT* client_rect = mode ?
+      &reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param)->rgrc[0] :
+      reinterpret_cast<RECT*>(l_param);
+  if (IsMaximized()) {
+    // Make the maximized mode client rect fit the screen exactly, by
+    // subtracting the border Windows automatically adds for maximized mode.
+    int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
+    InflateRect(client_rect, -border_thickness, -border_thickness);
+
+    // Find all auto-hide taskbars along the screen edges and adjust in by the
+    // thickness of the auto-hide taskbar on each such edge, so the window isn't
+    // treated as a "fullscreen app", which would cause the taskbars to
+    // disappear.
+    HMONITOR monitor = MonitorFromWindow(GetNativeView(),
+                                         MONITOR_DEFAULTTONULL);
+    if (win_util::EdgeHasTopmostAutoHideTaskbar(ABE_LEFT, monitor))
+      client_rect->left += win_util::kAutoHideTaskbarThicknessPx;
+    if (win_util::EdgeHasTopmostAutoHideTaskbar(ABE_TOP, monitor))
+      client_rect->top += win_util::kAutoHideTaskbarThicknessPx;
+    if (win_util::EdgeHasTopmostAutoHideTaskbar(ABE_RIGHT, monitor))
+      client_rect->right -= win_util::kAutoHideTaskbarThicknessPx;
+    if (win_util::EdgeHasTopmostAutoHideTaskbar(ABE_BOTTOM, monitor))
+      client_rect->bottom -= win_util::kAutoHideTaskbarThicknessPx;
+
+    // We cannot return WVR_REDRAW when there is nonclient area, or Windows
+    // exhibits bugs where client pixels and child HWNDs are mispositioned by
+    // the width/height of the upper-left nonclient area.
+    return 0;
+  }
+
+  // If the window bounds change, we're going to relayout and repaint anyway.
+  // Returning WVR_REDRAW avoids an extra paint before that of the old client
+  // pixels in the (now wrong) location, and thus makes actions like resizing a
+  // window from the left edge look slightly less broken.
+  return mode ? WVR_REDRAW : 0;
+}
+
+LRESULT WindowWin::OnNCHitTest(const CPoint& point) {
+  // First, give the NonClientView a chance to test the point to see if it
+  // provides any of the non-client area.
+  CPoint temp = point;
+  MapWindowPoints(HWND_DESKTOP, GetNativeView(), &temp, 1);
+  int component = non_client_view_->NonClientHitTest(gfx::Point(temp));
+  if (component != HTNOWHERE)
+    return component;
+
+  // Otherwise, we let Windows do all the native frame non-client handling for
+  // us.
+  return WidgetWin::OnNCHitTest(point);
+}
+
+namespace {
+struct ClipState {
+  // The window being painted.
+  HWND parent;
+
+  // DC painting to.
+  HDC dc;
+
+  // Origin of the window in terms of the screen.
+  int x;
+  int y;
+};
+
+// See comments in OnNCPaint for details of this function.
+static BOOL CALLBACK ClipDCToChild(HWND window, LPARAM param) {
+  ClipState* clip_state = reinterpret_cast<ClipState*>(param);
+  if (GetParent(window) == clip_state->parent && IsWindowVisible(window)) {
+    RECT bounds;
+    GetWindowRect(window, &bounds);
+    ExcludeClipRect(clip_state->dc,
+                    bounds.left - clip_state->x,
+                    bounds.top - clip_state->y,
+                    bounds.right - clip_state->x,
+                    bounds.bottom - clip_state->y);
+  }
+  return TRUE;
+}
+}  // namespace
+
+void WindowWin::OnNCPaint(HRGN rgn) {
+  // We only do non-client painting if we're not using the native frame.
+  if (non_client_view_->UseNativeFrame()) {
+    WidgetWin::OnNCPaint(rgn);
+    return;
+  }
+
+  // We have an NC region and need to paint it. We expand the NC region to
+  // include the dirty region of the root view. This is done to minimize
+  // paints.
+  CRect window_rect;
+  GetWindowRect(&window_rect);
+
+  if (window_rect.Width() != root_view_->width() ||
+      window_rect.Height() != root_view_->height()) {
+    // If the size of the window differs from the size of the root view it
+    // means we're being asked to paint before we've gotten a WM_SIZE. This can
+    // happen when the user is interactively resizing the window. To avoid
+    // mass flickering we don't do anything here. Once we get the WM_SIZE we'll
+    // reset the region of the window which triggers another WM_NCPAINT and
+    // all is well.
+    return;
+  }
+
+  CRect dirty_region;
+  // A value of 1 indicates paint all.
+  if (!rgn || rgn == reinterpret_cast<HRGN>(1)) {
+    dirty_region = CRect(0, 0, window_rect.Width(), window_rect.Height());
+  } else {
+    RECT rgn_bounding_box;
+    GetRgnBox(rgn, &rgn_bounding_box);
+    if (!IntersectRect(&dirty_region, &rgn_bounding_box, &window_rect))
+      return;  // Dirty region doesn't intersect window bounds, bale.
+
+    // rgn_bounding_box is in screen coordinates. Map it to window coordinates.
+    OffsetRect(&dirty_region, -window_rect.left, -window_rect.top);
+  }
+
+  // In theory GetDCEx should do what we want, but I couldn't get it to work.
+  // In particular the docs mentiond DCX_CLIPCHILDREN, but as far as I can tell
+  // it doesn't work at all. So, instead we get the DC for the window then
+  // manually clip out the children.
+  HDC dc = GetWindowDC(GetNativeView());
+  ClipState clip_state;
+  clip_state.x = window_rect.left;
+  clip_state.y = window_rect.top;
+  clip_state.parent = GetNativeView();
+  clip_state.dc = dc;
+  EnumChildWindows(GetNativeView(), &ClipDCToChild,
+                   reinterpret_cast<LPARAM>(&clip_state));
+
+  RootView* root_view = GetRootView();
+  gfx::Rect old_paint_region =
+      root_view->GetScheduledPaintRectConstrainedToSize();
+
+  if (!old_paint_region.IsEmpty()) {
+    // The root view has a region that needs to be painted. Include it in the
+    // region we're going to paint.
+
+    CRect old_paint_region_crect = old_paint_region.ToRECT();
+    CRect tmp = dirty_region;
+    UnionRect(&dirty_region, &tmp, &old_paint_region_crect);
+  }
+
+  root_view->SchedulePaint(gfx::Rect(dirty_region), false);
+
+  // ChromeCanvasPaints destructor does the actual painting. As such, wrap the
+  // following in a block to force paint to occur so that we can release the dc.
+  {
+    ChromeCanvasPaint canvas(dc, opaque(), dirty_region.left, dirty_region.top,
+                             dirty_region.Width(), dirty_region.Height());
+
+    root_view->ProcessPaint(&canvas);
+  }
+
+  ReleaseDC(GetNativeView(), dc);
+}
+
+void WindowWin::OnNCLButtonDown(UINT ht_component, const CPoint& point) {
+  // When we're using a native frame, window controls work without us
+  // interfering.
+  if (!non_client_view_->UseNativeFrame()) {
+    switch (ht_component) {
+      case HTCLOSE:
+      case HTMINBUTTON:
+      case HTMAXBUTTON: {
+        // When the mouse is pressed down in these specific non-client areas,
+        // we need to tell the RootView to send the mouse pressed event (which
+        // sets capture, allowing subsequent WM_LBUTTONUP (note, _not_
+        // WM_NCLBUTTONUP) to fire so that the appropriate WM_SYSCOMMAND can be
+        // sent by the applicable button's ButtonListener. We _have_ to do this
+        // way rather than letting Windows just send the syscommand itself (as
+        // would happen if we never did this dance) because for some insane
+        // reason DefWindowProc for WM_NCLBUTTONDOWN also renders the pressed
+        // window control button appearance, in the Windows classic style, over
+        // our view! Ick! By handling this message we prevent Windows from
+        // doing this undesirable thing, but that means we need to roll the
+        // sys-command handling ourselves.
+        ProcessNCMousePress(point, MK_LBUTTON);
+        return;
+      }
+    }
+  }
+
+  // TODO(beng): figure out why we need to run the system menu manually
+  //             ourselves. This is wrong and causes many subtle bugs.
+  //             From my initial research, it looks like DefWindowProc tries
+  //             to run it but fails before sending the initial WM_MENUSELECT
+  //             for the sysmenu.
+  if (ht_component == HTSYSMENU)
+    RunSystemMenu(non_client_view_->GetSystemMenuPoint());
+  else
+    WidgetWin::OnNCLButtonDown(ht_component, point);
+
+  /* TODO(beng): Fix the standard non-client over-painting bug. This code
+                 doesn't work but identifies the problem.
+  if (!IsMsgHandled()) {
+    // WindowWin::OnNCLButtonDown set the message as unhandled. This normally
+    // means WidgetWin::ProcessWindowMessage will pass it to
+    // DefWindowProc. Sadly, DefWindowProc for WM_NCLBUTTONDOWN does weird
+    // non-client painting, so we need to call it directly here inside a
+    // scoped update lock.
+    ScopedRedrawLock lock(this);
+    DefWindowProc(GetNativeView(), WM_NCLBUTTONDOWN, ht_component,
+                  MAKELPARAM(point.x, point.y));
+    SetMsgHandled(TRUE);
+  }
+  */
+}
+
+void WindowWin::OnNCRButtonDown(UINT ht_component, const CPoint& point) {
+  if (ht_component == HTCAPTION || ht_component == HTSYSMENU)
+    RunSystemMenu(gfx::Point(point));
+  else
+    WidgetWin::OnNCRButtonDown(ht_component, point);
+}
+
+LRESULT WindowWin::OnNCUAHDrawCaption(UINT msg, WPARAM w_param,
+                                      LPARAM l_param) {
+  // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for
+  // an explanation about why we need to handle this message.
+  SetMsgHandled(!non_client_view_->UseNativeFrame());
+  return 0;
+}
+
+LRESULT WindowWin::OnNCUAHDrawFrame(UINT msg, WPARAM w_param,
+                                    LPARAM l_param) {
+  // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for
+  // an explanation about why we need to handle this message.
+  SetMsgHandled(!non_client_view_->UseNativeFrame());
+  return 0;
+}
+
+LRESULT WindowWin::OnSetCursor(HWND window, UINT hittest_code, UINT message) {
+  // If the window is disabled, it's because we're showing a modal dialog box.
+  // We need to let DefWindowProc handle the message. That's because
+  // DefWindowProc for WM_SETCURSOR with message = some kind of mouse button
+  // down message sends the top level window a WM_ACTIVATEAPP message, which we
+  // otherwise wouldn't get. The symptom of not doing this is that if the user
+  // has a window in the background with a modal dialog open, they can't click
+  // on the disabled background window to bring the entire stack to the front.
+  // This is annoying because they then have to move all the foreground windows
+  // out of the way to be able to activate said window. I love how on Windows,
+  // the answer isn't always logical.
+  if (!IsWindowEnabled(GetNativeView()))
+    return WidgetWin::OnSetCursor(window, hittest_code, message);
+
+  int index = RC_NORMAL;
+  switch (hittest_code) {
+    case HTTOP:
+    case HTBOTTOM:
+      index = RC_VERTICAL;
+      break;
+    case HTTOPLEFT:
+    case HTBOTTOMRIGHT:
+      index = RC_NWSE;
+      break;
+    case HTTOPRIGHT:
+    case HTBOTTOMLEFT:
+      index = RC_NESW;
+      break;
+    case HTLEFT:
+    case HTRIGHT:
+      index = RC_HORIZONTAL;
+      break;
+    case HTCAPTION:
+    case HTCLIENT:
+      index = RC_NORMAL;
+      break;
+  }
+  SetCursor(resize_cursors_[index]);
+  return 0;
+}
+
+LRESULT WindowWin::OnSetIcon(UINT size_type, HICON new_icon) {
+  // This shouldn't hurt even if we're using the native frame.
+  ScopedRedrawLock lock(this);
+  return DefWindowProc(GetNativeView(), WM_SETICON, size_type,
+                       reinterpret_cast<LPARAM>(new_icon));
+}
+
+LRESULT WindowWin::OnSetText(const wchar_t* text) {
+  // This shouldn't hurt even if we're using the native frame.
+  ScopedRedrawLock lock(this);
+  return DefWindowProc(GetNativeView(), WM_SETTEXT, NULL,
+                       reinterpret_cast<LPARAM>(text));
+}
+
+void WindowWin::OnSettingChange(UINT flags, const wchar_t* section) {
+  if (!GetParent() && (flags == SPI_SETWORKAREA)) {
+    // Fire a dummy SetWindowPos() call, so we'll trip the code in
+    // OnWindowPosChanging() below that notices work area changes.
+    ::SetWindowPos(GetNativeView(), 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
+        SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+    SetMsgHandled(TRUE);
+  } else {
+    WidgetWin::OnSettingChange(flags, section);
+  }
+}
+
+void WindowWin::OnSize(UINT size_param, const CSize& new_size) {
+  // Don't no-op if the new_size matches current size. If our normal bounds
+  // and maximized bounds are the same, then we need to layout (because we
+  // layout differently when maximized).
+  SaveWindowPosition();
+  ChangeSize(size_param, new_size);
+  RedrawWindow(GetNativeView(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
+
+  // ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've
+  // invoked OnSize we ensure the RootView has been laid out.
+  ResetWindowRegion(false);
+}
+
+void WindowWin::OnSysCommand(UINT notification_code, CPoint click) {
+  // Windows uses the 4 lower order bits of |notification_code| for type-
+  // specific information so we must exclude this when comparing.
+  static const int sc_mask = 0xFFF0;
+  // Ignore size/move/maximize in fullscreen mode.
+  if (IsFullscreen() &&
+      (((notification_code & sc_mask) == SC_SIZE) ||
+       ((notification_code & sc_mask) == SC_MOVE) ||
+       ((notification_code & sc_mask) == SC_MAXIMIZE)))
+    return;
+  if (!non_client_view_->UseNativeFrame()) {
+    if ((notification_code & sc_mask) == SC_MINIMIZE ||
+        (notification_code & sc_mask) == SC_MAXIMIZE ||
+        (notification_code & sc_mask) == SC_RESTORE) {
+      non_client_view_->ResetWindowControls();
+    } else if ((notification_code & sc_mask) == SC_MOVE ||
+               (notification_code & sc_mask) == SC_SIZE) {
+      if (lock_updates_) {
+        // We were locked, before entering a resize or move modal loop. Now that
+        // we've begun to move the window, we need to unlock updates so that the
+        // sizing/moving feedback can be continuous.
+        UnlockUpdates();
+      }
+    }
+  }
+
+  // First see if the delegate can handle it.
+  if (window_delegate_->ExecuteWindowsCommand(notification_code))
+    return;
+
+  if (notification_code == IDC_ALWAYS_ON_TOP) {
+    is_always_on_top_ = !is_always_on_top_;
+
+    // Change the menu check state.
+    HMENU system_menu = GetSystemMenu(GetNativeView(), FALSE);
+    MENUITEMINFO menu_info;
+    memset(&menu_info, 0, sizeof(MENUITEMINFO));
+    menu_info.cbSize = sizeof(MENUITEMINFO);
+    BOOL r = GetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP,
+                             FALSE, &menu_info);
+    DCHECK(r);
+    menu_info.fMask = MIIM_STATE;
+    if (is_always_on_top_)
+      menu_info.fState = MFS_CHECKED;
+    r = SetMenuItemInfo(system_menu, IDC_ALWAYS_ON_TOP, FALSE, &menu_info);
+
+    // Now change the actual window's behavior.
+    AlwaysOnTopChanged();
+  } else if ((notification_code == SC_KEYMENU) && (click.x == VK_SPACE)) {
+    // Run the system menu at the NonClientView's desired location.
+    RunSystemMenu(non_client_view_->GetSystemMenuPoint());
+  } else {
+    // Use the default implementation for any other command.
+    DefWindowProc(GetNativeView(), WM_SYSCOMMAND, notification_code,
+                  MAKELPARAM(click.y, click.x));
+  }
+}
+
+void WindowWin::OnWindowPosChanging(WINDOWPOS* window_pos) {
+  if (force_hidden_count_) {
+    // Prevent the window from being made visible if we've been asked to do so.
+    // See comment in header as to why we might want this.
+    window_pos->flags &= ~SWP_SHOWWINDOW;
+  }
+
+  if (ignore_window_pos_changes_) {
+    // If somebody's trying to toggle our visibility, change the nonclient area,
+    // change our Z-order, or activate us, we should probably let it go through.
+    if (!(window_pos->flags & ((IsVisible() ? SWP_HIDEWINDOW : SWP_SHOWWINDOW) |
+        SWP_FRAMECHANGED)) &&
+        (window_pos->flags & (SWP_NOZORDER | SWP_NOACTIVATE))) {
+      // Just sizing/moving the window; ignore.
+      window_pos->flags |= SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW;
+      window_pos->flags &= ~(SWP_SHOWWINDOW | SWP_HIDEWINDOW);
+    }
+  } else if (!GetParent()) {
+    CRect window_rect;
+    HMONITOR monitor;
+    gfx::Rect monitor_rect, work_area;
+    if (GetWindowRect(&window_rect) &&
+        GetMonitorAndRects(window_rect, &monitor, &monitor_rect, &work_area)) {
+      if (monitor && (monitor == last_monitor_) &&
+          (IsFullscreen() || ((monitor_rect == last_monitor_rect_) &&
+                              (work_area != last_work_area_)))) {
+        // A rect for the monitor we're on changed.  Normally Windows notifies
+        // us about this (and thus we're reaching here due to the SetWindowPos()
+        // call in OnSettingChange() above), but with some software (e.g.
+        // nVidia's nView desktop manager) the work area can change asynchronous
+        // to any notification, and we're just sent a SetWindowPos() call with a
+        // new (frequently incorrect) position/size.  In either case, the best
+        // response is to throw away the existing position/size information in
+        // |window_pos| and recalculate it based on the new work rect.
+        gfx::Rect new_window_rect;
+        if (IsFullscreen()) {
+          new_window_rect = monitor_rect;
+        } else if (IsZoomed()) {
+          new_window_rect = work_area;
+          int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
+          new_window_rect.Inset(-border_thickness, -border_thickness);
+        } else {
+          new_window_rect = gfx::Rect(window_rect).AdjustToFit(work_area);
+        }
+        window_pos->x = new_window_rect.x();
+        window_pos->y = new_window_rect.y();
+        window_pos->cx = new_window_rect.width();
+        window_pos->cy = new_window_rect.height();
+        // WARNING!  Don't set SWP_FRAMECHANGED here, it breaks moving the child
+        // HWNDs for some reason.
+        window_pos->flags &= ~(SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW);
+        window_pos->flags |= SWP_NOCOPYBITS;
+
+        // Now ignore all immediately-following SetWindowPos() changes.  Windows
+        // likes to (incorrectly) recalculate what our position/size should be
+        // and send us further updates.
+        ignore_window_pos_changes_ = true;
+        DCHECK(ignore_pos_changes_factory_.empty());
+        MessageLoop::current()->PostTask(FROM_HERE,
+            ignore_pos_changes_factory_.NewRunnableMethod(
+            &WindowWin::StopIgnoringPosChanges));
+      }
+      last_monitor_ = monitor;
+      last_monitor_rect_ = monitor_rect;
+      last_work_area_ = work_area;
+    }
+  }
+
+  WidgetWin::OnWindowPosChanging(window_pos);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// WindowWin, private:
+
+void WindowWin::BecomeModal() {
+  // We implement modality by crawling up the hierarchy of windows starting
+  // at the owner, disabling all of them so that they don't receive input
+  // messages.
+  DCHECK(owning_hwnd_) << "Can't create a modal dialog without an owner";
+  HWND start = owning_hwnd_;
+  while (start != NULL) {
+    ::EnableWindow(start, FALSE);
+    start = ::GetParent(start);
+  }
+}
+
+void WindowWin::SetInitialFocus() {
+  if (!focus_on_creation_)
+    return;
+
+  View* v = window_delegate_->GetInitiallyFocusedView();
+  if (v) {
+    v->RequestFocus();
+  } else {
+    // The window does not get keyboard messages unless we focus it, not sure
+    // why.
+    SetFocus(GetNativeView());
+  }
+}
+
+void WindowWin::SetInitialBounds(const gfx::Rect& create_bounds) {
+  // First we obtain the window's saved show-style and store it. We need to do
+  // this here, rather than in Show() because by the time Show() is called,
+  // the window's size will have been reset (below) and the saved maximized
+  // state will have been lost. Sadly there's no way to tell on Windows when
+  // a window is restored from maximized state, so we can't more accurately
+  // track maximized state independently of sizing information.
+  window_delegate_->GetSavedMaximizedState(&saved_maximized_state_);
+
+  // Restore the window's placement from the controller.
+  gfx::Rect saved_bounds(create_bounds.ToRECT());
+  if (window_delegate_->GetSavedWindowBounds(&saved_bounds)) {
+    // Make sure the bounds are at least the minimum size.
+    if (saved_bounds.width() < minimum_size_.cx) {
+      saved_bounds.SetRect(saved_bounds.x(), saved_bounds.y(),
+                           saved_bounds.right() + minimum_size_.cx -
+                              saved_bounds.width(),
+                           saved_bounds.bottom());
+    }
+
+    if (saved_bounds.height() < minimum_size_.cy) {
+      saved_bounds.SetRect(saved_bounds.x(), saved_bounds.y(),
+                           saved_bounds.right(),
+                           saved_bounds.bottom() + minimum_size_.cy -
+                              saved_bounds.height());
+    }
+
+    // "Show state" (maximized, minimized, etc) is handled by Show().
+    // Don't use SetBounds here. SetBounds constrains to the size of the
+    // monitor, but we don't want that when creating a new window as the result
+    // of dragging out a tab to create a new window.
+    SetWindowPos(NULL, saved_bounds.x(), saved_bounds.y(),
+                 saved_bounds.width(), saved_bounds.height(), 0);
+  } else {
+    if (create_bounds.IsEmpty()) {
+      // No initial bounds supplied, so size the window to its content and
+      // center over its parent.
+      SizeWindowToDefault();
+    } else {
+      // Use the supplied initial bounds.
+      SetBounds(create_bounds);
+    }
+  }
+}
+
+void WindowWin::InitAlwaysOnTopState() {
+  is_always_on_top_ = false;
+  if (window_delegate_->GetSavedAlwaysOnTopState(&is_always_on_top_) &&
+      is_always_on_top_ != window_delegate_->IsAlwaysOnTop()) {
+    AlwaysOnTopChanged();
+  }
+
+  if (window_delegate_->HasAlwaysOnTopMenu())
+    AddAlwaysOnTopSystemMenuItem();
+}
+
+void WindowWin::AddAlwaysOnTopSystemMenuItem() {
+  // The Win32 API requires that we own the text.
+  always_on_top_menu_text_ = l10n_util::GetString(IDS_ALWAYS_ON_TOP);
+
+  // Let's insert a menu to the window.
+  HMENU system_menu = ::GetSystemMenu(GetNativeView(), FALSE);
+  int index = ::GetMenuItemCount(system_menu) - 1;
+  if (index < 0) {
+    // Paranoia check.
+    NOTREACHED();
+    index = 0;
+  }
+  // First we add the separator.
+  MENUITEMINFO menu_info;
+  memset(&menu_info, 0, sizeof(MENUITEMINFO));
+  menu_info.cbSize = sizeof(MENUITEMINFO);
+  menu_info.fMask = MIIM_FTYPE;
+  menu_info.fType = MFT_SEPARATOR;
+  ::InsertMenuItem(system_menu, index, TRUE, &menu_info);
+
+  // Then the actual menu.
+  menu_info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_STATE;
+  menu_info.fType = MFT_STRING;
+  menu_info.fState = MFS_ENABLED;
+  if (is_always_on_top_)
+    menu_info.fState |= MFS_CHECKED;
+  menu_info.wID = IDC_ALWAYS_ON_TOP;
+  menu_info.dwTypeData = const_cast<wchar_t*>(always_on_top_menu_text_.c_str());
+  ::InsertMenuItem(system_menu, index, TRUE, &menu_info);
+}
+
+void WindowWin::RestoreEnabledIfNecessary() {
+  if (is_modal_ && !restored_enabled_) {
+    restored_enabled_ = true;
+    // If we were run modally, we need to undo the disabled-ness we inflicted on
+    // the owner's parent hierarchy.
+    HWND start = owning_hwnd_;
+    while (start != NULL) {
+      ::EnableWindow(start, TRUE);
+      start = ::GetParent(start);
+    }
+  }
+}
+
+void WindowWin::AlwaysOnTopChanged() {
+  ::SetWindowPos(GetNativeView(),
+    is_always_on_top_ ? HWND_TOPMOST : HWND_NOTOPMOST,
+    0, 0, 0, 0,
+    SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
+}
+
+DWORD WindowWin::CalculateWindowStyle() {
+  DWORD window_styles =
+      WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_SYSMENU | WS_CAPTION;
+  bool can_resize = window_delegate_->CanResize();
+  bool can_maximize = window_delegate_->CanMaximize();
+  if (can_maximize) {
+    window_styles |= WS_OVERLAPPEDWINDOW;
+  } else if (can_resize) {
+    window_styles |= WS_OVERLAPPED | WS_THICKFRAME;
+  }
+  if (window_delegate_->AsDialogDelegate()) {
+    window_styles |= DS_MODALFRAME;
+    // NOTE: Turning this off means we lose the close button, which is bad.
+    // Turning it on though means the user can maximize or size the window
+    // from the system menu, which is worse. We may need to provide our own
+    // menu to get the close button to appear properly.
+    // window_styles &= ~WS_SYSMENU;
+  }
+  return window_styles;
+}
+
+DWORD WindowWin::CalculateWindowExStyle() {
+  DWORD window_ex_styles = 0;
+  if (window_delegate_->AsDialogDelegate())
+    window_ex_styles |= WS_EX_DLGMODALFRAME;
+  if (window_delegate_->IsAlwaysOnTop())
+    window_ex_styles |= WS_EX_TOPMOST;
+  return window_ex_styles;
+}
+
+void WindowWin::SaveWindowPosition() {
+  // The window delegate does the actual saving for us. It seems like (judging
+  // by go/crash) that in some circumstances we can end up here after
+  // WM_DESTROY, at which point the window delegate is likely gone. So just
+  // bail.
+  if (!window_delegate_)
+    return;
+
+  WINDOWPLACEMENT win_placement = { 0 };
+  win_placement.length = sizeof(WINDOWPLACEMENT);
+
+  BOOL r = GetWindowPlacement(GetNativeView(), &win_placement);
+  DCHECK(r);
+
+  bool maximized = (win_placement.showCmd == SW_SHOWMAXIMIZED);
+  CRect window_bounds(win_placement.rcNormalPosition);
+  window_delegate_->SaveWindowPlacement(
+      gfx::Rect(win_placement.rcNormalPosition), maximized, is_always_on_top_);
+}
+
+void WindowWin::LockUpdates() {
+  lock_updates_ = true;
+  saved_window_style_ = GetWindowLong(GWL_STYLE);
+  SetWindowLong(GWL_STYLE, saved_window_style_ & ~WS_VISIBLE);
+}
+
+void WindowWin::UnlockUpdates() {
+  SetWindowLong(GWL_STYLE, saved_window_style_);
+  lock_updates_ = false;
+}
+
+void WindowWin::ResetWindowRegion(bool force) {
+  // A native frame uses the native window region, and we don't want to mess
+  // with it.
+  if (non_client_view_->UseNativeFrame()) {
+    if (force)
+      SetWindowRgn(NULL, TRUE);
+    return;
+  }
+
+  // Changing the window region is going to force a paint. Only change the
+  // window region if the region really differs.
+  HRGN current_rgn = CreateRectRgn(0, 0, 0, 0);
+  int current_rgn_result = GetWindowRgn(GetNativeView(), current_rgn);
+
+  CRect window_rect;
+  GetWindowRect(&window_rect);
+  HRGN new_region;
+  gfx::Path window_mask;
+  non_client_view_->GetWindowMask(
+      gfx::Size(window_rect.Width(), window_rect.Height()), &window_mask);
+  new_region = window_mask.CreateHRGN();
+
+  if (current_rgn_result == ERROR || !EqualRgn(current_rgn, new_region)) {
+    // SetWindowRgn takes ownership of the HRGN created by CreateHRGN.
+    SetWindowRgn(new_region, TRUE);
+  } else {
+    DeleteObject(new_region);
+  }
+
+  DeleteObject(current_rgn);
+}
+
+void WindowWin::ProcessNCMousePress(const CPoint& point, int flags) {
+  CPoint temp = point;
+  MapWindowPoints(HWND_DESKTOP, GetNativeView(), &temp, 1);
+  UINT message_flags = 0;
+  if ((GetKeyState(VK_CONTROL) & 0x80) == 0x80)
+    message_flags |= MK_CONTROL;
+  if ((GetKeyState(VK_SHIFT) & 0x80) == 0x80)
+    message_flags |= MK_SHIFT;
+  message_flags |= flags;
+  ProcessMousePressed(temp, message_flags, false, false);
+}
+
+LRESULT WindowWin::CallDefaultNCActivateHandler(BOOL active) {
+  // The DefWindowProc handling for WM_NCACTIVATE renders the classic-look
+  // window title bar directly, so we need to use a redraw lock here to prevent
+  // it from doing so.
+  ScopedRedrawLock lock(this);
+  return DefWindowProc(GetNativeView(), WM_NCACTIVATE, active, 0);
+}
+
+void WindowWin::InitClass() {
+  static bool initialized = false;
+  if (!initialized) {
+    resize_cursors_[RC_NORMAL] = LoadCursor(NULL, IDC_ARROW);
+    resize_cursors_[RC_VERTICAL] = LoadCursor(NULL, IDC_SIZENS);
+    resize_cursors_[RC_HORIZONTAL] = LoadCursor(NULL, IDC_SIZEWE);
+    resize_cursors_[RC_NESW] = LoadCursor(NULL, IDC_SIZENESW);
+    resize_cursors_[RC_NWSE] = LoadCursor(NULL, IDC_SIZENWSE);
+    initialized = true;
+  }
+}
+
+namespace {
+// static
+static BOOL CALLBACK WindowCallbackProc(HWND hwnd, LPARAM lParam) {
+  WidgetWin* widget = reinterpret_cast<WidgetWin*>(
+      win_util::GetWindowUserData(hwnd));
+  if (!widget)
+    return TRUE;
+
+  // If the toplevel HWND is a Window, close it if it's identified as a
+  // secondary window.
+  Window* window = widget->GetWindow();
+  if (window) {
+    if (!window->IsAppWindow())
+      window->Close();
+  } else {
+    // If it's not a Window, then close it anyway since it probably is
+    // secondary.
+    widget->Close();
+  }
+  return TRUE;
+}
+}  // namespace
+
+void Window::CloseAllSecondaryWindows() {
+  EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, 0);
+}
+
+}  // namespace views
diff --git a/views/window/window_win.h b/views/window/window_win.h
new file mode 100644
index 0000000..76d5196
--- /dev/null
+++ b/views/window/window_win.h
@@ -0,0 +1,307 @@
+// Copyright (c) 2006-2008 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 VIEWS_WINDOW_WINDOW_WIN_H_
+#define VIEWS_WINDOW_WINDOW_WIN_H_
+
+#include "views/widget/widget_win.h"
+#include "views/window/client_view.h"
+#include "views/window/non_client_view.h"
+#include "views/window/window.h"
+
+namespace gfx {
+class Point;
+class Size;
+};
+
+namespace views {
+
+class Client;
+class WindowDelegate;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// WindowWin
+//
+//  A WindowWin is a WidgetWin that has a caption and a border. The frame is
+//  rendered by the operating system.
+//
+///////////////////////////////////////////////////////////////////////////////
+class WindowWin : public WidgetWin,
+                  public Window {
+ public:
+  virtual ~WindowWin();
+
+  // Show the window with the specified show command.
+  void Show(int show_state);
+
+  // Retrieve the show state of the window. This is one of the SW_SHOW* flags
+  // passed into Windows' ShowWindow method. For normal windows this defaults
+  // to SW_SHOWNORMAL, however windows (e.g. the main window) can override this
+  // method to provide different values (e.g. retrieve the user's specified
+  // show state from the shortcut starutp info).
+  virtual int GetShowState() const;
+
+  // Executes the specified SC_command.
+  void ExecuteSystemMenuCommand(int command);
+
+  // Hides the window if it hasn't already been force-hidden, then increments
+  // |force_hidden_count_| to prevent it from being shown again until
+  // PopForceHidden()) is called.
+  void PushForceHidden();
+
+  // Decrements |force_hidden_count_| and, if it is now zero, shows the window.
+  void PopForceHidden();
+
+  // Accessors and setters for various properties.
+  HWND owning_window() const { return owning_hwnd_; }
+  void set_focus_on_creation(bool focus_on_creation) {
+    focus_on_creation_ = focus_on_creation;
+  }
+
+  // Window overrides:
+  virtual gfx::Rect GetBounds() const;
+  virtual gfx::Rect GetNormalBounds() const;
+  virtual void SetBounds(const gfx::Rect& bounds);
+  virtual void SetBounds(const gfx::Rect& bounds,
+                         gfx::NativeWindow other_window);
+  virtual void Show();
+  virtual void Activate();
+  virtual void Close();
+  virtual void Maximize();
+  virtual void Minimize();
+  virtual void Restore();
+  virtual bool IsActive() const;
+  virtual bool IsVisible() const;
+  virtual bool IsMaximized() const;
+  virtual bool IsMinimized() const;
+  virtual void SetFullscreen(bool fullscreen);
+  virtual bool IsFullscreen() const;
+  virtual void EnableClose(bool enable);
+  virtual void DisableInactiveRendering();
+  virtual void UpdateWindowTitle();
+  virtual void UpdateWindowIcon();
+  virtual NonClientFrameView* CreateFrameViewForWindow();
+  virtual void UpdateFrameAfterFrameChange();
+  virtual WindowDelegate* GetDelegate() const;
+  virtual NonClientView* GetNonClientView() const;
+  virtual ClientView* GetClientView() const;
+  virtual gfx::NativeWindow GetNativeWindow() const;
+
+ protected:
+  friend Window;
+
+  // Constructs the WindowWin. |window_delegate| cannot be NULL.
+  explicit WindowWin(WindowDelegate* window_delegate);
+
+  // Create the Window.
+  // If parent is NULL, this WindowWin is top level on the desktop.
+  // If |bounds| is empty, the view is queried for its preferred size and
+  // centered on screen.
+  virtual void Init(HWND parent, const gfx::Rect& bounds);
+
+  // Sizes the window to the default size specified by its ClientView.
+  virtual void SizeWindowToDefault();
+
+  // Shows the system menu at the specified screen point.
+  void RunSystemMenu(const gfx::Point& point);
+
+  // Overridden from WidgetWin:
+  virtual void OnActivate(UINT action, BOOL minimized, HWND window);
+  virtual void OnActivateApp(BOOL active, DWORD thread_id);
+  virtual LRESULT OnAppCommand(HWND window, short app_command, WORD device,
+                               int keystate);
+  virtual void OnCommand(UINT notification_code, int command_id, HWND window);
+  virtual void OnDestroy();
+  virtual LRESULT OnDwmCompositionChanged(UINT msg, WPARAM w_param,
+                                          LPARAM l_param);
+  virtual void OnFinalMessage(HWND window);
+  virtual void OnGetMinMaxInfo(MINMAXINFO* minmax_info);
+  virtual void OnInitMenu(HMENU menu);
+  virtual void OnMouseLeave();
+  virtual LRESULT OnNCActivate(BOOL active);
+  virtual LRESULT OnNCCalcSize(BOOL mode, LPARAM l_param);
+  virtual LRESULT OnNCHitTest(const CPoint& point);
+  virtual void OnNCPaint(HRGN rgn);
+  virtual void OnNCLButtonDown(UINT ht_component, const CPoint& point);
+  virtual void OnNCRButtonDown(UINT ht_component, const CPoint& point);
+  virtual LRESULT OnNCUAHDrawCaption(UINT msg, WPARAM w_param, LPARAM l_param);
+  virtual LRESULT OnNCUAHDrawFrame(UINT msg, WPARAM w_param, LPARAM l_param);
+  virtual LRESULT OnSetCursor(HWND window, UINT hittest_code, UINT message);
+  virtual LRESULT OnSetIcon(UINT size_type, HICON new_icon);
+  virtual LRESULT OnSetText(const wchar_t* text);
+  virtual void OnSettingChange(UINT flags, const wchar_t* section);
+  virtual void OnSize(UINT size_param, const CSize& new_size);
+  virtual void OnSysCommand(UINT notification_code, CPoint click);
+  virtual void OnWindowPosChanging(WINDOWPOS* window_pos);
+  virtual Window* GetWindow() { return this; }
+  virtual const Window* GetWindow() const { return this; }
+
+  // Accessor for disable_inactive_rendering_.
+  bool disable_inactive_rendering() const {
+    return disable_inactive_rendering_;
+  }
+
+ private:
+  // Information saved before going into fullscreen mode, used to restore the
+  // window afterwards.
+  struct SavedWindowInfo {
+    bool maximized;
+    LONG style;
+    LONG ex_style;
+    RECT window_rect;
+  };
+
+  // Set the window as modal (by disabling all the other windows).
+  void BecomeModal();
+
+  // Sets-up the focus manager with the view that should have focus when the
+  // window is shown the first time.  If NULL is returned, the focus goes to the
+  // button if there is one, otherwise the to the Cancel button.
+  void SetInitialFocus();
+
+  // Place and size the window when it is created. |create_bounds| are the
+  // bounds used when the window was created.
+  void SetInitialBounds(const gfx::Rect& create_bounds);
+
+  // Restore saved always on stop state and add the always on top system menu
+  // if needed.
+  void InitAlwaysOnTopState();
+
+  // Add an item for "Always on Top" to the System Menu.
+  void AddAlwaysOnTopSystemMenuItem();
+
+  // If necessary, enables all ancestors.
+  void RestoreEnabledIfNecessary();
+
+  // Update the window style to reflect the always on top state.
+  void AlwaysOnTopChanged();
+
+  // Calculate the appropriate window styles for this window.
+  DWORD CalculateWindowStyle();
+  DWORD CalculateWindowExStyle();
+
+  // Asks the delegate if any to save the window's location and size.
+  void SaveWindowPosition();
+
+  // Lock or unlock the window from being able to redraw itself in response to
+  // updates to its invalid region.
+  class ScopedRedrawLock;
+  void LockUpdates();
+  void UnlockUpdates();
+
+  // Stops ignoring SetWindowPos() requests (see below).
+  void StopIgnoringPosChanges() { ignore_window_pos_changes_ = false; }
+
+  // Resets the window region for the current window bounds if necessary.
+  // If |force| is true, the window region is reset to NULL even for native
+  // frame windows.
+  void ResetWindowRegion(bool force);
+
+  // Converts a non-client mouse down message to a regular ChromeViews event
+  // and handle it. |point| is the mouse position of the message in screen
+  // coords. |flags| are flags that would be passed with a WM_L/M/RBUTTON*
+  // message and relate to things like which button was pressed. These are
+  // combined with flags relating to the current key state.
+  void ProcessNCMousePress(const CPoint& point, int flags);
+
+  // Calls the default WM_NCACTIVATE handler with the specified activation
+  // value, safely wrapping the call in a ScopedRedrawLock to prevent frame
+  // flicker.
+  LRESULT CallDefaultNCActivateHandler(BOOL active);
+
+  // Static resource initialization.
+  static void InitClass();
+  enum ResizeCursor {
+    RC_NORMAL = 0, RC_VERTICAL, RC_HORIZONTAL, RC_NESW, RC_NWSE
+  };
+  static HCURSOR resize_cursors_[6];
+
+  // Our window delegate (see Init method for documentation).
+  WindowDelegate* window_delegate_;
+
+  // The View that provides the non-client area of the window (title bar,
+  // window controls, sizing borders etc). To use an implementation other than
+  // the default, this class must be subclassed and this value set to the
+  // desired implementation before calling |Init|.
+  NonClientView* non_client_view_;
+
+  // Whether we should SetFocus() on a newly created window after
+  // Init(). Defaults to true.
+  bool focus_on_creation_;
+
+  // We need to save the parent window that spawned us, since GetParent()
+  // returns NULL for dialogs.
+  HWND owning_hwnd_;
+
+  // The smallest size the window can be.
+  CSize minimum_size_;
+
+  // Whether or not the window is modal. This comes from the delegate and is
+  // cached at Init time to avoid calling back to the delegate from the
+  // destructor.
+  bool is_modal_;
+
+  // Whether all ancestors have been enabled. This is only used if is_modal_ is
+  // true.
+  bool restored_enabled_;
+
+  // Whether the window is currently always on top.
+  bool is_always_on_top_;
+
+  // We need to own the text of the menu, the Windows API does not copy it.
+  std::wstring always_on_top_menu_text_;
+
+  // True if we're in fullscreen mode.
+  bool fullscreen_;
+
+  // Saved window information from before entering fullscreen mode.
+  SavedWindowInfo saved_window_info_;
+
+  // Set to true if the window is in the process of closing .
+  bool window_closed_;
+
+  // True when the window should be rendered as active, regardless of whether
+  // or not it actually is.
+  bool disable_inactive_rendering_;
+
+  // True if this window is the active top level window.
+  bool is_active_;
+
+  // True if updates to this window are currently locked.
+  bool lock_updates_;
+
+  // The window styles of the window before updates were locked.
+  DWORD saved_window_style_;
+
+  // The saved maximized state for this window. See note in SetInitialBounds
+  // that explains why we save this.
+  bool saved_maximized_state_;
+
+  // When true, this flag makes us discard incoming SetWindowPos() requests that
+  // only change our position/size.  (We still allow changes to Z-order,
+  // activation, etc.)
+  bool ignore_window_pos_changes_;
+
+  // The following factory is used to ignore SetWindowPos() calls for short time
+  // periods.
+  ScopedRunnableMethodFactory<WindowWin> ignore_pos_changes_factory_;
+
+  // If this is greater than zero, we should prevent attempts to make the window
+  // visible when we handle WM_WINDOWPOSCHANGING. Some calls like
+  // ShowWindow(SW_RESTORE) make the window visible in addition to restoring it,
+  // when all we want to do is restore it.
+  int force_hidden_count_;
+
+  // The last-seen monitor containing us, and its rect and work area.  These are
+  // used to catch updates to the rect and work area and react accordingly.
+  HMONITOR last_monitor_;
+  gfx::Rect last_monitor_rect_, last_work_area_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowWin);
+};
+
+}  // namespace views
+
+#endif  // VIEWS_WINDOW_WINDOW_WIN_H_