add cef window test

This commit is contained in:
brige 2024-12-17 23:22:22 +08:00
parent 79f86c0931
commit e9604915d9
66 changed files with 6906 additions and 235 deletions

49
src/CEF/BindingTest.cpp Normal file
View File

@ -0,0 +1,49 @@
// Copyright (c) 2012 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 "CEF/BindingTest.h"
#include <algorithm>
#include <string>
#include "CEF/TestRunner.h"
const char kTestUrlPath[] = "/binding";
const char kTestMessageName[] = "BindingTest";
// Handle messages in the browser process.
class Handler : public CefMessageRouterBrowserSide::Handler {
public:
Handler() {}
// Called due to cefQuery execution in binding.html.
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) override {
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (!IsTestURL(url, kTestUrlPath))
return false;
const std::string& message_name = request;
if (message_name.find(kTestMessageName) == 0) {
// Reverse the string and return.
std::string result = message_name.substr(sizeof(kTestMessageName));
std::reverse(result.begin(), result.end());
callback->Success(result);
return true;
}
return false;
}
};
namespace binding_test {
void CreateMessageHandlers(MessageHandlerSet& handlers) {
handlers.insert(new Handler());
}
}

12
src/CEF/BindingTest.h Normal file
View File

@ -0,0 +1,12 @@
// Copyright (c) 2012 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.
#pragma once
#include "CEF/TestRunner.h"
namespace binding_test {
// Create message handlers. Called from test_runner.cc.
void CreateMessageHandlers(MessageHandlerSet& handlers);
}

92
src/CEF/BrowserWindow.cpp Normal file
View File

@ -0,0 +1,92 @@
// 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 "CEF/BrowserWindow.h"
#include "include/base/cef_callback.h"
#include "CEF/MainMessageLoop.h"
BrowserWindow::BrowserWindow(Delegate* delegate)
: delegate_(delegate), is_closing_(false) {
DCHECK(delegate_);
}
void BrowserWindow::SetDeviceScaleFactor(float device_scale_factor) {}
float BrowserWindow::GetDeviceScaleFactor() const {
return 1.0f;
}
CefRefPtr<CefBrowser> BrowserWindow::GetBrowser() const {
REQUIRE_MAIN_THREAD();
return browser_;
}
bool BrowserWindow::IsClosing() const {
REQUIRE_MAIN_THREAD();
return is_closing_;
}
void BrowserWindow::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
REQUIRE_MAIN_THREAD();
DCHECK(!browser_);
browser_ = browser;
delegate_->OnBrowserCreated(browser);
}
void BrowserWindow::OnBrowserClosing(CefRefPtr<CefBrowser> browser) {
REQUIRE_MAIN_THREAD();
DCHECK_EQ(browser->GetIdentifier(), browser_->GetIdentifier());
is_closing_ = true;
delegate_->OnBrowserWindowClosing();
}
void BrowserWindow::OnBrowserClosed(CefRefPtr<CefBrowser> browser) {
REQUIRE_MAIN_THREAD();
if (browser_.get()) {
DCHECK_EQ(browser->GetIdentifier(), browser_->GetIdentifier());
browser_ = nullptr;
}
client_handler_->DetachDelegate();
client_handler_ = nullptr;
// |this| may be deleted.
delegate_->OnBrowserWindowDestroyed();
}
void BrowserWindow::OnSetAddress(const std::string& url) {
REQUIRE_MAIN_THREAD();
delegate_->OnSetAddress(url);
}
void BrowserWindow::OnSetTitle(const std::string& title) {
REQUIRE_MAIN_THREAD();
delegate_->OnSetTitle(title);
}
void BrowserWindow::OnSetFullscreen(bool fullscreen) {
REQUIRE_MAIN_THREAD();
delegate_->OnSetFullscreen(fullscreen);
}
void BrowserWindow::OnAutoResize(const CefSize& new_size) {
REQUIRE_MAIN_THREAD();
delegate_->OnAutoResize(new_size);
}
void BrowserWindow::OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) {
REQUIRE_MAIN_THREAD();
delegate_->OnSetLoadingState(isLoading, canGoBack, canGoForward);
}
void BrowserWindow::OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) {
REQUIRE_MAIN_THREAD();
delegate_->OnSetDraggableRegions(regions);
}

139
src/CEF/BrowserWindow.h Normal file
View File

@ -0,0 +1,139 @@
// 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.
#pragma once
#include <memory>
#include "include/cef_browser.h"
#include "CEF/ClientHandler.h"
#include "CEF/HumanApptypes.h"
// Represents a native child window hosting a single browser instance. The
// methods of this class must be called on the main thread unless otherwise
// indicated.
class BrowserWindow : public ClientHandler::Delegate {
public:
// This interface is implemented by the owner of the BrowserWindow. The
// methods of this class will be called on the main thread.
class Delegate {
public:
// Called when the browser has been created.
virtual void OnBrowserCreated(CefRefPtr<CefBrowser> browser) = 0;
// Called when the BrowserWindow is closing.
virtual void OnBrowserWindowClosing() {}
// Called when the BrowserWindow has been destroyed.
virtual void OnBrowserWindowDestroyed() = 0;
// Set the window URL address.
virtual void OnSetAddress(const std::string& url) = 0;
// Set the window title.
virtual void OnSetTitle(const std::string& title) = 0;
// Set fullscreen mode.
virtual void OnSetFullscreen(bool fullscreen) = 0;
// Auto-resize contents.
virtual void OnAutoResize(const CefSize& new_size) = 0;
// Set the loading state.
virtual void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) = 0;
// Set the draggable regions.
virtual void OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) = 0;
protected:
virtual ~Delegate() {}
};
// Create a new browser and native window.
virtual void CreateBrowser(ClientWindowHandle parent_handle,
const CefRect& rect,
const CefBrowserSettings& settings,
CefRefPtr<CefDictionaryValue> extra_info,
CefRefPtr<CefRequestContext> request_context) = 0;
// Retrieve the configuration that will be used when creating a popup window.
// The popup browser will initially be parented to |temp_handle| which should
// be a pre-existing hidden window. The native window will be created later
// after the browser has been created. This method will be called on the
// browser process UI thread.
virtual void GetPopupConfig(CefWindowHandle temp_handle,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) = 0;
// Show the popup window with correct parent and bounds in parent coordinates.
virtual void ShowPopup(ClientWindowHandle parent_handle,
int x,
int y,
size_t width,
size_t height) = 0;
// Show the window.
virtual void Show() = 0;
// Hide the window.
virtual void Hide() = 0;
// Set the window bounds in parent coordinates.
virtual void SetBounds(int x, int y, size_t width, size_t height) = 0;
// Set focus to the window.
virtual void SetFocus(bool focus) = 0;
// Set the device scale factor. Only used in combination with off-screen
// rendering.
virtual void SetDeviceScaleFactor(float device_scale_factor);
// Returns the device scale factor. Only used in combination with off-screen
// rendering.
virtual float GetDeviceScaleFactor() const;
// Returns the window handle.
virtual ClientWindowHandle GetWindowHandle() const = 0;
// Returns the browser owned by the window.
CefRefPtr<CefBrowser> GetBrowser() const;
// Returns true if the browser is closing.
bool IsClosing() const;
protected:
// Allow deletion via std::unique_ptr only.
friend std::default_delete<BrowserWindow>;
// Constructor may be called on any thread.
// |delegate| must outlive this object.
explicit BrowserWindow(Delegate* delegate);
// ClientHandler::Delegate methods.
void OnBrowserCreated(CefRefPtr<CefBrowser> browser) override;
void OnBrowserClosing(CefRefPtr<CefBrowser> browser) override;
void OnBrowserClosed(CefRefPtr<CefBrowser> browser) override;
void OnSetAddress(const std::string& url) override;
void OnSetTitle(const std::string& title) override;
void OnSetFullscreen(bool fullscreen) override;
void OnAutoResize(const CefSize& new_size) override;
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) override;
void OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) override;
Delegate* delegate_;
CefRefPtr<CefBrowser> browser_;
CefRefPtr<ClientHandler> client_handler_;
bool is_closing_;
private:
DISALLOW_COPY_AND_ASSIGN(BrowserWindow);
};

View File

@ -0,0 +1,125 @@
// 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 "CEF/BrowserWindowOsrWin.h"
#include "CEF/MainMessageLoop.h"
BrowserWindowOsrWin::BrowserWindowOsrWin(BrowserWindow::Delegate* delegate,
bool with_controls,
const std::string& startup_url,
const OsrRendererSettings& settings)
: BrowserWindow(delegate), osr_hwnd_(nullptr), device_scale_factor_(0) {
osr_window_ = new OsrWindowWin(this, settings);
client_handler_ =
new ClientHandlerOsr(this, osr_window_.get(), with_controls, startup_url);
}
void BrowserWindowOsrWin::CreateBrowser(
ClientWindowHandle parent_handle,
const CefRect& rect,
const CefBrowserSettings& settings,
CefRefPtr<CefDictionaryValue> extra_info,
CefRefPtr<CefRequestContext> request_context) {
REQUIRE_MAIN_THREAD();
// Create the new browser and native window on the UI thread.
RECT wnd_rect = {rect.x, rect.y, rect.x + rect.width, rect.y + rect.height};
osr_window_->CreateBrowser(parent_handle, wnd_rect, client_handler_, settings,
extra_info, request_context,
client_handler_->startup_url());
}
void BrowserWindowOsrWin::GetPopupConfig(CefWindowHandle temp_handle,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) {
CEF_REQUIRE_UI_THREAD();
windowInfo.SetAsWindowless(temp_handle);
windowInfo.shared_texture_enabled =
osr_window_->settings().shared_texture_enabled;
windowInfo.external_begin_frame_enabled =
osr_window_->settings().external_begin_frame_enabled;
// Don't activate the hidden browser on creation.
windowInfo.ex_style |= WS_EX_NOACTIVATE;
client = client_handler_;
}
void BrowserWindowOsrWin::ShowPopup(ClientWindowHandle parent_handle,
int x,
int y,
size_t width,
size_t height) {
REQUIRE_MAIN_THREAD();
if (osr_window_)
osr_window_->ShowPopup(parent_handle, x, y, width, height);
}
void BrowserWindowOsrWin::Show() {
REQUIRE_MAIN_THREAD();
if (osr_window_)
osr_window_->Show();
}
void BrowserWindowOsrWin::Hide() {
REQUIRE_MAIN_THREAD();
if (osr_window_)
osr_window_->Hide();
}
void BrowserWindowOsrWin::SetBounds(int x, int y, size_t width, size_t height) {
REQUIRE_MAIN_THREAD();
if (osr_window_)
osr_window_->SetBounds(x, y, width, height);
}
void BrowserWindowOsrWin::SetFocus(bool focus) {
REQUIRE_MAIN_THREAD();
if (osr_window_ && focus)
osr_window_->SetFocus();
}
void BrowserWindowOsrWin::SetDeviceScaleFactor(float device_scale_factor) {
REQUIRE_MAIN_THREAD();
if (device_scale_factor == device_scale_factor_)
return;
// Apply some sanity checks.
if (device_scale_factor < 1.0f || device_scale_factor > 4.0f)
return;
device_scale_factor_ = device_scale_factor;
if (osr_window_)
osr_window_->SetDeviceScaleFactor(device_scale_factor);
}
float BrowserWindowOsrWin::GetDeviceScaleFactor() const {
REQUIRE_MAIN_THREAD();
DCHECK_GT(device_scale_factor_, 0);
return device_scale_factor_;
}
ClientWindowHandle BrowserWindowOsrWin::GetWindowHandle() const {
REQUIRE_MAIN_THREAD();
return osr_hwnd_;
}
void BrowserWindowOsrWin::OnBrowserClosed(CefRefPtr<CefBrowser> browser) {
REQUIRE_MAIN_THREAD();
// Release the OSR window reference. It will be deleted on the UI thread.
osr_window_ = nullptr;
BrowserWindow::OnBrowserClosed(browser);
}
void BrowserWindowOsrWin::OnOsrNativeWindowCreated(HWND hwnd) {
REQUIRE_MAIN_THREAD();
DCHECK(!osr_hwnd_);
osr_hwnd_ = hwnd;
}

View File

@ -0,0 +1,61 @@
// 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.
#pragma once
#include "CEF/BrowserWindow.h"
#include "CEF/osr_window_win.h"
// Represents a native child window hosting a single off-screen browser
// instance. The methods of this class must be called on the main thread unless
// otherwise indicated.
class BrowserWindowOsrWin : public BrowserWindow,
public OsrWindowWin::Delegate {
public:
// Constructor may be called on any thread.
// |delegate| must outlive this object.
BrowserWindowOsrWin(BrowserWindow::Delegate* delegate,
bool with_controls,
const std::string& startup_url,
const OsrRendererSettings& settings);
// BrowserWindow methods.
void CreateBrowser(ClientWindowHandle parent_handle,
const CefRect& rect,
const CefBrowserSettings& settings,
CefRefPtr<CefDictionaryValue> extra_info,
CefRefPtr<CefRequestContext> request_context) override;
void GetPopupConfig(CefWindowHandle temp_handle,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) override;
void ShowPopup(ClientWindowHandle parent_handle,
int x,
int y,
size_t width,
size_t height) override;
void Show() override;
void Hide() override;
void SetBounds(int x, int y, size_t width, size_t height) override;
void SetFocus(bool focus) override;
void SetDeviceScaleFactor(float device_scale_factor) override;
float GetDeviceScaleFactor() const override;
ClientWindowHandle GetWindowHandle() const override;
private:
// ClienHandler::Delegate methods.
void OnBrowserClosed(CefRefPtr<CefBrowser> browser) override;
// OsrWindowWin::Delegate methods.
void OnOsrNativeWindowCreated(HWND hwnd) override;
// The below members are only accessed on the main thread.
scoped_refptr<OsrWindowWin> osr_window_;
HWND osr_hwnd_;
float device_scale_factor_;
DISALLOW_COPY_AND_ASSIGN(BrowserWindowOsrWin);
};

View File

