]> git.sesse.net Git - casparcg/blobdiff - dependencies64/cef/windows/tests/cefclient/browser/root_window_win.cc
Upgrade CEF to 3.3029.1611.g44e39a8 / Chromium 58.0.3029.81.
[casparcg] / dependencies64 / cef / windows / tests / cefclient / browser / root_window_win.cc
diff --git a/dependencies64/cef/windows/tests/cefclient/browser/root_window_win.cc b/dependencies64/cef/windows/tests/cefclient/browser/root_window_win.cc
new file mode 100644 (file)
index 0000000..c743c65
--- /dev/null
@@ -0,0 +1,992 @@
+// Copyright (c) 2015 The Chromium Embedded Framework 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 "tests/cefclient/browser/root_window_win.h"
+
+#include "include/base/cef_bind.h"
+#include "include/base/cef_build.h"
+#include "include/cef_app.h"
+#include "tests/cefclient/browser/browser_window_osr_win.h"
+#include "tests/cefclient/browser/browser_window_std_win.h"
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/resource.h"
+#include "tests/cefclient/browser/temp_window.h"
+#include "tests/cefclient/browser/window_test_runner_win.h"
+#include "tests/shared/browser/geometry_util.h"
+#include "tests/shared/browser/main_message_loop.h"
+#include "tests/shared/browser/util_win.h"
+#include "tests/shared/common/client_switches.h"
+
+#define MAX_URL_LENGTH  255
+#define BUTTON_WIDTH    72
+#define URLBAR_HEIGHT   24
+
+namespace client {
+
+namespace {
+
+// Message handler for the About box.
+INT_PTR CALLBACK AboutWndProc(HWND hDlg, UINT message,
+                              WPARAM wParam, LPARAM lParam) {
+  UNREFERENCED_PARAMETER(lParam);
+  switch (message) {
+    case WM_INITDIALOG:
+      return TRUE;
+
+    case WM_COMMAND:
+      if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
+        EndDialog(hDlg, LOWORD(wParam));
+        return TRUE;
+      }
+      break;
+  }
+  return FALSE;
+}
+
+int GetButtonWidth() {
+  static int button_width = BUTTON_WIDTH;
+  static bool initialized = false;
+
+  if (!initialized) {
+    button_width = LogicalToDevice(BUTTON_WIDTH, GetDeviceScaleFactor());
+    initialized = true;
+  }
+
+  return button_width;
+}
+
+int GetURLBarHeight() {
+  static int urlbar_height = URLBAR_HEIGHT;
+  static bool initialized = false;
+
+  if (!initialized) {
+    urlbar_height = LogicalToDevice(URLBAR_HEIGHT, GetDeviceScaleFactor());
+    initialized = true;
+  }
+
+  return urlbar_height;
+}
+
+}  // namespace
+
+RootWindowWin::RootWindowWin()
+    : delegate_(NULL),
+      with_controls_(false),
+      with_osr_(false),
+      is_popup_(false),
+      start_rect_(),
+      initialized_(false),
+      hwnd_(NULL),
+      draggable_region_(NULL),
+      font_(NULL),
+      back_hwnd_(NULL),
+      forward_hwnd_(NULL),
+      reload_hwnd_(NULL),
+      stop_hwnd_(NULL),
+      edit_hwnd_(NULL),
+      edit_wndproc_old_(NULL),
+      find_hwnd_(NULL),
+      find_message_id_(0),
+      find_wndproc_old_(NULL),
+      find_state_(),
+      find_next_(false),
+      find_match_case_last_(false),
+      window_destroyed_(false),
+      browser_destroyed_(false) {
+  find_buff_[0] = 0;
+
+  // Create a HRGN representing the draggable window area.
+  draggable_region_ = ::CreateRectRgn(0, 0, 0, 0);
+}
+
+RootWindowWin::~RootWindowWin() {
+  REQUIRE_MAIN_THREAD();
+
+  ::DeleteObject(draggable_region_);
+  ::DeleteObject(font_);
+
+  // The window and browser should already have been destroyed.
+  DCHECK(window_destroyed_);
+  DCHECK(browser_destroyed_);
+}
+
+void RootWindowWin::Init(RootWindow::Delegate* delegate,
+                         bool with_controls,
+                         bool with_osr,
+                         const CefRect& bounds,
+                         const CefBrowserSettings& settings,
+                         const std::string& url) {
+  DCHECK(delegate);
+  DCHECK(!initialized_);
+
+  delegate_ = delegate;
+  with_controls_ = with_controls;
+  with_osr_ = with_osr;
+
+  start_rect_.left = bounds.x;
+  start_rect_.top = bounds.y;
+  start_rect_.right = bounds.x + bounds.width;
+  start_rect_.bottom = bounds.y + bounds.height;
+
+  CreateBrowserWindow(url);
+
+  initialized_ = true;
+
+  // Create the native root window on the main thread.
+  if (CURRENTLY_ON_MAIN_THREAD()) {
+    CreateRootWindow(settings);
+  } else {
+    MAIN_POST_CLOSURE(
+        base::Bind(&RootWindowWin::CreateRootWindow, this, settings));
+  }
+}
+
+void RootWindowWin::InitAsPopup(RootWindow::Delegate* delegate,
+                                bool with_controls,
+                                bool with_osr,
+                                const CefPopupFeatures& popupFeatures,
+                                CefWindowInfo& windowInfo,
+                                CefRefPtr<CefClient>& client,
+                                CefBrowserSettings& settings) {
+  DCHECK(delegate);
+  DCHECK(!initialized_);
+
+  delegate_ = delegate;
+  with_controls_ = with_controls;
+  with_osr_ = with_osr;
+  is_popup_ = true;
+
+  if (popupFeatures.xSet)
+    start_rect_.left = popupFeatures.x;
+  if (popupFeatures.ySet)
+    start_rect_.top = popupFeatures.y;
+  if (popupFeatures.widthSet)
+    start_rect_.right = start_rect_.left + popupFeatures.width;
+  if (popupFeatures.heightSet)
+    start_rect_.bottom = start_rect_.top + popupFeatures.height;
+
+  CreateBrowserWindow(std::string());
+
+  initialized_ = true;
+
+  // The new popup is initially parented to a temporary window. The native root
+  // window will be created after the browser is created and the popup window
+  // will be re-parented to it at that time.
+  browser_window_->GetPopupConfig(TempWindow::GetWindowHandle(),
+                                  windowInfo, client, settings);
+}
+
+void RootWindowWin::Show(ShowMode mode) {
+  REQUIRE_MAIN_THREAD();
+
+  if (!hwnd_)
+    return;
+
+  int nCmdShow = SW_SHOWNORMAL;
+  switch (mode) {
+    case ShowMinimized:
+      nCmdShow = SW_SHOWMINIMIZED;
+      break;
+    case ShowMaximized:
+      nCmdShow = SW_SHOWMAXIMIZED;
+      break;
+    default:
+      break;
+  }
+
+  ShowWindow(hwnd_, nCmdShow);
+  UpdateWindow(hwnd_);
+}
+
+void RootWindowWin::Hide() {
+  REQUIRE_MAIN_THREAD();
+
+  if (hwnd_)
+    ShowWindow(hwnd_, SW_HIDE);
+}
+
+void RootWindowWin::SetBounds(int x, int y, size_t width, size_t height) {
+  REQUIRE_MAIN_THREAD();
+
+  if (hwnd_) {
+    SetWindowPos(hwnd_, NULL,
+                 x, y, static_cast<int>(width), static_cast<int>(height),
+                 SWP_NOZORDER);
+  }
+}
+
+void RootWindowWin::Close(bool force) {
+  REQUIRE_MAIN_THREAD();
+
+  if (hwnd_) {
+    if (force)
+      DestroyWindow(hwnd_);
+    else
+      PostMessage(hwnd_, WM_CLOSE, 0, 0);
+  }
+}
+
+void RootWindowWin::SetDeviceScaleFactor(float device_scale_factor) {
+  REQUIRE_MAIN_THREAD();
+
+  if (browser_window_)
+    browser_window_->SetDeviceScaleFactor(device_scale_factor);
+}
+
+float RootWindowWin::GetDeviceScaleFactor() const {
+  REQUIRE_MAIN_THREAD();
+
+  if (browser_window_)
+    return browser_window_->GetDeviceScaleFactor();
+  return client::GetDeviceScaleFactor();
+}
+
+CefRefPtr<CefBrowser> RootWindowWin::GetBrowser() const {
+  REQUIRE_MAIN_THREAD();
+
+  if (browser_window_)
+    return browser_window_->GetBrowser();
+  return NULL;
+}
+
+ClientWindowHandle RootWindowWin::GetWindowHandle() const {
+  REQUIRE_MAIN_THREAD();
+  return hwnd_;
+}
+
+void RootWindowWin::CreateBrowserWindow(const std::string& startup_url) {
+  if (with_osr_) {
+    OsrRenderer::Settings settings;
+    MainContext::Get()->PopulateOsrSettings(&settings);
+    browser_window_.reset(new BrowserWindowOsrWin(this, startup_url, settings));
+  } else {
+    browser_window_.reset(new BrowserWindowStdWin(this, startup_url));
+  }
+}
+
+void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings) {
+  REQUIRE_MAIN_THREAD();
+  DCHECK(!hwnd_);
+
+  HINSTANCE hInstance = GetModuleHandle(NULL);
+
+  // Load strings from the resource file.
+  const std::wstring& window_title = GetResourceString(IDS_APP_TITLE);
+  const std::wstring& window_class = GetResourceString(IDC_CEFCLIENT);
+
+  const cef_color_t background_color = MainContext::Get()->GetBackgroundColor();
+  const HBRUSH background_brush = CreateSolidBrush(
+      RGB(CefColorGetR(background_color),
+          CefColorGetG(background_color),
+          CefColorGetB(background_color)));
+
+  // Register the window class.
+  RegisterRootClass(hInstance, window_class, background_brush);
+
+  // Register the message used with the find dialog.
+  find_message_id_ = RegisterWindowMessage(FINDMSGSTRING);
+  CHECK(find_message_id_);
+
+  const DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
+
+  int x, y, width, height;
+  if (::IsRectEmpty(&start_rect_)) {
+    // Use the default window position/size.
+    x = y = width = height = CW_USEDEFAULT;
+  } else {
+    // Adjust the window size to account for window frame and controls.
+    RECT window_rect = start_rect_;
+    ::AdjustWindowRectEx(&window_rect, dwStyle, with_controls_, 0);
+    if (with_controls_)
+      window_rect.bottom += GetURLBarHeight();
+
+    x = start_rect_.left;
+    y = start_rect_.top;
+    width = window_rect.right - window_rect.left;
+    height = window_rect.bottom - window_rect.top;
+  }
+
+  // Create the main window initially hidden.
+  hwnd_ = CreateWindow(window_class.c_str(), window_title.c_str(),
+                       dwStyle,
+                       x, y, width, height,
+                       NULL, NULL, hInstance, NULL);
+  CHECK(hwnd_);
+
+  // Associate |this| with the main window.
+  SetUserDataPtr(hwnd_, this);
+
+  RECT rect;
+  GetClientRect(hwnd_, &rect);
+
+  if (with_controls_) {
+    // Create the child controls.
+    int x_offset = 0;
+
+    const int button_width = GetButtonWidth();
+    const int urlbar_height = GetURLBarHeight();
+    const int font_height =
+        LogicalToDevice(14, client::GetDeviceScaleFactor());
+
+    // Create a scaled font.
+    font_ = ::CreateFont(
+        -font_height, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE,
+        DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+        DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial");
+
+    back_hwnd_ = CreateWindow(
+        L"BUTTON", L"Back",
+        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
+        x_offset, 0, button_width, urlbar_height,
+        hwnd_, reinterpret_cast<HMENU>(IDC_NAV_BACK), hInstance, 0);
+    CHECK(back_hwnd_);
+    SendMessage(back_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_), TRUE);
+    x_offset += button_width;
+
+    forward_hwnd_ = CreateWindow(
+        L"BUTTON", L"Forward",
+        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
+        x_offset, 0, button_width, urlbar_height,
+        hwnd_, reinterpret_cast<HMENU>(IDC_NAV_FORWARD), hInstance, 0);
+    CHECK(forward_hwnd_);
+    SendMessage(forward_hwnd_, WM_SETFONT,
+                reinterpret_cast<WPARAM>(font_), TRUE);
+    x_offset += button_width;
+
+    reload_hwnd_ = CreateWindow(
+        L"BUTTON", L"Reload",
+        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON| WS_DISABLED,
+        x_offset, 0, button_width, urlbar_height,
+        hwnd_, reinterpret_cast<HMENU>(IDC_NAV_RELOAD), hInstance, 0);
+    CHECK(reload_hwnd_);
+    SendMessage(reload_hwnd_, WM_SETFONT,
+                reinterpret_cast<WPARAM>(font_), TRUE);
+    x_offset += button_width;
+
+    stop_hwnd_ = CreateWindow(
+        L"BUTTON", L"Stop",
+        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
+        x_offset, 0, button_width, urlbar_height,
+        hwnd_, reinterpret_cast<HMENU>(IDC_NAV_STOP), hInstance, 0);
+    CHECK(stop_hwnd_);
+    SendMessage(stop_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_), TRUE);
+    x_offset += button_width;
+
+    edit_hwnd_ = CreateWindow(
+        L"EDIT", 0,
+        WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL |
+        ES_AUTOHSCROLL| WS_DISABLED,
+        x_offset, 0, rect.right - button_width * 4, urlbar_height,
+        hwnd_, 0, hInstance, 0);
+    SendMessage(edit_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_), TRUE);
+    CHECK(edit_hwnd_);
+
+    // Override the edit control's window procedure.
+    edit_wndproc_old_ = SetWndProcPtr(edit_hwnd_, EditWndProc);
+
+    // Associate |this| with the edit window.
+    SetUserDataPtr(edit_hwnd_, this);
+
+    rect.top += urlbar_height;
+
+    if (!with_osr_) {
+      // Remove the menu items that are only used with OSR.
+      HMENU hMenu = ::GetMenu(hwnd_);
+      if (hMenu) {
+        HMENU hTestMenu = ::GetSubMenu(hMenu, 2);
+        if (hTestMenu) {
+          ::RemoveMenu(hTestMenu, ID_TESTS_OSR_FPS, MF_BYCOMMAND);
+          ::RemoveMenu(hTestMenu, ID_TESTS_OSR_DSF, MF_BYCOMMAND);
+        }
+      }
+    }
+  } else {
+    // No controls so also remove the default menu.
+    ::SetMenu(hwnd_, NULL);
+  }
+
+  if (!is_popup_) {
+    // Create the browser window.
+    CefRect cef_rect(rect.left, rect.top,
+                     rect.right - rect.left,
+                     rect.bottom - rect.top);
+    browser_window_->CreateBrowser(hwnd_, cef_rect, settings,
+                                   delegate_->GetRequestContext(this));
+  } else {
+    // With popups we already have a browser window. Parent the browser window
+    // to the root window and show it in the correct location.
+    browser_window_->ShowPopup(hwnd_,
+                               rect.left, rect.top,
+                               rect.right - rect.left,
+                               rect.bottom - rect.top);
+  }
+
+  // Show this window.
+  Show(ShowNormal);
+}
+
+// static
+void RootWindowWin::RegisterRootClass(HINSTANCE hInstance,
+                                      const std::wstring& window_class,
+                                      HBRUSH background_brush) {
+  // Only register the class one time.
+  static bool class_registered = false;
+  if (class_registered)
+    return;
+  class_registered = true;
+
+  WNDCLASSEX wcex;
+
+  wcex.cbSize = sizeof(WNDCLASSEX);
+
+  wcex.style         = CS_HREDRAW | CS_VREDRAW;
+  wcex.lpfnWndProc   = RootWndProc;
+  wcex.cbClsExtra    = 0;
+  wcex.cbWndExtra    = 0;
+  wcex.hInstance     = hInstance;
+  wcex.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CEFCLIENT));
+  wcex.hCursor       = LoadCursor(NULL, IDC_ARROW);
+  wcex.hbrBackground = background_brush;
+  wcex.lpszMenuName  = MAKEINTRESOURCE(IDC_CEFCLIENT);
+  wcex.lpszClassName = window_class.c_str();
+  wcex.hIconSm       = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
+
+  RegisterClassEx(&wcex);
+}
+
+// static
+LRESULT CALLBACK RootWindowWin::EditWndProc(HWND hWnd, UINT message,
+                                            WPARAM wParam, LPARAM lParam) {
+  REQUIRE_MAIN_THREAD();
+
+  RootWindowWin* self = GetUserDataPtr<RootWindowWin*>(hWnd);
+  DCHECK(self);
+  DCHECK(hWnd == self->edit_hwnd_);
+
+  switch (message) {
+    case WM_CHAR:
+      if (wParam == VK_RETURN) {
+        // When the user hits the enter key load the URL.
+        CefRefPtr<CefBrowser> browser = self->GetBrowser();
+        if (browser) {
+          wchar_t strPtr[MAX_URL_LENGTH+1] = {0};
+          *((LPWORD)strPtr) = MAX_URL_LENGTH;
+          LRESULT strLen = SendMessage(hWnd, EM_GETLINE, 0, (LPARAM)strPtr);
+          if (strLen > 0) {
+            strPtr[strLen] = 0;
+            browser->GetMainFrame()->LoadURL(strPtr);
+          }
+        }
+        return 0;
+      }
+      break;
+    case WM_NCDESTROY:
+      // Clear the reference to |self|.
+      SetUserDataPtr(hWnd, NULL);
+      self->edit_hwnd_ = NULL;
+      break;
+  }
+
+  return CallWindowProc(self->edit_wndproc_old_, hWnd, message, wParam, lParam);
+}
+
+// static
+LRESULT CALLBACK RootWindowWin::FindWndProc(HWND hWnd, UINT message,
+                                            WPARAM wParam, LPARAM lParam) {
+  REQUIRE_MAIN_THREAD();
+
+  RootWindowWin* self = GetUserDataPtr<RootWindowWin*>(hWnd);
+  DCHECK(self);
+  DCHECK(hWnd == self->find_hwnd_);
+
+  switch (message) {
+    case WM_ACTIVATE:
+      // Set this dialog as current when activated.
+      MainMessageLoop::Get()->SetCurrentModelessDialog(
+          wParam == 0 ? NULL : hWnd);
+      return FALSE;
+    case WM_NCDESTROY:
+      // Clear the reference to |self|.
+      SetUserDataPtr(hWnd, NULL);
+      self->find_hwnd_ = NULL;
+      break;
+  }
+
+  return CallWindowProc(self->find_wndproc_old_, hWnd, message, wParam, lParam);
+}
+
+// static
+LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd, UINT message,
+                                            WPARAM wParam, LPARAM lParam) {
+  REQUIRE_MAIN_THREAD();
+
+  RootWindowWin* self = GetUserDataPtr<RootWindowWin*>(hWnd);
+  if (!self)
+    return DefWindowProc(hWnd, message, wParam, lParam);
+  DCHECK(hWnd == self->hwnd_);
+
+  if (message == self->find_message_id_) {
+    // Message targeting the find dialog.
+    LPFINDREPLACE lpfr = reinterpret_cast<LPFINDREPLACE>(lParam);
+    CHECK(lpfr == &self->find_state_);
+    self->OnFindEvent();
+    return 0;
+  }
+
+  // Callback for the main window
+  switch (message) {
+    case WM_COMMAND:
+      if (self->OnCommand(LOWORD(wParam)))
+        return 0;
+      break;
+
+    case WM_PAINT:
+      self->OnPaint();
+      return 0;
+
+    case WM_SETFOCUS:
+      self->OnFocus();
+      return 0;
+
+    case WM_SIZE:
+      self->OnSize(wParam == SIZE_MINIMIZED);
+      break;
+
+    case WM_MOVING:
+    case WM_MOVE:
+      self->OnMove();
+      return 0;
+
+    case WM_ERASEBKGND:
+      if (self->OnEraseBkgnd())
+        break;
+      // Don't erase the background.
+      return 0;
+
+    case WM_ENTERMENULOOP:
+      if (!wParam) {
+        // Entering the menu loop for the application menu.
+        CefSetOSModalLoop(true);
+      }
+      break;
+
+    case WM_EXITMENULOOP:
+      if (!wParam) {
+        // Exiting the menu loop for the application menu.
+        CefSetOSModalLoop(false);
+      }
+      break;
+
+    case WM_CLOSE:
+      if (self->OnClose())
+        return 0;  // Cancel the close.
+      break;
+
+    case WM_NCHITTEST: {
+      LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
+      if (hit == HTCLIENT) {
+        POINTS points = MAKEPOINTS(lParam);
+        POINT point = { points.x, points.y };
+        ::ScreenToClient(hWnd, &point);
+        if (::PtInRegion(self->draggable_region_, point.x, point.y)) {
+          // If cursor is inside a draggable region return HTCAPTION to allow
+          // dragging.
+          return HTCAPTION;
+        }
+      }
+      return hit;
+    }
+
+    case WM_NCDESTROY:
+      // Clear the reference to |self|.
+      SetUserDataPtr(hWnd, NULL);
+      self->hwnd_ = NULL;
+      self->OnDestroyed();
+      return 0;
+  }
+
+  return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+void RootWindowWin::OnPaint() {
+  PAINTSTRUCT ps;
+  BeginPaint(hwnd_, &ps);
+  EndPaint(hwnd_, &ps);
+}
+
+void RootWindowWin::OnFocus() {
+  if (browser_window_)
+    browser_window_->SetFocus(true);
+}
+
+void RootWindowWin::OnSize(bool minimized) {
+  if (minimized) {
+    // Notify the browser window that it was hidden and do nothing further.
+    if (browser_window_)
+      browser_window_->Hide();
+    return;
+  }
+
+  if (browser_window_)
+    browser_window_->Show();
+
+  RECT rect;
+  GetClientRect(hwnd_, &rect);
+
+  if (with_controls_) {
+    static int button_width = GetButtonWidth();
+    static int urlbar_height = GetURLBarHeight();
+
+    // Resize the window and address bar to match the new frame size.
+    rect.top += urlbar_height;
+
+    int urloffset = rect.left + button_width * 4;
+
+    // |browser_hwnd| may be NULL if the browser has not yet been created.
+    HWND browser_hwnd = NULL;
+    if (browser_window_)
+      browser_hwnd = browser_window_->GetWindowHandle();
+
+    if (browser_hwnd) {
+      // Resize both the browser and the URL edit field.
+      HDWP hdwp = BeginDeferWindowPos(2);
+      hdwp = DeferWindowPos(hdwp, edit_hwnd_, NULL, urloffset,
+          0, rect.right - urloffset, urlbar_height, SWP_NOZORDER);
+      hdwp = DeferWindowPos(hdwp, browser_hwnd, NULL,
+          rect.left, rect.top, rect.right - rect.left,
+          rect.bottom - rect.top, SWP_NOZORDER);
+      BOOL result = EndDeferWindowPos(hdwp);
+      ALLOW_UNUSED_LOCAL(result);
+      DCHECK(result);
+    } else {
+      // Resize just the URL edit field.
+      SetWindowPos(edit_hwnd_, NULL, urloffset,
+          0, rect.right - urloffset, urlbar_height, SWP_NOZORDER);
+    }
+  } else if (browser_window_) {
+    // Size the browser window to the whole client area.
+    browser_window_->SetBounds(0, 0, rect.right, rect.bottom);
+  }
+}
+
+void RootWindowWin::OnMove() {
+  // Notify the browser of move events so that popup windows are displayed
+  // in the correct location and dismissed when the window moves.
+  CefRefPtr<CefBrowser> browser = GetBrowser();
+  if (browser)
+    browser->GetHost()->NotifyMoveOrResizeStarted();
+}
+
+bool RootWindowWin::OnEraseBkgnd() {
+  // Erase the background when the browser does not exist.
+  return (GetBrowser() == NULL);
+}
+
+bool RootWindowWin::OnCommand(UINT id) {
+  if (id >= ID_TESTS_FIRST && id <= ID_TESTS_LAST) {
+    delegate_->OnTest(this, id);
+    return true;
+  }
+
+  switch (id) {
+    case IDM_ABOUT:
+      OnAbout();
+      return true;
+    case IDM_EXIT:
+      delegate_->OnExit(this);
+      return true;
+    case ID_FIND:
+      OnFind();
+      return true;
+    case IDC_NAV_BACK:   // Back button
+      if (CefRefPtr<CefBrowser> browser = GetBrowser())
+        browser->GoBack();
+      return true;
+    case IDC_NAV_FORWARD:  // Forward button
+      if (CefRefPtr<CefBrowser> browser = GetBrowser())
+        browser->GoForward();
+      return true;
+    case IDC_NAV_RELOAD:  // Reload button
+      if (CefRefPtr<CefBrowser> browser = GetBrowser())
+        browser->Reload();
+      return true;
+    case IDC_NAV_STOP:  // Stop button
+      if (CefRefPtr<CefBrowser> browser = GetBrowser())
+        browser->StopLoad();
+      return true;
+  }
+
+  return false;
+}
+
+void RootWindowWin::OnFind() {
+  if (find_hwnd_) {
+    // Give focus to the existing find dialog.
+    ::SetFocus(find_hwnd_);
+    return;
+  }
+
+  // Configure dialog state.
+  ZeroMemory(&find_state_, sizeof(find_state_));
+  find_state_.lStructSize = sizeof(find_state_);
+  find_state_.hwndOwner = hwnd_;
+  find_state_.lpstrFindWhat = find_buff_;
+  find_state_.wFindWhatLen = sizeof(find_buff_);
+  find_state_.Flags = FR_HIDEWHOLEWORD | FR_DOWN;
+
+  // Create the dialog.
+  find_hwnd_ = FindText(&find_state_);
+
+  // Override the dialog's window procedure.
+  find_wndproc_old_ = SetWndProcPtr(find_hwnd_, FindWndProc);
+
+  // Associate |self| with the dialog.
+  SetUserDataPtr(find_hwnd_, this);
+}
+
+void RootWindowWin::OnFindEvent() {
+  CefRefPtr<CefBrowser> browser = GetBrowser();
+
+  if (find_state_.Flags & FR_DIALOGTERM) {
+    // The find dialog box has been dismissed so invalidate the handle and
+    // reset the search results.
+    if (browser) {
+      browser->GetHost()->StopFinding(true);
+      find_what_last_.clear();
+      find_next_ = false;
+    }
+  } else if ((find_state_.Flags & FR_FINDNEXT) && browser)  {
+    // Search for the requested string.
+    bool match_case = ((find_state_.Flags & FR_MATCHCASE) ? true : false);
+    const std::wstring& find_what = find_buff_;
+    if (match_case != find_match_case_last_ || find_what != find_what_last_) {
+      // The search string has changed, so reset the search results.
+      if (!find_what.empty()) {
+        browser->GetHost()->StopFinding(true);
+        find_next_ = false;
+      }
+      find_match_case_last_ = match_case;
+      find_what_last_ = find_buff_;
+    }
+
+    browser->GetHost()->Find(0, find_what,
+                             (find_state_.Flags & FR_DOWN) ? true : false,
+                             match_case, find_next_);
+    if (!find_next_)
+      find_next_ = true;
+  }
+}
+
+void RootWindowWin::OnAbout() {
+  // Show the about box.
+  DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd_,
+            AboutWndProc);
+}
+
+bool RootWindowWin::OnClose() {
+  if (browser_window_ && !browser_window_->IsClosing()) {
+    CefRefPtr<CefBrowser> browser = GetBrowser();
+    if (browser) {
+      // Notify the browser window that we would like to close it. This
+      // will result in a call to ClientHandler::DoClose() if the
+      // JavaScript 'onbeforeunload' event handler allows it.
+      browser->GetHost()->CloseBrowser(false);
+
+      // Cancel the close.
+      return true;
+    }
+  }
+
+  // Allow the close.
+  return false;
+}
+
+void RootWindowWin::OnDestroyed() {
+  window_destroyed_ = true;
+  NotifyDestroyedIfDone();
+}
+
+void RootWindowWin::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
+  REQUIRE_MAIN_THREAD();
+
+  if (is_popup_) {
+    // For popup browsers create the root window once the browser has been
+    // created.
+    CreateRootWindow(CefBrowserSettings());
+  } else {
+    // Make sure the browser is sized correctly.
+    OnSize(false);
+  }
+}
+
+void RootWindowWin::OnBrowserWindowDestroyed() {
+  REQUIRE_MAIN_THREAD();
+
+  browser_window_.reset();
+
+  if (!window_destroyed_) {
+    // The browser was destroyed first. This could be due to the use of
+    // off-screen rendering or execution of JavaScript window.close().
+    // Close the RootWindow.
+    Close(true);
+  }
+
+  browser_destroyed_ = true;
+  NotifyDestroyedIfDone();
+}
+
+void RootWindowWin::OnSetAddress(const std::string& url) {
+  REQUIRE_MAIN_THREAD();
+
+  if (edit_hwnd_)
+    SetWindowText(edit_hwnd_, CefString(url).ToWString().c_str());
+}
+
+void RootWindowWin::OnSetTitle(const std::string& title) {
+  REQUIRE_MAIN_THREAD();
+
+  if (hwnd_)
+    SetWindowText(hwnd_, CefString(title).ToWString().c_str());
+}
+
+void RootWindowWin::OnSetFullscreen(bool fullscreen) {
+  REQUIRE_MAIN_THREAD();
+
+  CefRefPtr<CefBrowser> browser = GetBrowser();
+  if (browser) {
+    scoped_ptr<window_test::WindowTestRunnerWin> test_runner(
+        new window_test::WindowTestRunnerWin());
+    if (fullscreen)
+      test_runner->Maximize(browser);
+    else
+      test_runner->Restore(browser);
+  }
+}
+
+void RootWindowWin::OnSetLoadingState(bool isLoading,
+                                      bool canGoBack,
+                                      bool canGoForward) {
+  REQUIRE_MAIN_THREAD();
+
+  if (with_controls_) {
+    EnableWindow(back_hwnd_, canGoBack);
+    EnableWindow(forward_hwnd_, canGoForward);
+    EnableWindow(reload_hwnd_, !isLoading);
+    EnableWindow(stop_hwnd_, isLoading);
+    EnableWindow(edit_hwnd_, TRUE);
+  }
+}
+
+namespace {
+
+LPCWSTR kParentWndProc = L"CefParentWndProc";
+LPCWSTR kDraggableRegion = L"CefDraggableRegion";
+
+LRESULT CALLBACK SubclassedWindowProc(
+    HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
+  WNDPROC hParentWndProc = reinterpret_cast<WNDPROC>(
+      ::GetPropW(hWnd, kParentWndProc));
+  HRGN hRegion = reinterpret_cast<HRGN>(
+      ::GetPropW(hWnd, kDraggableRegion));
+
+  if (message == WM_NCHITTEST) {
+    LRESULT hit = CallWindowProc(
+        hParentWndProc, hWnd, message, wParam, lParam);
+    if (hit == HTCLIENT) {
+      POINTS points = MAKEPOINTS(lParam);
+      POINT point = { points.x, points.y };
+      ::ScreenToClient(hWnd, &point);
+      if (::PtInRegion(hRegion, point.x, point.y)) {
+        // Let the parent window handle WM_NCHITTEST by returning HTTRANSPARENT
+        // in child windows.
+        return HTTRANSPARENT;
+      }
+    }
+    return hit;
+  }
+
+  return CallWindowProc(hParentWndProc, hWnd, message, wParam, lParam);
+}
+
+void SubclassWindow(HWND hWnd, HRGN hRegion) {
+  HANDLE hParentWndProc = ::GetPropW(hWnd, kParentWndProc);
+  if (hParentWndProc) {
+    return;
+  }
+
+  SetLastError(0);
+  LONG_PTR hOldWndProc = SetWindowLongPtr(
+      hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SubclassedWindowProc));
+  if (hOldWndProc == 0 && GetLastError() != ERROR_SUCCESS) {
+    return;
+  }
+
+  ::SetPropW(hWnd, kParentWndProc, reinterpret_cast<HANDLE>(hOldWndProc));
+  ::SetPropW(hWnd, kDraggableRegion, reinterpret_cast<HANDLE>(hRegion));
+}
+
+void UnSubclassWindow(HWND hWnd) {
+  LONG_PTR hParentWndProc = reinterpret_cast<LONG_PTR>(
+    ::GetPropW(hWnd, kParentWndProc));
+  if (hParentWndProc) {
+      LONG_PTR hPreviousWndProc =
+          SetWindowLongPtr(hWnd, GWLP_WNDPROC, hParentWndProc);
+      ALLOW_UNUSED_LOCAL(hPreviousWndProc);
+      DCHECK_EQ(hPreviousWndProc,
+                reinterpret_cast<LONG_PTR>(SubclassedWindowProc));
+  }
+
+  ::RemovePropW(hWnd, kParentWndProc);
+  ::RemovePropW(hWnd, kDraggableRegion);
+}
+
+BOOL CALLBACK SubclassWindowsProc(HWND hwnd, LPARAM lParam) {
+  SubclassWindow(hwnd, reinterpret_cast<HRGN>(lParam));
+  return TRUE;
+}
+
+BOOL CALLBACK UnSubclassWindowsProc(HWND hwnd, LPARAM lParam) {
+  UnSubclassWindow(hwnd);
+  return TRUE;
+}
+
+}  // namespace
+
+void RootWindowWin::OnSetDraggableRegions(
+    const std::vector<CefDraggableRegion>& regions) {
+  REQUIRE_MAIN_THREAD();
+
+  // Reset draggable region.
+  ::SetRectRgn(draggable_region_, 0, 0, 0, 0);
+
+  // Determine new draggable region.
+  std::vector<CefDraggableRegion>::const_iterator it = regions.begin();
+  for (;it != regions.end(); ++it) {
+    HRGN region = ::CreateRectRgn(
+        it->bounds.x, it->bounds.y,
+        it->bounds.x + it->bounds.width,
+        it->bounds.y + it->bounds.height);
+    ::CombineRgn(
+        draggable_region_, draggable_region_, region,
+        it->draggable ? RGN_OR : RGN_DIFF);
+    ::DeleteObject(region);
+  }
+
+  // Subclass child window procedures in order to do hit-testing.
+  // This will be a no-op, if it is already subclassed.
+  if (hwnd_) {
+    WNDENUMPROC proc = !regions.empty() ?
+        SubclassWindowsProc : UnSubclassWindowsProc;
+    ::EnumChildWindows(
+        hwnd_, proc, reinterpret_cast<LPARAM>(draggable_region_));
+  }
+}
+
+void RootWindowWin::NotifyDestroyedIfDone() {
+  // Notify once both the window and the browser have been destroyed.
+  if (window_destroyed_ && browser_destroyed_)
+    delegate_->OnRootWindowDestroyed(this);
+}
+
+}  // namespace client