add cef window test
This commit is contained in:
parent
79f86c0931
commit
e9604915d9
49
src/CEF/BindingTest.cpp
Normal file
49
src/CEF/BindingTest.cpp
Normal 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
12
src/CEF/BindingTest.h
Normal 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
92
src/CEF/BrowserWindow.cpp
Normal 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
139
src/CEF/BrowserWindow.h
Normal 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);
|
||||
};
|
||||
|
125
src/CEF/BrowserWindowOsrWin.cpp
Normal file
125
src/CEF/BrowserWindowOsrWin.cpp
Normal 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;
|
||||
}
|
61
src/CEF/BrowserWindowOsrWin.h
Normal file
61
src/CEF/BrowserWindowOsrWin.h
Normal 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);
|
||||
};
|
||||
|
120
src/CEF/BrowserWindowStdWin.cpp
Normal file
120
src/CEF/BrowserWindowStdWin.cpp
Normal 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
|
51
src/CEF/BrowserWindowStdWin.h
Normal file
51
src/CEF/BrowserWindowStdWin.h
Normal 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_
|
@ -21,7 +21,7 @@
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "CEF/HumanAppContext.h"
|
||||
#include "CEF/RootWindoManager.h"
|
||||
//#include "tests/cefclient/browser/test_runner.h"
|
||||
#include "CEF/TestRunner.h"
|
||||
#include "CEF/ExtensionUtil.h"
|
||||
#include "CEF/ResourceUtil.h"
|
||||
#include "CEF/HumanAppSwitches.h"
|
||||
@ -157,14 +157,14 @@ void LoadErrorPage(CefRefPtr<CefFrame> frame,
|
||||
"<h3>Page failed to load.</h3>"
|
||||
"URL: <a href=\""
|
||||
<< failed_url << "\">" << failed_url
|
||||
<< "</a><br/>Error: " << test_runner::GetErrorString(error_code) << " ("
|
||||
<< "</a><br/>Error: " << GetErrorString(error_code) << " ("
|
||||
<< error_code << ")";
|
||||
|
||||
if (!other_info.empty())
|
||||
ss << "<br/>" << other_info;
|
||||
|
||||
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.
|
||||
@ -220,8 +220,6 @@ std::string GetCertificateInformation(CefRefPtr<CefX509Certificate> cert,
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class ClientDownloadImageCallback : public CefDownloadImageCallback {
|
||||
public:
|
||||
explicit ClientDownloadImageCallback(CefRefPtr<ClientHandler> client_handler)
|
||||
@ -251,21 +249,21 @@ ClientHandler::ClientHandler(Delegate* delegate,
|
||||
download_favicon_images_(false),
|
||||
delegate_(delegate),
|
||||
browser_count_(0),
|
||||
console_log_file_(MainContext::Get()->GetConsoleLogPath()),
|
||||
console_log_file_(HumanAppContext::Get()->GetConsoleLogPath()),
|
||||
first_console_message_(true),
|
||||
focus_on_editable_field_(false),
|
||||
initial_navigation_(true) {
|
||||
DCHECK(!console_log_file_.empty());
|
||||
|
||||
resource_manager_ = new CefResourceManager();
|
||||
test_runner::SetupResourceManager(resource_manager_, &string_resource_map_);
|
||||
SetupResourceManager(resource_manager_, &string_resource_map_);
|
||||
|
||||
// Read command line settings.
|
||||
CefRefPtr<CefCommandLine> command_line =
|
||||
CefCommandLine::GetGlobalCommandLine();
|
||||
mouse_cursor_change_disabled_ =
|
||||
command_line->HasSwitch(switches::kMouseCursorChangeDisabled);
|
||||
offline_ = command_line->HasSwitch(switches::kOffline);
|
||||
command_line->HasSwitch(kMouseCursorChangeDisabled);
|
||||
offline_ = command_line->HasSwitch(kOffline);
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
// Optionally use the client-provided dialog implementation.
|
||||
@ -337,7 +335,7 @@ bool ClientHandler::OnChromeCommand(CefRefPtr<CefBrowser> browser,
|
||||
int command_id,
|
||||
cef_window_open_disposition_t disposition) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
DCHECK(MainContext::Get()->UseChromeRuntime());
|
||||
DCHECK(HumanAppContext::Get()->UseChromeRuntime());
|
||||
|
||||
if (!with_controls_ &&
|
||||
(disposition != WOD_CURRENT_TAB || !IsAllowedCommandId(command_id))) {
|
||||
@ -358,7 +356,7 @@ void ClientHandler::OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefMenuModel> model) {
|
||||
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_) {
|
||||
// Remove all disallowed menu items.
|
||||
FilterMenuModel(model);
|
||||
@ -507,7 +505,7 @@ bool ClientHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser,
|
||||
fclose(file);
|
||||
|
||||
if (first_console_message_) {
|
||||
test_runner::Alert(
|
||||
Alert(
|
||||
browser, "Console messages written to \"" + console_log_file_ + "\"");
|
||||
first_console_message_ = false;
|
||||
}
|
||||
@ -557,7 +555,7 @@ void ClientHandler::OnBeforeDownload(
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
// 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(
|
||||
@ -567,7 +565,7 @@ void ClientHandler::OnDownloadUpdated(
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (download_item->IsComplete()) {
|
||||
test_runner::Alert(browser, "File \"" +
|
||||
Alert(browser, "File \"" +
|
||||
download_item->GetFullPath().ToString() +
|
||||
"\" downloaded successfully.");
|
||||
}
|
||||
@ -580,7 +578,7 @@ bool ClientHandler::OnDragEnter(CefRefPtr<CefBrowser> browser,
|
||||
|
||||
// Forbid dragging of URLs and files.
|
||||
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;
|
||||
}
|
||||
|
||||
@ -609,7 +607,7 @@ bool ClientHandler::OnSetFocus(CefRefPtr<CefBrowser> browser,
|
||||
if (initial_navigation_) {
|
||||
CefRefPtr<CefCommandLine> command_line =
|
||||
CefCommandLine::GetGlobalCommandLine();
|
||||
if (command_line->HasSwitch(switches::kNoActivate)) {
|
||||
if (command_line->HasSwitch(kNoActivate)) {
|
||||
// Don't give focus to the browser on creation.
|
||||
return true;
|
||||
}
|
||||
@ -687,9 +685,9 @@ void ClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
||||
CefSize(1000, 1000));
|
||||
|
||||
CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
|
||||
if (extension_util::IsInternalExtension(extension->GetPath())) {
|
||||
if (IsInternalExtension(extension->GetPath())) {
|
||||
// Register the internal handler for extension resources.
|
||||
extension_util::AddInternalExtensionToResourceManager(extension,
|
||||
AddInternalExtensionToResourceManager(extension,
|
||||
resource_manager_);
|
||||
}
|
||||
}
|
||||
@ -785,7 +783,7 @@ bool ClientHandler::OnOpenURLFromTab(
|
||||
config->with_controls = with_controls_;
|
||||
config->with_osr = is_osr_;
|
||||
config->url = target_url;
|
||||
MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
|
||||
HumanAppContext::Get()->GetRootWindowManager()->CreateRootWindow(
|
||||
std::move(config));
|
||||
return true;
|
||||
}
|
||||
@ -883,12 +881,12 @@ bool ClientHandler::OnSelectClientCertificate(
|
||||
|
||||
CefRefPtr<CefCommandLine> command_line =
|
||||
CefCommandLine::GetGlobalCommandLine();
|
||||
if (!command_line->HasSwitch(switches::kSslClientCertificate)) {
|
||||
if (!command_line->HasSwitch(kSslClientCertificate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string& cert_name =
|
||||
command_line->GetSwitchValue(switches::kSslClientCertificate);
|
||||
command_line->GetSwitchValue(kSslClientCertificate);
|
||||
|
||||
if (cert_name.empty()) {
|
||||
callback->Select(nullptr);
|
||||
@ -977,7 +975,7 @@ CefRefPtr<CefResponseFilter> ClientHandler::GetResourceResponseFilter(
|
||||
CefRefPtr<CefResponse> response) {
|
||||
CEF_REQUIRE_IO_THREAD();
|
||||
|
||||
return test_runner::GetResourceResponseFilter(browser, frame, request,
|
||||
return GetResourceResponseFilter(browser, frame, request,
|
||||
response);
|
||||
}
|
||||
|
||||
@ -1012,7 +1010,7 @@ void ClientHandler::ShowDevTools(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefClient> client;
|
||||
CefBrowserSettings settings;
|
||||
|
||||
MainContext::Get()->PopulateBrowserSettings(&settings);
|
||||
HumanAppContext::Get()->PopulateBrowserSettings(&settings);
|
||||
|
||||
CefRefPtr<CefBrowserHost> host = browser->GetHost();
|
||||
|
||||
@ -1086,8 +1084,8 @@ void ClientHandler::ShowSSLInformation(CefRefPtr<CefBrowser> browser) {
|
||||
auto config = std::make_unique<RootWindowConfig>();
|
||||
config->with_controls = false;
|
||||
config->with_osr = is_osr_;
|
||||
config->url = test_runner::GetDataURI(ss.str(), "text/html");
|
||||
MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
|
||||
config->url = GetDataURI(ss.str(), "text/html");
|
||||
HumanAppContext::Get()->GetRootWindowManager()->CreateRootWindow(
|
||||
std::move(config));
|
||||
}
|
||||
|
||||
@ -1112,7 +1110,7 @@ bool ClientHandler::CreatePopupWindow(CefRefPtr<CefBrowser> browser,
|
||||
|
||||
// The popup browser will be parented to a new native window.
|
||||
// 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,
|
||||
client, settings);
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "include/wrapper/cef_message_router.h"
|
||||
#include "include/wrapper/cef_resource_manager.h"
|
||||
#include "CEF/HumanApptypes.h"
|
||||
//#include "tests/cefclient/browser/test_runner.h"
|
||||
#include "CEf/TestRunner.h"
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
#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.
|
||||
// Only accessed on the IO thread.
|
||||
//test_runner::StringResourceMap string_resource_map_;
|
||||
StringResourceMap string_resource_map_;
|
||||
|
||||
// MAIN THREAD MEMBERS
|
||||
// The following members will only be accessed on the main thread. This will
|
||||
|
@ -2,14 +2,12 @@
|
||||
// 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/client_handler_osr.h"
|
||||
#include "CEF/ClientHandlerOSR.h"
|
||||
|
||||
#include "include/base/cef_callback.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
ClientHandlerOsr::ClientHandlerOsr(Delegate* delegate,
|
||||
OsrDelegate* osr_delegate,
|
||||
bool with_controls,
|
||||
@ -182,5 +180,3 @@ void ClientHandlerOsr::OnAccessibilityLocationChange(
|
||||
return;
|
||||
osr_delegate_->UpdateAccessibilityLocation(value);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@ -2,13 +2,9 @@
|
||||
// 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_CLIENT_HANDLER_OSR_H_
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_OSR_H_
|
||||
#pragma once
|
||||
|
||||
#include "tests/cefclient/browser/client_handler.h"
|
||||
|
||||
namespace client {
|
||||
#include "CEF/ClientHandler.h"
|
||||
|
||||
// Client handler implementation for windowless browsers. There will only ever
|
||||
// be one browser per handler instance.
|
||||
@ -146,7 +142,3 @@ class ClientHandlerOsr : public ClientHandler,
|
||||
IMPLEMENT_REFCOUNTING(ClientHandlerOsr);
|
||||
DISALLOW_COPY_AND_ASSIGN(ClientHandlerOsr);
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_OSR_H_
|
||||
|
@ -2,13 +2,9 @@
|
||||
// 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/client_handler_std.h"
|
||||
|
||||
namespace client {
|
||||
#include "CEF/ClientHandlerStd.h"
|
||||
|
||||
ClientHandlerStd::ClientHandlerStd(Delegate* delegate,
|
||||
bool with_controls,
|
||||
const std::string& startup_url)
|
||||
: ClientHandler(delegate, /*is_osr=*/false, with_controls, startup_url) {}
|
||||
|
||||
} // namespace client
|
||||
|
@ -2,13 +2,9 @@
|
||||
// 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_CLIENT_HANDLER_STD_H_
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_STD_H_
|
||||
#pragma once
|
||||
|
||||
#include "tests/cefclient/browser/client_handler.h"
|
||||
|
||||
namespace client {
|
||||
#include "CEF/ClientHandler.h"
|
||||
|
||||
// Client handler implementation for windowed browsers. There will only ever be
|
||||
// one browser per handler instance.
|
||||
@ -23,7 +19,3 @@ class ClientHandlerStd : public ClientHandler {
|
||||
IMPLEMENT_REFCOUNTING(ClientHandlerStd);
|
||||
DISALLOW_COPY_AND_ASSIGN(ClientHandlerStd);
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_STD_H_
|
||||
|
168
src/CEF/DialogTest.cpp
Normal file
168
src/CEF/DialogTest.cpp
Normal 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
12
src/CEF/DialogTest.h
Normal 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);
|
||||
}
|
@ -48,7 +48,7 @@ bool ReadFileToString(const std::string& path,
|
||||
// Hence, the file is read sequentially as opposed to a one-shot read.
|
||||
while ((len = fread(buf.get(), 1, kBufferSize, file)) > 0) {
|
||||
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) {
|
||||
read_status = false;
|
||||
|
@ -22,7 +22,7 @@ extern const char kPathSep;
|
||||
// threads is not allowed.
|
||||
bool ReadFileToString(const std::string& path,
|
||||
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
|
||||
// previously there. Returns the number of bytes written, or -1 on error.
|
||||
|
34
src/CEF/GeometryUtil.cpp
Normal file
34
src/CEF/GeometryUtil.cpp
Normal 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
16
src/CEF/GeometryUtil.h
Normal 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);
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "HumanAppContext.h"
|
||||
#include "include/cef_browser.h"
|
||||
#include "include/cef_command_line.h"
|
||||
#include "include/views/cef_browser_view.h"
|
||||
@ -46,7 +47,7 @@ public:
|
||||
CefRefPtr<HumanAppBrowser> app,
|
||||
CefRefPtr<CefCommandLine> command_line) override {
|
||||
// Append Chromium command line parameters if touch events are enabled
|
||||
if (MainContext::Get()->TouchEventsEnabled())
|
||||
if (HumanAppContext::Get()->TouchEventsEnabled())
|
||||
command_line->AppendSwitchWithValue("touch-events", "enabled");
|
||||
}
|
||||
|
||||
|
36
src/CEF/HumanAppContentImplWin.cpp
Normal file
36
src/CEF/HumanAppContentImplWin.cpp
Normal 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;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "include/cef_parser.h"
|
||||
#include "CEF/HumanAppBrowser.h"
|
||||
#include "CEF/HumanAppSwitches.h"
|
||||
#include "CEF/RootWindoManager.h"
|
||||
|
||||
// The default URL to load in a browser window.
|
||||
const char kDefaultUrl[] = "http://www.google.com";
|
||||
|
@ -2,19 +2,13 @@
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// 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/wrapper/cef_closure_task.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
namespace {
|
||||
|
||||
MainMessageLoop* g_main_message_loop = nullptr;
|
||||
|
||||
} // namespace
|
||||
|
||||
MainMessageLoop::MainMessageLoop() {
|
||||
DCHECK(!g_main_message_loop);
|
||||
g_main_message_loop = this;
|
||||
@ -38,4 +32,3 @@ void MainMessageLoop::PostClosure(const base::RepeatingClosure& closure) {
|
||||
PostTask(CefCreateClosureTask(closure));
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@ -60,14 +60,14 @@ class MainMessageLoop {
|
||||
};
|
||||
|
||||
#define CURRENTLY_ON_MAIN_THREAD() \
|
||||
client::MainMessageLoop::Get()->RunsTasksOnCurrentThread()
|
||||
MainMessageLoop::Get()->RunsTasksOnCurrentThread()
|
||||
|
||||
#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) \
|
||||
client::MainMessageLoop::Get()->PostClosure(closure)
|
||||
MainMessageLoop::Get()->PostClosure(closure)
|
||||
|
||||
// Use this struct in conjuction with RefCountedThreadSafe to ensure that an
|
||||
// object is deleted on the main thread. For example:
|
||||
@ -95,7 +95,7 @@ struct DeleteOnMainThread {
|
||||
if (CURRENTLY_ON_MAIN_THREAD()) {
|
||||
delete x;
|
||||
} else {
|
||||
client::MainMessageLoop::Get()->PostClosure(base::BindOnce(
|
||||
MainMessageLoop::Get()->PostClosure(base::BindOnce(
|
||||
&DeleteOnMainThread::Destruct<T>, base::Unretained(x)));
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,13 @@
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "tests/shared/browser/main_message_loop_external_pump.h"
|
||||
#include "CEF/MainMessageLoopExternalPump.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
#include "include/cef_app.h"
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
#include "tests/shared/browser/main_message_loop.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
namespace {
|
||||
#include "CEF/MainMessageLoop.h"
|
||||
|
||||
// Special timer delay placeholder value. Intentionally 32-bit for Windows and
|
||||
// OS X platform API compatibility.
|
||||
@ -22,9 +18,8 @@ const int32 kTimerDelayPlaceholder = INT_MAX;
|
||||
// DoWork().
|
||||
const int64 kMaxTimerDelay = 1000 / 30; // 30fps
|
||||
|
||||
client::MainMessageLoopExternalPump* g_external_message_pump = nullptr;
|
||||
MainMessageLoopExternalPump* g_external_message_pump = nullptr;
|
||||
|
||||
} // namespace
|
||||
|
||||
MainMessageLoopExternalPump::MainMessageLoopExternalPump()
|
||||
: is_active_(false), reentrancy_detected_(false) {
|
||||
@ -104,4 +99,3 @@ bool MainMessageLoopExternalPump::PerformMessageLoopWork() {
|
||||
return reentrancy_detected_;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@ -2,13 +2,9 @@
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// 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
|
||||
|
||||
#include "tests/shared/browser/main_message_loop_std.h"
|
||||
|
||||
namespace client {
|
||||
#include "CEF/MainMessageLoopStd.h"
|
||||
|
||||
// This MessageLoop implementation simulates the embedding of CEF into an
|
||||
// existing host application that runs its own message loop. The scheduling
|
||||
@ -64,7 +60,3 @@ class MainMessageLoopExternalPump : public MainMessageLoopStd {
|
||||
bool is_active_;
|
||||
bool reentrancy_detected_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_EXTERNAL_PUMP_H_
|
||||
|
@ -2,18 +2,14 @@
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// 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 <memory>
|
||||
|
||||
#include "include/cef_app.h"
|
||||
#include "tests/shared/browser/util_win.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
namespace {
|
||||
#include "CEF/UtilWin.h"
|
||||
|
||||
// Message sent to get an additional time slice for pumping (processing) another
|
||||
// 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);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
std::unique_ptr<MainMessageLoopExternalPump>
|
||||
MainMessageLoopExternalPump::Create() {
|
||||
return std::make_unique<MainMessageLoopExternalPumpWin>();
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@ -2,12 +2,10 @@
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// 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"
|
||||
|
||||
namespace client {
|
||||
|
||||
MainMessageLoopStd::MainMessageLoopStd() {}
|
||||
|
||||
int MainMessageLoopStd::Run() {
|
||||
@ -33,5 +31,3 @@ void MainMessageLoopStd::SetCurrentModelessDialog(HWND hWndDialog) {
|
||||
// internally route dialog messages.
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace client
|
||||
|
@ -2,13 +2,9 @@
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// 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
|
||||
|
||||
#include "tests/shared/browser/main_message_loop.h"
|
||||
|
||||
namespace client {
|
||||
#include "CEF/MainMessageLoop.h"
|
||||
|
||||
// Represents the main message loop in the browser process. This implementation
|
||||
// is a light-weight wrapper around the Chromium UI thread.
|
||||
@ -30,6 +26,3 @@ class MainMessageLoopStd : public MainMessageLoop {
|
||||
DISALLOW_COPY_AND_ASSIGN(MainMessageLoopStd);
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_STD_H_
|
||||
|
584
src/CEF/MediaRouterTest.cpp
Normal file
584
src/CEF/MediaRouterTest.cpp
Normal 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
13
src/CEF/MediaRouterTest.h
Normal 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);
|
||||
}
|
270
src/CEF/OsrAccessibilityHelper.cpp
Normal file
270
src/CEF/OsrAccessibilityHelper.cpp
Normal 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
|
81
src/CEF/OsrAccessibilityHelper.h
Normal file
81
src/CEF/OsrAccessibilityHelper.h
Normal 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
1198
src/CEF/OsrWindowWin.cpp
Normal file
File diff suppressed because it is too large
Load Diff
207
src/CEF/OsrWindowWin.h
Normal file
207
src/CEF/OsrWindowWin.h
Normal 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
326
src/CEF/PreferencesTest.cpp
Normal 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
12
src/CEF/PreferencesTest.h
Normal 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);
|
||||
}
|
@ -75,8 +75,6 @@ class BinaryResourceProvider : public CefResourceManager::Provider {
|
||||
DISALLOW_COPY_AND_ASSIGN(BinaryResourceProvider);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Implemented in resource_util_win_idmap.cc.
|
||||
extern int GetResourceId(const char* resource_name);
|
||||
|
||||
|
55
src/CEF/ResourceUtilWinIdMap.cpp
Normal file
55
src/CEF/ResourceUtilWinIdMap.cpp
Normal 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;
|
||||
}
|
234
src/CEF/ResponseFilterTest.cpp
Normal file
234
src/CEF/ResponseFilterTest.cpp
Normal 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;
|
||||
}
|
||||
}
|
20
src/CEF/ResponseFilterTest.h
Normal file
20
src/CEF/ResponseFilterTest.h
Normal 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);
|
||||
}
|
@ -50,7 +50,7 @@ class ClientRequestContextHandler : public CefRequestContextHandler,
|
||||
std::istringstream f(extension_path);
|
||||
while (getline(f, part, ';')) {
|
||||
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,
|
||||
bool with_controls,
|
||||
bool with_osr) {
|
||||
const std::string& extension_url = extension_util::GetExtensionURL(extension);
|
||||
const std::string& extension_url = GetExtensionURL(extension);
|
||||
if (extension_url.empty()) {
|
||||
NOTREACHED() << "Extension cannot be loaded directly.";
|
||||
return nullptr;
|
||||
@ -253,7 +253,7 @@ void RootWindowManager::AddExtension(CefRefPtr<CefExtension> extension) {
|
||||
}
|
||||
|
||||
// Don't track extensions that can't be loaded directly.
|
||||
if (extension_util::GetExtensionURL(extension).empty())
|
||||
if (GetExtensionURL(extension).empty())
|
||||
return;
|
||||
|
||||
// Don't add the same extension multiple times.
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "CEF/HumanAppContext.h"
|
||||
#include "CEF/RootWindoManager.h"
|
||||
#include "CEF/MainMessageLoop.h"
|
||||
|
||||
RootWindowConfig::RootWindowConfig()
|
||||
: always_on_top(false),
|
||||
|
36
src/CEF/RootWindowCreate.cpp
Normal file
36
src/CEF/RootWindowCreate.cpp
Normal 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
1208
src/CEF/RootWindowWin.cpp
Normal file
File diff suppressed because it is too large
Load Diff
158
src/CEF/RootWindowWin.h
Normal file
158
src/CEF/RootWindowWin.h
Normal 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
145
src/CEF/SchemeTest.cpp
Normal 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
11
src/CEF/SchemeTest.h
Normal 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
379
src/CEF/ServerTest.cpp
Normal 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
12
src/CEF/ServerTest.h
Normal 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);
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
// 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/test_runner.h"
|
||||
#include "CEF/TestRunner.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
@ -15,25 +15,21 @@
|
||||
#include "include/cef_trace.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "include/wrapper/cef_stream_resource_handler.h"
|
||||
#include "tests/cefclient/browser/binding_test.h"
|
||||
#include "tests/cefclient/browser/client_handler.h"
|
||||
#include "tests/cefclient/browser/dialog_test.h"
|
||||
#include "tests/cefclient/browser/main_context.h"
|
||||
#include "tests/cefclient/browser/media_router_test.h"
|
||||
#include "tests/cefclient/browser/preferences_test.h"
|
||||
#include "tests/cefclient/browser/resource.h"
|
||||
#include "tests/cefclient/browser/response_filter_test.h"
|
||||
#include "tests/cefclient/browser/root_window_manager.h"
|
||||
#include "tests/cefclient/browser/scheme_test.h"
|
||||
#include "tests/cefclient/browser/server_test.h"
|
||||
#include "tests/cefclient/browser/urlrequest_test.h"
|
||||
#include "tests/cefclient/browser/window_test.h"
|
||||
#include "tests/shared/browser/resource_util.h"
|
||||
#include "CEF/BindingTest.h"
|
||||
#include "CEF/ClientHandler.h"
|
||||
#include "CEF/DialogTest.h"
|
||||
#include "CEF/HumanAppContext.h"
|
||||
#include "CEF/MediaRouterTest.h"
|
||||
#include "CEF/PreferencesTest.h"
|
||||
// #include "CEF/resource.h"
|
||||
#include "CEF/ResponseFilterTest.h"
|
||||
#include "CEF/RootWindoManager.h"
|
||||
#include "CEF/SchemeTest.h"
|
||||
#include "CEF/ServerTest.h"
|
||||
#include "CEF/UrlrequestTest.h"
|
||||
#include "CEF/WindowTest.h"
|
||||
#include "CEF/ResourceUtil.h"
|
||||
|
||||
namespace client {
|
||||
namespace test_runner {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kTestHost[] = "tests";
|
||||
const char kLocalHost[] = "localhost";
|
||||
@ -153,7 +149,7 @@ void RunNewWindowTest(CefRefPtr<CefBrowser> browser) {
|
||||
auto config = std::make_unique<RootWindowConfig>();
|
||||
config->with_controls = true;
|
||||
config->with_osr = browser->GetHost()->IsWindowRenderingDisabled();
|
||||
MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
|
||||
HumanAppContext::Get()->GetRootWindowManager()->CreateRootWindow(
|
||||
std::move(config));
|
||||
}
|
||||
|
||||
@ -219,7 +215,7 @@ class PromptHandler : public CefMessageRouterBrowserSide::Handler {
|
||||
if (fps <= 0) {
|
||||
// Reset to the default value.
|
||||
CefBrowserSettings settings;
|
||||
MainContext::Get()->PopulateBrowserSettings(&settings);
|
||||
HumanAppContext::Get()->PopulateBrowserSettings(&settings);
|
||||
fps = settings.windowless_frame_rate;
|
||||
}
|
||||
|
||||
@ -306,7 +302,7 @@ void EndTracing(CefRefPtr<CefBrowser> browser) {
|
||||
|
||||
void RunDialog() {
|
||||
static const char kDefaultFileName[] = "trace.txt";
|
||||
std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName);
|
||||
std::string path = HumanAppContext::Get()->GetDownloadPath(kDefaultFileName);
|
||||
if (path.empty())
|
||||
path = kDefaultFileName;
|
||||
|
||||
@ -357,7 +353,7 @@ void PrintToPDF(CefRefPtr<CefBrowser> browser) {
|
||||
|
||||
void RunDialog() {
|
||||
static const char kDefaultFileName[] = "output.pdf";
|
||||
std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName);
|
||||
std::string path = HumanAppContext::Get()->GetDownloadPath(kDefaultFileName);
|
||||
if (path.empty())
|
||||
path = kDefaultFileName;
|
||||
|
||||
@ -525,65 +521,64 @@ std::string RequestUrlFilter(const std::string& url) {
|
||||
return url_base + ".html" + url_suffix;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void RunTest(CefRefPtr<CefBrowser> browser, int id) {
|
||||
if (!browser)
|
||||
return;
|
||||
|
||||
switch (id) {
|
||||
case ID_TESTS_GETSOURCE:
|
||||
RunGetSourceTest(browser);
|
||||
break;
|
||||
case ID_TESTS_GETTEXT:
|
||||
RunGetTextTest(browser);
|
||||
break;
|
||||
case ID_TESTS_WINDOW_NEW:
|
||||
RunNewWindowTest(browser);
|
||||
break;
|
||||
case ID_TESTS_WINDOW_POPUP:
|
||||
RunPopupWindowTest(browser);
|
||||
break;
|
||||
case ID_TESTS_REQUEST:
|
||||
RunRequestTest(browser);
|
||||
break;
|
||||
case ID_TESTS_ZOOM_IN:
|
||||
ModifyZoom(browser, 0.5);
|
||||
break;
|
||||
case ID_TESTS_ZOOM_OUT:
|
||||
ModifyZoom(browser, -0.5);
|
||||
break;
|
||||
case ID_TESTS_ZOOM_RESET:
|
||||
browser->GetHost()->SetZoomLevel(0.0);
|
||||
break;
|
||||
case ID_TESTS_OSR_FPS:
|
||||
PromptFPS(browser);
|
||||
break;
|
||||
case ID_TESTS_OSR_DSF:
|
||||
PromptDSF(browser);
|
||||
break;
|
||||
case ID_TESTS_TRACING_BEGIN:
|
||||
BeginTracing();
|
||||
break;
|
||||
case ID_TESTS_TRACING_END:
|
||||
EndTracing(browser);
|
||||
break;
|
||||
case ID_TESTS_PRINT:
|
||||
browser->GetHost()->Print();
|
||||
break;
|
||||
case ID_TESTS_PRINT_TO_PDF:
|
||||
PrintToPDF(browser);
|
||||
break;
|
||||
case ID_TESTS_MUTE_AUDIO:
|
||||
MuteAudio(browser, true);
|
||||
break;
|
||||
case ID_TESTS_UNMUTE_AUDIO:
|
||||
MuteAudio(browser, false);
|
||||
break;
|
||||
case ID_TESTS_OTHER_TESTS:
|
||||
RunOtherTests(browser);
|
||||
break;
|
||||
}
|
||||
//
|
||||
// switch (id) {
|
||||
// case ID_TESTS_GETSOURCE:
|
||||
// RunGetSourceTest(browser);
|
||||
// break;
|
||||
// case ID_TESTS_GETTEXT:
|
||||
// RunGetTextTest(browser);
|
||||
// break;
|
||||
// case ID_TESTS_WINDOW_NEW:
|
||||
// RunNewWindowTest(browser);
|
||||
// break;
|
||||
// case ID_TESTS_WINDOW_POPUP:
|
||||
// RunPopupWindowTest(browser);
|
||||
// break;
|
||||
// case ID_TESTS_REQUEST:
|
||||
// RunRequestTest(browser);
|
||||
// break;
|
||||
// case ID_TESTS_ZOOM_IN:
|
||||
// ModifyZoom(browser, 0.5);
|
||||
// break;
|
||||
// case ID_TESTS_ZOOM_OUT:
|
||||
// ModifyZoom(browser, -0.5);
|
||||
// break;
|
||||
// case ID_TESTS_ZOOM_RESET:
|
||||
// browser->GetHost()->SetZoomLevel(0.0);
|
||||
// break;
|
||||
// case ID_TESTS_OSR_FPS:
|
||||
// PromptFPS(browser);
|
||||
// break;
|
||||
// case ID_TESTS_OSR_DSF:
|
||||
// PromptDSF(browser);
|
||||
// break;
|
||||
// case ID_TESTS_TRACING_BEGIN:
|
||||
// BeginTracing();
|
||||
// break;
|
||||
// case ID_TESTS_TRACING_END:
|
||||
// EndTracing(browser);
|
||||
// break;
|
||||
// case ID_TESTS_PRINT:
|
||||
// browser->GetHost()->Print();
|
||||
// break;
|
||||
// case ID_TESTS_PRINT_TO_PDF:
|
||||
// PrintToPDF(browser);
|
||||
// break;
|
||||
// case ID_TESTS_MUTE_AUDIO:
|
||||
// MuteAudio(browser, true);
|
||||
// break;
|
||||
// case ID_TESTS_UNMUTE_AUDIO:
|
||||
// MuteAudio(browser, false);
|
||||
// break;
|
||||
// case ID_TESTS_OTHER_TESTS:
|
||||
// RunOtherTests(browser);
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
|
||||
std::string DumpRequestContents(CefRefPtr<CefRequest> request) {
|
||||
@ -795,7 +790,7 @@ void Alert(CefRefPtr<CefBrowser> browser, const std::string& message) {
|
||||
if (browser->GetHost()->GetExtension()) {
|
||||
// Alerts originating from extension hosts should instead be displayed in
|
||||
// the active browser.
|
||||
browser = MainContext::Get()->GetRootWindowManager()->GetActiveBrowser();
|
||||
browser = HumanAppContext::Get()->GetRootWindowManager()->GetActiveBrowser();
|
||||
if (!browser)
|
||||
return;
|
||||
}
|
||||
@ -821,6 +816,7 @@ bool IsTestURL(const std::string& url, const std::string& path) {
|
||||
return url_path.find(path) == 0;
|
||||
}
|
||||
|
||||
namespace test_runner {
|
||||
void CreateMessageHandlers(MessageHandlerSet& handlers) {
|
||||
handlers.insert(new PromptHandler);
|
||||
|
||||
@ -848,18 +844,15 @@ void CreateMessageHandlers(MessageHandlerSet& handlers) {
|
||||
|
||||
void RegisterSchemeHandlers() {
|
||||
// Register the scheme handler.
|
||||
scheme_test::RegisterSchemeHandlers();
|
||||
RegisterSchemeHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
CefRefPtr<CefResponse> response) {
|
||||
// Create the response filter.
|
||||
return response_filter_test::GetResourceResponseFilter(browser, frame,
|
||||
return GetResourceResponseFilter(browser, frame,
|
||||
request, response);
|
||||
}
|
||||
|
||||
} // namespace test_runner
|
||||
} // namespace client
|
||||
|
@ -2,8 +2,7 @@
|
||||
// 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_TEST_RUNNER_H_
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_TEST_RUNNER_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
@ -14,9 +13,6 @@
|
||||
#include "include/wrapper/cef_message_router.h"
|
||||
#include "include/wrapper/cef_resource_manager.h"
|
||||
|
||||
namespace client {
|
||||
namespace test_runner {
|
||||
|
||||
// Run a test.
|
||||
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
|
||||
// deleted when the ClientHandler is destroyed.
|
||||
typedef std::set<CefMessageRouterBrowserSide::Handler*> MessageHandlerSet;
|
||||
namespace test_runner {
|
||||
void CreateMessageHandlers(MessageHandlerSet& handlers);
|
||||
|
||||
// Register scheme handlers for tests.
|
||||
void RegisterSchemeHandlers();
|
||||
}
|
||||
|
||||
// Create a resource response filter for tests.
|
||||
CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
|
||||
@ -62,8 +60,3 @@ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
CefRefPtr<CefResponse> response);
|
||||
|
||||
} // namespace test_runner
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_TEST_RUNNER_H_
|
||||
|
177
src/CEF/UrlrequestTest.cpp
Normal file
177
src/CEF/UrlrequestTest.cpp
Normal 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
12
src/CEF/UrlrequestTest.h
Normal 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
169
src/CEF/UtilWin.cpp
Normal 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
36
src/CEF/UtilWin.h
Normal 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
114
src/CEF/WindowTest.cpp
Normal 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
12
src/CEF/WindowTest.h
Normal 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);
|
||||
}
|
28
src/CEF/WindowTestRunner.cpp
Normal file
28
src/CEF/WindowTestRunner.cpp
Normal 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;
|
||||
}
|
27
src/CEF/WindowTestRunner.h
Normal file
27
src/CEF/WindowTestRunner.h
Normal 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() {}
|
||||
};
|
51
src/CEF/WindowTestRunnerViews.cpp
Normal file
51
src/CEF/WindowTestRunnerViews.cpp
Normal 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();
|
||||
}
|
22
src/CEF/WindowTestRunnerViews.h
Normal file
22
src/CEF/WindowTestRunnerViews.h
Normal 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;
|
||||
};
|
129
src/CEF/WindowTestRunnerWin.cpp
Normal file
129
src/CEF/WindowTestRunnerWin.cpp
Normal 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));
|
||||
}
|
||||
}
|
23
src/CEF/WindowTestRunnerWin.h
Normal file
23
src/CEF/WindowTestRunnerWin.h
Normal 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
86
src/CEF/resource.h
Normal 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
|
Loading…
Reference in New Issue
Block a user