@ -0,0 +1,120 @@
// 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/browser_window_std_win.h"
#include "tests/cefclient/browser/client_handler_std.h"
#include "tests/shared/browser/main_message_loop.h"
namespace client {
BrowserWindowStdWin::BrowserWindowStdWin(Delegate* delegate,
bool with_controls,
const std::string& startup_url)
: BrowserWindow(delegate) {
client_handler_ = new ClientHandlerStd(this, with_controls, startup_url);
}
void BrowserWindowStdWin::CreateBrowser(
ClientWindowHandle parent_handle,
const CefRect& rect,
const CefBrowserSettings& settings,
CefRefPtr<CefDictionaryValue> extra_info,
CefRefPtr<CefRequestContext> request_context) {
REQUIRE_MAIN_THREAD();
CefWindowInfo window_info;
window_info.SetAsChild(parent_handle, rect);
if (GetWindowLongPtr(parent_handle, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
// Don't activate the browser window on creation.
window_info.ex_style |= WS_EX_NOACTIVATE;
}
CefBrowserHost::CreateBrowser(window_info, client_handler_,
client_handler_->startup_url(), settings,
extra_info, request_context);
}
void BrowserWindowStdWin::GetPopupConfig(CefWindowHandle temp_handle,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) {
CEF_REQUIRE_UI_THREAD();
// The window will be properly sized after the browser is created.
windowInfo.SetAsChild(temp_handle, CefRect());
// Don't activate the hidden browser window on creation.
windowInfo.ex_style |= WS_EX_NOACTIVATE;
client = client_handler_;
}
void BrowserWindowStdWin::ShowPopup(ClientWindowHandle parent_handle,
int x,
int y,
size_t width,
size_t height) {
REQUIRE_MAIN_THREAD();
HWND hwnd = GetWindowHandle();
if (hwnd) {
SetParent(hwnd, parent_handle);
SetWindowPos(hwnd, nullptr, x, y, static_cast<int>(width),
static_cast<int>(height), SWP_NOZORDER | SWP_NOACTIVATE);
const bool no_activate =
GetWindowLongPtr(parent_handle, GWL_EXSTYLE) & WS_EX_NOACTIVATE;
ShowWindow(hwnd, no_activate ? SW_SHOWNOACTIVATE : SW_SHOW);
}
}
void BrowserWindowStdWin::Show() {
REQUIRE_MAIN_THREAD();
HWND hwnd = GetWindowHandle();
if (hwnd && !::IsWindowVisible(hwnd))
ShowWindow(hwnd, SW_SHOW);
}
void BrowserWindowStdWin::Hide() {
REQUIRE_MAIN_THREAD();
HWND hwnd = GetWindowHandle();
if (hwnd) {
// When the frame window is minimized set the browser window size to 0x0 to
// reduce resource usage.
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
}
}
void BrowserWindowStdWin::SetBounds(int x, int y, size_t width, size_t height) {
REQUIRE_MAIN_THREAD();
HWND hwnd = GetWindowHandle();
if (hwnd) {
// Set the browser window bounds.
SetWindowPos(hwnd, nullptr, x, y, static_cast<int>(width),
static_cast<int>(height), SWP_NOZORDER);
}
}
void BrowserWindowStdWin::SetFocus(bool focus) {
REQUIRE_MAIN_THREAD();
if (browser_)
browser_->GetHost()->SetFocus(focus);
}
ClientWindowHandle BrowserWindowStdWin::GetWindowHandle() const {
REQUIRE_MAIN_THREAD();
if (browser_)
return browser_->GetHost()->GetWindowHandle();
return nullptr;
}
} // namespace client

View File

@ -0,0 +1,51 @@
// 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.
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_WIN_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_WIN_H_
#pragma once
#include "tests/cefclient/browser/browser_window.h"
namespace client {
// Represents a native child window hosting a single windowed browser instance.
// The methods of this class must be called on the main thread unless otherwise
// indicated.
class BrowserWindowStdWin : public BrowserWindow {
public:
// Constructor may be called on any thread.
// |delegate| must outlive this object.
BrowserWindowStdWin(Delegate* delegate,
bool with_controls,
const std::string& startup_url);
// BrowserWindow methods.
void CreateBrowser(ClientWindowHandle parent_handle,
const CefRect& rect,
const CefBrowserSettings& settings,
CefRefPtr<CefDictionaryValue> extra_info,
CefRefPtr<CefRequestContext> request_context) override;
void GetPopupConfig(CefWindowHandle temp_handle,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) override;
void ShowPopup(ClientWindowHandle parent_handle,
int x,
int y,
size_t width,
size_t height) override;
void Show() override;
void Hide() override;
void SetBounds(int x, int y, size_t width, size_t height) override;
void SetFocus(bool focus) override;
ClientWindowHandle GetWindowHandle() const override;
private:
DISALLOW_COPY_AND_ASSIGN(BrowserWindowStdWin);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_WIN_H_

View File

@ -21,7 +21,7 @@
#include "include/wrapper/cef_closure_task.h" #include "include/wrapper/cef_closure_task.h"
#include "CEF/HumanAppContext.h" #include "CEF/HumanAppContext.h"
#include "CEF/RootWindoManager.h" #include "CEF/RootWindoManager.h"
//#include "tests/cefclient/browser/test_runner.h" #include "CEF/TestRunner.h"
#include "CEF/ExtensionUtil.h" #include "CEF/ExtensionUtil.h"
#include "CEF/ResourceUtil.h" #include "CEF/ResourceUtil.h"
#include "CEF/HumanAppSwitches.h" #include "CEF/HumanAppSwitches.h"
@ -157,14 +157,14 @@ void LoadErrorPage(CefRefPtr<CefFrame> frame,
"<h3>Page failed to load.</h3>" "<h3>Page failed to load.</h3>"
"URL: <a href=\"" "URL: <a href=\""
<< failed_url << "\">" << failed_url << failed_url << "\">" << failed_url
<< "</a><br/>Error: " << test_runner::GetErrorString(error_code) << " (" << "</a><br/>Error: " << GetErrorString(error_code) << " ("
<< error_code << ")"; << error_code << ")";
if (!other_info.empty()) if (!other_info.empty())
ss << "<br/>" << other_info; ss << "<br/>" << other_info;
ss << "</body></html>"; ss << "</body></html>";
frame->LoadURL(test_runner::GetDataURI(ss.str(), "text/html")); frame->LoadURL(GetDataURI(ss.str(), "text/html"));
} }
// Return HTML string with information about a certificate. // Return HTML string with information about a certificate.
@ -220,8 +220,6 @@ std::string GetCertificateInformation(CefRefPtr<CefX509Certificate> cert,
return ss.str(); return ss.str();
} }
} // namespace
class ClientDownloadImageCallback : public CefDownloadImageCallback { class ClientDownloadImageCallback : public CefDownloadImageCallback {
public: public:
explicit ClientDownloadImageCallback(CefRefPtr<ClientHandler> client_handler) explicit ClientDownloadImageCallback(CefRefPtr<ClientHandler> client_handler)
@ -251,21 +249,21 @@ ClientHandler::ClientHandler(Delegate* delegate,
download_favicon_images_(false), download_favicon_images_(false),
delegate_(delegate), delegate_(delegate),
browser_count_(0), browser_count_(0),
console_log_file_(MainContext::Get()->GetConsoleLogPath()), console_log_file_(HumanAppContext::Get()->GetConsoleLogPath()),
first_console_message_(true), first_console_message_(true),
focus_on_editable_field_(false), focus_on_editable_field_(false),
initial_navigation_(true) { initial_navigation_(true) {
DCHECK(!console_log_file_.empty()); DCHECK(!console_log_file_.empty());
resource_manager_ = new CefResourceManager(); resource_manager_ = new CefResourceManager();
test_runner::SetupResourceManager(resource_manager_, &string_resource_map_); SetupResourceManager(resource_manager_, &string_resource_map_);
// Read command line settings. // Read command line settings.
CefRefPtr<CefCommandLine> command_line = CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine(); CefCommandLine::GetGlobalCommandLine();
mouse_cursor_change_disabled_ = mouse_cursor_change_disabled_ =
command_line->HasSwitch(switches::kMouseCursorChangeDisabled); command_line->HasSwitch(kMouseCursorChangeDisabled);
offline_ = command_line->HasSwitch(switches::kOffline); offline_ = command_line->HasSwitch(kOffline);
#if defined(OS_LINUX) #if defined(OS_LINUX)
// Optionally use the client-provided dialog implementation. // Optionally use the client-provided dialog implementation.
@ -337,7 +335,7 @@ bool ClientHandler::OnChromeCommand(CefRefPtr<CefBrowser> browser,
int command_id, int command_id,
cef_window_open_disposition_t disposition) { cef_window_open_disposition_t disposition) {
CEF_REQUIRE_UI_THREAD(); CEF_REQUIRE_UI_THREAD();
DCHECK(MainContext::Get()->UseChromeRuntime()); DCHECK(HumanAppContext::Get()->UseChromeRuntime());
if (!with_controls_ && if (!with_controls_ &&
(disposition != WOD_CURRENT_TAB || !IsAllowedCommandId(command_id))) { (disposition != WOD_CURRENT_TAB || !IsAllowedCommandId(command_id))) {
@ -358,7 +356,7 @@ void ClientHandler::OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefMenuModel> model) { CefRefPtr<CefMenuModel> model) {
CEF_REQUIRE_UI_THREAD(); CEF_REQUIRE_UI_THREAD();
const bool use_chrome_runtime = MainContext::Get()->UseChromeRuntime(); const bool use_chrome_runtime = HumanAppContext::Get()->UseChromeRuntime();
if (use_chrome_runtime && !with_controls_) { if (use_chrome_runtime && !with_controls_) {
// Remove all disallowed menu items. // Remove all disallowed menu items.
FilterMenuModel(model); FilterMenuModel(model);
@ -507,7 +505,7 @@ bool ClientHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser,
fclose(file); fclose(file);
if (first_console_message_) { if (first_console_message_) {
test_runner::Alert( Alert(
browser, "Console messages written to \"" + console_log_file_ + "\""); browser, "Console messages written to \"" + console_log_file_ + "\"");
first_console_message_ = false; first_console_message_ = false;
} }
@ -557,7 +555,7 @@ void ClientHandler::OnBeforeDownload(
CEF_REQUIRE_UI_THREAD(); CEF_REQUIRE_UI_THREAD();
// Continue the download and show the "Save As" dialog. // Continue the download and show the "Save As" dialog.
callback->Continue(MainContext::Get()->GetDownloadPath(suggested_name), true); callback->Continue(HumanAppContext::Get()->GetDownloadPath(suggested_name), true);
} }
void ClientHandler::OnDownloadUpdated( void ClientHandler::OnDownloadUpdated(
@ -567,7 +565,7 @@ void ClientHandler::OnDownloadUpdated(
CEF_REQUIRE_UI_THREAD(); CEF_REQUIRE_UI_THREAD();
if (download_item->IsComplete()) { if (download_item->IsComplete()) {
test_runner::Alert(browser, "File \"" + Alert(browser, "File \"" +
download_item->GetFullPath().ToString() + download_item->GetFullPath().ToString() +
"\" downloaded successfully."); "\" downloaded successfully.");
} }
@ -580,7 +578,7 @@ bool ClientHandler::OnDragEnter(CefRefPtr<CefBrowser> browser,
// Forbid dragging of URLs and files. // Forbid dragging of URLs and files.
if ((mask & DRAG_OPERATION_LINK) && !dragData->IsFragment()) { if ((mask & DRAG_OPERATION_LINK) && !dragData->IsFragment()) {
test_runner::Alert(browser, "cefclient blocks dragging of URLs and files"); Alert(browser, "cefclient blocks dragging of URLs and files");
return true; return true;
} }
@ -609,7 +607,7 @@ bool ClientHandler::OnSetFocus(CefRefPtr<CefBrowser> browser,
if (initial_navigation_) { if (initial_navigation_) {
CefRefPtr<CefCommandLine> command_line = CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine(); CefCommandLine::GetGlobalCommandLine();
if (command_line->HasSwitch(switches::kNoActivate)) { if (command_line->HasSwitch(kNoActivate)) {
// Don't give focus to the browser on creation. // Don't give focus to the browser on creation.
return true; return true;
} }
@ -687,9 +685,9 @@ void ClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
CefSize(1000, 1000)); CefSize(1000, 1000));
CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension(); CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
if (extension_util::IsInternalExtension(extension->GetPath())) { if (IsInternalExtension(extension->GetPath())) {
// Register the internal handler for extension resources. // Register the internal handler for extension resources.
extension_util::AddInternalExtensionToResourceManager(extension, AddInternalExtensionToResourceManager(extension,
resource_manager_); resource_manager_);
} }
} }
@ -785,7 +783,7 @@ bool ClientHandler::OnOpenURLFromTab(
config->with_controls = with_controls_; config->with_controls = with_controls_;
config->with_osr = is_osr_; config->with_osr = is_osr_;
config->url = target_url; config->url = target_url;
MainContext::Get()->GetRootWindowManager()->CreateRootWindow( HumanAppContext::Get()->GetRootWindowManager()->CreateRootWindow(
std::move(config)); std::move(config));
return true; return true;
} }
@ -883,12 +881,12 @@ bool ClientHandler::OnSelectClientCertificate(
CefRefPtr<CefCommandLine> command_line = CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine(); CefCommandLine::GetGlobalCommandLine();
if (!command_line->HasSwitch(switches::kSslClientCertificate)) { if (!command_line->HasSwitch(kSslClientCertificate)) {
return false; return false;
} }
const std::string& cert_name = const std::string& cert_name =
command_line->GetSwitchValue(switches::kSslClientCertificate); command_line->GetSwitchValue(kSslClientCertificate);
if (cert_name.empty()) { if (cert_name.empty()) {
callback->Select(nullptr); callback->Select(nullptr);
@ -977,7 +975,7 @@ CefRefPtr<CefResponseFilter> ClientHandler::GetResourceResponseFilter(
CefRefPtr<CefResponse> response) { CefRefPtr<CefResponse> response) {
CEF_REQUIRE_IO_THREAD(); CEF_REQUIRE_IO_THREAD();
return test_runner::GetResourceResponseFilter(browser, frame, request, return GetResourceResponseFilter(browser, frame, request,
response); response);
} }
@ -1012,7 +1010,7 @@ void ClientHandler::ShowDevTools(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefClient> client; CefRefPtr<CefClient> client;
CefBrowserSettings settings; CefBrowserSettings settings;
MainContext::Get()->PopulateBrowserSettings(&settings); HumanAppContext::Get()->PopulateBrowserSettings(&settings);
CefRefPtr<CefBrowserHost> host = browser->GetHost(); CefRefPtr<CefBrowserHost> host = browser->GetHost();
@ -1086,8 +1084,8 @@ void ClientHandler::ShowSSLInformation(CefRefPtr<CefBrowser> browser) {
auto config = std::make_unique<RootWindowConfig>(); auto config = std::make_unique<RootWindowConfig>();
config->with_controls = false; config->with_controls = false;
config->with_osr = is_osr_; config->with_osr = is_osr_;
config->url = test_runner::GetDataURI(ss.str(), "text/html"); config->url = GetDataURI(ss.str(), "text/html");
MainContext::Get()->GetRootWindowManager()->CreateRootWindow( HumanAppContext::Get()->GetRootWindowManager()->CreateRootWindow(
std::move(config)); std::move(config));
} }
@ -1112,7 +1110,7 @@ bool ClientHandler::CreatePopupWindow(CefRefPtr<CefBrowser> browser,
// The popup browser will be parented to a new native window. // The popup browser will be parented to a new native window.
// Don't show URL bar and navigation buttons on DevTools windows. // Don't show URL bar and navigation buttons on DevTools windows.
MainContext::Get()->GetRootWindowManager()->CreateRootWindowAsPopup( HumanAppContext::Get()->GetRootWindowManager()->CreateRootWindowAsPopup(
with_controls_ && !is_devtools, is_osr_, popupFeatures, windowInfo, with_controls_ && !is_devtools, is_osr_, popupFeatures, windowInfo,
client, settings); client, settings);

View File

@ -11,7 +11,7 @@
#include "include/wrapper/cef_message_router.h" #include "include/wrapper/cef_message_router.h"
#include "include/wrapper/cef_resource_manager.h" #include "include/wrapper/cef_resource_manager.h"
#include "CEF/HumanApptypes.h" #include "CEF/HumanApptypes.h"
//#include "tests/cefclient/browser/test_runner.h" #include "CEf/TestRunner.h"
#if defined(OS_LINUX) #if defined(OS_LINUX)
#include "tests/cefclient/browser/dialog_handler_gtk.h" #include "tests/cefclient/browser/dialog_handler_gtk.h"
@ -399,7 +399,7 @@ class ClientHandler : public CefClient,
// Used to manage string resources in combination with StringResourceProvider. // Used to manage string resources in combination with StringResourceProvider.
// Only accessed on the IO thread. // Only accessed on the IO thread.
//test_runner::StringResourceMap string_resource_map_; StringResourceMap string_resource_map_;
// MAIN THREAD MEMBERS // MAIN THREAD MEMBERS
// The following members will only be accessed on the main thread. This will // The following members will only be accessed on the main thread. This will

View File

@ -2,14 +2,12 @@
// reserved. Use of this source code is governed by a BSD-style license that // reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file. // can be found in the LICENSE file.
#include "tests/cefclient/browser/client_handler_osr.h" #include "CEF/ClientHandlerOSR.h"
#include "include/base/cef_callback.h" #include "include/base/cef_callback.h"
#include "include/wrapper/cef_closure_task.h" #include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h" #include "include/wrapper/cef_helpers.h"
namespace client {
ClientHandlerOsr::ClientHandlerOsr(Delegate* delegate, ClientHandlerOsr::ClientHandlerOsr(Delegate* delegate,
OsrDelegate* osr_delegate, OsrDelegate* osr_delegate,
bool with_controls, bool with_controls,
@ -182,5 +180,3 @@ void ClientHandlerOsr::OnAccessibilityLocationChange(
return; return;
osr_delegate_->UpdateAccessibilityLocation(value); osr_delegate_->UpdateAccessibilityLocation(value);
} }
} // namespace client

View File

@ -2,13 +2,9 @@
// reserved. Use of this source code is governed by a BSD-style license that // reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file. // can be found in the LICENSE file.
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_OSR_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_OSR_H_
#pragma once #pragma once
#include "tests/cefclient/browser/client_handler.h" #include "CEF/ClientHandler.h"
namespace client {
// Client handler implementation for windowless browsers. There will only ever // Client handler implementation for windowless browsers. There will only ever
// be one browser per handler instance. // be one browser per handler instance.
@ -146,7 +142,3 @@ class ClientHandlerOsr : public ClientHandler,
IMPLEMENT_REFCOUNTING(ClientHandlerOsr); IMPLEMENT_REFCOUNTING(ClientHandlerOsr);
DISALLOW_COPY_AND_ASSIGN(ClientHandlerOsr); DISALLOW_COPY_AND_ASSIGN(ClientHandlerOsr);
}; };
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_OSR_H_

View File

@ -2,13 +2,9 @@
// reserved. Use of this source code is governed by a BSD-style license that // reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file. // can be found in the LICENSE file.
#include "tests/cefclient/browser/client_handler_std.h" #include "CEF/ClientHandlerStd.h"
namespace client {
ClientHandlerStd::ClientHandlerStd(Delegate* delegate, ClientHandlerStd::ClientHandlerStd(Delegate* delegate,
bool with_controls, bool with_controls,
const std::string& startup_url) const std::string& startup_url)
: ClientHandler(delegate, /*is_osr=*/false, with_controls, startup_url) {} : ClientHandler(delegate, /*is_osr=*/false, with_controls, startup_url) {}
} // namespace client

View File

@ -2,13 +2,9 @@
// reserved. Use of this source code is governed by a BSD-style license that // reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file. // can be found in the LICENSE file.
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_STD_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_STD_H_
#pragma once #pragma once
#include "tests/cefclient/browser/client_handler.h" #include "CEF/ClientHandler.h"
namespace client {
// Client handler implementation for windowed browsers. There will only ever be // Client handler implementation for windowed browsers. There will only ever be
// one browser per handler instance. // one browser per handler instance.
@ -23,7 +19,3 @@ class ClientHandlerStd : public ClientHandler {
IMPLEMENT_REFCOUNTING(ClientHandlerStd); IMPLEMENT_REFCOUNTING(ClientHandlerStd);
DISALLOW_COPY_AND_ASSIGN(ClientHandlerStd); DISALLOW_COPY_AND_ASSIGN(ClientHandlerStd);
}; };
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_STD_H_

168
src/CEF/DialogTest.cpp Normal file
View File

@ -0,0 +1,168 @@
// Copyright (c) 2012 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 "CEF/DialogTest.h"
#include <string>
#include "include/cef_browser.h"
#include "include/wrapper/cef_helpers.h"
#include "CEF/TestRunner.h"
#include "CEF/FileUtil.h"
const char kTestUrlPath[] = "/dialogs";
const char kFileOpenPngMessageName[] = "DialogTest.FileOpenPng";
const char kFileOpenImageMessageName[] = "DialogTest.FileOpenImage";
const char kFileOpenMultipleMessageName[] = "DialogTest.FileOpenMultiple";
const char kFileOpenFolderMessageName[] = "DialogTest.FileOpenFolder";
const char kFileSaveMessageName[] = "DialogTest.FileSave";
// Store persistent dialog state information.
class DialogState : public base::RefCountedThreadSafe<DialogState> {
public:
DialogState() : mode_(FILE_DIALOG_OPEN), pending_(false) {}
cef_file_dialog_mode_t mode_;
CefString last_file_;
bool pending_;
DISALLOW_COPY_AND_ASSIGN(DialogState);
};
// Callback executed when the file dialog is dismissed.
class DialogCallback : public CefRunFileDialogCallback {
public:
DialogCallback(
CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback,
scoped_refptr<DialogState> dialog_state)
: router_callback_(router_callback), dialog_state_(dialog_state) {}
virtual void OnFileDialogDismissed(
const std::vector<CefString>& file_paths) override {
CEF_REQUIRE_UI_THREAD();
DCHECK(dialog_state_->pending_);
if (!file_paths.empty()) {
dialog_state_->last_file_ = file_paths[0];
if (dialog_state_->mode_ == FILE_DIALOG_OPEN_FOLDER) {
std::string last_file = dialog_state_->last_file_;
if (last_file[last_file.length() - 1] != kPathSep) {
// Add a trailing slash so we know it's a directory. Otherwise, file
// dialogs will think the last path component is a file name.
last_file += kPathSep;
dialog_state_->last_file_ = last_file;
}
}
}
// Send a message back to the render process with the list of file paths.
std::string response;
for (int i = 0; i < static_cast<int>(file_paths.size()); ++i) {
if (!response.empty())
response += "|"; // Use a delimiter disallowed in file paths.
response += file_paths[i];
}
router_callback_->Success(response);
router_callback_ = nullptr;
dialog_state_->pending_ = false;
dialog_state_ = nullptr;
}
private:
CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback_;
scoped_refptr<DialogState> dialog_state_;
IMPLEMENT_REFCOUNTING(DialogCallback);
DISALLOW_COPY_AND_ASSIGN(DialogCallback);
};
// Handle messages in the browser process.
class Handler : public CefMessageRouterBrowserSide::Handler {
public:
Handler() {}
// Called due to cefQuery execution in dialogs.html.
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) override {
CEF_REQUIRE_UI_THREAD();
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (!IsTestURL(url, kTestUrlPath))
return false;
if (!dialog_state_.get())
dialog_state_ = new DialogState;
// Make sure we're only running one dialog at a time.
DCHECK(!dialog_state_->pending_);
std::vector<CefString> accept_filters;
std::string title;
const std::string& message_name = request;
if (message_name == kFileOpenPngMessageName) {
dialog_state_->mode_ = FILE_DIALOG_OPEN;
title = "My Open PNG Dialog";
accept_filters.push_back(".png");
} else if (message_name == kFileOpenImageMessageName) {
dialog_state_->mode_ = FILE_DIALOG_OPEN;
title = "My Open Image Dialog";
accept_filters.push_back("image/*");
} else if (message_name == kFileOpenMultipleMessageName) {
dialog_state_->mode_ = FILE_DIALOG_OPEN_MULTIPLE;
title = "My Open MultiType Dialog";
} else if (message_name == kFileOpenFolderMessageName) {
dialog_state_->mode_ = FILE_DIALOG_OPEN_FOLDER;
title = "My Open Folder Dialog";
} else if (message_name == kFileSaveMessageName) {
dialog_state_->mode_ = FILE_DIALOG_SAVE;
title = "My Save Dialog";
} else {
NOTREACHED();
return true;
}
if (accept_filters.empty() &&
dialog_state_->mode_ != FILE_DIALOG_OPEN_FOLDER) {
// Build filters based on mime time.
accept_filters.push_back("text/*");
// Build filters based on file extension.
accept_filters.push_back(".log");
accept_filters.push_back(".patch");
// Add specific filters as-is.
accept_filters.push_back("Document Files|.doc;.odt");
accept_filters.push_back("Image Files|.png;.jpg;.gif");
accept_filters.push_back("PDF Files|.pdf");
}
dialog_state_->pending_ = true;
browser->GetHost()->RunFileDialog(
dialog_state_->mode_, title, dialog_state_->last_file_, accept_filters,
new DialogCallback(callback, dialog_state_));
return true;
}
private:
scoped_refptr<DialogState> dialog_state_;
DISALLOW_COPY_AND_ASSIGN(Handler);
};
namespace dialog_test {
void CreateMessageHandlers(MessageHandlerSet& handlers) {
handlers.insert(new Handler());
}
}

12
src/CEF/DialogTest.h Normal file
View File

@ -0,0 +1,12 @@
// Copyright (c) 2012 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.
#pragma once
#include "CEF/TestRunner.h"
namespace dialog_test {
// Create message handlers. Called from test_runner.cc.
void CreateMessageHandlers(MessageHandlerSet& handlers);
}

View File

@ -48,7 +48,7 @@ bool ReadFileToString(const std::string& path,
// Hence, the file is read sequentially as opposed to a one-shot read. // Hence, the file is read sequentially as opposed to a one-shot read.
while ((len = fread(buf.get(), 1, kBufferSize, file)) > 0) { while ((len = fread(buf.get(), 1, kBufferSize, file)) > 0) {
if (contents) if (contents)
contents->append(buf.get(), std::min(len, max_size - size)); contents->append(buf.get(), min(len, max_size - size));
if ((max_size - size) < len) { if ((max_size - size) < len) {
read_status = false; read_status = false;

View File

@ -22,7 +22,7 @@ extern const char kPathSep;
// threads is not allowed. // threads is not allowed.
bool ReadFileToString(const std::string& path, bool ReadFileToString(const std::string& path,
std::string* contents, std::string* contents,
size_t max_size = std::numeric_limits<size_t>::max()); size_t max_size = (std::numeric_limits<size_t>::max)());
// Writes the given buffer into the file, overwriting any data that was // Writes the given buffer into the file, overwriting any data that was
// previously there. Returns the number of bytes written, or -1 on error. // previously there. Returns the number of bytes written, or -1 on error.

34
src/CEF/GeometryUtil.cpp Normal file
View File

@ -0,0 +1,34 @@
// 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 "CEF/GeometryUtil.h"
#include <cmath>
int LogicalToDevice(int value, float device_scale_factor) {
float scaled_val = static_cast<float>(value) * device_scale_factor;
return static_cast<int>(std::floor(scaled_val));
}
CefRect LogicalToDevice(const CefRect& value, float device_scale_factor) {
return CefRect(LogicalToDevice(value.x, device_scale_factor),
LogicalToDevice(value.y, device_scale_factor),
LogicalToDevice(value.width, device_scale_factor),
LogicalToDevice(value.height, device_scale_factor));
}
int DeviceToLogical(int value, float device_scale_factor) {
float scaled_val = static_cast<float>(value) / device_scale_factor;
return static_cast<int>(std::floor(scaled_val));
}
void DeviceToLogical(CefMouseEvent& value, float device_scale_factor) {
value.x = DeviceToLogical(value.x, device_scale_factor);
value.y = DeviceToLogical(value.y, device_scale_factor);
}
void DeviceToLogical(CefTouchEvent& value, float device_scale_factor) {
value.x = DeviceToLogical(value.x, device_scale_factor);
value.y = DeviceToLogical(value.y, device_scale_factor);
}

16
src/CEF/GeometryUtil.h Normal file
View File

@ -0,0 +1,16 @@
// 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.
#pragma once
#include "include/internal/cef_types_wrappers.h"
// Convert |value| from logical coordinates to device coordinates.
int LogicalToDevice(int value, float device_scale_factor);
CefRect LogicalToDevice(const CefRect& value, float device_scale_factor);
// Convert |value| from device coordinates to logical coordinates.
int DeviceToLogical(int value, float device_scale_factor);
void DeviceToLogical(CefMouseEvent& value, float device_scale_factor);
void DeviceToLogical(CefTouchEvent& value, float device_scale_factor);

View File

@ -6,6 +6,7 @@
#include <string> #include <string>
#include "HumanAppContext.h"
#include "include/cef_browser.h" #include "include/cef_browser.h"
#include "include/cef_command_line.h" #include "include/cef_command_line.h"
#include "include/views/cef_browser_view.h" #include "include/views/cef_browser_view.h"
@ -46,7 +47,7 @@ public:
CefRefPtr<HumanAppBrowser> app, CefRefPtr<HumanAppBrowser> app,
CefRefPtr<CefCommandLine> command_line) override { CefRefPtr<CefCommandLine> command_line) override {
// Append Chromium command line parameters if touch events are enabled // Append Chromium command line parameters if touch events are enabled
if (MainContext::Get()->TouchEventsEnabled()) if (HumanAppContext::Get()->TouchEventsEnabled())
command_line->AppendSwitchWithValue("touch-events", "enabled"); command_line->AppendSwitchWithValue("touch-events", "enabled");
} }

View File

@ -0,0 +1,36 @@
// 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 "CEF/HumanAppContextImpl.h"
#include <direct.h>
#include <shlobj.h>
std::string HumanAppContextImpl::GetDownloadPath(const std::string& file_name) {
TCHAR szFolderPath[MAX_PATH];
std::string path;
// Save the file in the user's "My Documents" folder.
if (SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_PERSONAL | CSIDL_FLAG_CREATE,
nullptr, 0, szFolderPath))) {
path = CefString(szFolderPath);
path += "\\" + file_name;
}
return path;
}
std::string HumanAppContextImpl::GetAppWorkingDirectory() {
char szWorkingDir[MAX_PATH + 1];
if (_getcwd(szWorkingDir, MAX_PATH) == nullptr) {
szWorkingDir[0] = 0;
} else {
// Add trailing path separator.
size_t len = strlen(szWorkingDir);
szWorkingDir[len] = '\\';
szWorkingDir[len + 1] = 0;
}
return szWorkingDir;
}

View File

@ -9,6 +9,7 @@
#include "include/cef_parser.h" #include "include/cef_parser.h"
#include "CEF/HumanAppBrowser.h" #include "CEF/HumanAppBrowser.h"
#include "CEF/HumanAppSwitches.h" #include "CEF/HumanAppSwitches.h"
#include "CEF/RootWindoManager.h"
// The default URL to load in a browser window. // The default URL to load in a browser window.
const char kDefaultUrl[] = "http://www.google.com"; const char kDefaultUrl[] = "http://www.google.com";

View File

@ -2,19 +2,13 @@
// reserved. Use of this source code is governed by a BSD-style license that // reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file. // can be found in the LICENSE file.
#include "tests/shared/browser/main_message_loop.h" #include "CEF/MainMessageLoop.h"
#include "include/cef_task.h" #include "include/cef_task.h"
#include "include/wrapper/cef_closure_task.h" #include "include/wrapper/cef_closure_task.h"
namespace client {
namespace {
MainMessageLoop* g_main_message_loop = nullptr; MainMessageLoop* g_main_message_loop = nullptr;
} // namespace
MainMessageLoop::MainMessageLoop() { MainMessageLoop::MainMessageLoop() {
DCHECK(!g_main_message_loop); DCHECK(!g_main_message_loop);
g_main_message_loop = this; g_main_message_loop = this;
@ -38,4 +32,3 @@ void MainMessageLoop::PostClosure(const base::RepeatingClosure& closure) {
PostTask(CefCreateClosureTask(closure)); PostTask(CefCreateClosureTask(closure));
} }
} // namespace client

View File

@ -60,14 +60,14 @@ class MainMessageLoop {
}; };
#define CURRENTLY_ON_MAIN_THREAD() \ #define CURRENTLY_ON_MAIN_THREAD() \
client::MainMessageLoop::Get()->RunsTasksOnCurrentThread() MainMessageLoop::Get()->RunsTasksOnCurrentThread()
#define REQUIRE_MAIN_THREAD() DCHECK(CURRENTLY_ON_MAIN_THREAD()) #define REQUIRE_MAIN_THREAD() DCHECK(CURRENTLY_ON_MAIN_THREAD())
#define MAIN_POST_TASK(task) client::MainMessageLoop::Get()->PostTask(task) #define MAIN_POST_TASK(task) MainMessageLoop::Get()->PostTask(task)
#define MAIN_POST_CLOSURE(closure) \ #define MAIN_POST_CLOSURE(closure) \
client::MainMessageLoop::Get()->PostClosure(closure) MainMessageLoop::Get()->PostClosure(closure)
// Use this struct in conjuction with RefCountedThreadSafe to ensure that an // Use this struct in conjuction with RefCountedThreadSafe to ensure that an
// object is deleted on the main thread. For example: // object is deleted on the main thread. For example:
@ -95,7 +95,7 @@ struct DeleteOnMainThread {
if (CURRENTLY_ON_MAIN_THREAD()) { if (CURRENTLY_ON_MAIN_THREAD()) {
delete x; delete x;
} else { } else {
client::MainMessageLoop::Get()->PostClosure(base::BindOnce( MainMessageLoop::Get()->PostClosure(base::BindOnce(
&DeleteOnMainThread::Destruct<T>, base::Unretained(x))); &DeleteOnMainThread::Destruct<T>, base::Unretained(x)));
} }
} }

View File

@ -2,17 +2,13 @@
// reserved. Use of this source code is governed by a BSD-style license that // reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file. // can be found in the LICENSE file.
#include "tests/shared/browser/main_message_loop_external_pump.h" #include "CEF/MainMessageLoopExternalPump.h"
#include <climits> #include <climits>
#include "include/cef_app.h" #include "include/cef_app.h"
#include "include/wrapper/cef_helpers.h" #include "include/wrapper/cef_helpers.h"
#include "tests/shared/browser/main_message_loop.h" #include "CEF/MainMessageLoop.h"
namespace client {
namespace {
// Special timer delay placeholder value. Intentionally 32-bit for Windows and // Special timer delay placeholder value. Intentionally 32-bit for Windows and
// OS X platform API compatibility. // OS X platform API compatibility.
@ -22,9 +18,8 @@ const int32 kTimerDelayPlaceholder = INT_MAX;
// DoWork(). // DoWork().
const int64 kMaxTimerDelay = 1000 / 30; // 30fps const int64 kMaxTimerDelay = 1000 / 30; // 30fps
client::MainMessageLoopExternalPump* g_external_message_pump = nullptr; MainMessageLoopExternalPump* g_external_message_pump = nullptr;
} // namespace
MainMessageLoopExternalPump::MainMessageLoopExternalPump() MainMessageLoopExternalPump::MainMessageLoopExternalPump()
: is_active_(false), reentrancy_detected_(false) { : is_active_(false), reentrancy_detected_(false) {
@ -104,4 +99,3 @@ bool MainMessageLoopExternalPump::PerformMessageLoopWork() {
return reentrancy_detected_; return reentrancy_detected_;
} }
} // namespace client

View File

@ -2,13 +2,9 @@
// reserved. Use of this source code is governed by a BSD-style license that // reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file. // can be found in the LICENSE file.
#ifndef CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_EXTERNAL_PUMP_H_
#define CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_EXTERNAL_PUMP_H_
#pragma once #pragma once
#include "tests/shared/browser/main_message_loop_std.h" #include "CEF/MainMessageLoopStd.h"
namespace client {
// This MessageLoop implementation simulates the embedding of CEF into an // This MessageLoop implementation simulates the embedding of CEF into an
// existing host application that runs its own message loop. The scheduling // existing host application that runs its own message loop. The scheduling
@ -64,7 +60,3 @@ class MainMessageLoopExternalPump : public MainMessageLoopStd {
bool is_active_; bool is_active_;
bool reentrancy_detected_; bool reentrancy_detected_;
}; };
} // namespace client
#endif // CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_EXTERNAL_PUMP_H_

View File

@ -2,18 +2,14 @@
// reserved. Use of this source code is governed by a BSD-style license that // reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file. // can be found in the LICENSE file.
#include "tests/shared/browser/main_message_loop_external_pump.h" #include "CEF/MainMessageLoopExternalPump.h"
#include <CommCtrl.h> #include <CommCtrl.h>
#include <memory> #include <memory>
#include "include/cef_app.h" #include "include/cef_app.h"
#include "tests/shared/browser/util_win.h" #include "CEF/UtilWin.h"
namespace client {
namespace {
// Message sent to get an additional time slice for pumping (processing) another // Message sent to get an additional time slice for pumping (processing) another
// task (a series of such messages creates a continuous task pump). // task (a series of such messages creates a continuous task pump).
@ -143,12 +139,8 @@ LRESULT CALLBACK MainMessageLoopExternalPumpWin::WndProc(HWND hwnd,
return DefWindowProc(hwnd, msg, wparam, lparam); return DefWindowProc(hwnd, msg, wparam, lparam);
} }
} // namespace
// static // static
std::unique_ptr<MainMessageLoopExternalPump> std::unique_ptr<MainMessageLoopExternalPump>
MainMessageLoopExternalPump::Create() { MainMessageLoopExternalPump::Create() {
return std::make_unique<MainMessageLoopExternalPumpWin>(); return std::make_unique<MainMessageLoopExternalPumpWin>();
} }
} // namespace client

View File

@ -2,12 +2,10 @@
// reserved. Use of this source code is governed by a BSD-style license that // reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file. // can be found in the LICENSE file.
#include "tests/shared/browser/main_message_loop_std.h" #include "CEF/MainMessageLoopStd.h"
#include "include/cef_app.h" #include "include/cef_app.h"
namespace client {
MainMessageLoopStd::MainMessageLoopStd() {} MainMessageLoopStd::MainMessageLoopStd() {}
int MainMessageLoopStd::Run() { int MainMessageLoopStd::Run() {
@ -33,5 +31,3 @@ void MainMessageLoopStd::SetCurrentModelessDialog(HWND hWndDialog) {
// internally route dialog messages. // internally route dialog messages.
} }
#endif #endif
} // namespace client

View File

@ -2,13 +2,9 @@
// reserved. Use of this source code is governed by a BSD-style license that // reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file. // can be found in the LICENSE file.
#ifndef CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_STD_H_
#define CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_STD_H_
#pragma once #pragma once
#include "tests/shared/browser/main_message_loop.h" #include "CEF/MainMessageLoop.h"
namespace client {
// Represents the main message loop in the browser process. This implementation // Represents the main message loop in the browser process. This implementation
// is a light-weight wrapper around the Chromium UI thread. // is a light-weight wrapper around the Chromium UI thread.
@ -30,6 +26,3 @@ class MainMessageLoopStd : public MainMessageLoop {
DISALLOW_COPY_AND_ASSIGN(MainMessageLoopStd); DISALLOW_COPY_AND_ASSIGN(MainMessageLoopStd);
}; };
} // namespace client
#endif // CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_STD_H_

584
src/CEF/MediaRouterTest.cpp Normal file
View File

@ -0,0 +1,584 @@
// Copyright (c) 2020 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 "CEF/MediaRouterTest.h"
#include <string>
#include <vector>
#include "include/base/cef_logging.h"
#include "include/cef_media_router.h"
#include "include/cef_parser.h"
#include "CEF/TestRunner.h"
const char kTestUrlPath[] = "/media_router";
// Application-specific error codes.
const int kMessageFormatError = 1;
const int kRequestFailedError = 2;
// Message strings.
const char kNameKey[] = "name";
const char kNameValueSubscribe[] = "subscribe";
const char kNameValueCreateRoute[] = "createRoute";
const char kNameValueTerminateRoute[] = "terminateRoute";
const char kNameValueSendMessage[] = "sendMessage";
const char kSourceKey[] = "source_urn";
const char kSinkKey[] = "sink_id";
const char kRouteKey[] = "route_id";
const char kMessageKey[] = "message";
const char kSuccessKey[] = "success";
const char kPayloadKey[] = "payload";
// Convert a dictionary value to a JSON string.
CefString GetJSON(CefRefPtr<CefDictionaryValue> dictionary) {
CefRefPtr<CefValue> value = CefValue::Create();
value->SetDictionary(dictionary);
return CefWriteJSON(value, JSON_WRITER_DEFAULT);
}
typedef CefMessageRouterBrowserSide::Callback CallbackType;
void SendSuccess(CefRefPtr<CallbackType> callback,
CefRefPtr<CefDictionaryValue> result) {
callback->Success(GetJSON(result));
}
void SendFailure(CefRefPtr<CallbackType> callback,
int error_code,
const std::string& error_message) {
callback->Failure(error_code, error_message);
}
// Callback for CefMediaRouter::CreateRoute.
class MediaRouteCreateCallback : public CefMediaRouteCreateCallback {
public:
explicit MediaRouteCreateCallback(CefRefPtr<CallbackType> create_callback)
: create_callback_(create_callback) {}
// CefMediaRouteCreateCallback method:
void OnMediaRouteCreateFinished(RouteCreateResult result,
const CefString& error,
CefRefPtr<CefMediaRoute> route) override {
CEF_REQUIRE_UI_THREAD();
if (result == CEF_MRCR_OK) {
CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
dict->SetString(kRouteKey, route->GetId());
SendSuccess(create_callback_, dict);
} else {
SendFailure(create_callback_, kRequestFailedError + result, error);
}
create_callback_ = nullptr;
}
private:
CefRefPtr<CallbackType> create_callback_;
IMPLEMENT_REFCOUNTING(MediaRouteCreateCallback);
DISALLOW_COPY_AND_ASSIGN(MediaRouteCreateCallback);
};
// Observes MediaRouter events. Only accessed on the UI thread.
class MediaObserver : public CefMediaObserver {
public:
typedef std::vector<CefRefPtr<CefMediaRoute>> MediaRouteVector;
typedef std::vector<CefRefPtr<CefMediaSink>> MediaSinkVector;
MediaObserver(CefRefPtr<CefMediaRouter> media_router,
CefRefPtr<CallbackType> subscription_callback)
: media_router_(media_router),
subscription_callback_(subscription_callback),
next_sink_query_id_(0),
pending_sink_query_id_(-1),
pending_sink_callbacks_(0U) {}
~MediaObserver() override { ClearSinkInfoMap(); }
bool CreateRoute(const std::string& source_urn,
const std::string& sink_id,
CefRefPtr<CallbackType> callback,
std::string& error) {
CefRefPtr<CefMediaSource> source = GetSource(source_urn);
if (!source) {
error = "Invalid source: " + source_urn;
return false;
}
CefRefPtr<CefMediaSink> sink = GetSink(sink_id);
if (!sink) {
error = "Invalid sink: " + sink_id;
return false;
}
media_router_->CreateRoute(source, sink,
new MediaRouteCreateCallback(callback));
return true;
}
bool TerminateRoute(const std::string& route_id, std::string& error) {
CefRefPtr<CefMediaRoute> route = GetRoute(route_id);
if (!route) {
error = "Invalid route: " + route_id;
return false;
}
route->Terminate();
return true;
}
bool SendRouteMessage(const std::string& route_id,
const std::string& message,
std::string& error) {
CefRefPtr<CefMediaRoute> route = GetRoute(route_id);
if (!route) {
error = "Invalid route: " + route_id;
return false;
}
route->SendRouteMessage(message.c_str(), message.size());
return true;
}
protected:
class DeviceInfoCallback : public CefMediaSinkDeviceInfoCallback {
public:
// Callback to be executed when the device info is available.
using CallbackType =
base::OnceCallback<void(const std::string& sink_id,
const CefMediaSinkDeviceInfo& device_info)>;
DeviceInfoCallback(const std::string& sink_id, CallbackType callback)
: sink_id_(sink_id), callback_(std::move(callback)) {}
void OnMediaSinkDeviceInfo(
const CefMediaSinkDeviceInfo& device_info) override {
CEF_REQUIRE_UI_THREAD();
std::move(callback_).Run(sink_id_, device_info);
}
private:
const std::string sink_id_;
CallbackType callback_;
IMPLEMENT_REFCOUNTING(DeviceInfoCallback);
DISALLOW_COPY_AND_ASSIGN(DeviceInfoCallback);
};
// CefMediaObserver methods:
void OnSinks(const MediaSinkVector& sinks) override {
CEF_REQUIRE_UI_THREAD();
ClearSinkInfoMap();
// Reset pending sink state.
pending_sink_callbacks_ = sinks.size();
pending_sink_query_id_ = ++next_sink_query_id_;
if (sinks.empty()) {
// No sinks, send the response immediately.
SendSinksResponse();
return;
}
MediaSinkVector::const_iterator it = sinks.begin();
for (size_t idx = 0; it != sinks.end(); ++it, ++idx) {
CefRefPtr<CefMediaSink> sink = *it;
const std::string& sink_id = sink->GetId();
SinkInfo* info = new SinkInfo;
info->sink = sink;
sink_info_map_.insert(std::make_pair(sink_id, info));
// Request the device info asynchronously. Send the response once all
// callbacks have executed.
auto callback = base::BindOnce(&MediaObserver::OnSinkDeviceInfo, this,
pending_sink_query_id_);
sink->GetDeviceInfo(new DeviceInfoCallback(sink_id, std::move(callback)));
}
}
void OnRoutes(const MediaRouteVector& routes) override {
CEF_REQUIRE_UI_THREAD();
route_map_.clear();
CefRefPtr<CefDictionaryValue> payload = CefDictionaryValue::Create();
CefRefPtr<CefListValue> routes_list = CefListValue::Create();
routes_list->SetSize(routes.size());
MediaRouteVector::const_iterator it = routes.begin();
for (size_t idx = 0; it != routes.end(); ++it, ++idx) {
CefRefPtr<CefMediaRoute> route = *it;
const std::string& route_id = route->GetId();
route_map_.insert(std::make_pair(route_id, route));
CefRefPtr<CefDictionaryValue> route_dict = CefDictionaryValue::Create();
route_dict->SetString("id", route_id);
route_dict->SetString(kSourceKey, route->GetSource()->GetId());
route_dict->SetString(kSinkKey, route->GetSink()->GetId());
routes_list->SetDictionary(idx, route_dict);
}
payload->SetList("routes_list", routes_list);
SendResponse("onRoutes", payload);
}
void OnRouteStateChanged(CefRefPtr<CefMediaRoute> route,
ConnectionState state) override {
CEF_REQUIRE_UI_THREAD();
CefRefPtr<CefDictionaryValue> payload = CefDictionaryValue::Create();
payload->SetString(kRouteKey, route->GetId());
payload->SetInt("connection_state", state);
SendResponse("onRouteStateChanged", payload);
}
void OnRouteMessageReceived(CefRefPtr<CefMediaRoute> route,
const void* message,
size_t message_size) override {
CEF_REQUIRE_UI_THREAD();
std::string message_str(static_cast<const char*>(message), message_size);
CefRefPtr<CefDictionaryValue> payload = CefDictionaryValue::Create();
payload->SetString(kRouteKey, route->GetId());
payload->SetString(kMessageKey, message_str);
SendResponse("onRouteMessageReceived", payload);
}
private:
CefRefPtr<CefMediaSource> GetSource(const std::string& source_urn) {
CefRefPtr<CefMediaSource> source = media_router_->GetSource(source_urn);
if (!source)
return nullptr;
return source;
}
CefRefPtr<CefMediaSink> GetSink(const std::string& sink_id) {
SinkInfoMap::const_iterator it = sink_info_map_.find(sink_id);
if (it != sink_info_map_.end())
return it->second->sink;
return nullptr;
}
void ClearSinkInfoMap() {
SinkInfoMap::const_iterator it = sink_info_map_.begin();
for (; it != sink_info_map_.end(); ++it) {
delete it->second;
}
sink_info_map_.clear();
}
void OnSinkDeviceInfo(int sink_query_id,
const std::string& sink_id,
const CefMediaSinkDeviceInfo& device_info) {
// Discard callbacks that arrive after a new call to OnSinks().
if (sink_query_id != pending_sink_query_id_)
return;
SinkInfoMap::const_iterator it = sink_info_map_.find(sink_id);
if (it != sink_info_map_.end()) {
it->second->device_info = device_info;
}
// Send the response once we've received all expected callbacks.
DCHECK_GT(pending_sink_callbacks_, 0U);
if (--pending_sink_callbacks_ == 0U) {
SendSinksResponse();
}
}
CefRefPtr<CefMediaRoute> GetRoute(const std::string& route_id) {
RouteMap::const_iterator it = route_map_.find(route_id);
if (it != route_map_.end())
return it->second;
return nullptr;
}
void SendResponse(const std::string& name,
CefRefPtr<CefDictionaryValue> payload) {
CefRefPtr<CefDictionaryValue> result = CefDictionaryValue::Create();
result->SetString(kNameKey, name);
result->SetDictionary(kPayloadKey, payload);
SendSuccess(subscription_callback_, result);
}
void SendSinksResponse() {
CefRefPtr<CefDictionaryValue> payload = CefDictionaryValue::Create();
CefRefPtr<CefListValue> sinks_list = CefListValue::Create();
sinks_list->SetSize(sink_info_map_.size());
SinkInfoMap::const_iterator it = sink_info_map_.begin();
for (size_t idx = 0; it != sink_info_map_.end(); ++it, ++idx) {
const SinkInfo* info = it->second;
CefRefPtr<CefDictionaryValue> sink_dict = CefDictionaryValue::Create();
sink_dict->SetString("id", it->first);
sink_dict->SetString("name", info->sink->GetName());
sink_dict->SetString("desc", info->sink->GetDescription());
sink_dict->SetInt("icon", info->sink->GetIconType());
sink_dict->SetString("ip_address",
CefString(&info->device_info.ip_address));
sink_dict->SetInt("port", info->device_info.port);
sink_dict->SetString("model_name",
CefString(&info->device_info.model_name));
sink_dict->SetString("type",
info->sink->IsCastSink()
? "cast"
: info->sink->IsDialSink() ? "dial" : "unknown");
sinks_list->SetDictionary(idx, sink_dict);
}
payload->SetList("sinks_list", sinks_list);
SendResponse("onSinks", payload);
}
CefRefPtr<CefMediaRouter> media_router_;
CefRefPtr<CallbackType> subscription_callback_;
struct SinkInfo {
CefRefPtr<CefMediaSink> sink;
CefMediaSinkDeviceInfo device_info;
};
typedef std::map<std::string, SinkInfo*> SinkInfoMap;
// Used to uniquely identify a call to OnSinks(), for the purpose of
// associating OnMediaSinkDeviceInfo() callbacks.
int next_sink_query_id_;
// State from the most recent call to OnSinks().
SinkInfoMap sink_info_map_;
int pending_sink_query_id_;
size_t pending_sink_callbacks_;
// State from the most recent call to OnRoutes().
typedef std::map<std::string, CefRefPtr<CefMediaRoute>> RouteMap;
RouteMap route_map_;
IMPLEMENT_REFCOUNTING(MediaObserver);
DISALLOW_COPY_AND_ASSIGN(MediaObserver);
};
// Handle messages in the browser process. Only accessed on the UI thread.
class Handler : public CefMessageRouterBrowserSide::Handler {
public:
typedef std::vector<std::string> NameVector;
Handler() { CEF_REQUIRE_UI_THREAD(); }
virtual ~Handler() {
SubscriptionStateMap::iterator it = subscription_state_map_.begin();
for (; it != subscription_state_map_.end(); ++it) {
delete it->second;
}
}
// Called due to cefQuery execution in media_router.html.
bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) override {
CEF_REQUIRE_UI_THREAD();
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (!IsTestURL(url, kTestUrlPath))
return false;
// Parse |request| as a JSON dictionary.
CefRefPtr<CefDictionaryValue> request_dict = ParseJSON(request);
if (!request_dict) {
SendFailure(callback, kMessageFormatError, "Incorrect message format");
return true;
}
// Verify the "name" key.
if (!VerifyKey(request_dict, kNameKey, VTYPE_STRING, callback))
return true;
const std::string& message_name = request_dict->GetString(kNameKey);
if (message_name == kNameValueSubscribe) {
// Subscribe to notifications from the media router.
if (!persistent) {
SendFailure(callback, kMessageFormatError,
"Subscriptions must be persistent");
return true;
}
if (!CreateSubscription(browser, query_id, callback)) {
SendFailure(callback, kRequestFailedError,
"Browser is already subscribed");
}
return true;
}
// All other messages require a current subscription.
CefRefPtr<MediaObserver> media_observer =
GetMediaObserver(browser->GetIdentifier());
if (!media_observer) {
SendFailure(callback, kRequestFailedError,
"Browser is not currently subscribed");
}
if (message_name == kNameValueCreateRoute) {
// Create a new route.
// Verify the "source_urn" key.
if (!VerifyKey(request_dict, kSourceKey, VTYPE_STRING, callback))
return true;
// Verify the "sink_id" key.
if (!VerifyKey(request_dict, kSinkKey, VTYPE_STRING, callback))
return true;
const std::string& source_urn = request_dict->GetString(kSourceKey);
const std::string& sink_id = request_dict->GetString(kSinkKey);
// |callback| will be executed once the route is created.
std::string error;
if (!media_observer->CreateRoute(source_urn, sink_id, callback, error)) {
SendFailure(callback, kRequestFailedError, error);
}
return true;
} else if (message_name == kNameValueTerminateRoute) {
// Terminate an existing route.
// Verify the "route" key.
if (!VerifyKey(request_dict, kRouteKey, VTYPE_STRING, callback))
return true;
const std::string& route_id = request_dict->GetString(kRouteKey);
std::string error;
if (!media_observer->TerminateRoute(route_id, error)) {
SendFailure(callback, kRequestFailedError, error);
} else {
SendSuccessACK(callback);
}
return true;
} else if (message_name == kNameValueSendMessage) {
// Send a route message.
// Verify the "route_id" key.
if (!VerifyKey(request_dict, kRouteKey, VTYPE_STRING, callback))
return true;
// Verify the "message" key.
if (!VerifyKey(request_dict, kMessageKey, VTYPE_STRING, callback))
return true;
const std::string& route_id = request_dict->GetString(kRouteKey);
const std::string& message = request_dict->GetString(kMessageKey);
std::string error;
if (!media_observer->SendRouteMessage(route_id, message, error)) {
SendFailure(callback, kRequestFailedError, error);
} else {
SendSuccessACK(callback);
}
return true;
}
return false;
}
void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id) override {
CEF_REQUIRE_UI_THREAD();
RemoveSubscription(browser->GetIdentifier(), query_id);
}
private:
static void SendSuccessACK(CefRefPtr<Callback> callback) {
CefRefPtr<CefDictionaryValue> result = CefDictionaryValue::Create();
result->SetBool(kSuccessKey, true);
SendSuccess(callback, result);
}
// Convert a JSON string to a dictionary value.
static CefRefPtr<CefDictionaryValue> ParseJSON(const CefString& string) {
CefRefPtr<CefValue> value = CefParseJSON(string, JSON_PARSER_RFC);
if (value.get() && value->GetType() == VTYPE_DICTIONARY)
return value->GetDictionary();
return nullptr;
}
// Verify that |key| exists in |dictionary| and has type |value_type|. Fails
// |callback| and returns false on failure.
static bool VerifyKey(CefRefPtr<CefDictionaryValue> dictionary,
const char* key,
cef_value_type_t value_type,
CefRefPtr<Callback> callback) {
if (!dictionary->HasKey(key) || dictionary->GetType(key) != value_type) {
SendFailure(
callback, kMessageFormatError,
"Missing or incorrectly formatted message key: " + std::string(key));
return false;
}
return true;
}
// Subscription state associated with a single browser.
struct SubscriptionState {
int64 query_id;
CefRefPtr<MediaObserver> observer;
CefRefPtr<CefRegistration> registration;
};
bool CreateSubscription(CefRefPtr<CefBrowser> browser,
int64 query_id,
CefRefPtr<Callback> callback) {
const int browser_id = browser->GetIdentifier();
if (subscription_state_map_.find(browser_id) !=
subscription_state_map_.end()) {
// An subscription already exists for this browser.
return false;
}
CefRefPtr<CefMediaRouter> media_router =
browser->GetHost()->GetRequestContext()->GetMediaRouter(nullptr);
SubscriptionState* state = new SubscriptionState();
state->query_id = query_id;
state->observer = new MediaObserver(media_router, callback);
state->registration = media_router->AddObserver(state->observer);
subscription_state_map_.insert(std::make_pair(browser_id, state));
// Trigger sink and route callbacks.
media_router->NotifyCurrentSinks();
media_router->NotifyCurrentRoutes();
return true;
}
void RemoveSubscription(int browser_id, int64 query_id) {
SubscriptionStateMap::iterator it =
subscription_state_map_.find(browser_id);
if (it != subscription_state_map_.end() &&
it->second->query_id == query_id) {
delete it->second;
subscription_state_map_.erase(it);
}
}
CefRefPtr<MediaObserver> GetMediaObserver(int browser_id) {
SubscriptionStateMap::const_iterator it =
subscription_state_map_.find(browser_id);
if (it != subscription_state_map_.end()) {
return it->second->observer;
}
return nullptr;
}
// Map of browser ID to SubscriptionState object.
typedef std::map<int, SubscriptionState*> SubscriptionStateMap;
SubscriptionStateMap subscription_state_map_;
DISALLOW_COPY_AND_ASSIGN(Handler);
};
namespace media_router_test {
void CreateMessageHandlers(MessageHandlerSet& handlers) {
handlers.insert(new Handler());
}
}

13
src/CEF/MediaRouterTest.h Normal file
View File

@ -0,0 +1,13 @@
// Copyright (c) 2020 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.
#pragma once
#include "CEF/TestRunner.h"
namespace media_router_test {
// Create message handlers. Called from test_runner.cc.
void CreateMessageHandlers(MessageHandlerSet& handlers);
}

View File

@ -0,0 +1,270 @@
// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
// 2013 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 "tests/cefclient/browser/osr_accessibility_helper.h"
#include "tests/cefclient/browser/osr_accessibility_node.h"
namespace client {
OsrAXTree::OsrAXTree() : root_node_id_(-1) {}
OsrAXNode* OsrAXTree::GetNode(int nodeId) const {
auto result = node_map_.find(nodeId);
if (result != node_map_.end()) {
return result->second;
}
return nullptr;
}
void OsrAXTree::EraseNode(int nodeId) {
node_map_.erase(nodeId);
}
void OsrAXTree::AddNode(OsrAXNode* node) {
node_map_[node->OsrAXNodeId()] = node;
}
void OsrAXTree::UpdateTreeData(CefRefPtr<CefDictionaryValue> value) {
if (value->HasKey("parent_tree_id")) {
parent_tree_id_ = value->GetString("parent_tree_id");
} else {
parent_tree_id_ = "";
}
// may also update following:
// doctype, title, url, mimetype
}
OsrAccessibilityHelper::OsrAccessibilityHelper(CefRefPtr<CefValue> value,
CefRefPtr<CefBrowser> browser)
: focused_node_id_(-1),
browser_(browser) {
UpdateAccessibilityTree(value);
}
int OsrAccessibilityHelper::CastToInt(CefRefPtr<CefValue> value) {
if (value->GetType() == VTYPE_STRING) {
const std::string& str = value->GetString();
return atoi(str.c_str());
} else {
return value->GetInt();
}
}
void OsrAccessibilityHelper::UpdateAccessibilityLocation(
CefRefPtr<CefValue> value) {
if (!value || value->GetType() != VTYPE_LIST) {
return;
}
CefRefPtr<CefListValue> locationChangeList = value->GetList();
size_t locationChangeCount = locationChangeList->GetSize();
if (locationChangeCount == 0) {
return;
}
for (size_t i = 0; i < locationChangeCount; i++) {
CefRefPtr<CefDictionaryValue> locationChangeDict =
locationChangeList->GetDictionary(i);
if (!locationChangeDict->HasKey("ax_tree_id") ||
!locationChangeDict->HasKey("new_location") ||
!locationChangeDict->HasKey("id")) {
continue;
}
CefString treeId = locationChangeDict->GetString("ax_tree_id");
int nodeId = CastToInt(locationChangeDict->GetValue("id"));
CefRefPtr<CefDictionaryValue> newLocationDict =
locationChangeDict->GetDictionary("new_location");
if (!newLocationDict) {
continue;
}
OsrAXNode* node = GetNode(treeId, nodeId);
if (!node) {
continue;
}
node->UpdateLocation(newLocationDict);
}
}
void OsrAccessibilityHelper::UpdateAccessibilityTree(
CefRefPtr<CefValue> value) {
if (!value || value->GetType() != VTYPE_DICTIONARY) {
return;
}
CefRefPtr<CefDictionaryValue> mainDict = value->GetDictionary();
if (!mainDict->HasKey("ax_tree_id") || !mainDict->HasKey("updates")) {
return;
}
CefString treeId = mainDict->GetString("ax_tree_id");
CefRefPtr<CefListValue> updatesList = mainDict->GetList("updates");
size_t updatesCount = updatesList->GetSize();
if (updatesCount == 0) {
return;
}
for (size_t i = 0; i < updatesCount; i++) {
CefRefPtr<CefDictionaryValue> updateDict = updatesList->GetDictionary(i);
UpdateLayout(treeId, updateDict);
}
}
OsrAXNode* OsrAccessibilityHelper::GetRootNode() const {
return GetTreeRootNode(root_tree_id_);
}
OsrAXNode* OsrAccessibilityHelper::GetFocusedNode() const {
auto tree = accessibility_node_map_.find(focused_tree_id_);
if (tree != accessibility_node_map_.end()) {
return tree->second.GetNode(focused_node_id_);
}
return nullptr;
}
OsrAXNode* OsrAccessibilityHelper::GetTreeRootNode(
const CefString& treeId) const {
auto tree = accessibility_node_map_.find(treeId);
if (tree != accessibility_node_map_.end()) {
return tree->second.GetNode(tree->second.GetRootNodeId());
}
return nullptr;
}
void OsrAccessibilityHelper::UpdateLayout(
const CefString& treeId,
CefRefPtr<CefDictionaryValue> update) {
if (!update) {
return;
}
// If a node is to be cleared
if (update->HasKey("node_id_to_clear")) {
int nodeId = CastToInt(update->GetValue("node_id_to_clear"));
// reset root node if that is to be cleared
auto tree = accessibility_node_map_.find(treeId);
if (tree != accessibility_node_map_.end()) {
if (tree->second.GetRootNodeId() == nodeId) {
root_tree_id_ = "";
tree->second.SetRootNodeId(-1);
}
}
if ((focused_tree_id_ == treeId) && (focused_node_id_ == nodeId)) {
UpdateFocusedNode("", -1);
}
OsrAXNode* node = GetNode(treeId, nodeId);
DestroyNode(node);
}
// get tree data
if (update->HasKey("tree_data") && update->HasKey("has_tree_data") &&
update->GetBool("has_tree_data")) {
CefRefPtr<CefDictionaryValue> tree_data =
update->GetDictionary("tree_data");
auto& tree = accessibility_node_map_[treeId];
tree.UpdateTreeData(tree_data);
if (tree.GetParentTreeId().empty()) {
root_tree_id_ = treeId;
}
if (tree_data->HasKey("focus_id") && tree_data->HasKey("focused_tree_id")) {
UpdateFocusedNode(tree_data->GetString("focused_tree_id"),
CastToInt(tree_data->GetValue("focus_id")));
}
}
// Now initialize/update the node data.
if (update->HasKey("nodes")) {
CefRefPtr<CefListValue> nodes = update->GetList("nodes");
for (size_t index = 0; index < nodes->GetSize(); index++) {
CefRefPtr<CefDictionaryValue> node = nodes->GetDictionary(index);
if (node) {
auto& tree = accessibility_node_map_[treeId];
int nodeId = CastToInt(node->GetValue("id"));
OsrAXNode* axNode = tree.GetNode(nodeId);
// Create if it is a new one
if (axNode) {
axNode->UpdateValue(node);
} else {
axNode = OsrAXNode::CreateNode(treeId, nodeId, node, this);
tree.AddNode(axNode);
}
}
}
}
if (update->HasKey("root_id")) {
int nodeId = CastToInt(update->GetValue("root_id"));
OsrAXNode* node = GetNode(treeId, nodeId);
if (node != nullptr) {
auto& tree = accessibility_node_map_[treeId];
tree.SetRootNodeId(nodeId);
}
}
}
void OsrAccessibilityHelper::UpdateFocusedNode(const CefString& treeId,
int nodeId) {
if ((focused_tree_id_ == treeId) && (focused_node_id_ == nodeId)) {
return;
}
focused_tree_id_ = treeId;
focused_node_id_ = nodeId;
// Now Notify Screen Reader
OsrAXNode* axNode = GetFocusedNode();
if (axNode) {
axNode->NotifyAccessibilityEvent("focus");
}
}
void OsrAccessibilityHelper::Reset() {
accessibility_node_map_.clear();
root_tree_id_ = "";
focused_tree_id_ = "";
focused_node_id_ = -1;
}
void OsrAccessibilityHelper::DestroyNode(OsrAXNode* node) {
if (node) {
CefString treeId = node->OsrAXTreeId();
int numChilds = node->GetChildCount();
if (numChilds > 0) {
for (int i = 0; i < numChilds; i++) {
OsrAXNode* childNode = node->ChildAtIndex(i);
if (!childNode) {
continue;
}
childNode->SetParent(nullptr);
if (childNode->OsrAXTreeId() == treeId) {
DestroyNode(childNode);
}
}
}
auto tree = accessibility_node_map_.find(treeId);
if (tree != accessibility_node_map_.end()) {
tree->second.EraseNode(node->OsrAXNodeId());
}
node->Destroy();
}
}
OsrAXNode* OsrAccessibilityHelper::GetNode(const CefString& treeId,
int nodeId) const {
auto tree = accessibility_node_map_.find(treeId);
if (tree != accessibility_node_map_.end()) {
return tree->second.GetNode(nodeId);
}
return nullptr;
}
} // namespace client

View File

@ -0,0 +1,81 @@
// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
// 2013 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 CEF_TESTS_CEFCLIENT_BROWSER_OSR_ACCESSIBILITY_HELPER_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_ACCESSIBILITY_HELPER_H_
#include <map>
#include "include/cef_browser.h"
namespace client {
class OsrAXNode;
class OsrAccessibilityHelper;
class OsrAXTree {
public:
OsrAXTree();
OsrAXNode* GetNode(int nodeId) const;
void EraseNode(int nodeId);
void UpdateTreeData(CefRefPtr<CefDictionaryValue> value);
void AddNode(OsrAXNode* node);
const CefString& GetParentTreeId() const { return parent_tree_id_; }
int GetRootNodeId() const { return root_node_id_; }
void SetRootNodeId(int nodeId) { root_node_id_ = nodeId; }
private:
CefString parent_tree_id_;
int root_node_id_;
std::map<int, OsrAXNode*> node_map_;
};
// Helper class that abstracts Renderer Accessibility tree and provides a
// uniform interface to be consumed by IAccessible interface on Windows and
// NSAccessibility implementation on Mac in CefClient.
class OsrAccessibilityHelper {
public:
OsrAccessibilityHelper(CefRefPtr<CefValue> value,
CefRefPtr<CefBrowser> browser);
void UpdateAccessibilityTree(CefRefPtr<CefValue> value);
void UpdateAccessibilityLocation(CefRefPtr<CefValue> value);
OsrAXNode* GetRootNode() const;
OsrAXNode* GetFocusedNode() const;
CefWindowHandle GetWindowHandle() const {
return browser_->GetHost()->GetWindowHandle();
}
CefRefPtr<CefBrowser> GetBrowser() const { return browser_; }
OsrAXNode* GetNode(const CefString& treeId, int nodeId) const;
OsrAXNode* GetTreeRootNode(const CefString& treeId) const;
static int CastToInt(CefRefPtr<CefValue> value);
private:
void Reset();
void UpdateLayout(const CefString& treeId,
CefRefPtr<CefDictionaryValue> update);
void UpdateFocusedNode(const CefString& treeId, int nodeId);
// Destroy the node and remove from Map
void DestroyNode(OsrAXNode* node);
CefString root_tree_id_;
CefString focused_tree_id_;
int focused_node_id_;
CefRefPtr<CefBrowser> browser_;
std::map<CefString, OsrAXTree> accessibility_node_map_;
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_ACCESSIBILITY_HELPER_H_

1198
src/CEF/OsrWindowWin.cpp Normal file

File diff suppressed because it is too large Load Diff

207
src/CEF/OsrWindowWin.h Normal file
View File

@ -0,0 +1,207 @@
// 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.
#pragma once
#include "include/base/cef_callback.h"
#include "include/base/cef_ref_counted.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
#include "CEF/ClientHandlerOSR.h.h"
#include "CEF/osr_accessibility_node.h"
#include "CEF/osr_dragdrop_win.h"
#include "CEF/osr_render_handler_win.h"
#include "CEF/osr_renderer_settings.h"
class OsrAccessibilityHelper;
class OsrImeHandlerWin;
// Represents the native parent window for an off-screen browser. This object
// must live on the CEF UI thread in order to handle CefRenderHandler callbacks.
// The methods of this class are thread-safe unless otherwise indicated.
class OsrWindowWin
: public base::RefCountedThreadSafe<OsrWindowWin, CefDeleteOnUIThread>,
public ClientHandlerOsr::OsrDelegate
#if defined(CEF_USE_ATL)
,
public OsrDragEvents
#endif
{
public:
// This interface is implemented by the owner of the OsrWindowWin. The
// methods of this class will be called on the main thread.
class Delegate {
public:
// Called after the native window has been created.
virtual void OnOsrNativeWindowCreated(HWND hwnd) = 0;
protected:
virtual ~Delegate() {}
};
// |delegate| must outlive this object.
OsrWindowWin(Delegate* delegate, const OsrRendererSettings& settings);
// Create a new browser and native window.
void CreateBrowser(HWND parent_hwnd,
const RECT& rect,
CefRefPtr<CefClient> handler,
const CefBrowserSettings& settings,
CefRefPtr<CefDictionaryValue> extra_info,
CefRefPtr<CefRequestContext> request_context,
const std::string& startup_url);
// Show the popup window with correct parent and bounds in parent coordinates.
void ShowPopup(HWND parent_hwnd, int x, int y, size_t width, size_t height);
void Show();
void Hide();
void SetBounds(int x, int y, size_t width, size_t height);
void SetFocus();
void SetDeviceScaleFactor(float device_scale_factor);
const OsrRendererSettings& settings() const { return settings_; }
private:
// Only allow deletion via scoped_refptr.
friend struct CefDeleteOnThread<TID_UI>;
friend class base::RefCountedThreadSafe<OsrWindowWin, CefDeleteOnUIThread>;
~OsrWindowWin();
// Manage native window lifespan.
void Create(HWND parent_hwnd, const RECT& rect);
void Destroy();
void NotifyNativeWindowCreated(HWND hwnd);
static void RegisterOsrClass(HINSTANCE hInstance, HBRUSH background_brush);
static LRESULT CALLBACK OsrWndProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// WndProc message handlers.
void OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam);
void OnSize();
void OnFocus(bool setFocus);
void OnCaptureLost();
void OnKeyEvent(UINT message, WPARAM wParam, LPARAM lParam);
void OnPaint();
bool OnEraseBkgnd();
bool OnTouchEvent(UINT message, WPARAM wParam, LPARAM lParam);
void OnIMESetContext(UINT message, WPARAM wParam, LPARAM lParam);
void OnIMEStartComposition();
void OnIMEComposition(UINT message, WPARAM wParam, LPARAM lParam);
void OnIMECancelCompositionEvent();
// Manage popup bounds.
bool IsOverPopupWidget(int x, int y) const;
int GetPopupXOffset() const;
int GetPopupYOffset() const;
void ApplyPopupOffset(int& x, int& y) const;
// ClientHandlerOsr::OsrDelegate methods.
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
bool GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override;
void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override;
bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
int viewX,
int viewY,
int& screenX,
int& screenY) override;
bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) override;
void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) override;
void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) override;
void OnPaint(CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList& dirtyRects,
const void* buffer,
int width,
int height) override;
void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList& dirtyRects,
void* share_handle) override;
void OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
cef_cursor_type_t type,
const CefCursorInfo& custom_cursor_info) override;
bool StartDragging(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> drag_data,
CefRenderHandler::DragOperationsMask allowed_ops,
int x,
int y) override;
void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
CefRenderHandler::DragOperation operation) override;
void OnImeCompositionRangeChanged(
CefRefPtr<CefBrowser> browser,
const CefRange& selection_range,
const CefRenderHandler::RectList& character_bounds) override;
void UpdateAccessibilityTree(CefRefPtr<CefValue> value) override;
void UpdateAccessibilityLocation(CefRefPtr<CefValue> value) override;
#if defined(CEF_USE_ATL)
// OsrDragEvents methods.
CefBrowserHost::DragOperationsMask OnDragEnter(
CefRefPtr<CefDragData> drag_data,
CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) override;
CefBrowserHost::DragOperationsMask OnDragOver(
CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) override;
void OnDragLeave() override;
CefBrowserHost::DragOperationsMask OnDrop(
CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) override;
#endif // defined(CEF_USE_ATL)
void EnsureRenderHandler();
// Only accessed on the main thread.
Delegate* delegate_;
const OsrRendererSettings settings_;
HWND hwnd_;
std::unique_ptr<OsrRenderHandlerWin> render_handler_;
// Class that encapsulates IMM32 APIs and controls IMEs attached to a window.
std::unique_ptr<OsrImeHandlerWin> ime_handler_;
RECT client_rect_;
float device_scale_factor_;
CefRefPtr<CefBrowser> browser_;
#if defined(CEF_USE_ATL)
CComPtr<DropTargetWin> drop_target_;
CefRenderHandler::DragOperation current_drag_op_;
// Class that abstracts the accessibility information received from the
// renderer.
std::unique_ptr<OsrAccessibilityHelper> accessibility_handler_;
IAccessible* accessibility_root_;
#endif
bool hidden_;
// Mouse state tracking.
POINT last_mouse_pos_;
POINT current_mouse_pos_;
bool mouse_rotation_;
bool mouse_tracking_;
int last_click_x_;
int last_click_y_;
CefBrowserHost::MouseButtonType last_click_button_;
int last_click_count_;
double last_click_time_;
bool last_mouse_down_on_view_;
DISALLOW_COPY_AND_ASSIGN(OsrWindowWin);
};

326
src/CEF/PreferencesTest.cpp Normal file
View File

@ -0,0 +1,326 @@
// 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 "CEF/PreferencesTest.h"
#include <sstream>
#include <string>
#include <vector>
#include "include/base/cef_logging.h"
#include "include/cef_command_line.h"
#include "include/cef_parser.h"
#include "CEF/TestRunner.h"
const char kTestUrlPath[] = "/preferences";
// Application-specific error codes.
const int kMessageFormatError = 1;
const int kPreferenceApplicationError = 1;
// Common to all messages.
const char kNameKey[] = "name";
const char kNameValueGet[] = "preferences_get";
const char kNameValueSet[] = "preferences_set";
const char kNameValueState[] = "preferences_state";
// Used with "preferences_get" messages.
const char kIncludeDefaultsKey[] = "include_defaults";
// Used with "preferences_set" messages.
const char kPreferencesKey[] = "preferences";
// Handle messages in the browser process. Only accessed on the UI thread.
class Handler : public CefMessageRouterBrowserSide::Handler {
public:
typedef std::vector<std::string> NameVector;
Handler() { CEF_REQUIRE_UI_THREAD(); }
// Called due to cefQuery execution in preferences.html.
bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) override {
CEF_REQUIRE_UI_THREAD();
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (!IsTestURL(url, kTestUrlPath))
return false;
// Parse |request| as a JSON dictionary.
CefRefPtr<CefDictionaryValue> request_dict = ParseJSON(request);
if (!request_dict) {
callback->Failure(kMessageFormatError, "Incorrect message format");
return true;
}
// Verify the "name" key.
if (!VerifyKey(request_dict, kNameKey, VTYPE_STRING, callback))
return true;
const std::string& message_name = request_dict->GetString(kNameKey);
if (message_name == kNameValueGet) {
// JavaScript is requesting a JSON representation of the preferences tree.
// Verify the "include_defaults" key.
if (!VerifyKey(request_dict, kIncludeDefaultsKey, VTYPE_BOOL, callback))
return true;
const bool include_defaults = request_dict->GetBool(kIncludeDefaultsKey);
OnPreferencesGet(browser, include_defaults, callback);
return true;
} else if (message_name == kNameValueSet) {
// JavaScript is requesting that preferences be updated to match the
// specified JSON representation.
// Verify the "preferences" key.
if (!VerifyKey(request_dict, kPreferencesKey, VTYPE_DICTIONARY, callback))
return true;
CefRefPtr<CefDictionaryValue> preferences =
request_dict->GetDictionary(kPreferencesKey);
OnPreferencesSet(browser, preferences, callback);
return true;
} else if (message_name == kNameValueState) {
// JavaScript is requesting global state information.
OnPreferencesState(browser, callback);
return true;
}
return false;
}
private:
// Execute |callback| with the preferences dictionary as a JSON string.
static void OnPreferencesGet(CefRefPtr<CefBrowser> browser,
bool include_defaults,
CefRefPtr<Callback> callback) {
CefRefPtr<CefRequestContext> context =
browser->GetHost()->GetRequestContext();
// Retrieve all preference values.
CefRefPtr<CefDictionaryValue> prefs =
context->GetAllPreferences(include_defaults);
// Serialize the preferences to JSON and return to the JavaScript caller.
callback->Success(GetJSON(prefs));
}
// Set preferences based on the contents of |preferences|. Execute |callback|
// with a descriptive result message.
static void OnPreferencesSet(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDictionaryValue> preferences,
CefRefPtr<Callback> callback) {
CefRefPtr<CefRequestContext> context =
browser->GetHost()->GetRequestContext();
CefRefPtr<CefValue> value = CefValue::Create();
value->SetDictionary(preferences);
std::string error;
NameVector changed_names;
// Apply preferences. This may result in errors.
const bool success =
ApplyPrefs(context, std::string(), value, error, changed_names);
// Create a message that accurately represents the result.
std::string message;
if (!changed_names.empty()) {
std::stringstream ss;
ss << "Successfully changed " << changed_names.size() << " preferences; ";
for (size_t i = 0; i < changed_names.size(); ++i) {
ss << changed_names[i];
if (i < changed_names.size() - 1)
ss << ", ";
}
message = ss.str();
}
if (!success) {
DCHECK(!error.empty());
if (!message.empty())
message += "\n";
message += error;
}
if (changed_names.empty()) {
if (!message.empty())
message += "\n";
message += "No preferences changed.";
}
// Return the message to the JavaScript caller.
if (success)
callback->Success(message);
else
callback->Failure(kPreferenceApplicationError, message);
}
// Execute |callback| with the global state dictionary as a JSON string.
static void OnPreferencesState(CefRefPtr<CefBrowser> browser,
CefRefPtr<Callback> callback) {
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
// If spell checking is disabled via the command-line then it cannot be
// enabled via preferences.
dict->SetBool("spellcheck_disabled",
command_line->HasSwitch("disable-spell-checking"));
// If proxy settings are configured via the command-line then they cannot
// be modified via preferences.
dict->SetBool("proxy_configured",
command_line->HasSwitch("no-proxy-server") ||
command_line->HasSwitch("proxy-auto-detect") ||
command_line->HasSwitch("proxy-pac-url") ||
command_line->HasSwitch("proxy-server"));
// If allow running insecure content is enabled via the command-line then it
// cannot be enabled via preferences.
dict->SetBool("allow_running_insecure_content",
command_line->HasSwitch("allow-running-insecure-content"));
// Serialize the state to JSON and return to the JavaScript caller.
callback->Success(GetJSON(dict));
}
// Convert a JSON string to a dictionary value.
static CefRefPtr<CefDictionaryValue> ParseJSON(const CefString& string) {
CefRefPtr<CefValue> value = CefParseJSON(string, JSON_PARSER_RFC);
if (value.get() && value->GetType() == VTYPE_DICTIONARY)
return value->GetDictionary();
return nullptr;
}
// Convert a dictionary value to a JSON string.
static CefString GetJSON(CefRefPtr<CefDictionaryValue> dictionary) {
CefRefPtr<CefValue> value = CefValue::Create();
value->SetDictionary(dictionary);
return CefWriteJSON(value, JSON_WRITER_DEFAULT);
}
// Verify that |key| exists in |dictionary| and has type |value_type|. Fails
// |callback| and returns false on failure.
static bool VerifyKey(CefRefPtr<CefDictionaryValue> dictionary,
const char* key,
cef_value_type_t value_type,
CefRefPtr<Callback> callback) {
if (!dictionary->HasKey(key) || dictionary->GetType(key) != value_type) {
callback->Failure(
kMessageFormatError,
"Missing or incorrectly formatted message key: " + std::string(key));
return false;
}
return true;
}
// Apply preferences. Returns true on success. Returns false and sets |error|
// to a descriptive error string on failure. |changed_names| is the list of
// preferences that were successfully changed.
static bool ApplyPrefs(CefRefPtr<CefRequestContext> context,
const std::string& name,
CefRefPtr<CefValue> value,
std::string& error,
NameVector& changed_names) {
if (!name.empty() && context->HasPreference(name)) {
// The preference exists. Set the value.
return SetPref(context, name, value, error, changed_names);
}
if (value->GetType() == VTYPE_DICTIONARY) {
// A dictionary type value that is not an existing preference. Try to set
// each of the elements individually.
CefRefPtr<CefDictionaryValue> dict = value->GetDictionary();
CefDictionaryValue::KeyList keys;
dict->GetKeys(keys);
for (size_t i = 0; i < keys.size(); ++i) {
const std::string& key = keys[i];
const std::string& current_name = name.empty() ? key : name + "." + key;
if (!ApplyPrefs(context, current_name, dict->GetValue(key), error,
changed_names)) {
return false;
}
}
return true;
}
error = "Trying to create an unregistered preference: " + name;
return false;
}
// Set a specific preference value. Returns true if the value is set
// successfully or has not changed. If the value has changed then |name| will
// be added to |changed_names|. Returns false and sets |error| to a
// descriptive error string on failure.
static bool SetPref(CefRefPtr<CefRequestContext> context,
const std::string& name,
CefRefPtr<CefValue> value,
std::string& error,
NameVector& changed_names) {
CefRefPtr<CefValue> existing_value = context->GetPreference(name);
DCHECK(existing_value);
if (value->GetType() == VTYPE_STRING &&
existing_value->GetType() != VTYPE_STRING) {
// Since |value| is coming from JSON all basic types will be represented
// as strings. Convert to the expected data type.
const std::string& string_val = value->GetString();
switch (existing_value->GetType()) {
case VTYPE_BOOL:
if (string_val == "true" || string_val == "1")
value->SetBool(true);
else if (string_val == "false" || string_val == "0")
value->SetBool(false);
break;
case VTYPE_INT:
value->SetInt(atoi(string_val.c_str()));
break;
case VTYPE_DOUBLE:
value->SetInt(atof(string_val.c_str()));
break;
default:
// Other types cannot be converted.
break;
}
}
// Nothing to do if the value hasn't changed.
if (existing_value->IsEqual(value))
return true;
// Attempt to set the preference.
CefString error_str;
if (!context->SetPreference(name, value, error_str)) {
error = error_str.ToString() + ": " + name;
return false;
}
// The preference was set successfully.
changed_names.push_back(name);
return true;
}
DISALLOW_COPY_AND_ASSIGN(Handler);
};
namespace preferences_test {
void CreateMessageHandlers(MessageHandlerSet& handlers) {
handlers.insert(new Handler());
}
}

12
src/CEF/PreferencesTest.h Normal file
View File

@ -0,0 +1,12 @@
// 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.
#pragma once
#include "CEF/TestRunner.h"
namespace preferences_test {
// Create message handlers. Called from test_runner.cc.
void CreateMessageHandlers(MessageHandlerSet& handlers);
}

View File

@ -75,8 +75,6 @@ class BinaryResourceProvider : public CefResourceManager::Provider {
DISALLOW_COPY_AND_ASSIGN(BinaryResourceProvider); DISALLOW_COPY_AND_ASSIGN(BinaryResourceProvider);
}; };
} // namespace
// Implemented in resource_util_win_idmap.cc. // Implemented in resource_util_win_idmap.cc.
extern int GetResourceId(const char* resource_name); extern int GetResourceId(const char* resource_name);

View File

@ -0,0 +1,55 @@
// Copyright (c) 2013 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 <cstring>
#include "CEF/resource.h"
int GetResourceId(const char* resource_name) {
// Map of resource labels to BINARY id values.
static struct _resource_map {
const char* name;
int id;
} resource_map[] = {
{"binding.html", IDS_BINDING_HTML},
{"dialogs.html", IDS_DIALOGS_HTML},
{"draggable.html", IDS_DRAGGABLE_HTML},
{"extensions/set_page_color/icon.png",
IDS_EXTENSIONS_SET_PAGE_COLOR_ICON_PNG},
{"extensions/set_page_color/manifest.json",
IDS_EXTENSIONS_SET_PAGE_COLOR_MANIFEST_JSON},
{"extensions/set_page_color/popup.html",
IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_HTML},
{"extensions/set_page_color/popup.js",
IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_JS},
{"localstorage.html", IDS_LOCALSTORAGE_HTML},
{"logo.png", IDS_LOGO_PNG},
{"media_router.html", IDS_MEDIA_ROUTER_HTML},
{"menu_icon.1x.png", IDS_MENU_ICON_1X_PNG},
{"menu_icon.2x.png", IDS_MENU_ICON_2X_PNG},
{"osr_test.html", IDS_OSRTEST_HTML},
{"other_tests.html", IDS_OTHER_TESTS_HTML},
{"pdf.html", IDS_PDF_HTML},
{"pdf.pdf", IDS_PDF_PDF},
{"performance.html", IDS_PERFORMANCE_HTML},
{"performance2.html", IDS_PERFORMANCE2_HTML},
{"preferences.html", IDS_PREFERENCES_HTML},
{"response_filter.html", IDS_RESPONSE_FILTER_HTML},
{"server.html", IDS_SERVER_HTML},
{"transparency.html", IDS_TRANSPARENCY_HTML},
{"urlrequest.html", IDS_URLREQUEST_HTML},
{"websocket.html", IDS_WEBSOCKET_HTML},
{"window.html", IDS_WINDOW_HTML},
{"window_icon.1x.png", IDS_WINDOW_ICON_1X_PNG},
{"window_icon.2x.png", IDS_WINDOW_ICON_2X_PNG},
{"xmlhttprequest.html", IDS_XMLHTTPREQUEST_HTML},
};
for (size_t i = 0; i < sizeof(resource_map) / sizeof(_resource_map); ++i) {
if (!strcmp(resource_map[i].name, resource_name))
return resource_map[i].id;
}
return 0;
}

View File

@ -0,0 +1,234 @@
// 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 "CEF/ResponseFilterTest.h"
#include <algorithm>
#include <sstream>
#include <string>
#include "include/base/cef_logging.h"
#include "include/cef_command_line.h"
#include "CEF/TestRunner.h"
#include "CEF/HumanAppSwitches.h"
const char kTestUrlPath[] = "/response_filter";
const char kFindString[] = "REPLACE_THIS_STRING";
const char kReplaceString[] = "This is the replaced string!";
// Helper for passing params to Write().
#define WRITE_PARAMS data_out_ptr, data_out_size, data_out_written
// Filter the contents of response_filter.html by replacing all instances of
// |kFindString| with |kReplaceString|. Pass the `--enable-filter-testing`
// command-line flag (which shrinks the buffer size to 32 bytes) to better test
// the logic in this implementation.
class FindReplaceResponseFilter : public CefResponseFilter {
public:
FindReplaceResponseFilter()
: find_match_offset_(0U),
replace_overflow_size_(0U),
replace_count_(0U) {}
bool InitFilter() override {
const size_t find_size = sizeof(kFindString) - 1;
const size_t replace_size = sizeof(kReplaceString) - 1;
// Determine a reasonable amount of space for find/replace overflow. For
// example, the amount of space required if the search string is
// found/replaced 10 times (plus space for the count).
if (replace_size > find_size)
replace_overflow_size_ = (replace_size - find_size + 3) * 10;
return true;
}
FilterStatus Filter(void* data_in,
size_t data_in_size,
size_t& data_in_read,
void* data_out,
size_t data_out_size,
size_t& data_out_written) override {
DCHECK((data_in_size == 0U && !data_in) || (data_in_size > 0U && data_in));
DCHECK_EQ(data_in_read, 0U);
DCHECK(data_out);
DCHECK_GT(data_out_size, 0U);
DCHECK_EQ(data_out_written, 0U);
// All data will be read.
data_in_read = data_in_size;
const size_t find_size = sizeof(kFindString) - 1;
const char* data_in_ptr = static_cast<char*>(data_in);
char* data_out_ptr = static_cast<char*>(data_out);
// Reset the overflow.
std::string old_overflow;
if (!overflow_.empty()) {
old_overflow = overflow_;
overflow_.clear();
}
const size_t likely_out_size =
data_in_size + replace_overflow_size_ + old_overflow.size();
if (data_out_size < likely_out_size) {
// We'll likely need to use the overflow buffer. Size it appropriately.
overflow_.reserve(likely_out_size - data_out_size);
}
if (!old_overflow.empty()) {
// Write the overflow from last time.
Write(old_overflow.c_str(), old_overflow.size(), WRITE_PARAMS);
}
// Evaluate each character in the input buffer. Track how many characters in
// a row match kFindString. If kFindString is completely matched then write
// kReplaceString. Otherwise, write the input characters as-is.
for (size_t i = 0U; i < data_in_size; ++i) {
if (data_in_ptr[i] == kFindString[find_match_offset_]) {
// Matched the next character in the find string.
if (++find_match_offset_ == find_size) {
// Complete match of the find string. Write the replace string.
std::stringstream ss;
ss << ++replace_count_ << ". " << kReplaceString;
const std::string& replace_str = ss.str();
Write(replace_str.c_str(), replace_str.size(), WRITE_PARAMS);
// Start over looking for a match.
find_match_offset_ = 0;
}
continue;
}
// Character did not match the find string.
if (find_match_offset_ > 0) {
// Write the portion of the find string that has matched so far.
Write(kFindString, find_match_offset_, WRITE_PARAMS);
// Start over looking for a match.
find_match_offset_ = 0;
}
// Write the current character.
Write(&data_in_ptr[i], 1, WRITE_PARAMS);
}
// If a match is currently in-progress we need more data. Otherwise, we're
// done.
return find_match_offset_ > 0 ? RESPONSE_FILTER_NEED_MORE_DATA
: RESPONSE_FILTER_DONE;
}
private:
inline void Write(const char* str,
size_t str_size,
char*& data_out_ptr,
size_t data_out_size,
size_t& data_out_written) {
// Number of bytes remaining in the output buffer.
const size_t remaining_space = data_out_size - data_out_written;
// Maximum number of bytes we can write into the output buffer.
const size_t max_write = min(str_size, remaining_space);
// Write the maximum portion that fits in the output buffer.
if (max_write == 1) {
// Small optimization for single character writes.
*data_out_ptr = str[0];
data_out_ptr += 1;
data_out_written += 1;
} else if (max_write > 1) {
memcpy(data_out_ptr, str, max_write);
data_out_ptr += max_write;
data_out_written += max_write;
}
if (max_write < str_size) {
// Need to write more bytes than will fit in the output buffer. Store the
// remainder in the overflow buffer.
overflow_ += std::string(str + max_write, str_size - max_write);
}
}
// The portion of the find string that is currently matching.
size_t find_match_offset_;
// The likely amount of overflow.
size_t replace_overflow_size_;
// Overflow from the output buffer.
std::string overflow_;
// Number of times the the string was found/replaced.
size_t replace_count_;
IMPLEMENT_REFCOUNTING(FindReplaceResponseFilter);
};
// Filter that writes out all of the contents unchanged.
class PassThruResponseFilter : public CefResponseFilter {
public:
PassThruResponseFilter() {}
bool InitFilter() override { return true; }
FilterStatus Filter(void* data_in,
size_t data_in_size,
size_t& data_in_read,
void* data_out,
size_t data_out_size,
size_t& data_out_written) override {
DCHECK((data_in_size == 0U && !data_in) || (data_in_size > 0U && data_in));
DCHECK_EQ(data_in_read, 0U);
DCHECK(data_out);
DCHECK_GT(data_out_size, 0U);
DCHECK_EQ(data_out_written, 0U);
// All data will be read.
data_in_read = data_in_size;
// Write out the contents unchanged.
data_out_written = min(data_in_read, data_out_size);
if (data_out_written > 0)
memcpy(data_out, data_in, data_out_written);
return RESPONSE_FILTER_DONE;
}
private:
IMPLEMENT_REFCOUNTING(PassThruResponseFilter);
};
// Returns true if |url| starts with the value specified via the `--filter-url`
// command-line flag.
bool MatchesFilterURL(const std::string& url) {
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
if (command_line->HasSwitch(kFilterURL)) {
const std::string& filter_url =
command_line->GetSwitchValue(kFilterURL);
return url.find(filter_url) == 0;
}
return false;
}
namespace response_filter_test {
CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) {
// Use the find/replace filter on the test URL.
const std::string& url = request->GetURL();
if (IsTestURL(url, kTestUrlPath))
return new FindReplaceResponseFilter();
if (MatchesFilterURL(url))
return new PassThruResponseFilter();
return nullptr;
}
}

View File

@ -0,0 +1,20 @@
// 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.
#pragma once
#include "include/cef_browser.h"
#include "include/cef_request.h"
#include "include/cef_response.h"
#include "include/cef_response_filter.h"
namespace response_filter_test {
// Create a resource response filter. Called from test_runner.cc.
CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response);
}

View File

@ -50,7 +50,7 @@ class ClientRequestContextHandler : public CefRequestContextHandler,
std::istringstream f(extension_path); std::istringstream f(extension_path);
while (getline(f, part, ';')) { while (getline(f, part, ';')) {
if (!part.empty()) if (!part.empty())
extension_util::LoadExtension(request_context, part, this); LoadExtension(request_context, part, this);
} }
} }
} }
@ -159,7 +159,7 @@ scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsExtension(
base::OnceClosure close_callback, base::OnceClosure close_callback,
bool with_controls, bool with_controls,
bool with_osr) { bool with_osr) {
const std::string& extension_url = extension_util::GetExtensionURL(extension); const std::string& extension_url = GetExtensionURL(extension);
if (extension_url.empty()) { if (extension_url.empty()) {
NOTREACHED() << "Extension cannot be loaded directly."; NOTREACHED() << "Extension cannot be loaded directly.";
return nullptr; return nullptr;
@ -253,7 +253,7 @@ void RootWindowManager::AddExtension(CefRefPtr<CefExtension> extension) {
} }
// Don't track extensions that can't be loaded directly. // Don't track extensions that can't be loaded directly.
if (extension_util::GetExtensionURL(extension).empty()) if (GetExtensionURL(extension).empty())
return; return;
// Don't add the same extension multiple times. // Don't add the same extension multiple times.

View File

@ -8,6 +8,7 @@
#include "CEF/HumanAppContext.h" #include "CEF/HumanAppContext.h"
#include "CEF/RootWindoManager.h" #include "CEF/RootWindoManager.h"
#include "CEF/MainMessageLoop.h"
RootWindowConfig::RootWindowConfig() RootWindowConfig::RootWindowConfig()
: always_on_top(false), : always_on_top(false),

View File

@ -0,0 +1,36 @@
// Copyright (c) 2016 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 "CEF//RootWindow.h"
// #include "CEF/Rroot_window_views.h"
#if defined(OS_WIN)
#include "CEF/RootWindowWin.h"
#elif defined(OS_LINUX)
#include "tests/cefclient/browser/root_window_gtk.h"
#elif defined(OS_MAC)
#include "tests/cefclient/browser/root_window_mac.h"
#endif
namespace client {
// static
scoped_refptr<RootWindow> RootWindow::Create(bool use_views) {
// if (use_views) {
// return new RootWindowViews();
// }
#if defined(OS_WIN)
return new RootWindowWin();
#elif defined(OS_LINUX)
return new RootWindowGtk();
#elif defined(OS_MAC)
return new RootWindowMac();
#else
#error Unsupported platform
#endif
}
} // namespace client

1208
src/CEF/RootWindowWin.cpp Normal file

File diff suppressed because it is too large Load Diff

158
src/CEF/RootWindowWin.h Normal file
View File

@ -0,0 +1,158 @@
// 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.
#pragma once
#include <windows.h>
#include <commdlg.h>
#include <memory>
#include <string>
#include "CEF/BrowserWindow.h"
#include "CEF/RootWindow.h"
// Windows implementation of a top-level native window in the browser process.
// The methods of this class must be called on the main thread unless otherwise
// indicated.
class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
public:
// Constructor may be called on any thread.
RootWindowWin();
~RootWindowWin();
// RootWindow methods.
void Init(RootWindow::Delegate* delegate,
std::unique_ptr<RootWindowConfig> config,
const CefBrowserSettings& settings) override;
void InitAsPopup(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) override;
void Show(ShowMode mode) override;
void Hide() override;
void SetBounds(int x, int y, size_t width, size_t height) override;
void Close(bool force) override;
void SetDeviceScaleFactor(float device_scale_factor) override;
float GetDeviceScaleFactor() const override;
CefRefPtr<CefBrowser> GetBrowser() const override;
ClientWindowHandle GetWindowHandle() const override;
bool WithWindowlessRendering() const override;
bool WithExtension() const override;
private:
void CreateBrowserWindow(const std::string& startup_url);
void CreateRootWindow(const CefBrowserSettings& settings,
bool initially_hidden);
// Register the root window class.
static void RegisterRootClass(HINSTANCE hInstance,
const std::wstring& window_class,
HBRUSH background_brush);
// Window procedure for the edit field.
static LRESULT CALLBACK EditWndProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// Window procedure for the find dialog.
static LRESULT CALLBACK FindWndProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// Window procedure for the root window.
static LRESULT CALLBACK RootWndProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// Event handlers.
void OnPaint();
void OnFocus();
void OnActivate(bool active);
void OnSize(bool minimized);
void OnMove();
void OnDpiChanged(WPARAM wParam, LPARAM lParam);
bool OnEraseBkgnd();
bool OnCommand(UINT id);
void OnFind();
void OnFindEvent();
void OnAbout();
void OnNCCreate(LPCREATESTRUCT lpCreateStruct);
void OnCreate(LPCREATESTRUCT lpCreateStruct);
bool OnClose();
void OnDestroyed();
// BrowserWindow::Delegate methods.
void OnBrowserCreated(CefRefPtr<CefBrowser> browser) override;
void OnBrowserWindowDestroyed() override;
void OnSetAddress(const std::string& url) override;
void OnSetTitle(const std::string& title) override;
void OnSetFullscreen(bool fullscreen) override;
void OnAutoResize(const CefSize& new_size) override;
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) override;
void OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) override;
void NotifyDestroyedIfDone();
// After initialization all members are only accessed on the main thread.
// Members set during initialization.
bool with_controls_;
bool always_on_top_;
bool with_osr_;
bool with_extension_;
bool is_popup_;
RECT start_rect_;
std::unique_ptr<BrowserWindow> browser_window_;
CefBrowserSettings browser_settings_;
bool initialized_;
// Main window.
HWND hwnd_;
// Draggable region.
HRGN draggable_region_;
// Font for buttons and text fields.
HFONT font_;
int font_height_;
// Buttons.
HWND back_hwnd_;
HWND forward_hwnd_;
HWND reload_hwnd_;
HWND stop_hwnd_;
// URL text field.
HWND edit_hwnd_;
WNDPROC edit_wndproc_old_;
// Find dialog.
HWND find_hwnd_;
UINT find_message_id_;
WNDPROC find_wndproc_old_;
// Find dialog state.
FINDREPLACE find_state_;
WCHAR find_buff_[80];
std::wstring find_what_last_;
bool find_next_;
bool find_match_case_last_;
bool window_destroyed_;
bool browser_destroyed_;
bool called_enable_non_client_dpi_scaling_;
DISALLOW_COPY_AND_ASSIGN(RootWindowWin);
};

145
src/CEF/SchemeTest.cpp Normal file
View File

@ -0,0 +1,145 @@
// Copyright (c) 2012 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 "CEF/SchemeTest.h"
#include <algorithm>
#include <string>
#include <math.h>
#include "include/cef_browser.h"
#include "include/cef_callback.h"
#include "include/cef_frame.h"
#include "include/cef_request.h"
#include "include/cef_resource_handler.h"
#include "include/cef_response.h"
#include "include/cef_scheme.h"
#include "include/wrapper/cef_helpers.h"
#include "CEF/TestRunner.h"
#include "CEF/ResourceUtil.h"
// Implementation of the schema handler for client:// requests.
class ClientSchemeHandler : public CefResourceHandler {
public:
ClientSchemeHandler() : offset_(0) {}
bool Open(CefRefPtr<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> callback) override {
DCHECK(!CefCurrentlyOn(TID_UI) && !CefCurrentlyOn(TID_IO));
// The request will be continued or canceled based on the return value.
handle_request = true;
bool handled = false;
std::string url = request->GetURL();
if (strstr(url.c_str(), "handler.html") != nullptr) {
// Build the response html
data_ =
"<html><head><title>Client Scheme Handler</title></head>"
"<body bgcolor=\"white\">"
"This contents of this page page are served by the "
"ClientSchemeHandler class handling the client:// protocol."
"<br/>You should see an image:"
"<br/><img src=\"client://tests/logo.png\"><pre>";
// Output a string representation of the request
const std::string& dump = DumpRequestContents(request);
data_.append(dump);
data_.append(
"</pre><br/>Try the test form:"
"<form method=\"POST\" action=\"handler.html\">"
"<input type=\"text\" name=\"field1\">"
"<input type=\"text\" name=\"field2\">"
"<input type=\"submit\">"
"</form></body></html>");
handled = true;
// Set the resulting mime type
mime_type_ = "text/html";
} else if (strstr(url.c_str(), "logo.png") != nullptr) {
// Load the response image
if (LoadBinaryResource("logo.png", data_)) {
handled = true;
// Set the resulting mime type
mime_type_ = "image/png";
}
}
return handled;
}
void GetResponseHeaders(CefRefPtr<CefResponse> response,
int64& response_length,
CefString& redirectUrl) override {
CEF_REQUIRE_IO_THREAD();
DCHECK(!data_.empty());
response->SetMimeType(mime_type_);
response->SetStatus(200);
// Set the resulting response length
response_length = data_.length();
}
void Cancel() override { CEF_REQUIRE_IO_THREAD(); }
bool Read(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> callback) override {
DCHECK(!CefCurrentlyOn(TID_UI) && !CefCurrentlyOn(TID_IO));
bool has_data = false;
bytes_read = 0;
if (offset_ < data_.length()) {
// Copy the next block of data into the buffer.
int transfer_size =
min(bytes_to_read, static_cast<int>(data_.length() - offset_));
memcpy(data_out, data_.c_str() + offset_, transfer_size);
offset_ += transfer_size;
bytes_read = transfer_size;
has_data = true;
}
return has_data;
}
private:
std::string data_;
std::string mime_type_;
size_t offset_;
IMPLEMENT_REFCOUNTING(ClientSchemeHandler);
DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandler);
};
// Implementation of the factory for for creating schema handlers.
class ClientSchemeHandlerFactory : public CefSchemeHandlerFactory {
public:
ClientSchemeHandlerFactory() {}
// Return a new scheme handler instance to handle the request.
CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& scheme_name,
CefRefPtr<CefRequest> request) override {
CEF_REQUIRE_IO_THREAD();
return new ClientSchemeHandler();
}
IMPLEMENT_REFCOUNTING(ClientSchemeHandlerFactory);
DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerFactory);
};
void RegisterSchemeHandlers() {
CefRegisterSchemeHandlerFactory("client", "tests",
new ClientSchemeHandlerFactory());
}

11
src/CEF/SchemeTest.h Normal file
View File

@ -0,0 +1,11 @@
// Copyright (c) 2009 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.
#pragma once
// Create and register the custom scheme handler. See
// common/scheme_handler_common.h for registration of the custom scheme
// name/type which must occur in all processes. Called from test_runner.cc.
void RegisterSchemeHandlers();

379
src/CEF/ServerTest.cpp Normal file
View File

@ -0,0 +1,379 @@
// Copyright (c) 2017 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 "CEF/ServerTest.h"
#include <algorithm>
#include <memory>
#include <string>
#include "include/base/cef_callback.h"
#include "include/base/cef_weak_ptr.h"
#include "include/cef_parser.h"
#include "include/cef_server.h"
#include "include/wrapper/cef_closure_task.h"
#include "CEF/ResourceUtil.h"
// Application-specific error codes.
const int kMessageFormatError = 1;
const int kActionStateError = 1;
// JSON dictionary keys.
const char kActionKey[] = "action";
const char kResultKey[] = "result";
const char kPortKey[] = "port";
const char kStatusKey[] = "status";
const char kMessageKey[] = "message";
// Required URL for cefQuery execution.
const char kTestUrl[] = "http://tests/server";
// Server default values.
const char kServerAddress[] = "127.0.0.1";
const int kServerPortDefault = 8099;
const int kServerBacklog = 10;
const char kDefaultPath[] = "websocket.html";
// Handles the HTTP/WebSocket server.
class ServerHandler : public CefServerHandler {
public:
using CompleteCallback = base::OnceCallback<void(bool /* success */)>;
ServerHandler() {}
// |complete_callback| will be executed on the UI thread after completion.
void StartServer(int port, CompleteCallback complete_callback) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!server_);
DCHECK(port >= 1025 && port <= 65535);
port_ = port;
complete_callback_ = std::move(complete_callback);
CefServer::CreateServer(kServerAddress, port, kServerBacklog, this);
}
// |complete_callback| will be executed on the UI thread after completion.
void StopServer(CompleteCallback complete_callback) {
CEF_REQUIRE_UI_THREAD();
DCHECK(server_);
complete_callback_ = std::move(complete_callback);
server_->Shutdown();
}
// CefServerHandler methods are called on the server thread.
void OnServerCreated(CefRefPtr<CefServer> server) override {
DCHECK(!server_);
server_ = server;
RunCompleteCallback(server->IsRunning());
}
void OnServerDestroyed(CefRefPtr<CefServer> server) override {
DCHECK(server_);
server_ = nullptr;
RunCompleteCallback(true);
}
void OnClientConnected(CefRefPtr<CefServer> server,
int connection_id) override {}
void OnClientDisconnected(CefRefPtr<CefServer> server,
int connection_id) override {}
void OnHttpRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request) override {
// Parse the request URL and retrieve the path without leading slash.
CefURLParts url_parts;
CefParseURL(request->GetURL(), url_parts);
std::string path = CefString(&url_parts.path);
if (!path.empty() && path[0] == '/')
path = path.substr(1);
if (path.empty())
path = kDefaultPath;
std::string mime_type;
const size_t sep = path.find_last_of(".");
if (sep != std::string::npos) {
// Determine the mime type based on the extension.
mime_type = CefGetMimeType(path.substr(sep + 1));
} else {
// No extension. Assume html.
path += ".html";
}
if (mime_type.empty())
mime_type = "text/html";
CefRefPtr<CefStreamReader> stream;
CefResponse::HeaderMap extra_headers;
if (path == "request.html") {
// Return the request contents.
stream = GetDumpResponse(request, extra_headers);
}
if (!stream) {
// Load any resource supported by cefclient.
stream = GetBinaryResourceReader(path.c_str());
}
if (stream) {
SendHttpResponseStream(server, connection_id, mime_type, stream,
extra_headers);
} else {
server->SendHttp404Response(connection_id);
}
}
void OnWebSocketRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
// Always accept WebSocket connections.
callback->Continue();
}
void OnWebSocketConnected(CefRefPtr<CefServer> server,
int connection_id) override {}
void OnWebSocketMessage(CefRefPtr<CefServer> server,
int connection_id,
const void* data,
size_t data_size) override {
// Echo the reverse of the message.
std::string message(static_cast<const char*>(data), data_size);
std::reverse(message.begin(), message.end());
server->SendWebSocketMessage(connection_id, message.data(), message.size());
}
int port() const { return port_; }
private:
void RunCompleteCallback(bool success) {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::BindOnce(&ServerHandler::RunCompleteCallback,
this, success));
return;
}
if (!complete_callback_.is_null()) {
std::move(complete_callback_).Run(success);
}
}
static void SendHttpResponseStream(CefRefPtr<CefServer> server,
int connection_id,
const std::string& mime_type,
CefRefPtr<CefStreamReader> stream,
CefResponse::HeaderMap extra_headers) {
// Determine the stream size.
stream->Seek(0, SEEK_END);
int64 content_length = stream->Tell();
stream->Seek(0, SEEK_SET);
// Send response headers.
server->SendHttpResponse(connection_id, 200, mime_type, content_length,
extra_headers);
// Send stream contents.
char buffer[8192];
size_t read;
do {
read = stream->Read(buffer, 1, sizeof(buffer));
if (read > 0)
server->SendRawData(connection_id, buffer, read);
} while (!stream->Eof() && read != 0);
// Close the connection.
server->CloseConnection(connection_id);
}
CefRefPtr<CefServer> server_;
// The below members are only accessed on the UI thread.
int port_;
CompleteCallback complete_callback_;
IMPLEMENT_REFCOUNTING(ServerHandler);
DISALLOW_COPY_AND_ASSIGN(ServerHandler);
};
// Handle messages in the browser process.
class Handler : public CefMessageRouterBrowserSide::Handler {
public:
Handler() : weak_ptr_factory_(this) {}
virtual ~Handler() {
if (handler_) {
handler_->StopServer(ServerHandler::CompleteCallback());
handler_ = nullptr;
}
}
// Called due to cefQuery execution in server.html.
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) override {
CEF_REQUIRE_UI_THREAD();
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (url.find(kTestUrl) != 0)
return false;
// Parse |request| as a JSON dictionary.
CefRefPtr<CefDictionaryValue> request_dict = ParseJSON(request);
if (!request_dict) {
callback->Failure(kMessageFormatError, "Incorrect message format");
return true;
}
if (!VerifyKey(request_dict, kActionKey, VTYPE_STRING, callback))
return true;
const std::string& action = request_dict->GetString(kActionKey);
if (action == "query") {
HandleQueryAction(request_dict, callback);
} else if (action == "start") {
HandleStartAction(request_dict, callback);
} else if (action == "stop") {
HandleStopAction(request_dict, callback);
} else {
callback->Failure(kMessageFormatError, "Unrecognized action: " + action);
}
return true;
}
private:
// Return current server status.
void HandleQueryAction(CefRefPtr<CefDictionaryValue> request_dict,
CefRefPtr<Callback> callback) {
CefRefPtr<CefDictionaryValue> result_dict = CefDictionaryValue::Create();
if (handler_) {
result_dict->SetInt(kPortKey, handler_->port());
result_dict->SetString(kStatusKey, "running");
} else {
result_dict->SetInt(kPortKey, kServerPortDefault);
result_dict->SetString(kStatusKey, "stopped");
}
SendResponse(callback, true, result_dict);
}
// Start the server.
void HandleStartAction(CefRefPtr<CefDictionaryValue> request_dict,
CefRefPtr<Callback> callback) {
if (handler_) {
callback->Failure(kActionStateError, "Server is currently running");
return;
}
if (!VerifyKey(request_dict, kPortKey, VTYPE_INT, callback))
return;
const int port = request_dict->GetInt(kPortKey);
if (port < 8000 || port > 65535) {
callback->Failure(kMessageFormatError, "Invalid port number specified");
return;
}
handler_ = new ServerHandler();
// Start the server. OnComplete will be executed upon completion.
handler_->StartServer(
port, base::BindOnce(&Handler::OnStartComplete,
weak_ptr_factory_.GetWeakPtr(), callback));
}
// Stop the server.
void HandleStopAction(CefRefPtr<CefDictionaryValue> request_dict,
CefRefPtr<Callback> callback) {
if (!handler_) {
callback->Failure(kActionStateError, "Server is not currently running");
return;
}
// Stop the server. OnComplete will be executed upon completion.
handler_->StopServer(base::BindOnce(
&Handler::OnStopComplete, weak_ptr_factory_.GetWeakPtr(), callback));
handler_ = nullptr;
}
// Server start completed.
void OnStartComplete(CefRefPtr<Callback> callback, bool success) {
CEF_REQUIRE_UI_THREAD();
CefRefPtr<CefDictionaryValue> result_dict = CefDictionaryValue::Create();
if (!success) {
handler_ = nullptr;
result_dict->SetString(kMessageKey, "Server failed to start.");
}
SendResponse(callback, success, result_dict);
}
// Server stop completed.
void OnStopComplete(CefRefPtr<Callback> callback, bool success) {
CEF_REQUIRE_UI_THREAD();
CefRefPtr<CefDictionaryValue> result_dict = CefDictionaryValue::Create();
if (!success) {
result_dict->SetString(kMessageKey, "Server failed to stop.");
}
SendResponse(callback, success, result_dict);
}
// Send a response in the format expected by server.html.
static void SendResponse(CefRefPtr<Callback> callback,
bool success,
CefRefPtr<CefDictionaryValue> result_dict) {
if (!result_dict) {
result_dict = CefDictionaryValue::Create();
}
result_dict->SetString(kResultKey, success ? "success" : "failure");
CefRefPtr<CefValue> value = CefValue::Create();
value->SetDictionary(result_dict);
const std::string& response = CefWriteJSON(value, JSON_WRITER_DEFAULT);
callback->Success(response);
}
// Convert a JSON string to a dictionary value.
static CefRefPtr<CefDictionaryValue> ParseJSON(const CefString& string) {
CefRefPtr<CefValue> value = CefParseJSON(string, JSON_PARSER_RFC);
if (value.get() && value->GetType() == VTYPE_DICTIONARY)
return value->GetDictionary();
return nullptr;
}
// Verify that |key| exists in |dictionary| and has type |value_type|. Fails
// |callback| and returns false on failure.
static bool VerifyKey(CefRefPtr<CefDictionaryValue> dictionary,
const char* key,
cef_value_type_t value_type,
CefRefPtr<Callback> callback) {
if (!dictionary->HasKey(key) || dictionary->GetType(key) != value_type) {
callback->Failure(
kMessageFormatError,
"Missing or incorrectly formatted message key: " + std::string(key));
return false;
}
return true;
}
// Non-nullptr while the server is running.
CefRefPtr<ServerHandler> handler_;
// Must be the last member.
base::WeakPtrFactory<Handler> weak_ptr_factory_;
};
namespace server_test {
void CreateMessageHandlers(MessageHandlerSet& handlers) {
handlers.insert(new Handler());
}
}

12
src/CEF/ServerTest.h Normal file
View File

@ -0,0 +1,12 @@
// Copyright (c) 2017 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.
#pragma once
#include "CEF/TestRunner.h"
namespace server_test {
// Create message handlers. Called from test_runner.cc.
void CreateMessageHandlers(MessageHandlerSet& handlers);
}

View File

@ -2,7 +2,7 @@
// reserved. Use of this source code is governed by a BSD-style license that // reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file. // can be found in the LICENSE file.
#include "tests/cefclient/browser/test_runner.h" #include "CEF/TestRunner.h"
#include <algorithm> #include <algorithm>
#include <map> #include <map>
@ -15,25 +15,21 @@
#include "include/cef_trace.h" #include "include/cef_trace.h"
#include "include/wrapper/cef_closure_task.h" #include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_stream_resource_handler.h" #include "include/wrapper/cef_stream_resource_handler.h"
#include "tests/cefclient/browser/binding_test.h" #include "CEF/BindingTest.h"
#include "tests/cefclient/browser/client_handler.h" #include "CEF/ClientHandler.h"
#include "tests/cefclient/browser/dialog_test.h" #include "CEF/DialogTest.h"
#include "tests/cefclient/browser/main_context.h" #include "CEF/HumanAppContext.h"
#include "tests/cefclient/browser/media_router_test.h" #include "CEF/MediaRouterTest.h"
#include "tests/cefclient/browser/preferences_test.h" #include "CEF/PreferencesTest.h"
#include "tests/cefclient/browser/resource.h" // #include "CEF/resource.h"
#include "tests/cefclient/browser/response_filter_test.h" #include "CEF/ResponseFilterTest.h"
#include "tests/cefclient/browser/root_window_manager.h" #include "CEF/RootWindoManager.h"
#include "tests/cefclient/browser/scheme_test.h" #include "CEF/SchemeTest.h"
#include "tests/cefclient/browser/server_test.h" #include "CEF/ServerTest.h"
#include "tests/cefclient/browser/urlrequest_test.h" #include "CEF/UrlrequestTest.h"
#include "tests/cefclient/browser/window_test.h" #include "CEF/WindowTest.h"
#include "tests/shared/browser/resource_util.h" #include "CEF/ResourceUtil.h"
namespace client {
namespace test_runner {
namespace {
const char kTestHost[] = "tests"; const char kTestHost[] = "tests";
const char kLocalHost[] = "localhost"; const char kLocalHost[] = "localhost";
@ -153,7 +149,7 @@ void RunNewWindowTest(CefRefPtr<CefBrowser> browser) {
auto config = std::make_unique<RootWindowConfig>(); auto config = std::make_unique<RootWindowConfig>();
config->with_controls = true; config->with_controls = true;
config->with_osr = browser->GetHost()->IsWindowRenderingDisabled(); config->with_osr = browser->GetHost()->IsWindowRenderingDisabled();
MainContext::Get()->GetRootWindowManager()->CreateRootWindow( HumanAppContext::Get()->GetRootWindowManager()->CreateRootWindow(
std::move(config)); std::move(config));
} }
@ -219,7 +215,7 @@ class PromptHandler : public CefMessageRouterBrowserSide::Handler {
if (fps <= 0) { if (fps <= 0) {
// Reset to the default value. // Reset to the default value.
CefBrowserSettings settings; CefBrowserSettings settings;
MainContext::Get()->PopulateBrowserSettings(&settings); HumanAppContext::Get()->PopulateBrowserSettings(&settings);
fps = settings.windowless_frame_rate; fps = settings.windowless_frame_rate;
} }
@ -306,7 +302,7 @@ void EndTracing(CefRefPtr<CefBrowser> browser) {
void RunDialog() { void RunDialog() {
static const char kDefaultFileName[] = "trace.txt"; static const char kDefaultFileName[] = "trace.txt";
std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName); std::string path = HumanAppContext::Get()->GetDownloadPath(kDefaultFileName);
if (path.empty()) if (path.empty())
path = kDefaultFileName; path = kDefaultFileName;
@ -357,7 +353,7 @@ void PrintToPDF(CefRefPtr<CefBrowser> browser) {
void RunDialog() { void RunDialog() {
static const char kDefaultFileName[] = "output.pdf"; static const char kDefaultFileName[] = "output.pdf";
std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName); std::string path = HumanAppContext::Get()->GetDownloadPath(kDefaultFileName);
if (path.empty()) if (path.empty())
path = kDefaultFileName; path = kDefaultFileName;
@ -525,65 +521,64 @@ std::string RequestUrlFilter(const std::string& url) {
return url_base + ".html" + url_suffix; return url_base + ".html" + url_suffix;
} }
} // namespace
void RunTest(CefRefPtr<CefBrowser> browser, int id) { void RunTest(CefRefPtr<CefBrowser> browser, int id) {
if (!browser) if (!browser)
return; return;
//
switch (id) { // switch (id) {
case ID_TESTS_GETSOURCE: // case ID_TESTS_GETSOURCE:
RunGetSourceTest(browser); // RunGetSourceTest(browser);
break; // break;
case ID_TESTS_GETTEXT: // case ID_TESTS_GETTEXT:
RunGetTextTest(browser); // RunGetTextTest(browser);
break; // break;
case ID_TESTS_WINDOW_NEW: // case ID_TESTS_WINDOW_NEW:
RunNewWindowTest(browser); // RunNewWindowTest(browser);
break; // break;
case ID_TESTS_WINDOW_POPUP: // case ID_TESTS_WINDOW_POPUP:
RunPopupWindowTest(browser); // RunPopupWindowTest(browser);
break; // break;
case ID_TESTS_REQUEST: // case ID_TESTS_REQUEST:
RunRequestTest(browser); // RunRequestTest(browser);
break; // break;
case ID_TESTS_ZOOM_IN: // case ID_TESTS_ZOOM_IN:
ModifyZoom(browser, 0.5); // ModifyZoom(browser, 0.5);
break; // break;
case ID_TESTS_ZOOM_OUT: // case ID_TESTS_ZOOM_OUT:
ModifyZoom(browser, -0.5); // ModifyZoom(browser, -0.5);
break; // break;
case ID_TESTS_ZOOM_RESET: // case ID_TESTS_ZOOM_RESET:
browser->GetHost()->SetZoomLevel(0.0); // browser->GetHost()->SetZoomLevel(0.0);
break; // break;
case ID_TESTS_OSR_FPS: // case ID_TESTS_OSR_FPS:
PromptFPS(browser); // PromptFPS(browser);
break; // break;
case ID_TESTS_OSR_DSF: // case ID_TESTS_OSR_DSF:
PromptDSF(browser); // PromptDSF(browser);
break; // break;
case ID_TESTS_TRACING_BEGIN: // case ID_TESTS_TRACING_BEGIN:
BeginTracing(); // BeginTracing();
break; // break;
case ID_TESTS_TRACING_END: // case ID_TESTS_TRACING_END:
EndTracing(browser); // EndTracing(browser);
break; // break;
case ID_TESTS_PRINT: // case ID_TESTS_PRINT:
browser->GetHost()->Print(); // browser->GetHost()->Print();
break; // break;
case ID_TESTS_PRINT_TO_PDF: // case ID_TESTS_PRINT_TO_PDF:
PrintToPDF(browser); // PrintToPDF(browser);
break; // break;
case ID_TESTS_MUTE_AUDIO: // case ID_TESTS_MUTE_AUDIO:
MuteAudio(browser, true); // MuteAudio(browser, true);
break; // break;
case ID_TESTS_UNMUTE_AUDIO: // case ID_TESTS_UNMUTE_AUDIO:
MuteAudio(browser, false); // MuteAudio(browser, false);
break; // break;
case ID_TESTS_OTHER_TESTS: // case ID_TESTS_OTHER_TESTS:
RunOtherTests(browser); // RunOtherTests(browser);
break; // break;
} // }
} }
std::string DumpRequestContents(CefRefPtr<CefRequest> request) { std::string DumpRequestContents(CefRefPtr<CefRequest> request) {
@ -795,7 +790,7 @@ void Alert(CefRefPtr<CefBrowser> browser, const std::string& message) {
if (browser->GetHost()->GetExtension()) { if (browser->GetHost()->GetExtension()) {
// Alerts originating from extension hosts should instead be displayed in // Alerts originating from extension hosts should instead be displayed in
// the active browser. // the active browser.
browser = MainContext::Get()->GetRootWindowManager()->GetActiveBrowser(); browser = HumanAppContext::Get()->GetRootWindowManager()->GetActiveBrowser();
if (!browser) if (!browser)
return; return;
} }
@ -821,45 +816,43 @@ bool IsTestURL(const std::string& url, const std::string& path) {
return url_path.find(path) == 0; return url_path.find(path) == 0;
} }
void CreateMessageHandlers(MessageHandlerSet& handlers) { namespace test_runner {
handlers.insert(new PromptHandler); void CreateMessageHandlers(MessageHandlerSet& handlers) {
handlers.insert(new PromptHandler);
// Create the binding test handlers. // Create the binding test handlers.
binding_test::CreateMessageHandlers(handlers); binding_test::CreateMessageHandlers(handlers);
// Create the dialog test handlers. // Create the dialog test handlers.
dialog_test::CreateMessageHandlers(handlers); dialog_test::CreateMessageHandlers(handlers);
// Create the media router test handlers. // Create the media router test handlers.
media_router_test::CreateMessageHandlers(handlers); media_router_test::CreateMessageHandlers(handlers);
// Create the preferences test handlers. // Create the preferences test handlers.
preferences_test::CreateMessageHandlers(handlers); preferences_test::CreateMessageHandlers(handlers);
// Create the server test handlers. // Create the server test handlers.
server_test::CreateMessageHandlers(handlers); server_test::CreateMessageHandlers(handlers);
// Create the urlrequest test handlers. // Create the urlrequest test handlers.
urlrequest_test::CreateMessageHandlers(handlers); urlrequest_test::CreateMessageHandlers(handlers);
// Create the window test handlers. // Create the window test handlers.
window_test::CreateMessageHandlers(handlers); window_test::CreateMessageHandlers(handlers);
}
void RegisterSchemeHandlers() {
// Register the scheme handler.
RegisterSchemeHandlers();
}
} }
void RegisterSchemeHandlers() {
// Register the scheme handler.
scheme_test::RegisterSchemeHandlers();
}
CefRefPtr<CefResponseFilter> GetResourceResponseFilter( CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
CefRefPtr<CefBrowser> browser, CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request, CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) { CefRefPtr<CefResponse> response) {
// Create the response filter. // Create the response filter.
return response_filter_test::GetResourceResponseFilter(browser, frame, return GetResourceResponseFilter(browser, frame,
request, response); request, response);
} }
} // namespace test_runner
} // namespace client

View File

@ -2,8 +2,7 @@
// reserved. Use of this source code is governed by a BSD-style license that // reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file. // can be found in the LICENSE file.
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_TEST_RUNNER_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_TEST_RUNNER_H_
#pragma once #pragma once
#include <set> #include <set>
@ -14,9 +13,6 @@
#include "include/wrapper/cef_message_router.h" #include "include/wrapper/cef_message_router.h"
#include "include/wrapper/cef_resource_manager.h" #include "include/wrapper/cef_resource_manager.h"
namespace client {
namespace test_runner {
// Run a test. // Run a test.
void RunTest(CefRefPtr<CefBrowser> browser, int id); void RunTest(CefRefPtr<CefBrowser> browser, int id);
@ -51,10 +47,12 @@ bool IsTestURL(const std::string& url, const std::string& path);
// Create all CefMessageRouterBrowserSide::Handler objects. They will be // Create all CefMessageRouterBrowserSide::Handler objects. They will be
// deleted when the ClientHandler is destroyed. // deleted when the ClientHandler is destroyed.
typedef std::set<CefMessageRouterBrowserSide::Handler*> MessageHandlerSet; typedef std::set<CefMessageRouterBrowserSide::Handler*> MessageHandlerSet;
void CreateMessageHandlers(MessageHandlerSet& handlers); namespace test_runner {
void CreateMessageHandlers(MessageHandlerSet& handlers);
// Register scheme handlers for tests. // Register scheme handlers for tests.
void RegisterSchemeHandlers(); void RegisterSchemeHandlers();
}
// Create a resource response filter for tests. // Create a resource response filter for tests.
CefRefPtr<CefResponseFilter> GetResourceResponseFilter( CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
@ -62,8 +60,3 @@ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
CefRefPtr<CefFrame> frame, CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request, CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response); CefRefPtr<CefResponse> response);
} // namespace test_runner
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_TEST_RUNNER_H_

177
src/CEF/UrlrequestTest.cpp Normal file
View File

@ -0,0 +1,177 @@
// 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 "CEF/UrlrequestTest.h"
#include <memory>
#include <string>
#include "include/base/cef_callback.h"
#include "include/base/cef_logging.h"
#include "include/cef_urlrequest.h"
#include "include/wrapper/cef_helpers.h"
#include "CEF/TestRunner.h"
const char kTestUrlPath[] = "/urlrequest";
const char kTestMessageName[] = "URLRequestTest";
// Implementation of CefURLRequestClient that stores response information. Only
// accessed on the UI thread.
class RequestClient : public CefURLRequestClient {
public:
// Callback to be executed on request completion.
using Callback =
base::OnceCallback<void(CefURLRequest::ErrorCode /*error_code*/,
const std::string& /*download_data*/)>;
explicit RequestClient(Callback callback) : callback_(std::move(callback)) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!callback_.is_null());
}
void Detach() {
CEF_REQUIRE_UI_THREAD();
if (!callback_.is_null())
callback_.Reset();
}
void OnRequestComplete(CefRefPtr<CefURLRequest> request) override {
CEF_REQUIRE_UI_THREAD();
if (!callback_.is_null()) {
std::move(callback_).Run(request->GetRequestError(), download_data_);
}
}
void OnUploadProgress(CefRefPtr<CefURLRequest> request,
int64 current,
int64 total) override {}
void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
int64 current,
int64 total) override {}
void OnDownloadData(CefRefPtr<CefURLRequest> request,
const void* data,
size_t data_length) override {
CEF_REQUIRE_UI_THREAD();
download_data_ += std::string(static_cast<const char*>(data), data_length);
}
bool GetAuthCredentials(bool isProxy,
const CefString& host,
int port,
const CefString& realm,
const CefString& scheme,
CefRefPtr<CefAuthCallback> callback) override {
return false;
}
private:
Callback callback_;
std::string download_data_;
IMPLEMENT_REFCOUNTING(RequestClient);
DISALLOW_COPY_AND_ASSIGN(RequestClient);
};
// Handle messages in the browser process. Only accessed on the UI thread.
class Handler : public CefMessageRouterBrowserSide::Handler {
public:
Handler() { CEF_REQUIRE_UI_THREAD(); }
~Handler() { CancelPendingRequest(); }
// Called due to cefQuery execution in urlrequest.html.
bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) override {
CEF_REQUIRE_UI_THREAD();
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (!IsTestURL(url, kTestUrlPath))
return false;
const std::string& message_name = request;
if (message_name.find(kTestMessageName) == 0) {
const std::string& load_url =
message_name.substr(sizeof(kTestMessageName));
CancelPendingRequest();
DCHECK(!callback_.get());
DCHECK(!urlrequest_.get());
callback_ = callback;
// Create a CefRequest for the specified URL.
CefRefPtr<CefRequest> cef_request = CefRequest::Create();
cef_request->SetURL(load_url);
cef_request->SetMethod("GET");
// Callback to be executed on request completion.
// It's safe to use base::Unretained() here because there is only one
// RequestClient pending at any given time and we explicitly detach the
// callback in the Handler destructor.
auto request_callback =
base::BindOnce(&Handler::OnRequestComplete, base::Unretained(this));
// Create and start a new CefURLRequest associated with the frame, so
// that it shares authentication with ClientHandler::GetAuthCredentials.
urlrequest_ = frame->CreateURLRequest(
cef_request, new RequestClient(std::move(request_callback)));
return true;
}
return false;
}
private:
// Cancel the currently pending URL request, if any.
void CancelPendingRequest() {
CEF_REQUIRE_UI_THREAD();
if (urlrequest_.get()) {
// Don't execute the callback when we explicitly cancel the request.
static_cast<RequestClient*>(urlrequest_->GetClient().get())->Detach();
urlrequest_->Cancel();
urlrequest_ = nullptr;
}
if (callback_.get()) {
// Must always execute |callback_| before deleting it.
callback_->Failure(ERR_ABORTED, GetErrorString(ERR_ABORTED));
callback_ = nullptr;
}
}
void OnRequestComplete(CefURLRequest::ErrorCode error_code,
const std::string& download_data) {
CEF_REQUIRE_UI_THREAD();
if (error_code == ERR_NONE)
callback_->Success(download_data);
else
callback_->Failure(error_code, GetErrorString(error_code));
callback_ = nullptr;
urlrequest_ = nullptr;
}
CefRefPtr<Callback> callback_;
CefRefPtr<CefURLRequest> urlrequest_;
DISALLOW_COPY_AND_ASSIGN(Handler);
};
namespace urlrequest_test {
void CreateMessageHandlers(MessageHandlerSet& handlers) {
handlers.insert(new Handler());
}
}

12
src/CEF/UrlrequestTest.h Normal file
View File

@ -0,0 +1,12 @@
// 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.
#pragma once
#include "CEF/TestRunner.h"
namespace urlrequest_test {
// Create message handlers. Called from test_runner.cc.
void CreateMessageHandlers(MessageHandlerSet& handlers);
}

169
src/CEF/UtilWin.cpp Normal file
View File

@ -0,0 +1,169 @@
// 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 "CEF/UtilWin.h"
#include "include/base/cef_logging.h"
LARGE_INTEGER qi_freq_ = {};
uint64_t GetTimeNow() {
if (!qi_freq_.HighPart && !qi_freq_.LowPart) {
QueryPerformanceFrequency(&qi_freq_);
}
LARGE_INTEGER t = {};
QueryPerformanceCounter(&t);
return static_cast<uint64_t>((t.QuadPart / double(qi_freq_.QuadPart)) *
1000000);
}
void SetUserDataPtr(HWND hWnd, void* ptr) {
SetLastError(ERROR_SUCCESS);
LONG_PTR result =
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(ptr));
CHECK(result != 0 || GetLastError() == ERROR_SUCCESS);
}
WNDPROC SetWndProcPtr(HWND hWnd, WNDPROC wndProc) {
WNDPROC old =
reinterpret_cast<WNDPROC>(::GetWindowLongPtr(hWnd, GWLP_WNDPROC));
CHECK(old != nullptr);
LONG_PTR result = ::SetWindowLongPtr(hWnd, GWLP_WNDPROC,
reinterpret_cast<LONG_PTR>(wndProc));
CHECK(result != 0 || GetLastError() == ERROR_SUCCESS);
return old;
}
std::wstring GetResourceString(UINT id) {
#define MAX_LOADSTRING 100
TCHAR buff[MAX_LOADSTRING] = {0};
LoadString(::GetModuleHandle(nullptr), id, buff, MAX_LOADSTRING);
return buff;
}
int GetCefMouseModifiers(WPARAM wparam) {
int modifiers = 0;
if (wparam & MK_CONTROL)
modifiers |= EVENTFLAG_CONTROL_DOWN;
if (wparam & MK_SHIFT)
modifiers |= EVENTFLAG_SHIFT_DOWN;
if (IsKeyDown(VK_MENU))
modifiers |= EVENTFLAG_ALT_DOWN;
if (wparam & MK_LBUTTON)
modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
if (wparam & MK_MBUTTON)
modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
if (wparam & MK_RBUTTON)
modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
// Low bit set from GetKeyState indicates "toggled".
if (::GetKeyState(VK_NUMLOCK) & 1)
modifiers |= EVENTFLAG_NUM_LOCK_ON;
if (::GetKeyState(VK_CAPITAL) & 1)
modifiers |= EVENTFLAG_CAPS_LOCK_ON;
return modifiers;
}
int GetCefKeyboardModifiers(WPARAM wparam, LPARAM lparam) {
int modifiers = 0;
if (IsKeyDown(VK_SHIFT))
modifiers |= EVENTFLAG_SHIFT_DOWN;
if (IsKeyDown(VK_CONTROL))
modifiers |= EVENTFLAG_CONTROL_DOWN;
if (IsKeyDown(VK_MENU))
modifiers |= EVENTFLAG_ALT_DOWN;
// Low bit set from GetKeyState indicates "toggled".
if (::GetKeyState(VK_NUMLOCK) & 1)
modifiers |= EVENTFLAG_NUM_LOCK_ON;
if (::GetKeyState(VK_CAPITAL) & 1)
modifiers |= EVENTFLAG_CAPS_LOCK_ON;
switch (wparam) {
case VK_RETURN:
if ((lparam >> 16) & KF_EXTENDED)
modifiers |= EVENTFLAG_IS_KEY_PAD;
break;
case VK_INSERT:
case VK_DELETE:
case VK_HOME:
case VK_END:
case VK_PRIOR:
case VK_NEXT:
case VK_UP:
case VK_DOWN:
case VK_LEFT:
case VK_RIGHT:
if (!((lparam >> 16) & KF_EXTENDED))
modifiers |= EVENTFLAG_IS_KEY_PAD;
break;
case VK_NUMLOCK:
case VK_NUMPAD0:
case VK_NUMPAD1:
case VK_NUMPAD2:
case VK_NUMPAD3:
case VK_NUMPAD4:
case VK_NUMPAD5:
case VK_NUMPAD6:
case VK_NUMPAD7:
case VK_NUMPAD8:
case VK_NUMPAD9:
case VK_DIVIDE:
case VK_MULTIPLY:
case VK_SUBTRACT:
case VK_ADD:
case VK_DECIMAL:
case VK_CLEAR:
modifiers |= EVENTFLAG_IS_KEY_PAD;
break;
case VK_SHIFT:
if (IsKeyDown(VK_LSHIFT))
modifiers |= EVENTFLAG_IS_LEFT;
else if (IsKeyDown(VK_RSHIFT))
modifiers |= EVENTFLAG_IS_RIGHT;
break;
case VK_CONTROL:
if (IsKeyDown(VK_LCONTROL))
modifiers |= EVENTFLAG_IS_LEFT;
else if (IsKeyDown(VK_RCONTROL))
modifiers |= EVENTFLAG_IS_RIGHT;
break;
case VK_MENU:
if (IsKeyDown(VK_LMENU))
modifiers |= EVENTFLAG_IS_LEFT;
else if (IsKeyDown(VK_RMENU))
modifiers |= EVENTFLAG_IS_RIGHT;
break;
case VK_LWIN:
modifiers |= EVENTFLAG_IS_LEFT;
break;
case VK_RWIN:
modifiers |= EVENTFLAG_IS_RIGHT;
break;
}
return modifiers;
}
bool IsKeyDown(WPARAM wparam) {
return (GetKeyState(wparam) & 0x8000) != 0;
}
float GetDeviceScaleFactor() {
static float scale_factor = 1.0;
static bool initialized = false;
if (!initialized) {
// This value is safe to cache for the life time of the app since the user
// must logout to change the DPI setting. This value also applies to all
// screens.
HDC screen_dc = ::GetDC(nullptr);
int dpi_x = GetDeviceCaps(screen_dc, LOGPIXELSX);
scale_factor = static_cast<float>(dpi_x) / 96.0f;
::ReleaseDC(nullptr, screen_dc);
initialized = true;
}
return scale_factor;
}

36
src/CEF/UtilWin.h Normal file
View File

@ -0,0 +1,36 @@
// 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.
#pragma once
#include <windows.h>
#include <string>
#include "include/internal/cef_types_wrappers.h"
// Returns the current time in microseconds.
uint64_t GetTimeNow();
// Set the window's user data pointer.
void SetUserDataPtr(HWND hWnd, void* ptr);
// Return the window's user data pointer.
template <typename T>
T GetUserDataPtr(HWND hWnd) {
return reinterpret_cast<T>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
}
// Set the window's window procedure pointer and return the old value.
WNDPROC SetWndProcPtr(HWND hWnd, WNDPROC wndProc);
// Return the resource string with the specified id.
std::wstring GetResourceString(UINT id);
int GetCefMouseModifiers(WPARAM wparam);
int GetCefKeyboardModifiers(WPARAM wparam, LPARAM lparam);
bool IsKeyDown(WPARAM wparam);
// Returns the device scale factor. For example, 200% display scaling will
// return 2.0.
float GetDeviceScaleFactor();

114
src/CEF/WindowTest.cpp Normal file
View File

@ -0,0 +1,114 @@
// Copyright (c) 2013 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 "CEF/WindowTest.h"
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include "include/base/cef_callback.h"
#include "include/wrapper/cef_stream_resource_handler.h"
#include "CEF/HumanAppContext.h"
#include "CEF/TestRunner.h"
#include "CEF/WindowTestRunner.h"
#if defined(OS_WIN) || defined(OS_LINUX)
#include "CEF/WindowTestRunnerViews.h"
#endif
#if defined(OS_WIN)
#include "CEF/WindowTestRunnerWin.h"
#elif defined(OS_LINUX)
#include "tests/cefclient/browser/window_test_runner_gtk.h"
#elif defined(OS_MAC)
#include "tests/cefclient/browser/window_test_runner_mac.h"
#endif
const char kTestUrlPath[] = "/window";
const char kMessagePositionName[] = "WindowTest.Position";
const char kMessageMinimizeName[] = "WindowTest.Minimize";
const char kMessageMaximizeName[] = "WindowTest.Maximize";
const char kMessageRestoreName[] = "WindowTest.Restore";
// Create the appropriate platform test runner object.
std::unique_ptr<WindowTestRunner> CreateWindowTestRunner() {
#if defined(OS_WIN) || defined(OS_LINUX)
if (HumanAppContext::Get()->UseViews())
return std::make_unique<WindowTestRunnerViews>();
#endif
#if defined(OS_WIN)
return std::make_unique<WindowTestRunnerWin>();
#elif defined(OS_LINUX)
return std::make_unique<WindowTestRunnerGtk>();
#elif defined(OS_MAC)
return std::make_unique<WindowTestRunnerMac>();
#else
#error "No implementation available for your platform."
#endif
}
// Handle messages in the browser process.
class Handler : public CefMessageRouterBrowserSide::Handler {
public:
Handler() : runner_(CreateWindowTestRunner()) {}
// Called due to cefBroadcast execution in window.html.
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) override {
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (!IsTestURL(url, kTestUrlPath))
return false;
const std::string& message_name = request;
if (message_name.find(kMessagePositionName) == 0) {
// Parse the comma-delimited list of integer values.
std::vector<int> vec;
const std::string& vals =
message_name.substr(sizeof(kMessagePositionName));
std::stringstream ss(vals);
int i;
while (ss >> i) {
vec.push_back(i);
if (ss.peek() == ',')
ss.ignore();
}
if (vec.size() == 4) {
// Execute SetPos() on the main thread.
runner_->SetPos(browser, vec[0], vec[1], vec[2], vec[3]);
}
} else if (message_name == kMessageMinimizeName) {
// Execute Minimize() on the main thread.
runner_->Minimize(browser);
} else if (message_name == kMessageMaximizeName) {
// Execute Maximize() on the main thread.
runner_->Maximize(browser);
} else if (message_name == kMessageRestoreName) {
// Execute Restore() on the main thread.
runner_->Restore(browser);
} else {
NOTREACHED();
}
callback->Success("");
return true;
}
private:
std::unique_ptr<WindowTestRunner> runner_;
};
namespace window_test {
void CreateMessageHandlers(MessageHandlerSet& handlers) {
handlers.insert(new Handler());
}
}

12
src/CEF/WindowTest.h Normal file
View File

@ -0,0 +1,12 @@
// Copyright (c) 2013 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.
#pragma once
#include "CEF/TestRunner.h"
namespace window_test {
// Create message handlers. Called from test_runner.cc.
void CreateMessageHandlers(MessageHandlerSet& handlers);
}

View File

@ -0,0 +1,28 @@
// Copyright (c) 2016 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 "CEF/WindowTestRunner.h"
// static
void WindowTestRunner::ModifyBounds(const CefRect& display, CefRect& window) {
window.x += display.x;
window.y += display.y;
if (window.x < display.x)
window.x = display.x;
if (window.y < display.y)
window.y = display.y;
if (window.width < 100)
window.width = 100;
else if (window.width >= display.width)
window.width = display.width;
if (window.height < 100)
window.height = 100;
else if (window.height >= display.height)
window.height = display.height;
if (window.x + window.width >= display.x + display.width)
window.x = display.x + display.width - window.width;
if (window.y + window.height >= display.y + display.height)
window.y = display.y + display.height - window.height;
}

View File

@ -0,0 +1,27 @@
// Copyright (c) 2016 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.
#pragma once
#include "include/cef_browser.h"
// Implement this interface for different platforms. Methods will be called on
// the browser process UI thread unless otherwise indicated.
class WindowTestRunner {
public:
virtual void SetPos(CefRefPtr<CefBrowser> browser,
int x,
int y,
int width,
int height) = 0;
virtual void Minimize(CefRefPtr<CefBrowser> browser) = 0;
virtual void Maximize(CefRefPtr<CefBrowser> browser) = 0;
virtual void Restore(CefRefPtr<CefBrowser> browser) = 0;
// Fit |window| inside |display|. Coordinates are relative to the upper-left
// corner of the display.
static void ModifyBounds(const CefRect& display, CefRect& window);
virtual ~WindowTestRunner() {}
};

View File

@ -0,0 +1,51 @@
// Copyright (c) 2016 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 "CEF/WindowTestRunnerViews.h"
#include "include/views/cef_browser_view.h"
#include "include/views/cef_display.h"
#include "include/views/cef_window.h"
#include "include/wrapper/cef_helpers.h"
CefRefPtr<CefWindow> GetWindow(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
DCHECK(browser->GetHost()->HasView());
CefRefPtr<CefBrowserView> browser_view =
CefBrowserView::GetForBrowser(browser);
DCHECK(browser_view.get());
CefRefPtr<CefWindow> window = browser_view->GetWindow();
DCHECK(window.get());
return window;
}
WindowTestRunnerViews::WindowTestRunnerViews() {}
void WindowTestRunnerViews::SetPos(CefRefPtr<CefBrowser> browser,
int x,
int y,
int width,
int height) {
CefRefPtr<CefWindow> window = GetWindow(browser);
CefRect window_bounds(x, y, width, height);
ModifyBounds(window->GetDisplay()->GetWorkArea(), window_bounds);
window->SetBounds(window_bounds);
}
void WindowTestRunnerViews::Minimize(CefRefPtr<CefBrowser> browser) {
GetWindow(browser)->Minimize();
}
void WindowTestRunnerViews::Maximize(CefRefPtr<CefBrowser> browser) {
GetWindow(browser)->Maximize();
}
void WindowTestRunnerViews::Restore(CefRefPtr<CefBrowser> browser) {
GetWindow(browser)->Restore();
}

View File

@ -0,0 +1,22 @@
// Copyright (c) 2016 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.
#pragma once
#include "CEF/WindowTestRunner.h"
// Views platform implementation.
class WindowTestRunnerViews : public WindowTestRunner {
public:
WindowTestRunnerViews();
void SetPos(CefRefPtr<CefBrowser> browser,
int x,
int y,
int width,
int height) override;
void Minimize(CefRefPtr<CefBrowser> browser) override;
void Maximize(CefRefPtr<CefBrowser> browser) override;
void Restore(CefRefPtr<CefBrowser> browser) override;
};

View File

@ -0,0 +1,129 @@
// Copyright (c) 2013 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 "CEF/WindowTestRunnerWin.h"
#include "CEF/MainMessageLoop.h"
HWND GetRootHwnd(CefRefPtr<CefBrowser> browser) {
return ::GetAncestor(browser->GetHost()->GetWindowHandle(), GA_ROOT);
}
// Toggles the current display state.
void Toggle(HWND root_hwnd, UINT nCmdShow) {
// Retrieve current window placement information.
WINDOWPLACEMENT placement;
::GetWindowPlacement(root_hwnd, &placement);
if (placement.showCmd == nCmdShow)
::ShowWindow(root_hwnd, SW_RESTORE);
else
::ShowWindow(root_hwnd, nCmdShow);
}
void SetPosImpl(CefRefPtr<CefBrowser> browser,
int x,
int y,
int width,
int height) {
HWND root_hwnd = GetRootHwnd(browser);
if (!root_hwnd)
return;
// Retrieve current window placement information.
WINDOWPLACEMENT placement;
::GetWindowPlacement(root_hwnd, &placement);
// Retrieve information about the display that contains the window.
HMONITOR monitor =
MonitorFromRect(&placement.rcNormalPosition, MONITOR_DEFAULTTONEAREST);
MONITORINFO info;
info.cbSize = sizeof(info);
GetMonitorInfo(monitor, &info);
// Make sure the window is inside the display.
CefRect display_rect(info.rcWork.left, info.rcWork.top,
info.rcWork.right - info.rcWork.left,
info.rcWork.bottom - info.rcWork.top);
CefRect window_rect(x, y, width, height);
WindowTestRunner::ModifyBounds(display_rect, window_rect);
if (placement.showCmd == SW_MINIMIZE || placement.showCmd == SW_MAXIMIZE) {
// The window is currently minimized or maximized. Restore it to the desired
// position.
placement.rcNormalPosition.left = window_rect.x;
placement.rcNormalPosition.right = window_rect.x + window_rect.width;
placement.rcNormalPosition.top = window_rect.y;
placement.rcNormalPosition.bottom = window_rect.y + window_rect.height;
::SetWindowPlacement(root_hwnd, &placement);
::ShowWindow(root_hwnd, SW_RESTORE);
} else {
// Set the window position.
::SetWindowPos(root_hwnd, nullptr, window_rect.x, window_rect.y,
window_rect.width, window_rect.height, SWP_NOZORDER);
}
}
void MinimizeImpl(CefRefPtr<CefBrowser> browser) {
HWND root_hwnd = GetRootHwnd(browser);
if (!root_hwnd)
return;
Toggle(root_hwnd, SW_MINIMIZE);
}
void MaximizeImpl(CefRefPtr<CefBrowser> browser) {
HWND root_hwnd = GetRootHwnd(browser);
if (!root_hwnd)
return;
Toggle(root_hwnd, SW_MAXIMIZE);
}
void RestoreImpl(CefRefPtr<CefBrowser> browser) {
HWND root_hwnd = GetRootHwnd(browser);
if (!root_hwnd)
return;
::ShowWindow(root_hwnd, SW_RESTORE);
}
WindowTestRunnerWin::WindowTestRunnerWin() {}
void WindowTestRunnerWin::SetPos(CefRefPtr<CefBrowser> browser,
int x,
int y,
int width,
int height) {
if (CURRENTLY_ON_MAIN_THREAD()) {
SetPosImpl(browser, x, y, width, height);
} else {
// Execute on the main application thread.
MAIN_POST_CLOSURE(base::BindOnce(SetPosImpl, browser, x, y, width, height));
}
}
void WindowTestRunnerWin::Minimize(CefRefPtr<CefBrowser> browser) {
if (CURRENTLY_ON_MAIN_THREAD()) {
MinimizeImpl(browser);
} else {
// Execute on the main application thread.
MAIN_POST_CLOSURE(base::BindOnce(MinimizeImpl, browser));
}
}
void WindowTestRunnerWin::Maximize(CefRefPtr<CefBrowser> browser) {
if (CURRENTLY_ON_MAIN_THREAD()) {
MaximizeImpl(browser);
} else {
// Execute on the main application thread.
MAIN_POST_CLOSURE(base::BindOnce(MaximizeImpl, browser));
}
}
void WindowTestRunnerWin::Restore(CefRefPtr<CefBrowser> browser) {
if (CURRENTLY_ON_MAIN_THREAD()) {
RestoreImpl(browser);
} else {
// Execute on the main application thread.
MAIN_POST_CLOSURE(base::BindOnce(RestoreImpl, browser));
}
}

View File

@ -0,0 +1,23 @@
// Copyright (c) 2016 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.
#pragma once
#include "CEF/WindowTestRunner.h"
// Windows platform implementation. Methods are safe to call on any browser
// process thread.
class WindowTestRunnerWin : public WindowTestRunner {
public:
WindowTestRunnerWin();
void SetPos(CefRefPtr<CefBrowser> browser,
int x,
int y,
int width,
int height) override;
void Minimize(CefRefPtr<CefBrowser> browser) override;
void Maximize(CefRefPtr<CefBrowser> browser) override;
void Restore(CefRefPtr<CefBrowser> browser) override;
};

86
src/CEF/resource.h Normal file
View File

@ -0,0 +1,86 @@
// Copyright (c) 2013 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.
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by cefclient.rc
//
#define BINARY 256
#define IDC_MYICON 2
#define IDD_CEFCLIENT_DIALOG 102
#define IDS_APP_TITLE 103
#define IDD_ABOUTBOX 103
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDI_CEFCLIENT 107
#define IDI_SMALL 108
#define IDC_CEFCLIENT 109
#define IDR_MAINFRAME 128
#define IDC_NAV_BACK 200
#define IDC_NAV_FORWARD 201
#define IDC_NAV_RELOAD 202
#define IDC_NAV_STOP 203
#define ID_QUIT 32500
#define ID_FIND 32501
#define ID_TESTS_FIRST 32700
#define ID_TESTS_GETSOURCE 32700
#define ID_TESTS_GETTEXT 32701
#define ID_TESTS_OTHER_TESTS 32702
#define ID_TESTS_WINDOW_NEW 32703
#define ID_TESTS_WINDOW_POPUP 32704
#define ID_TESTS_PRINT 32705
#define ID_TESTS_REQUEST 32706
#define ID_TESTS_TRACING_BEGIN 32707
#define ID_TESTS_TRACING_END 32708
#define ID_TESTS_ZOOM_IN 32709
#define ID_TESTS_ZOOM_OUT 32710
#define ID_TESTS_ZOOM_RESET 32711
#define ID_TESTS_OSR_FPS 32712
#define ID_TESTS_OSR_DSF 32713
#define ID_TESTS_PRINT_TO_PDF 32714
#define ID_TESTS_MUTE_AUDIO 32715
#define ID_TESTS_UNMUTE_AUDIO 32716
#define ID_TESTS_LAST 32716
#define IDC_STATIC -1
#define IDS_BINDING_HTML 1000
#define IDS_DIALOGS_HTML 1001
#define IDS_DRAGGABLE_HTML 1002
#define IDS_LOCALSTORAGE_HTML 1003
#define IDS_LOGO_PNG 1004
#define IDS_MEDIA_ROUTER_HTML 1005
#define IDS_MENU_ICON_1X_PNG 1006
#define IDS_MENU_ICON_2X_PNG 1007
#define IDS_OSRTEST_HTML 1008
#define IDS_OTHER_TESTS_HTML 1009
#define IDS_PDF_HTML 1010
#define IDS_PDF_PDF 1011
#define IDS_PERFORMANCE_HTML 1012
#define IDS_PERFORMANCE2_HTML 1013
#define IDS_PREFERENCES_HTML 1014
#define IDS_RESPONSE_FILTER_HTML 1015
#define IDS_SERVER_HTML 1016
#define IDS_TRANSPARENCY_HTML 1017
#define IDS_URLREQUEST_HTML 1018
#define IDS_WEBSOCKET_HTML 1019
#define IDS_WINDOW_HTML 1020
#define IDS_WINDOW_ICON_1X_PNG 1021
#define IDS_WINDOW_ICON_2X_PNG 1022
#define IDS_XMLHTTPREQUEST_HTML 1023
#define IDS_EXTENSIONS_SET_PAGE_COLOR_ICON_PNG 1030
#define IDS_EXTENSIONS_SET_PAGE_COLOR_MANIFEST_JSON 1031
#define IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_HTML 1032
#define IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_JS 1033
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 130
#define _APS_NEXT_COMMAND_VALUE 32774
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 111
#endif
#endif