modify cef

This commit is contained in:
brige 2024-12-16 21:34:53 +08:00
parent e3175def71
commit 79f86c0931
39 changed files with 6181 additions and 7 deletions

1357
src/CEF/ClientHandler.cpp Normal file

File diff suppressed because it is too large Load Diff

439
src/CEF/ClientHandler.h Normal file
View File

@ -0,0 +1,439 @@
// Copyright (c) 2011 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 <set>
#include <string>
#include "include/cef_client.h"
#include "include/wrapper/cef_helpers.h"
#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"
#if defined(OS_LINUX)
#include "tests/cefclient/browser/dialog_handler_gtk.h"
#include "tests/cefclient/browser/print_handler_gtk.h"
#endif
class ClientDownloadImageCallback;
// Client handler abstract base class. Provides common functionality shared by
// all concrete client handler implementations.
class ClientHandler : public CefClient,
public CefCommandHandler,
public CefContextMenuHandler,
public CefDisplayHandler,
public CefDownloadHandler,
public CefDragHandler,
public CefFocusHandler,
public CefKeyboardHandler,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefRequestHandler,
public CefResourceRequestHandler {
public:
// Implement this interface to receive notification of ClientHandler
// events. The methods of this class will be called on the main thread unless
// otherwise indicated.
class Delegate {
public:
// Called when the browser is created.
virtual void OnBrowserCreated(CefRefPtr<CefBrowser> browser) = 0;
// Called when the browser is closing.
virtual void OnBrowserClosing(CefRefPtr<CefBrowser> browser) = 0;
// Called when the browser has been closed.
virtual void OnBrowserClosed(CefRefPtr<CefBrowser> browser) = 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 the Favicon image.
virtual void OnSetFavicon(CefRefPtr<CefImage> image) {}
// 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;
// Set focus to the next/previous control.
virtual void OnTakeFocus(bool next) {}
// Called on the UI thread before a context menu is displayed.
virtual void OnBeforeContextMenu(CefRefPtr<CefMenuModel> model) {}
protected:
virtual ~Delegate() {}
};
typedef std::set<CefMessageRouterBrowserSide::Handler*> MessageHandlerSet;
// Constructor may be called on any thread.
// |delegate| must outlive this object or DetachDelegate() must be called.
ClientHandler(Delegate* delegate,
bool is_osr,
bool with_controls,
const std::string& startup_url);
// This object may outlive the Delegate object so it's necessary for the
// Delegate to detach itself before destruction.
void DetachDelegate();
// CefClient methods
CefRefPtr<CefCommandHandler> GetCommandHandler() override { return this; }
CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() override {
return this;
}
CefRefPtr<CefDisplayHandler> GetDisplayHandler() override { return this; }
CefRefPtr<CefDownloadHandler> GetDownloadHandler() override { return this; }
CefRefPtr<CefDragHandler> GetDragHandler() override { return this; }
CefRefPtr<CefFocusHandler> GetFocusHandler() override { return this; }
CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() override { return this; }
CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; }
CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; }
CefRefPtr<CefRequestHandler> GetRequestHandler() override { return this; }
bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message) override;
#if defined(OS_LINUX)
CefRefPtr<CefDialogHandler> GetDialogHandler() override {
return dialog_handler_;
}
CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() override {
return dialog_handler_;
}
CefRefPtr<CefPrintHandler> GetPrintHandler() override {
return print_handler_;
}
#endif
// CefCommandHandler methods
bool OnChromeCommand(CefRefPtr<CefBrowser> browser,
int command_id,
cef_window_open_disposition_t disposition) override;
// CefContextMenuHandler methods
void OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefContextMenuParams> params,
CefRefPtr<CefMenuModel> model) override;
bool OnContextMenuCommand(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefContextMenuParams> params,
int command_id,
EventFlags event_flags) override;
// CefDisplayHandler methods
void OnAddressChange(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& url) override;
void OnTitleChange(CefRefPtr<CefBrowser> browser,
const CefString& title) override;
void OnFaviconURLChange(CefRefPtr<CefBrowser> browser,
const std::vector<CefString>& icon_urls) override;
void OnFullscreenModeChange(CefRefPtr<CefBrowser> browser,
bool fullscreen) override;
bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
cef_log_severity_t level,
const CefString& message,
const CefString& source,
int line) override;
bool OnAutoResize(CefRefPtr<CefBrowser> browser,
const CefSize& new_size) override;
bool OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
cef_cursor_type_t type,
const CefCursorInfo& custom_cursor_info) override;
// CefDownloadHandler methods
bool CanDownload(CefRefPtr<CefBrowser> browser,
const CefString& url,
const CefString& request_method) override;
void OnBeforeDownload(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
const CefString& suggested_name,
CefRefPtr<CefBeforeDownloadCallback> callback) override;
void OnDownloadUpdated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
CefRefPtr<CefDownloadItemCallback> callback) override;
// CefDragHandler methods
bool OnDragEnter(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> dragData,
CefDragHandler::DragOperationsMask mask) override;
void OnDraggableRegionsChanged(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const std::vector<CefDraggableRegion>& regions) override;
// CefFocusHandler methods
void OnTakeFocus(CefRefPtr<CefBrowser> browser, bool next) override;
bool OnSetFocus(CefRefPtr<CefBrowser> browser, FocusSource source) override;
// CefKeyboardHandler methods
bool OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
const CefKeyEvent& event,
CefEventHandle os_event,
bool* is_keyboard_shortcut) override;
// CefLifeSpanHandler methods
bool OnBeforePopup(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
const CefString& target_frame_name,
CefLifeSpanHandler::WindowOpenDisposition target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings,
CefRefPtr<CefDictionaryValue>& extra_info,
bool* no_javascript_access) override;
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
bool DoClose(CefRefPtr<CefBrowser> browser) override;
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
// CefLoadHandler methods
void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
bool isLoading,
bool canGoBack,
bool canGoForward) override;
void OnLoadError(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
ErrorCode errorCode,
const CefString& errorText,
const CefString& failedUrl) override;
// CefRequestHandler methods
bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
bool user_gesture,
bool is_redirect) override;
bool OnOpenURLFromTab(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
CefRequestHandler::WindowOpenDisposition target_disposition,
bool user_gesture) override;
CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
bool is_navigation,
bool is_download,
const CefString& request_initiator,
bool& disable_default_handling) override;
bool GetAuthCredentials(CefRefPtr<CefBrowser> browser,
const CefString& origin_url,
bool isProxy,
const CefString& host,
int port,
const CefString& realm,
const CefString& scheme,
CefRefPtr<CefAuthCallback> callback) override;
bool OnQuotaRequest(CefRefPtr<CefBrowser> browser,
const CefString& origin_url,
int64 new_size,
CefRefPtr<CefCallback> callback) override;
bool OnCertificateError(CefRefPtr<CefBrowser> browser,
ErrorCode cert_error,
const CefString& request_url,
CefRefPtr<CefSSLInfo> ssl_info,
CefRefPtr<CefCallback> callback) override;
bool OnSelectClientCertificate(
CefRefPtr<CefBrowser> browser,
bool isProxy,
const CefString& host,
int port,
const X509CertificateList& certificates,
CefRefPtr<CefSelectClientCertificateCallback> callback) override;
void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
TerminationStatus status) override;
void OnDocumentAvailableInMainFrame(CefRefPtr<CefBrowser> browser) override;
// CefResourceRequestHandler methods
cef_return_value_t OnBeforeResourceLoad(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override;
CefRefPtr<CefResourceHandler> GetResourceHandler(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) override;
CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) override;
void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
bool& allow_os_execution) override;
// Returns the number of browsers currently using this handler. Can only be
// called on the CEF UI thread.
int GetBrowserCount() const;
// Show a new DevTools popup window.
void ShowDevTools(CefRefPtr<CefBrowser> browser,
const CefPoint& inspect_element_at);
// Close the existing DevTools popup window, if any.
void CloseDevTools(CefRefPtr<CefBrowser> browser);
// Test if the current site has SSL information available.
bool HasSSLInformation(CefRefPtr<CefBrowser> browser);
// Show SSL information for the current site.
void ShowSSLInformation(CefRefPtr<CefBrowser> browser);
// Set a string resource for loading via StringResourceProvider.
void SetStringResource(const std::string& page, const std::string& data);
// Returns the Delegate.
Delegate* delegate() const { return delegate_; }
// Returns the startup URL.
std::string startup_url() const { return startup_url_; }
// Set/get whether the client should download favicon images. Only safe to
// call immediately after client creation or on the browser process UI thread.
bool download_favicon_images() const { return download_favicon_images_; }
void set_download_favicon_images(bool allow) {
download_favicon_images_ = allow;
}
private:
friend class ClientDownloadImageCallback;
// Create a new popup window using the specified information. |is_devtools|
// will be true if the window will be used for DevTools. Return true to
// proceed with popup browser creation or false to cancel the popup browser.
// May be called on any thead.
bool CreatePopupWindow(CefRefPtr<CefBrowser> browser,
bool is_devtools,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings);
// Execute Delegate notifications on the main thread.
void NotifyBrowserCreated(CefRefPtr<CefBrowser> browser);
void NotifyBrowserClosing(CefRefPtr<CefBrowser> browser);
void NotifyBrowserClosed(CefRefPtr<CefBrowser> browser);
void NotifyAddress(const CefString& url);
void NotifyTitle(const CefString& title);
void NotifyFavicon(CefRefPtr<CefImage> image);
void NotifyFullscreen(bool fullscreen);
void NotifyAutoResize(const CefSize& new_size);
void NotifyLoadingState(bool isLoading, bool canGoBack, bool canGoForward);
void NotifyDraggableRegions(const std::vector<CefDraggableRegion>& regions);
void NotifyTakeFocus(bool next);
// Test context menu creation.
void BuildTestMenu(CefRefPtr<CefMenuModel> model);
bool ExecuteTestMenu(int command_id);
void SetOfflineState(CefRefPtr<CefBrowser> browser, bool offline);
// Filter menu and keyboard shortcut commands.
void FilterMenuModel(CefRefPtr<CefMenuModel> model);
bool IsAllowedCommandId(int command_id);
// THREAD SAFE MEMBERS
// The following members may be accessed from any thread.
// True if this handler uses off-screen rendering.
const bool is_osr_;
// True if this handler shows controls.
const bool with_controls_;
// The startup URL.
const std::string startup_url_;
// True if mouse cursor change is disabled.
bool mouse_cursor_change_disabled_;
// True if the browser is currently offline.
bool offline_;
// True if Favicon images should be downloaded.
bool download_favicon_images_;
#if defined(OS_LINUX)
// Custom dialog handler for GTK.
CefRefPtr<ClientDialogHandlerGtk> dialog_handler_;
CefRefPtr<ClientPrintHandlerGtk> print_handler_;
#endif
// Handles the browser side of query routing. The renderer side is handled
// in client_renderer.cc.
CefRefPtr<CefMessageRouterBrowserSide> message_router_;
// Manages the registration and delivery of resources.
CefRefPtr<CefResourceManager> resource_manager_;
// Used to manage string resources in combination with StringResourceProvider.
// Only accessed on the IO thread.
//test_runner::StringResourceMap string_resource_map_;
// MAIN THREAD MEMBERS
// The following members will only be accessed on the main thread. This will
// be the same as the CEF UI thread except when using multi-threaded message
// loop mode on Windows.
Delegate* delegate_;
// UI THREAD MEMBERS
// The following members will only be accessed on the CEF UI thread.
// Track state information for the text context menu.
struct TestMenuState {
TestMenuState() : check_item(true), radio_item(0) {}
bool check_item;
int radio_item;
} test_menu_state_;
// The current number of browsers using this handler.
int browser_count_;
// Console logging state.
const std::string console_log_file_;
bool first_console_message_;
// True if an editable field currently has focus.
bool focus_on_editable_field_;
// True for the initial navigation after browser creation.
bool initial_navigation_;
// Set of Handlers registered with the message router.
MessageHandlerSet message_handler_set_;
DISALLOW_COPY_AND_ASSIGN(ClientHandler);
};

View File

@ -0,0 +1,186 @@
// 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/client_handler_osr.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,
const std::string& startup_url)
: ClientHandler(delegate, /*is_osr=*/true, with_controls, startup_url),
osr_delegate_(osr_delegate) {
DCHECK(osr_delegate_);
}
void ClientHandlerOsr::DetachOsrDelegate() {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI,
base::BindOnce(&ClientHandlerOsr::DetachOsrDelegate, this));
return;
}
DCHECK(osr_delegate_);
osr_delegate_ = nullptr;
}
void ClientHandlerOsr::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
if (osr_delegate_)
osr_delegate_->OnAfterCreated(browser);
ClientHandler::OnAfterCreated(browser);
}
void ClientHandlerOsr::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
if (osr_delegate_)
osr_delegate_->OnBeforeClose(browser);
ClientHandler::OnBeforeClose(browser);
}
bool ClientHandlerOsr::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return false;
return osr_delegate_->GetRootScreenRect(browser, rect);
}
void ClientHandlerOsr::GetViewRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_) {
// Never return an empty rectangle.
rect.width = rect.height = 1;
return;
}
osr_delegate_->GetViewRect(browser, rect);
}
bool ClientHandlerOsr::GetScreenPoint(CefRefPtr<CefBrowser> browser,
int viewX,
int viewY,
int& screenX,
int& screenY) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return false;
return osr_delegate_->GetScreenPoint(browser, viewX, viewY, screenX, screenY);
}
bool ClientHandlerOsr::GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return false;
return osr_delegate_->GetScreenInfo(browser, screen_info);
}
void ClientHandlerOsr::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
return osr_delegate_->OnPopupShow(browser, show);
}
void ClientHandlerOsr::OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
return osr_delegate_->OnPopupSize(browser, rect);
}
void ClientHandlerOsr::OnPaint(CefRefPtr<CefBrowser> browser,
PaintElementType type,
const RectList& dirtyRects,
const void* buffer,
int width,
int height) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
osr_delegate_->OnPaint(browser, type, dirtyRects, buffer, width, height);
}
void ClientHandlerOsr::OnAcceleratedPaint(
CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList& dirtyRects,
void* share_handle) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
osr_delegate_->OnAcceleratedPaint(browser, type, dirtyRects, share_handle);
}
bool ClientHandlerOsr::StartDragging(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> drag_data,
CefRenderHandler::DragOperationsMask allowed_ops,
int x,
int y) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return false;
return osr_delegate_->StartDragging(browser, drag_data, allowed_ops, x, y);
}
void ClientHandlerOsr::UpdateDragCursor(
CefRefPtr<CefBrowser> browser,
CefRenderHandler::DragOperation operation) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
osr_delegate_->UpdateDragCursor(browser, operation);
}
void ClientHandlerOsr::OnImeCompositionRangeChanged(
CefRefPtr<CefBrowser> browser,
const CefRange& selection_range,
const CefRenderHandler::RectList& character_bounds) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
osr_delegate_->OnImeCompositionRangeChanged(browser, selection_range,
character_bounds);
}
void ClientHandlerOsr::OnAccessibilityTreeChange(CefRefPtr<CefValue> value) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
osr_delegate_->UpdateAccessibilityTree(value);
}
bool ClientHandlerOsr::OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
cef_cursor_type_t type,
const CefCursorInfo& custom_cursor_info) {
CEF_REQUIRE_UI_THREAD();
if (ClientHandler::OnCursorChange(browser, cursor, type,
custom_cursor_info)) {
return true;
}
if (osr_delegate_) {
osr_delegate_->OnCursorChange(browser, cursor, type, custom_cursor_info);
}
return true;
}
void ClientHandlerOsr::OnAccessibilityLocationChange(
CefRefPtr<CefValue> value) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
osr_delegate_->UpdateAccessibilityLocation(value);
}
} // namespace client

152
src/CEF/ClientHandlerOSR.h Normal file
View File

@ -0,0 +1,152 @@
// 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_CLIENT_HANDLER_OSR_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_OSR_H_
#pragma once
#include "tests/cefclient/browser/client_handler.h"
namespace client {
// Client handler implementation for windowless browsers. There will only ever
// be one browser per handler instance.
class ClientHandlerOsr : public ClientHandler,
public CefAccessibilityHandler,
public CefRenderHandler {
public:
// Implement this interface to receive notification of ClientHandlerOsr
// events. The methods of this class will be called on the CEF UI thread.
class OsrDelegate {
public:
// These methods match the CefLifeSpanHandler interface.
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) = 0;
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) = 0;
// These methods match the CefRenderHandler interface.
virtual bool GetRootScreenRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) = 0;
virtual void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) = 0;
virtual bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
int viewX,
int viewY,
int& screenX,
int& screenY) = 0;
virtual bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) = 0;
virtual void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) = 0;
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) = 0;
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList& dirtyRects,
const void* buffer,
int width,
int height) = 0;
virtual void OnAcceleratedPaint(
CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList& dirtyRects,
void* share_handle) {}
virtual bool StartDragging(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> drag_data,
CefRenderHandler::DragOperationsMask allowed_ops,
int x,
int y) = 0;
virtual void UpdateDragCursor(
CefRefPtr<CefBrowser> browser,
CefRenderHandler::DragOperation operation) = 0;
virtual void OnImeCompositionRangeChanged(
CefRefPtr<CefBrowser> browser,
const CefRange& selection_range,
const CefRenderHandler::RectList& character_bounds) = 0;
// These methods match the CefDisplayHandler interface.
virtual void OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
cef_cursor_type_t type,
const CefCursorInfo& custom_cursor_info) = 0;
virtual void UpdateAccessibilityTree(CefRefPtr<CefValue> value) = 0;
virtual void UpdateAccessibilityLocation(CefRefPtr<CefValue> value) = 0;
protected:
virtual ~OsrDelegate() {}
};
ClientHandlerOsr(Delegate* delegate,
OsrDelegate* osr_delegate,
bool with_controls,
const std::string& startup_url);
// This object may outlive the OsrDelegate object so it's necessary for the
// OsrDelegate to detach itself before destruction.
void DetachOsrDelegate();
// CefClient methods.
CefRefPtr<CefRenderHandler> GetRenderHandler() override { return this; }
CefRefPtr<CefAccessibilityHandler> GetAccessibilityHandler() override {
return this;
}
// CefLifeSpanHandler methods.
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
// CefRenderHandler methods.
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;
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;
// CefDisplayHandler methods.
bool OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
cef_cursor_type_t type,
const CefCursorInfo& custom_cursor_info) override;
// CefAccessibilityHandler methods.
void OnAccessibilityTreeChange(CefRefPtr<CefValue> value) override;
void OnAccessibilityLocationChange(CefRefPtr<CefValue> value) override;
private:
// Only accessed on the UI thread.
OsrDelegate* osr_delegate_;
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(ClientHandlerOsr);
DISALLOW_COPY_AND_ASSIGN(ClientHandlerOsr);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_OSR_H_

View File

@ -0,0 +1,14 @@
// 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/client_handler_std.h"
namespace client {
ClientHandlerStd::ClientHandlerStd(Delegate* delegate,
bool with_controls,
const std::string& startup_url)
: ClientHandler(delegate, /*is_osr=*/false, with_controls, startup_url) {}
} // namespace client

View File

@ -0,0 +1,29 @@
// 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_CLIENT_HANDLER_STD_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_STD_H_
#pragma once
#include "tests/cefclient/browser/client_handler.h"
namespace client {
// Client handler implementation for windowed browsers. There will only ever be
// one browser per handler instance.
class ClientHandlerStd : public ClientHandler {
public:
ClientHandlerStd(Delegate* delegate,
bool with_controls,
const std::string& startup_url);
private:
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(ClientHandlerStd);
DISALLOW_COPY_AND_ASSIGN(ClientHandlerStd);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_STD_H_

247
src/CEF/ExtensionUtil.cpp Normal file
View File

@ -0,0 +1,247 @@
// 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/ExtensionUtil.h"
#include <algorithm>
#include <memory>
#include "include/base/cef_callback.h"
#include "include/base/cef_cxx17_backports.h"
#include "include/cef_parser.h"
#include "include/cef_path_util.h"
#include "include/wrapper/cef_closure_task.h"
#include "CEF/FileUtil.h"
#include "CEF/ResourceUtil.h"
std::string GetResourcesPath() {
CefString resources_dir;
if (CefGetPath(PK_DIR_RESOURCES, resources_dir) && !resources_dir.empty()) {
return resources_dir.ToString() + kPathSep;
}
return std::string();
}
// Internal extension paths may be prefixed with PK_DIR_RESOURCES and always
// use forward slash as path separator.
std::string GetInternalPath(const std::string& extension_path) {
std::string resources_path_lower = GetResourcesPath();
std::string extension_path_lower = extension_path;
#if defined(OS_WIN)
// Convert to lower-case, since Windows paths are case-insensitive.
std::transform(resources_path_lower.begin(), resources_path_lower.end(),
resources_path_lower.begin(), ::tolower);
std::transform(extension_path_lower.begin(), extension_path_lower.end(),
extension_path_lower.begin(), ::tolower);
#endif
std::string internal_path;
if (!resources_path_lower.empty() &&
extension_path_lower.find(resources_path_lower) == 0U) {
internal_path = extension_path.substr(resources_path_lower.size());
} else {
internal_path = extension_path;
}
#if defined(OS_WIN)
// Normalize path separators.
std::replace(internal_path.begin(), internal_path.end(), '\\', '/');
#endif
return internal_path;
}
using ManifestCallback =
base::OnceCallback<void(CefRefPtr<CefDictionaryValue> /*manifest*/)>;
void RunManifestCallback(ManifestCallback callback,
CefRefPtr<CefDictionaryValue> manifest) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute on the browser UI thread.
CefPostTask(TID_UI, base::BindOnce(std::move(callback), manifest));
return;
}
std::move(callback).Run(manifest);
}
// Asynchronously reads the manifest and executes |callback| on the UI thread.
void GetInternalManifest(const std::string& extension_path,
ManifestCallback callback) {
if (!CefCurrentlyOn(TID_FILE_USER_BLOCKING)) {
// Execute on the browser FILE thread.
CefPostTask(TID_FILE_USER_BLOCKING,
base::BindOnce(GetInternalManifest, extension_path,
std::move(callback)));
return;
}
const std::string& manifest_path = GetInternalExtensionResourcePath(
JoinPath(extension_path, "manifest.json"));
std::string manifest_contents;
if (!LoadBinaryResource(manifest_path.c_str(), manifest_contents) ||
manifest_contents.empty()) {
LOG(ERROR) << "Failed to load manifest from " << manifest_path;
RunManifestCallback(std::move(callback), nullptr);
return;
}
CefString error_msg;
CefRefPtr<CefValue> value =
CefParseJSONAndReturnError(manifest_contents, JSON_PARSER_RFC, error_msg);
if (!value || value->GetType() != VTYPE_DICTIONARY) {
if (error_msg.empty())
error_msg = "Incorrectly formatted dictionary contents.";
LOG(ERROR) << "Failed to parse manifest from " << manifest_path << "; "
<< error_msg.ToString();
RunManifestCallback(std::move(callback), nullptr);
return;
}
RunManifestCallback(std::move(callback), value->GetDictionary());
}
void LoadExtensionWithManifest(CefRefPtr<CefRequestContext> request_context,
const std::string& extension_path,
CefRefPtr<CefExtensionHandler> handler,
CefRefPtr<CefDictionaryValue> manifest) {
CEF_REQUIRE_UI_THREAD();
// Load the extension internally. Resource requests will be handled via
// AddInternalExtensionToResourceManager.
request_context->LoadExtension(extension_path, manifest, handler);
}
bool IsInternalExtension(const std::string& extension_path) {
// List of internally handled extensions.
static const char* extensions[] = {"set_page_color"};
const std::string& internal_path = GetInternalPath(extension_path);
for (size_t i = 0; i < base::size(extensions); ++i) {
// Exact match or first directory component.
const std::string& extension = extensions[i];
if (internal_path == extension ||
internal_path.find(extension + '/') == 0) {
return true;
}
}
return false;
}
std::string GetInternalExtensionResourcePath(
const std::string& extension_path) {
return "extensions/" + GetInternalPath(extension_path);
}
std::string GetExtensionResourcePath(const std::string& extension_path,
bool* internal) {
const bool is_internal = IsInternalExtension(extension_path);
if (internal)
*internal = is_internal;
if (is_internal)
return GetInternalExtensionResourcePath(extension_path);
return extension_path;
}
bool GetExtensionResourceContents(const std::string& extension_path,
std::string& contents) {
CEF_REQUIRE_FILE_USER_BLOCKING_THREAD();
if (IsInternalExtension(extension_path)) {
const std::string& contents_path =
GetInternalExtensionResourcePath(extension_path);
return LoadBinaryResource(contents_path.c_str(), contents);
}
return ReadFileToString(extension_path, &contents);
}
void LoadExtension(CefRefPtr<CefRequestContext> request_context,
const std::string& extension_path,
CefRefPtr<CefExtensionHandler> handler) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute on the browser UI thread.
CefPostTask(TID_UI, base::BindOnce(LoadExtension, request_context,
extension_path, handler));
return;
}
if (IsInternalExtension(extension_path)) {
// Read the extension manifest and load asynchronously.
GetInternalManifest(
extension_path,
base::BindOnce(LoadExtensionWithManifest, request_context,
extension_path, handler));
} else {
// Load the extension from disk.
request_context->LoadExtension(extension_path, nullptr, handler);
}
}
void AddInternalExtensionToResourceManager(
CefRefPtr<CefExtension> extension,
CefRefPtr<CefResourceManager> resource_manager) {
DCHECK(IsInternalExtension(extension->GetPath()));
if (!CefCurrentlyOn(TID_IO)) {
// Execute on the browser IO thread.
CefPostTask(TID_IO, base::BindOnce(AddInternalExtensionToResourceManager,
extension, resource_manager));
return;
}
const std::string& origin = GetExtensionOrigin(extension->GetIdentifier());
const std::string& resource_path =
GetInternalExtensionResourcePath(extension->GetPath());
// Add provider for bundled resource files.
#if defined(OS_WIN)
// Read resources from the binary.
resource_manager->AddProvider(
CreateBinaryResourceProvider(origin, resource_path), 50, std::string());
#elif defined(OS_POSIX)
// Read resources from a directory on disk.
std::string resource_dir;
if (GetResourceDir(resource_dir)) {
resource_dir += "/" + resource_path;
resource_manager->AddDirectoryProvider(origin, resource_dir, 50,
std::string());
}
#endif
}
std::string GetExtensionOrigin(const std::string& extension_id) {
return "chrome-extension://" + extension_id + "/";
}
std::string GetExtensionURL(CefRefPtr<CefExtension> extension) {
CefRefPtr<CefDictionaryValue> browser_action =
extension->GetManifest()->GetDictionary("browser_action");
if (browser_action) {
const std::string& default_popup =
browser_action->GetString("default_popup");
if (!default_popup.empty())
return GetExtensionOrigin(extension->GetIdentifier()) + default_popup;
}
return std::string();
}
std::string GetExtensionIconPath(CefRefPtr<CefExtension> extension,
bool* internal) {
CefRefPtr<CefDictionaryValue> browser_action =
extension->GetManifest()->GetDictionary("browser_action");
if (browser_action) {
const std::string& default_icon = browser_action->GetString("default_icon");
if (!default_icon.empty()) {
return GetExtensionResourcePath(
JoinPath(extension->GetPath(), default_icon), internal);
}
}
return std::string();
}

71
src/CEF/ExtensionUtil.h Normal file
View File

@ -0,0 +1,71 @@
// 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 <string>
#include "include/cef_extension.h"
#include "include/cef_extension_handler.h"
#include "include/wrapper/cef_resource_manager.h"
// Returns true if |extension_path| can be handled internally via
// LoadBinaryResource. This checks a hard-coded list of allowed extension path
// components.
bool IsInternalExtension(const std::string& extension_path);
// Returns the path relative to the resource directory after removing the
// PK_DIR_RESOURCES prefix. This will be the relative path expected by
// LoadBinaryResource (uses '/' as path separator on all platforms). Only call
// this method for internal extensions, either when IsInternalExtension returns
// true or when the extension is handled internally through some means other
// than LoadBinaryResource. Use GetExtensionResourcePath instead if you are
// unsure whether the extension is internal or external.
std::string GetInternalExtensionResourcePath(const std::string& extension_path);
// Returns the resource path for |extension_path|. For external extensions this
// will be the full file path on disk. For internal extensions this will be the
// relative path expected by LoadBinaryResource (uses '/' as path separator on
// all platforms). Internal extensions must be on the hard-coded list enforced
// by IsInternalExtension. If |internal| is non-nullptr it will be set to true
// if the extension is handled internally.
std::string GetExtensionResourcePath(const std::string& extension_path,
bool* internal);
// Read the contents of |extension_path| into |contents|. For external
// extensions this will read the file from disk. For internal extensions this
// will call LoadBinaryResource. Internal extensions must be on the hard-coded
// list enforced by IsInternalExtension. Returns true on success. Must be
// called on the FILE thread.
bool GetExtensionResourceContents(const std::string& extension_path,
std::string& contents);
// Load |extension_path| in |request_context|. May be an internal or external
// extension. Internal extensions must be on the hard-coded list enforced by
// IsInternalExtension.
void LoadExtension(CefRefPtr<CefRequestContext> request_context,
const std::string& extension_path,
CefRefPtr<CefExtensionHandler> handler);
// Register an internal handler for extension resources. Internal extensions
// must be on the hard-coded list enforced by IsInternalExtension.
void AddInternalExtensionToResourceManager(
CefRefPtr<CefExtension> extension,
CefRefPtr<CefResourceManager> resource_manager);
// Returns the URL origin for |extension_id|.
std::string GetExtensionOrigin(const std::string& extension_id);
// Parse browser_action manifest values as defined at
// https://developer.chrome.com/extensions/browserAction
// Look for a browser_action.default_popup manifest value.
std::string GetExtensionURL(CefRefPtr<CefExtension> extension);
// Look for a browser_action.default_icon manifest value and return the resource
// path. If |internal| is non-nullptr it will be set to true if the extension is
// handled internally.
std::string GetExtensionIconPath(CefRefPtr<CefExtension> extension,
bool* internal);

112
src/CEF/FileUtil.cpp Normal file
View File

@ -0,0 +1,112 @@
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
// 2012 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 "CEF/FileUtil.h"
#include <algorithm>
#include <cstdio>
#include <memory>
#include "include/base/cef_build.h"
#include "include/cef_task.h"
bool AllowFileIO() {
if (CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)) {
NOTREACHED() << "file IO is not allowed on the current thread";
return false;
}
return true;
}
#if defined(OS_WIN)
const char kPathSep = '\\';
#else
const char kPathSep = '/';
#endif
bool ReadFileToString(const std::string& path,
std::string* contents,
size_t max_size) {
if (!AllowFileIO())
return false;
if (contents)
contents->clear();
FILE* file = fopen(path.c_str(), "rb");
if (!file)
return false;
const size_t kBufferSize = 1 << 16;
std::unique_ptr<char[]> buf(new char[kBufferSize]);
size_t len;
size_t size = 0;
bool read_status = true;
// Many files supplied in |path| have incorrect size (proc files etc).
// 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));
if ((max_size - size) < len) {
read_status = false;
break;
}
size += len;
}
read_status = read_status && !ferror(file);
fclose(file);
return read_status;
}
int WriteFile(const std::string& path, const char* data, int size) {
if (!AllowFileIO())
return -1;
FILE* file = fopen(path.c_str(), "wb");
if (!file)
return -1;
int written = 0;
do {
size_t write = fwrite(data + written, 1, size - written, file);
if (write == 0)
break;
written += static_cast<int>(write);
} while (written < size);
fclose(file);
return written;
}
std::string JoinPath(const std::string& path1, const std::string& path2) {
if (path1.empty() && path2.empty())
return std::string();
if (path1.empty())
return path2;
if (path2.empty())
return path1;
std::string result = path1;
if (result[result.size() - 1] != kPathSep)
result += kPathSep;
if (path2[0] == kPathSep)
result += path2.substr(1);
else
result += path2;
return result;
}
std::string GetFileExtension(const std::string& path) {
size_t sep = path.find_last_of(".");
if (sep != std::string::npos)
return path.substr(sep + 1);
return std::string();
}

38
src/CEF/FileUtil.h Normal file
View File

@ -0,0 +1,38 @@
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
// 2012 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.
#pragma once
#include <limits>
#include <string>
// Platform-specific path separator.
extern const char kPathSep;
// Reads the file at |path| into |contents| and returns true on success and
// false on error. In case of I/O error, |contents| holds the data that could
// be read from the file before the error occurred. When the file size exceeds
// max_size|, the function returns false with |contents| holding the file
// truncated to |max_size|. |contents| may be nullptr, in which case this
// function is useful for its side effect of priming the disk cache (could be
// used for unit tests). Calling this function on the browser process UI or IO
// threads is not allowed.
bool ReadFileToString(const std::string& path,
std::string* contents,
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.
// Calling this function on the browser process UI or IO threads is not allowed.
int WriteFile(const std::string& path, const char* data, int size);
// Combines |path1| and |path2| with the correct platform-specific path
// separator.
std::string JoinPath(const std::string& path1, const std::string& path2);
// Extracts the file extension from |path|.
std::string GetFileExtension(const std::string& path);

View File

@ -375,3 +375,8 @@ const PerfTestEntry kPerfTests[] = {
const int kPerfTestsCount = (sizeof(kPerfTests) / sizeof(kPerfTests[0]));
#if DCHECK_IS_ON()
const int kDefaultIterations = 100000;
#else
const int kDefaultIterations = 10000;
#endif

View File

@ -11,12 +11,54 @@
#include "include/views/cef_browser_view.h"
#include "include/views/cef_window.h"
#include "include/wrapper/cef_helpers.h"
#include "include/cef_crash_util.h"
#include "include/cef_file_util.h"
#include "CEF/HumanAppSwitches.h"
class HumanAppBrowserDelegate : public HumanAppBrowser::Delegate {
public:
HumanAppBrowserDelegate() = default;
void OnContextInitialized(CefRefPtr<HumanAppBrowser> app) override {
if (CefCrashReportingEnabled()) {
// Set some crash keys for testing purposes. Keys must be defined in the
// "crash_reporter.cfg" file. See cef_crash_util.h for details.
CefSetCrashKeyValue("testkey_small1", "value1_small_browser");
CefSetCrashKeyValue("testkey_small2", "value2_small_browser");
CefSetCrashKeyValue("testkey_medium1", "value1_medium_browser");
CefSetCrashKeyValue("testkey_medium2", "value2_medium_browser");
CefSetCrashKeyValue("testkey_large1", "value1_large_browser");
CefSetCrashKeyValue("testkey_large2", "value2_large_browser");
}
const std::string& crl_sets_path =
CefCommandLine::GetGlobalCommandLine()->GetSwitchValue(
kCRLSetsPath);
if (!crl_sets_path.empty()) {
// Load the CRLSets file from the specified path.
CefLoadCRLSetsFile(crl_sets_path);
}
}
void OnBeforeCommandLineProcessing(
CefRefPtr<HumanAppBrowser> app,
CefRefPtr<CefCommandLine> command_line) override {
// Append Chromium command line parameters if touch events are enabled
if (MainContext::Get()->TouchEventsEnabled())
command_line->AppendSwitchWithValue("touch-events", "enabled");
}
private:
DISALLOW_COPY_AND_ASSIGN(HumanAppBrowserDelegate);
IMPLEMENT_REFCOUNTING(HumanAppBrowserDelegate);
};
HumanAppBrowser::HumanAppBrowser() {
CreateDelegates(delegates_);
}
// static
@ -33,7 +75,6 @@ void HumanAppBrowser::PopulateSettings(CefRefPtr<CefCommandLine> command_line,
}
std::vector<std::string> cookieable_schemes;
RegisterCookieableSchemes(cookieable_schemes);
if (!cookieable_schemes.empty()) {
std::string list_str;
for (const auto& scheme : cookieable_schemes) {

View File

@ -28,11 +28,6 @@ class HumanAppBrowser : public HumanApp, public CefBrowserProcessHandler {
CefSettings& settings);
private:
static void RegisterCookieableSchemes(
std::vector<std::string>& cookieable_schemes);
static void CreateDelegates(DelegateSet& delegates);
void OnBeforeCommandLineProcessing(
const CefString& process_type,
CefRefPtr<CefCommandLine> command_line) override;

View File

@ -0,0 +1,25 @@
// 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/HumanAppContext.h"
#include "include/base/cef_logging.h"
HumanAppContext* g_main_context = nullptr;
// static
HumanAppContext* HumanAppContext::Get() {
DCHECK(g_main_context);
return g_main_context;
}
HumanAppContext::HumanAppContext() {
DCHECK(!g_main_context);
g_main_context = this;
}
HumanAppContext::~HumanAppContext() {
g_main_context = nullptr;
}

69
src/CEF/HumanAppContext.h Normal file
View File

@ -0,0 +1,69 @@
// 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 <string>
#include "include/base/cef_macros.h"
#include "include/base/cef_ref_counted.h"
#include "include/internal/cef_types_wrappers.h"
#include "CEF/OsrRendererSettings.h"
class RootWindowManager;
// Used to store global context in the browser process. The methods of this
// class are thread-safe unless otherwise indicated.
class HumanAppContext {
public:
// Returns the singleton instance of this object.
static HumanAppContext* Get();
// Returns the full path to the console log file.
virtual std::string GetConsoleLogPath() = 0;
// Returns the full path to |file_name|.
virtual std::string GetDownloadPath(const std::string& file_name) = 0;
// Returns the app working directory including trailing path separator.
virtual std::string GetAppWorkingDirectory() = 0;
// Returns the main application URL.
virtual std::string GetMainURL() = 0;
// Returns the background color.
virtual cef_color_t GetBackgroundColor() = 0;
// Returns true if the Chrome runtime will be used.
virtual bool UseChromeRuntime() = 0;
// Returns true if the Views framework will be used.
virtual bool UseViews() = 0;
// Returns true if windowless (off-screen) rendering will be used.
virtual bool UseWindowlessRendering() = 0;
// Returns true if touch events are enabled.
virtual bool TouchEventsEnabled() = 0;
// Returns true if the default popup implementation should be used.
virtual bool UseDefaultPopup() = 0;
// Populate |settings| based on command-line arguments.
virtual void PopulateSettings(CefSettings* settings) = 0;
virtual void PopulateBrowserSettings(CefBrowserSettings* settings) = 0;
virtual void PopulateOsrSettings(OsrRendererSettings* settings) = 0;
// Returns the object used to create/manage RootWindow instances.
virtual RootWindowManager* GetRootWindowManager() = 0;
protected:
HumanAppContext();
virtual ~HumanAppContext();
private:
DISALLOW_COPY_AND_ASSIGN(HumanAppContext);
};

View File

@ -0,0 +1,267 @@
// 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 <algorithm>
#include "include/cef_parser.h"
#include "CEF/HumanAppBrowser.h"
#include "CEF/HumanAppSwitches.h"
// The default URL to load in a browser window.
const char kDefaultUrl[] = "http://www.google.com";
// Returns the ARGB value for |color|.
cef_color_t ParseColor(const std::string& color) {
std::string colorToLower;
colorToLower.resize(color.size());
std::transform(color.begin(), color.end(), colorToLower.begin(), ::tolower);
if (colorToLower == "black")
return CefColorSetARGB(255, 0, 0, 0);
else if (colorToLower == "blue")
return CefColorSetARGB(255, 0, 0, 255);
else if (colorToLower == "green")
return CefColorSetARGB(255, 0, 255, 0);
else if (colorToLower == "red")
return CefColorSetARGB(255, 255, 0, 0);
else if (colorToLower == "white")
return CefColorSetARGB(255, 255, 255, 255);
// Use the default color.
return 0;
}
HumanAppContextImpl::HumanAppContextImpl(CefRefPtr<CefCommandLine> command_line,
bool terminate_when_all_windows_closed)
: command_line_(command_line),
terminate_when_all_windows_closed_(terminate_when_all_windows_closed) {
DCHECK(command_line_.get());
// Set the main URL.
if (command_line_->HasSwitch(kUrl))
main_url_ = command_line_->GetSwitchValue(kUrl);
if (main_url_.empty())
main_url_ = kDefaultUrl;
// Whether windowless (off-screen) rendering will be used.
use_windowless_rendering_ =
command_line_->HasSwitch(kOffScreenRenderingEnabled);
if (use_windowless_rendering_ &&
command_line_->HasSwitch(kOffScreenFrameRate)) {
windowless_frame_rate_ =
atoi(command_line_->GetSwitchValue(kOffScreenFrameRate)
.ToString()
.c_str());
}
// Whether transparent painting is used with windowless rendering.
const bool use_transparent_painting =
use_windowless_rendering_ &&
command_line_->HasSwitch(kTransparentPaintingEnabled);
#if defined(OS_WIN)
// Shared texture is only supported on Windows.
shared_texture_enabled_ =
use_windowless_rendering_ &&
command_line_->HasSwitch(kSharedTextureEnabled);
#endif
external_begin_frame_enabled_ =
use_windowless_rendering_ &&
command_line_->HasSwitch(kExternalBeginFrameEnabled);
if (windowless_frame_rate_ <= 0) {
// Choose a reasonable default rate based on the OSR mode.
#if defined(OS_WIN)
windowless_frame_rate_ = shared_texture_enabled_ ? 60 : 30;
#else
windowless_frame_rate_ = 30;
#endif
}
// Enable experimental Chrome runtime. See issue #2969 for details.
use_chrome_runtime_ =
command_line_->HasSwitch(kEnableChromeRuntime);
if (use_windowless_rendering_ && use_chrome_runtime_) {
LOG(ERROR)
<< "Windowless rendering is not supported with the Chrome runtime.";
use_chrome_runtime_ = false;
}
// Whether the Views framework will be used.
use_views_ = command_line_->HasSwitch(kUseViews);
if (use_windowless_rendering_ && use_views_) {
LOG(ERROR)
<< "Windowless rendering is not supported by the Views framework.";
use_views_ = false;
}
#if defined(OS_WIN) || defined(OS_LINUX)
if (use_chrome_runtime_ && !use_views_ &&
!command_line->HasSwitch(kUseNative)) {
LOG(WARNING) << "Chrome runtime defaults to the Views framework.";
use_views_ = true;
}
#else // !(defined(OS_WIN) || defined(OS_LINUX))
if (use_chrome_runtime_ && !use_views_) {
// TODO(chrome): Add support for this runtime configuration (e.g. a fully
// styled Chrome window with cefclient menu customizations). In the mean
// time this can be demo'd with "cefsimple --enable-chrome-runtime".
LOG(WARNING) << "Chrome runtime requires the Views framework.";
use_views_ = true;
}
#endif // !(defined(OS_WIN) || defined(OS_LINUX))
if (use_views_ && command_line->HasSwitch(kHideFrame) &&
!command_line_->HasSwitch(kUrl)) {
// Use the draggable regions test as the default URL for frameless windows.
main_url_ = "http://tests/draggable";
}
if (command_line_->HasSwitch(kBackgroundColor)) {
// Parse the background color value.
background_color_ =
ParseColor(command_line_->GetSwitchValue(kBackgroundColor));
}
if (background_color_ == 0 && !use_views_) {
// Set an explicit background color.
background_color_ = CefColorSetARGB(255, 255, 255, 255);
}
// |browser_background_color_| should remain 0 to enable transparent painting.
if (!use_transparent_painting) {
browser_background_color_ = background_color_;
}
}
HumanAppContextImpl::~HumanAppContextImpl() {
// The context must either not have been initialized, or it must have also
// been shut down.
DCHECK(!initialized_ || shutdown_);
}
std::string HumanAppContextImpl::GetConsoleLogPath() {
return GetAppWorkingDirectory() + "console.log";
}
std::string HumanAppContextImpl::GetMainURL() {
return main_url_;
}
cef_color_t HumanAppContextImpl::GetBackgroundColor() {
return background_color_;
}
bool HumanAppContextImpl::UseChromeRuntime() {
return use_chrome_runtime_;
}
bool HumanAppContextImpl::UseViews() {
return use_views_;
}
bool HumanAppContextImpl::UseWindowlessRendering() {
return use_windowless_rendering_;
}
bool HumanAppContextImpl::TouchEventsEnabled() {
return command_line_->GetSwitchValue("touch-events") == "enabled";
}
bool HumanAppContextImpl::UseDefaultPopup() {
return !use_windowless_rendering_ &&
command_line_->HasSwitch(kUseDefaultPopup);
}
void HumanAppContextImpl::PopulateSettings(CefSettings* settings) {
HumanAppBrowser::PopulateSettings(command_line_, *settings);
if (use_chrome_runtime_)
settings->chrome_runtime = true;
CefString(&settings->cache_path) =
command_line_->GetSwitchValue(kCachePath);
if (use_windowless_rendering_)
settings->windowless_rendering_enabled = true;
if (browser_background_color_ != 0)
settings->background_color = browser_background_color_;
if (command_line_->HasSwitch("lang")) {
// Use the same locale for the Accept-Language HTTP request header.
CefString(&settings->accept_language_list) =
command_line_->GetSwitchValue("lang");
}
}
void HumanAppContextImpl::PopulateBrowserSettings(CefBrowserSettings* settings) {
settings->windowless_frame_rate = windowless_frame_rate_;
if (browser_background_color_ != 0)
settings->background_color = browser_background_color_;
if (use_chrome_runtime_ &&
command_line_->HasSwitch(kHideChromeStatusBubble)) {
settings->chrome_status_bubble = STATE_DISABLED;
}
}
void HumanAppContextImpl::PopulateOsrSettings(OsrRendererSettings* settings) {
settings->show_update_rect =
command_line_->HasSwitch(kShowUpdateRect);
#if defined(OS_WIN)
settings->shared_texture_enabled = shared_texture_enabled_;
#endif
settings->external_begin_frame_enabled = external_begin_frame_enabled_;
settings->begin_frame_rate = windowless_frame_rate_;
if (browser_background_color_ != 0)
settings->background_color = browser_background_color_;
}
RootWindowManager* HumanAppContextImpl::GetRootWindowManager() {
DCHECK(InValidState());
return root_window_manager_.get();
}
bool HumanAppContextImpl::Initialize(const CefMainArgs& args,
const CefSettings& settings,
CefRefPtr<CefApp> application,
void* windows_sandbox_info) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!initialized_);
DCHECK(!shutdown_);
if (!CefInitialize(args, settings, application, windows_sandbox_info))
return false;
// Need to create the RootWindowManager after calling CefInitialize because
// TempWindowX11 uses cef_get_xdisplay().
root_window_manager_.reset(
new RootWindowManager(terminate_when_all_windows_closed_));
initialized_ = true;
return true;
}
void HumanAppContextImpl::Shutdown() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(initialized_);
DCHECK(!shutdown_);
root_window_manager_.reset();
CefShutdown();
shutdown_ = true;
}

View File

@ -0,0 +1,87 @@
// 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 <string>
#include "include/base/cef_thread_checker.h"
#include "include/cef_app.h"
#include "include/cef_command_line.h"
#include "CEF/HumanAppContext.h"
class HumanAppContextImpl : public HumanAppContext {
public:
HumanAppContextImpl(CefRefPtr<CefCommandLine> command_line,
bool terminate_when_all_windows_closed);
// MainContext members.
std::string GetConsoleLogPath() override;
std::string GetDownloadPath(const std::string& file_name) override;
std::string GetAppWorkingDirectory() override;
std::string GetMainURL() override;
cef_color_t GetBackgroundColor() override;
bool UseChromeRuntime() override;
bool UseViews() override;
bool UseWindowlessRendering() override;
bool TouchEventsEnabled() override;
bool UseDefaultPopup() override;
void PopulateSettings(CefSettings* settings) override;
void PopulateBrowserSettings(CefBrowserSettings* settings) override;
void PopulateOsrSettings(OsrRendererSettings* settings) override;
RootWindowManager* GetRootWindowManager() override;
// Initialize CEF and associated main context state. This method must be
// called on the same thread that created this object.
bool Initialize(const CefMainArgs& args,
const CefSettings& settings,
CefRefPtr<CefApp> application,
void* windows_sandbox_info);
// Shut down CEF and associated context state. This method must be called on
// the same thread that created this object.
void Shutdown();
private:
// Allow deletion via std::unique_ptr only.
friend std::default_delete<HumanAppContextImpl>;
~HumanAppContextImpl();
// Returns true if the context is in a valid state (initialized and not yet
// shut down).
bool InValidState() const { return initialized_ && !shutdown_; }
CefRefPtr<CefCommandLine> command_line_;
const bool terminate_when_all_windows_closed_;
// Track context state. Accessing these variables from multiple threads is
// safe because only a single thread will exist at the time that they're set
// (during context initialization and shutdown).
bool initialized_ = false;
bool shutdown_ = false;
std::string main_url_;
cef_color_t background_color_ = 0;
cef_color_t browser_background_color_ = 0;
bool use_windowless_rendering_;
int windowless_frame_rate_ = 0;
bool use_chrome_runtime_;
bool use_views_;
std::unique_ptr<RootWindowManager> root_window_manager_;
#if defined(OS_WIN)
bool shared_texture_enabled_;
#endif
bool external_begin_frame_enabled_;
// Used to verify that methods are called on the correct thread.
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(HumanAppContextImpl);
};

29
src/CEF/HumanApptypes.h Normal file
View File

@ -0,0 +1,29 @@
// 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_CLIENT_TYPES_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_TYPES_H_
#pragma once
#include "include/cef_base.h"
#if defined(OS_LINUX)
#include <gtk/gtk.h>
// The Linux client uses GTK instead of the underlying platform type (X11).
#define ClientWindowHandle GtkWidget*
#else
#define ClientWindowHandle CefWindowHandle
#endif
#if defined(OS_MAC)
#define ClientNativeMacWindow void*
#ifdef __OBJC__
#define CAST_CLIENT_NATIVE_MAC_WINDOW_TO_NSWINDOW(native) \
(__bridge NSWindow*)native
#define CAST_NSWINDOW_TO_CLIENT_NATIVE_MAC_WINDOW(window) (__bridge void*)window
#endif // __OBJC__
#endif // defined OS_MAC
#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_TYPES_H_

304
src/CEF/ImageCache.cpp Normal file
View File

@ -0,0 +1,304 @@
// 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/ImageCache.h"
#include <algorithm>
#include "CEF/FileUtil.h"
#include "CEF/ResourceUtil.h"
const char kEmptyId[] = "__empty";
ImageCache::ImageCache() {}
ImageCache::~ImageCache() {
CEF_REQUIRE_UI_THREAD();
}
ImageCache::ImageRep::ImageRep(const std::string& path, float scale_factor)
: path_(path), scale_factor_(scale_factor) {
DCHECK(!path_.empty());
DCHECK_GT(scale_factor_, 0.0f);
}
ImageCache::ImageInfo::ImageInfo(const std::string& id,
const ImageRepSet& reps,
bool internal,
bool force_reload)
: id_(id), reps_(reps), internal_(internal), force_reload_(force_reload) {
#ifndef NDEBUG
DCHECK(!id_.empty());
if (id_ != kEmptyId)
DCHECK(!reps_.empty());
#endif
}
// static
ImageCache::ImageInfo ImageCache::ImageInfo::Empty() {
return ImageInfo(kEmptyId, ImageRepSet(), true, false);
}
// static
ImageCache::ImageInfo ImageCache::ImageInfo::Create1x(
const std::string& id,
const std::string& path_1x,
bool internal) {
ImageRepSet reps;
reps.push_back(ImageRep(path_1x, 1.0f));
return ImageInfo(id, reps, internal, false);
}
// static
ImageCache::ImageInfo ImageCache::ImageInfo::Create2x(
const std::string& id,
const std::string& path_1x,
const std::string& path_2x,
bool internal) {
ImageRepSet reps;
reps.push_back(ImageRep(path_1x, 1.0f));
reps.push_back(ImageRep(path_2x, 2.0f));
return ImageInfo(id, reps, internal, false);
}
// static
ImageCache::ImageInfo ImageCache::ImageInfo::Create2x(const std::string& id) {
return Create2x(id, id + ".1x.png", id + ".2x.png", true);
}
struct ImageCache::ImageContent {
ImageContent() {}
struct RepContent {
RepContent(ImageType type, float scale_factor, const std::string& contents)
: type_(type), scale_factor_(scale_factor), contents_(contents) {}
ImageType type_;
float scale_factor_;
std::string contents_;
};
typedef std::vector<RepContent> RepContentSet;
RepContentSet contents_;
CefRefPtr<CefImage> image_;
};
void ImageCache::LoadImages(const ImageInfoSet& image_info,
LoadImagesCallback callback) {
DCHECK(!image_info.empty());
DCHECK(!callback.is_null());
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::BindOnce(&ImageCache::LoadImages, this,
image_info, std::move(callback)));
return;
}
ImageSet images;
bool missing_images = false;
ImageInfoSet::const_iterator it = image_info.begin();
for (; it != image_info.end(); ++it) {
const ImageInfo& info = *it;
if (info.id_ == kEmptyId) {
// Image intentionally left empty.
images.push_back(nullptr);
continue;
}
ImageMap::iterator it2 = image_map_.find(info.id_);
if (it2 != image_map_.end()) {
if (!info.force_reload_) {
// Image already exists.
images.push_back(it2->second);
continue;
}
// Remove the existing image from the map.
image_map_.erase(it2);
}
// Load the image.
images.push_back(nullptr);
if (!missing_images)
missing_images = true;
}
if (missing_images) {
CefPostTask(TID_FILE_USER_BLOCKING,
base::BindOnce(&ImageCache::LoadMissing, this, image_info,
images, std::move(callback)));
} else {
std::move(callback).Run(images);
}
}
CefRefPtr<CefImage> ImageCache::GetCachedImage(const std::string& image_id) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!image_id.empty());
ImageMap::const_iterator it = image_map_.find(image_id);
if (it != image_map_.end())
return it->second;
return nullptr;
}
// static
ImageCache::ImageType ImageCache::GetImageType(const std::string& path) {
std::string ext = GetFileExtension(path);
if (ext.empty())
return TYPE_NONE;
std::transform(ext.begin(), ext.end(), ext.begin(), tolower);
if (ext == "png")
return TYPE_PNG;
if (ext == "jpg" || ext == "jpeg")
return TYPE_JPEG;
return TYPE_NONE;
}
void ImageCache::LoadMissing(const ImageInfoSet& image_info,
const ImageSet& images,
LoadImagesCallback callback) {
CEF_REQUIRE_FILE_USER_BLOCKING_THREAD();
DCHECK_EQ(image_info.size(), images.size());
ImageContentSet contents;
ImageInfoSet::const_iterator it1 = image_info.begin();
ImageSet::const_iterator it2 = images.begin();
for (; it1 != image_info.end() && it2 != images.end(); ++it1, ++it2) {
const ImageInfo& info = *it1;
ImageContent content;
if (*it2 || info.id_ == kEmptyId) {
// Image already exists or is intentionally empty.
content.image_ = *it2;
} else {
LoadImageContents(info, &content);
}
contents.push_back(content);
}
CefPostTask(TID_UI, base::BindOnce(&ImageCache::UpdateCache, this, image_info,
contents, std::move(callback)));
}
// static
bool ImageCache::LoadImageContents(const ImageInfo& info,
ImageContent* content) {
CEF_REQUIRE_FILE_USER_BLOCKING_THREAD();
ImageRepSet::const_iterator it = info.reps_.begin();
for (; it != info.reps_.end(); ++it) {
const ImageRep& rep = *it;
ImageType rep_type;
std::string rep_contents;
if (!LoadImageContents(rep.path_, info.internal_, &rep_type,
&rep_contents)) {
LOG(ERROR) << "Failed to load image " << info.id_ << " from path "
<< rep.path_;
return false;
}
content->contents_.push_back(
ImageContent::RepContent(rep_type, rep.scale_factor_, rep_contents));
}
return true;
}
// static
bool ImageCache::LoadImageContents(const std::string& path,
bool internal,
ImageType* type,
std::string* contents) {
CEF_REQUIRE_FILE_USER_BLOCKING_THREAD();
*type = GetImageType(path);
if (*type == TYPE_NONE)
return false;
if (internal) {
if (!LoadBinaryResource(path.c_str(), *contents))
return false;
} else if (!ReadFileToString(path, contents)) {
return false;
}
return !contents->empty();
}
void ImageCache::UpdateCache(const ImageInfoSet& image_info,
const ImageContentSet& contents,
LoadImagesCallback callback) {
CEF_REQUIRE_UI_THREAD();
DCHECK_EQ(image_info.size(), contents.size());
ImageSet images;
ImageInfoSet::const_iterator it1 = image_info.begin();
ImageContentSet::const_iterator it2 = contents.begin();
for (; it1 != image_info.end() && it2 != contents.end(); ++it1, ++it2) {
const ImageInfo& info = *it1;
const ImageContent& content = *it2;
if (content.image_ || info.id_ == kEmptyId) {
// Image already exists or is intentionally empty.
images.push_back(content.image_);
} else {
CefRefPtr<CefImage> image = CreateImage(info.id_, content);
images.push_back(image);
// Add the image to the map.
image_map_.insert(std::make_pair(info.id_, image));
}
}
std::move(callback).Run(images);
}
// static
CefRefPtr<CefImage> ImageCache::CreateImage(const std::string& image_id,
const ImageContent& content) {
CEF_REQUIRE_UI_THREAD();
// Shouldn't be creating an image if one already exists.
DCHECK(!content.image_);
if (content.contents_.empty())
return nullptr;
CefRefPtr<CefImage> image = CefImage::CreateImage();
ImageContent::RepContentSet::const_iterator it = content.contents_.begin();
for (; it != content.contents_.end(); ++it) {
const ImageContent::RepContent& rep = *it;
if (rep.type_ == TYPE_PNG) {
if (!image->AddPNG(rep.scale_factor_, rep.contents_.c_str(),
rep.contents_.size())) {
LOG(ERROR) << "Failed to create image " << image_id << " for PNG@"
<< rep.scale_factor_;
return nullptr;
}
} else if (rep.type_ == TYPE_JPEG) {
if (!image->AddJPEG(rep.scale_factor_, rep.contents_.c_str(),
rep.contents_.size())) {
LOG(ERROR) << "Failed to create image " << image_id << " for JPG@"
<< rep.scale_factor_;
return nullptr;
}
} else {
NOTREACHED();
return nullptr;
}
}
return image;
}

121
src/CEF/ImageCache.h Normal file
View File

@ -0,0 +1,121 @@
// 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 <map>
#include <vector>
#include "include/base/cef_callback.h"
#include "include/base/cef_ref_counted.h"
#include "include/cef_image.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
// Simple image caching implementation.
class ImageCache
: public base::RefCountedThreadSafe<ImageCache, CefDeleteOnUIThread> {
public:
ImageCache();
// Image representation at a specific scale factor.
struct ImageRep {
ImageRep(const std::string& path, float scale_factor);
// Full file system path.
std::string path_;
// Image scale factor (usually 1.0f or 2.0f).
float scale_factor_;
};
using ImageRepSet = std::vector<ImageRep>;
// Unique image that may have multiple representations.
struct ImageInfo {
ImageInfo(const std::string& id,
const ImageRepSet& reps,
bool internal,
bool force_reload);
// Helper for returning an empty image.
static ImageInfo Empty();
// Helpers for creating common representations.
static ImageInfo Create1x(const std::string& id,
const std::string& path_1x,
bool internal);
static ImageInfo Create2x(const std::string& id,
const std::string& path_1x,
const std::string& path_2x,
bool internal);
static ImageInfo Create2x(const std::string& id);
// Image unique ID.
std::string id_;
// Image representations to load.
ImageRepSet reps_;
// True if the image is internal (loaded via LoadBinaryResource).
bool internal_;
// True to force reload.
bool force_reload_;
};
using ImageInfoSet = std::vector<ImageInfo>;
using ImageSet = std::vector<CefRefPtr<CefImage>>;
using LoadImagesCallback =
base::OnceCallback<void(const ImageSet& /*images*/)>;
// Loads the images represented by |image_info|. Executes |callback|
// either synchronously or asychronously on the UI thread after completion.
void LoadImages(const ImageInfoSet& image_info, LoadImagesCallback callback);
// Returns an image that has already been cached. Must be called on the
// UI thread.
CefRefPtr<CefImage> GetCachedImage(const std::string& image_id);
private:
// Only allow deletion via scoped_refptr.
friend struct CefDeleteOnThread<TID_UI>;
friend class base::RefCountedThreadSafe<ImageCache, CefDeleteOnUIThread>;
~ImageCache();
enum ImageType {
TYPE_NONE,
TYPE_PNG,
TYPE_JPEG,
};
static ImageType GetImageType(const std::string& path);
struct ImageContent;
using ImageContentSet = std::vector<ImageContent>;
// Load missing image contents on the FILE thread.
void LoadMissing(const ImageInfoSet& image_info,
const ImageSet& images,
LoadImagesCallback callback);
static bool LoadImageContents(const ImageInfo& info, ImageContent* content);
static bool LoadImageContents(const std::string& path,
bool internal,
ImageType* type,
std::string* contents);
// Create missing CefImage representations on the UI thread.
void UpdateCache(const ImageInfoSet& image_info,
const ImageContentSet& contents,
LoadImagesCallback callback);
static CefRefPtr<CefImage> CreateImage(const std::string& image_id,
const ImageContent& content);
// Map image ID to image representation. Only accessed on the UI thread.
using ImageMap = std::map<std::string, CefRefPtr<CefImage>>;
ImageMap image_map_;
};

View File

@ -0,0 +1,41 @@
// 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/shared/browser/main_message_loop.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;
}
MainMessageLoop::~MainMessageLoop() {
g_main_message_loop = nullptr;
}
// static
MainMessageLoop* MainMessageLoop::Get() {
DCHECK(g_main_message_loop);
return g_main_message_loop;
}
void MainMessageLoop::PostClosure(base::OnceClosure closure) {
PostTask(CefCreateClosureTask(std::move(closure)));
}
void MainMessageLoop::PostClosure(const base::RepeatingClosure& closure) {
PostTask(CefCreateClosureTask(closure));
}
} // namespace client

103
src/CEF/MainMessageLoop.h Normal file
View File

@ -0,0 +1,103 @@
// 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/base/cef_callback.h"
#include "include/cef_task.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
// Represents the message loop running on the main application thread in the
// browser process. This will be the same as the CEF UI thread on Linux, OS X
// and Windows when not using multi-threaded message loop mode. The methods of
// this class are thread-safe unless otherwise indicated.
class MainMessageLoop {
public:
// Returns the singleton instance of this object.
static MainMessageLoop* Get();
// Run the message loop. The thread that this method is called on will be
// considered the main thread. This blocks until Quit() is called.
virtual int Run() = 0;
// Quit the message loop.
virtual void Quit() = 0;
// Post a task for execution on the main message loop.
virtual void PostTask(CefRefPtr<CefTask> task) = 0;
// Returns true if this message loop runs tasks on the current thread.
virtual bool RunsTasksOnCurrentThread() const = 0;
#if defined(OS_WIN)
// Set the current modeless dialog on Windows for proper delivery of dialog
// messages when using multi-threaded message loop mode. This method must be
// called from the main thread. See http://support.microsoft.com/kb/71450 for
// background.
virtual void SetCurrentModelessDialog(HWND hWndDialog) = 0;
#endif
// Post a closure for execution on the main message loop.
void PostClosure(base::OnceClosure closure);
void PostClosure(const base::RepeatingClosure& closure);
protected:
// Only allow deletion via std::unique_ptr.
friend std::default_delete<MainMessageLoop>;
MainMessageLoop();
virtual ~MainMessageLoop();
private:
DISALLOW_COPY_AND_ASSIGN(MainMessageLoop);
};
#define CURRENTLY_ON_MAIN_THREAD() \
client::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_CLOSURE(closure) \
client::MainMessageLoop::Get()->PostClosure(closure)
// Use this struct in conjuction with RefCountedThreadSafe to ensure that an
// object is deleted on the main thread. For example:
//
// class Foo : public base::RefCountedThreadSafe<Foo, DeleteOnMainThread> {
// public:
// Foo();
// void DoSomething();
//
// private:
// // Allow deletion via scoped_refptr only.
// friend struct DeleteOnMainThread;
// friend class base::RefCountedThreadSafe<Foo, DeleteOnMainThread>;
//
// virtual ~Foo() {}
// };
//
// base::scoped_refptr<Foo> foo = new Foo();
// foo->DoSomething();
// foo = nullptr; // Deletion of |foo| will occur on the main thread.
//
struct DeleteOnMainThread {
template <typename T>
static void Destruct(const T* x) {
if (CURRENTLY_ON_MAIN_THREAD()) {
delete x;
} else {
client::MainMessageLoop::Get()->PostClosure(base::BindOnce(
&DeleteOnMainThread::Destruct<T>, base::Unretained(x)));
}
}
};

View File

@ -0,0 +1,107 @@
// 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 "tests/shared/browser/main_message_loop_external_pump.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 {
// Special timer delay placeholder value. Intentionally 32-bit for Windows and
// OS X platform API compatibility.
const int32 kTimerDelayPlaceholder = INT_MAX;
// The maximum number of milliseconds we're willing to wait between calls to
// DoWork().
const int64 kMaxTimerDelay = 1000 / 30; // 30fps
client::MainMessageLoopExternalPump* g_external_message_pump = nullptr;
} // namespace
MainMessageLoopExternalPump::MainMessageLoopExternalPump()
: is_active_(false), reentrancy_detected_(false) {
DCHECK(!g_external_message_pump);
g_external_message_pump = this;
}
MainMessageLoopExternalPump::~MainMessageLoopExternalPump() {
g_external_message_pump = nullptr;
}
MainMessageLoopExternalPump* MainMessageLoopExternalPump::Get() {
return g_external_message_pump;
}
void MainMessageLoopExternalPump::OnScheduleWork(int64 delay_ms) {
REQUIRE_MAIN_THREAD();
if (delay_ms == kTimerDelayPlaceholder && IsTimerPending()) {
// Don't set the maximum timer requested from DoWork() if a timer event is
// currently pending.
return;
}
KillTimer();
if (delay_ms <= 0) {
// Execute the work immediately.
DoWork();
} else {
// Never wait longer than the maximum allowed time.
if (delay_ms > kMaxTimerDelay)
delay_ms = kMaxTimerDelay;
// Results in call to OnTimerTimeout() after the specified delay.
SetTimer(delay_ms);
}
}
void MainMessageLoopExternalPump::OnTimerTimeout() {
REQUIRE_MAIN_THREAD();
KillTimer();
DoWork();
}
void MainMessageLoopExternalPump::DoWork() {
const bool was_reentrant = PerformMessageLoopWork();
if (was_reentrant) {
// Execute the remaining work as soon as possible.
OnScheduleMessagePumpWork(0);
} else if (!IsTimerPending()) {
// Schedule a timer event at the maximum allowed time. This may be dropped
// in OnScheduleWork() if another timer event is already in-flight.
OnScheduleMessagePumpWork(kTimerDelayPlaceholder);
}
}
bool MainMessageLoopExternalPump::PerformMessageLoopWork() {
if (is_active_) {
// When CefDoMessageLoopWork() is called there may be various callbacks
// (such as paint and IPC messages) that result in additional calls to this
// method. If re-entrancy is detected we must repost a request again to the
// owner thread to ensure that the discarded call is executed in the future.
reentrancy_detected_ = true;
return false;
}
reentrancy_detected_ = false;
is_active_ = true;
CefDoMessageLoopWork();
is_active_ = false;
// |reentrancy_detected_| may have changed due to re-entrant calls to this
// method.
return reentrancy_detected_;
}
} // namespace client

View File

@ -0,0 +1,70 @@
// 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.
#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 {
// This MessageLoop implementation simulates the embedding of CEF into an
// existing host application that runs its own message loop. The scheduling
// implementation provided by this class is very simplistic and does not handle
// all cases (for example, nested message loops on Windows will not function
// correctly). See comments in Chromium's platform-specific
// base/message_loop/message_pump_* source files for additional guidance when
// implementing CefBrowserProcessHandler::OnScheduleMessagePumpWork() in your
// application. Run cefclient or ceftests with the
// "--external-message-pump" command-line flag to test this mode.
class MainMessageLoopExternalPump : public MainMessageLoopStd {
public:
// Creates the singleton instance of this object. Must be called on the main
// application thread.
static std::unique_ptr<MainMessageLoopExternalPump> Create();
// Returns the singleton instance of this object. Safe to call from any
// thread.
static MainMessageLoopExternalPump* Get();
// Called from CefBrowserProcessHandler::OnScheduleMessagePumpWork() on any
// thread. The platform subclass must implement this method and schedule a
// call to OnScheduleWork() on the main application thread.
virtual void OnScheduleMessagePumpWork(int64 delay_ms) = 0;
protected:
// Only allow deletion via std::unique_ptr.
friend std::default_delete<MainMessageLoopExternalPump>;
// Construct and destruct this object on the main application thread.
MainMessageLoopExternalPump();
~MainMessageLoopExternalPump();
// The platform subclass calls this method on the main application thread in
// response to the OnScheduleMessagePumpWork() call.
void OnScheduleWork(int64 delay_ms);
// The platform subclass calls this method on the main application thread when
// the pending work timer times out.
void OnTimerTimeout();
// Control the pending work timer in the platform subclass. Only called on
// the main application thread.
virtual void SetTimer(int64 delay_ms) = 0;
virtual void KillTimer() = 0;
virtual bool IsTimerPending() = 0;
private:
// Handle work processing.
void DoWork();
bool PerformMessageLoopWork();
bool is_active_;
bool reentrancy_detected_;
};
} // namespace client
#endif // CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_EXTERNAL_PUMP_H_

View File

@ -0,0 +1,154 @@
// 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 "tests/shared/browser/main_message_loop_external_pump.h"
#include <CommCtrl.h>
#include <memory>
#include "include/cef_app.h"
#include "tests/shared/browser/util_win.h"
namespace client {
namespace {
// Message sent to get an additional time slice for pumping (processing) another
// task (a series of such messages creates a continuous task pump).
static const int kMsgHaveWork = WM_USER + 1;
class MainMessageLoopExternalPumpWin : public MainMessageLoopExternalPump {
public:
MainMessageLoopExternalPumpWin();
~MainMessageLoopExternalPumpWin();
// MainMessageLoopStd methods:
void Quit() override;
int Run() override;
// MainMessageLoopExternalPump methods:
void OnScheduleMessagePumpWork(int64 delay_ms) override;
protected:
// MainMessageLoopExternalPump methods:
void SetTimer(int64 delay_ms) override;
void KillTimer() override;
bool IsTimerPending() override { return timer_pending_; }
private:
static LRESULT CALLBACK WndProc(HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam);
// True if a timer event is currently pending.
bool timer_pending_;
// HWND owned by the thread that CefDoMessageLoopWork should be invoked on.
HWND main_thread_target_;
};
MainMessageLoopExternalPumpWin::MainMessageLoopExternalPumpWin()
: timer_pending_(false), main_thread_target_(nullptr) {
HINSTANCE hInstance = GetModuleHandle(nullptr);
const wchar_t* const kClassName = L"CEFMainTargetHWND";
WNDCLASSEX wcex = {};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = kClassName;
RegisterClassEx(&wcex);
// Create the message handling window.
main_thread_target_ =
CreateWindowW(kClassName, nullptr, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0,
HWND_MESSAGE, nullptr, hInstance, nullptr);
DCHECK(main_thread_target_);
SetUserDataPtr(main_thread_target_, this);
}
MainMessageLoopExternalPumpWin::~MainMessageLoopExternalPumpWin() {
KillTimer();
if (main_thread_target_)
DestroyWindow(main_thread_target_);
}
void MainMessageLoopExternalPumpWin::Quit() {
PostMessage(nullptr, WM_QUIT, 0, 0);
}
int MainMessageLoopExternalPumpWin::Run() {
// Run the message loop.
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
KillTimer();
// We need to run the message pump until it is idle. However we don't have
// that information here so we run the message loop "for a while".
for (int i = 0; i < 10; ++i) {
// Do some work.
CefDoMessageLoopWork();
// Sleep to allow the CEF proc to do work.
Sleep(50);
}
return 0;
}
void MainMessageLoopExternalPumpWin::OnScheduleMessagePumpWork(int64 delay_ms) {
// This method may be called on any thread.
PostMessage(main_thread_target_, kMsgHaveWork, 0,
static_cast<LPARAM>(delay_ms));
}
void MainMessageLoopExternalPumpWin::SetTimer(int64 delay_ms) {
DCHECK(!timer_pending_);
DCHECK_GT(delay_ms, 0);
timer_pending_ = true;
::SetTimer(main_thread_target_, 1, static_cast<UINT>(delay_ms), nullptr);
}
void MainMessageLoopExternalPumpWin::KillTimer() {
if (timer_pending_) {
::KillTimer(main_thread_target_, 1);
timer_pending_ = false;
}
}
// static
LRESULT CALLBACK MainMessageLoopExternalPumpWin::WndProc(HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam) {
if (msg == WM_TIMER || msg == kMsgHaveWork) {
MainMessageLoopExternalPumpWin* message_loop =
GetUserDataPtr<MainMessageLoopExternalPumpWin*>(hwnd);
if (msg == kMsgHaveWork) {
// OnScheduleMessagePumpWork() request.
const int64 delay_ms = static_cast<int64>(lparam);
message_loop->OnScheduleWork(delay_ms);
} else {
// Timer timed out.
message_loop->OnTimerTimeout();
}
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
} // namespace
// static
std::unique_ptr<MainMessageLoopExternalPump>
MainMessageLoopExternalPump::Create() {
return std::make_unique<MainMessageLoopExternalPumpWin>();
}
} // namespace client

View File

@ -0,0 +1,37 @@
// 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/shared/browser/main_message_loop_std.h"
#include "include/cef_app.h"
namespace client {
MainMessageLoopStd::MainMessageLoopStd() {}
int MainMessageLoopStd::Run() {
CefRunMessageLoop();
return 0;
}
void MainMessageLoopStd::Quit() {
CefQuitMessageLoop();
}
void MainMessageLoopStd::PostTask(CefRefPtr<CefTask> task) {
CefPostTask(TID_UI, task);
}
bool MainMessageLoopStd::RunsTasksOnCurrentThread() const {
return CefCurrentlyOn(TID_UI);
}
#if defined(OS_WIN)
void MainMessageLoopStd::SetCurrentModelessDialog(HWND hWndDialog) {
// Nothing to do here. The Chromium message loop implementation will
// internally route dialog messages.
}
#endif
} // namespace client

View File

@ -0,0 +1,35 @@
// 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_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 {
// Represents the main message loop in the browser process. This implementation
// is a light-weight wrapper around the Chromium UI thread.
class MainMessageLoopStd : public MainMessageLoop {
public:
MainMessageLoopStd();
// MainMessageLoop methods.
int Run() override;
void Quit() override;
void PostTask(CefRefPtr<CefTask> task) override;
bool RunsTasksOnCurrentThread() const override;
#if defined(OS_WIN)
void SetCurrentModelessDialog(HWND hWndDialog) override;
#endif
private:
DISALLOW_COPY_AND_ASSIGN(MainMessageLoopStd);
};
} // namespace client
#endif // CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_STD_H_

View File

@ -0,0 +1,30 @@
// 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 "include/internal/cef_types.h"
struct OsrRendererSettings {
OsrRendererSettings()
: show_update_rect(false),
background_color(0),
shared_texture_enabled(false),
external_begin_frame_enabled(false),
begin_frame_rate(0) {}
// If true draw a border around update rectangles.
bool show_update_rect;
// Background color. Enables transparency if the alpha component is 0.
cef_color_t background_color;
// Render using shared textures. Supported on Windows only via D3D11.
bool shared_texture_enabled;
// Client implements a BeginFrame timer by calling
// CefBrowserHost::SendExternalBeginFrame at the specified frame rate.
bool external_begin_frame_enabled;
int begin_frame_rate;
};

33
src/CEF/ResourceUtil.h Normal file
View File

@ -0,0 +1,33 @@
// 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 <string>
#include "include/cef_image.h"
#include "include/cef_stream.h"
#if defined(OS_WIN)
#include "include/wrapper/cef_resource_manager.h"
#endif
#if defined(OS_POSIX)
// Returns the directory containing resource files.
bool GetResourceDir(std::string& dir);
#endif
// Retrieve a resource as a string.
bool LoadBinaryResource(const char* resource_name, std::string& resource_data);
// Retrieve a resource as a steam reader.
CefRefPtr<CefStreamReader> GetBinaryResourceReader(const char* resource_name);
#if defined(OS_WIN)
// Create a new provider for loading binary resources.
CefResourceManager::Provider* CreateBinaryResourceProvider(
const std::string& url_path,
const std::string& resource_path_prefix);
#endif

121
src/CEF/ResourceUtilWin.cpp Normal file
View File

@ -0,0 +1,121 @@
// 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/ResourceUtil.h"
#include "include/base/cef_logging.h"
#include "include/cef_stream.h"
#include "include/wrapper/cef_byte_read_handler.h"
#include "include/wrapper/cef_stream_resource_handler.h"
bool LoadBinaryResource(int binaryId, DWORD& dwSize, LPBYTE& pBytes) {
HINSTANCE hInst = GetModuleHandle(nullptr);
HRSRC hRes =
FindResource(hInst, MAKEINTRESOURCE(binaryId), MAKEINTRESOURCE(256));
if (hRes) {
HGLOBAL hGlob = LoadResource(hInst, hRes);
if (hGlob) {
dwSize = SizeofResource(hInst, hRes);
pBytes = (LPBYTE)LockResource(hGlob);
if (dwSize > 0 && pBytes)
return true;
}
}
return false;
}
// Provider of binary resources.
class BinaryResourceProvider : public CefResourceManager::Provider {
public:
BinaryResourceProvider(const std::string& url_path,
const std::string& resource_path_prefix)
: url_path_(url_path), resource_path_prefix_(resource_path_prefix) {
DCHECK(!url_path.empty());
if (!resource_path_prefix_.empty() &&
resource_path_prefix_[resource_path_prefix_.length() - 1] != '/') {
resource_path_prefix_ += "/";
}
}
bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
CEF_REQUIRE_IO_THREAD();
const std::string& url = request->url();
if (url.find(url_path_) != 0L) {
// Not handled by this provider.
return false;
}
CefRefPtr<CefResourceHandler> handler;
std::string relative_path = url.substr(url_path_.length());
if (!relative_path.empty()) {
if (!resource_path_prefix_.empty())
relative_path = resource_path_prefix_ + relative_path;
CefRefPtr<CefStreamReader> stream =
GetBinaryResourceReader(relative_path.data());
if (stream.get()) {
handler = new CefStreamResourceHandler(
request->mime_type_resolver().Run(url), stream);
}
}
request->Continue(handler);
return true;
}
private:
std::string url_path_;
std::string resource_path_prefix_;
DISALLOW_COPY_AND_ASSIGN(BinaryResourceProvider);
};
} // namespace
// Implemented in resource_util_win_idmap.cc.
extern int GetResourceId(const char* resource_name);
bool LoadBinaryResource(const char* resource_name, std::string& resource_data) {
int resource_id = GetResourceId(resource_name);
if (resource_id == 0)
return false;
DWORD dwSize;
LPBYTE pBytes;
if (LoadBinaryResource(resource_id, dwSize, pBytes)) {
resource_data = std::string(reinterpret_cast<char*>(pBytes), dwSize);
return true;
}
NOTREACHED(); // The resource should be found.
return false;
}
CefRefPtr<CefStreamReader> GetBinaryResourceReader(const char* resource_name) {
int resource_id = GetResourceId(resource_name);
if (resource_id == 0)
return nullptr;
DWORD dwSize;
LPBYTE pBytes;
if (LoadBinaryResource(resource_id, dwSize, pBytes)) {
return CefStreamReader::CreateForHandler(
new CefByteReadHandler(pBytes, dwSize, nullptr));
}
NOTREACHED(); // The resource should be found.
return nullptr;
}
CefResourceManager::Provider* CreateBinaryResourceProvider(
const std::string& url_path,
const std::string& resource_path_prefix) {
return new BinaryResourceProvider(url_path, resource_path_prefix);
}

View File

@ -0,0 +1,441 @@
// 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/RootWindoManager.h"
#include <sstream>
#include "include/base/cef_callback.h"
#include "include/base/cef_logging.h"
#include "include/wrapper/cef_helpers.h"
#include "CEF/ClientHandlerStd.h"
#include "CEF/HumanAppContext.h"
//#include "tests/cefclient/browser/test_runner.h"
#include "CEF/ExtensionUtil.h"
#include "CEF/FileUtil.h"
#include "CEF/ResourceUtil.h"
#include "CEF/HumanAppSwitches.h"
class ClientRequestContextHandler : public CefRequestContextHandler,
public CefExtensionHandler {
public:
ClientRequestContextHandler() {}
// CefRequestContextHandler methods:
void OnRequestContextInitialized(
CefRefPtr<CefRequestContext> request_context) override {
CEF_REQUIRE_UI_THREAD();
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
if (command_line->HasSwitch(kLoadExtension)) {
if (HumanAppContext::Get()
->GetRootWindowManager()
->request_context_per_browser()) {
// The example extension loading implementation requires all browsers to
// share the same request context.
LOG(ERROR)
<< "Cannot mix --load-extension and --request-context-per-browser";
return;
}
// Load one or more extension paths specified on the command-line and
// delimited with semicolon.
const std::string& extension_path =
command_line->GetSwitchValue(kLoadExtension);
if (!extension_path.empty()) {
std::string part;
std::istringstream f(extension_path);
while (getline(f, part, ';')) {
if (!part.empty())
extension_util::LoadExtension(request_context, part, this);
}
}
}
}
// CefExtensionHandler methods:
void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override {
CEF_REQUIRE_UI_THREAD();
HumanAppContext::Get()->GetRootWindowManager()->AddExtension(extension);
}
CefRefPtr<CefBrowser> GetActiveBrowser(CefRefPtr<CefExtension> extension,
CefRefPtr<CefBrowser> browser,
bool include_incognito) override {
CEF_REQUIRE_UI_THREAD();
// Return the browser for the active/foreground window.
CefRefPtr<CefBrowser> active_browser =
HumanAppContext::Get()->GetRootWindowManager()->GetActiveBrowser();
if (!active_browser) {
LOG(WARNING)
<< "No active browser available for extension "
<< browser->GetHost()->GetExtension()->GetIdentifier().ToString();
} else {
// The active browser should not be hosting an extension.
DCHECK(!active_browser->GetHost()->GetExtension());
}
return active_browser;
}
private:
IMPLEMENT_REFCOUNTING(ClientRequestContextHandler);
DISALLOW_COPY_AND_ASSIGN(ClientRequestContextHandler);
};
RootWindowManager::RootWindowManager(bool terminate_when_all_windows_closed)
: terminate_when_all_windows_closed_(terminate_when_all_windows_closed) {
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
DCHECK(command_line.get());
request_context_per_browser_ =
command_line->HasSwitch(kRequestContextPerBrowser);
request_context_shared_cache_ =
command_line->HasSwitch(kRequestContextSharedCache);
}
RootWindowManager::~RootWindowManager() {
// All root windows should already have been destroyed.
DCHECK(root_windows_.empty());
}
scoped_refptr<RootWindow> RootWindowManager::CreateRootWindow(
std::unique_ptr<RootWindowConfig> config) {
CefBrowserSettings settings;
HumanAppContext::Get()->PopulateBrowserSettings(&settings);
scoped_refptr<RootWindow> root_window =
RootWindow::Create(HumanAppContext::Get()->UseViews());
root_window->Init(this, std::move(config), settings);
// Store a reference to the root window on the main thread.
OnRootWindowCreated(root_window);
return root_window;
}
scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsPopup(
bool with_controls,
bool with_osr,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) {
CEF_REQUIRE_UI_THREAD();
HumanAppContext::Get()->PopulateBrowserSettings(&settings);
if (HumanAppContext::Get()->UseDefaultPopup()) {
// Use default window creation for the popup. A new |client| instance is
// still required by cefclient architecture.
client = new ClientHandlerStd(/*delegate=*/nullptr, with_controls,
/*startup_url=*/CefString());
return nullptr;
}
if (!temp_window_) {
// TempWindow must be created on the UI thread.
temp_window_.reset(new TempWindow());
}
scoped_refptr<RootWindow> root_window =
RootWindow::Create(HumanAppContext::Get()->UseViews());
root_window->InitAsPopup(this, with_controls, with_osr, popupFeatures,
windowInfo, client, settings);
// Store a reference to the root window on the main thread.
OnRootWindowCreated(root_window);
return root_window;
}
scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsExtension(
CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
base::OnceClosure close_callback,
bool with_controls,
bool with_osr) {
const std::string& extension_url = extension_util::GetExtensionURL(extension);
if (extension_url.empty()) {
NOTREACHED() << "Extension cannot be loaded directly.";
return nullptr;
}
// Create an initially hidden browser window that loads the extension URL.
// We'll show the window when the desired size becomes available via
// ClientHandler::OnAutoResize.
auto config = std::make_unique<RootWindowConfig>();
config->with_controls = with_controls;
config->with_osr = with_osr;
config->with_extension = true;
config->initially_hidden = true;
config->source_bounds = source_bounds;
config->parent_window = parent_window;
config->close_callback = std::move(close_callback);
config->url = extension_url;
return CreateRootWindow(std::move(config));
}
bool RootWindowManager::HasRootWindowAsExtension(
CefRefPtr<CefExtension> extension) {
REQUIRE_MAIN_THREAD();
for (auto root_window : root_windows_) {
if (!root_window->WithExtension())
continue;
CefRefPtr<CefBrowser> browser = root_window->GetBrowser();
if (!browser)
continue;
CefRefPtr<CefExtension> browser_extension =
browser->GetHost()->GetExtension();
DCHECK(browser_extension);
if (browser_extension->GetIdentifier() == extension->GetIdentifier())
return true;
}
return false;
}
scoped_refptr<RootWindow> RootWindowManager::GetWindowForBrowser(
int browser_id) const {
REQUIRE_MAIN_THREAD();
for (auto root_window : root_windows_) {
CefRefPtr<CefBrowser> browser = root_window->GetBrowser();
if (browser.get() && browser->GetIdentifier() == browser_id)
return root_window;
}
return nullptr;
}
scoped_refptr<RootWindow> RootWindowManager::GetActiveRootWindow() const {
REQUIRE_MAIN_THREAD();
return active_root_window_;
}
CefRefPtr<CefBrowser> RootWindowManager::GetActiveBrowser() const {
base::AutoLock lock_scope(active_browser_lock_);
return active_browser_;
}
void RootWindowManager::CloseAllWindows(bool force) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(base::BindOnce(&RootWindowManager::CloseAllWindows,
base::Unretained(this), force));
return;
}
if (root_windows_.empty())
return;
// Use a copy of |root_windows_| because the original set may be modified
// in OnRootWindowDestroyed while iterating.
RootWindowSet root_windows = root_windows_;
for (auto root_window : root_windows) {
root_window->Close(force);
}
}
void RootWindowManager::AddExtension(CefRefPtr<CefExtension> extension) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(base::BindOnce(&RootWindowManager::AddExtension,
base::Unretained(this), extension));
return;
}
// Don't track extensions that can't be loaded directly.
if (extension_util::GetExtensionURL(extension).empty())
return;
// Don't add the same extension multiple times.
ExtensionSet::const_iterator it = extensions_.begin();
for (; it != extensions_.end(); ++it) {
if ((*it)->GetIdentifier() == extension->GetIdentifier())
return;
}
extensions_.insert(extension);
NotifyExtensionsChanged();
}
void RootWindowManager::OnRootWindowCreated(
scoped_refptr<RootWindow> root_window) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(base::BindOnce(&RootWindowManager::OnRootWindowCreated,
base::Unretained(this), root_window));
return;
}
root_windows_.insert(root_window);
if (!root_window->WithExtension()) {
root_window->OnExtensionsChanged(extensions_);
if (root_windows_.size() == 1U) {
// The first non-extension root window should be considered the active
// window.
OnRootWindowActivated(root_window.get());
}
}
}
void RootWindowManager::NotifyExtensionsChanged() {
REQUIRE_MAIN_THREAD();
for (auto root_window : root_windows_) {
if (!root_window->WithExtension())
root_window->OnExtensionsChanged(extensions_);
}
}
CefRefPtr<CefRequestContext> RootWindowManager::GetRequestContext(
RootWindow* root_window) {
REQUIRE_MAIN_THREAD();
if (request_context_per_browser_) {
// Create a new request context for each browser.
CefRequestContextSettings settings;
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
if (command_line->HasSwitch(kCachePath)) {
if (request_context_shared_cache_) {
// Give each browser the same cache path. The resulting context objects
// will share the same storage internally.
CefString(&settings.cache_path) =
command_line->GetSwitchValue(kCachePath);
} else {
// Give each browser a unique cache path. This will create completely
// isolated context objects.
std::stringstream ss;
ss << command_line->GetSwitchValue(kCachePath).ToString()
<< kPathSep << time(nullptr);
CefString(&settings.cache_path) = ss.str();
}
}
return CefRequestContext::CreateContext(settings,
new ClientRequestContextHandler);
}
// All browsers will share the global request context.
if (!shared_request_context_.get()) {
shared_request_context_ = CefRequestContext::CreateContext(
CefRequestContext::GetGlobalContext(), new ClientRequestContextHandler);
}
return shared_request_context_;
}
scoped_refptr<ImageCache> RootWindowManager::GetImageCache() {
CEF_REQUIRE_UI_THREAD();
if (!image_cache_) {
image_cache_ = new ImageCache;
}
return image_cache_;
}
void RootWindowManager::OnTest(RootWindow* root_window, int test_id) {
REQUIRE_MAIN_THREAD();
//test_runner::RunTest(root_window->GetBrowser(), test_id);
}
void RootWindowManager::OnExit(RootWindow* root_window) {
REQUIRE_MAIN_THREAD();
CloseAllWindows(false);
}
void RootWindowManager::OnRootWindowDestroyed(RootWindow* root_window) {
REQUIRE_MAIN_THREAD();
RootWindowSet::iterator it = root_windows_.find(root_window);
DCHECK(it != root_windows_.end());
if (it != root_windows_.end())
root_windows_.erase(it);
if (root_window == active_root_window_) {
active_root_window_ = nullptr;
base::AutoLock lock_scope(active_browser_lock_);
active_browser_ = nullptr;
}
if (terminate_when_all_windows_closed_ && root_windows_.empty()) {
// All windows have closed. Clean up on the UI thread.
CefPostTask(TID_UI, base::BindOnce(&RootWindowManager::CleanupOnUIThread,
base::Unretained(this)));
}
}
void RootWindowManager::OnRootWindowActivated(RootWindow* root_window) {
REQUIRE_MAIN_THREAD();
if (root_window->WithExtension()) {
// We don't want extension apps to become the active RootWindow.
return;
}
if (root_window == active_root_window_)
return;
active_root_window_ = root_window;
{
base::AutoLock lock_scope(active_browser_lock_);
// May be nullptr at this point, in which case we'll make the association in
// OnBrowserCreated.
active_browser_ = active_root_window_->GetBrowser();
}
}
void RootWindowManager::OnBrowserCreated(RootWindow* root_window,
CefRefPtr<CefBrowser> browser) {
REQUIRE_MAIN_THREAD();
if (root_window == active_root_window_) {
base::AutoLock lock_scope(active_browser_lock_);
active_browser_ = browser;
}
}
void RootWindowManager::CreateExtensionWindow(
CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
base::OnceClosure close_callback,
bool with_osr) {
REQUIRE_MAIN_THREAD();
if (!HasRootWindowAsExtension(extension)) {
CreateRootWindowAsExtension(extension, source_bounds, parent_window,
std::move(close_callback), false, with_osr);
}
}
void RootWindowManager::CleanupOnUIThread() {
CEF_REQUIRE_UI_THREAD();
if (temp_window_) {
// TempWindow must be destroyed on the UI thread.
temp_window_.reset(nullptr);
}
if (image_cache_) {
image_cache_ = nullptr;
}
// Quit the main message loop.
MainMessageLoop::Get()->Quit();
}

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

@ -0,0 +1,139 @@
// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#pragma once
#include <memory>
#include <set>
#include "include/cef_command_line.h"
#include "include/cef_request_context_handler.h"
#include "CEF/ImageCache.h"
#include "CEF/RootWindow.h"
#include "CEF/TempWindow.h"
// Used to create/manage RootWindow instances. The methods of this class can be
// called from any browser process thread unless otherwise indicated.
class RootWindowManager : public RootWindow::Delegate {
public:
// If |terminate_when_all_windows_closed| is true quit the main message loop
// after all windows have closed.
explicit RootWindowManager(bool terminate_when_all_windows_closed);
// Create a new top-level native window. This method can be called from
// anywhere.
scoped_refptr<RootWindow> CreateRootWindow(
std::unique_ptr<RootWindowConfig> config);
// Create a new native popup window.
// If |with_controls| is true the window will show controls.
// If |with_osr| is true the window will use off-screen rendering.
// This method is called from ClientHandler::CreatePopupWindow() to
// create a new popup or DevTools window. Must be called on the UI thread.
scoped_refptr<RootWindow> CreateRootWindowAsPopup(
bool with_controls,
bool with_osr,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings);
// Create a new top-level native window to host |extension|.
// If |with_controls| is true the window will show controls.
// If |with_osr| is true the window will use off-screen rendering.
// This method can be called from anywhere.
scoped_refptr<RootWindow> CreateRootWindowAsExtension(
CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
base::OnceClosure close_callback,
bool with_controls,
bool with_osr);
// Returns true if a window hosting |extension| currently exists. Must be
// called on the main thread.
bool HasRootWindowAsExtension(CefRefPtr<CefExtension> extension);
// Returns the RootWindow associated with the specified browser ID. Must be
// called on the main thread.
scoped_refptr<RootWindow> GetWindowForBrowser(int browser_id) const;
// Returns the currently active/foreground RootWindow. May return nullptr.
// Must be called on the main thread.
scoped_refptr<RootWindow> GetActiveRootWindow() const;
// Returns the currently active/foreground browser. May return nullptr. Safe
// to call from any thread.
CefRefPtr<CefBrowser> GetActiveBrowser() const;
// Close all existing windows. If |force| is true onunload handlers will not
// be executed.
void CloseAllWindows(bool force);
// Manage the set of loaded extensions. RootWindows will be notified via the
// OnExtensionsChanged method.
void AddExtension(CefRefPtr<CefExtension> extension);
bool request_context_per_browser() const {
return request_context_per_browser_;
}
private:
// Allow deletion via std::unique_ptr only.
friend std::default_delete<RootWindowManager>;
~RootWindowManager();
void OnRootWindowCreated(scoped_refptr<RootWindow> root_window);
void NotifyExtensionsChanged();
// RootWindow::Delegate methods.
CefRefPtr<CefRequestContext> GetRequestContext(
RootWindow* root_window) override;
scoped_refptr<ImageCache> GetImageCache() override;
void OnTest(RootWindow* root_window, int test_id) override;
void OnExit(RootWindow* root_window) override;
void OnRootWindowDestroyed(RootWindow* root_window) override;
void OnRootWindowActivated(RootWindow* root_window) override;
void OnBrowserCreated(RootWindow* root_window,
CefRefPtr<CefBrowser> browser) override;
void CreateExtensionWindow(CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
base::OnceClosure close_callback,
bool with_osr) override;
void CleanupOnUIThread();
const bool terminate_when_all_windows_closed_;
bool request_context_per_browser_;
bool request_context_shared_cache_;
// Existing root windows. Only accessed on the main thread.
typedef std::set<scoped_refptr<RootWindow>> RootWindowSet;
RootWindowSet root_windows_;
// The currently active/foreground RootWindow. Only accessed on the main
// thread.
scoped_refptr<RootWindow> active_root_window_;
// The currently active/foreground browser. Access is protected by
// |active_browser_lock_;
mutable base::Lock active_browser_lock_;
CefRefPtr<CefBrowser> active_browser_;
// Singleton window used as the temporary parent for popup browsers.
std::unique_ptr<TempWindow> temp_window_;
CefRefPtr<CefRequestContext> shared_request_context_;
// Loaded extensions. Only accessed on the main thread.
ExtensionSet extensions_;
scoped_refptr<ImageCache> image_cache_;
DISALLOW_COPY_AND_ASSIGN(RootWindowManager);
};

43
src/CEF/RootWindow.cpp Normal file
View File

@ -0,0 +1,43 @@
// 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/RootWindow.h"
#include "include/base/cef_callback_helpers.h"
#include "CEF/HumanAppContext.h"
#include "CEF/RootWindoManager.h"
RootWindowConfig::RootWindowConfig()
: always_on_top(false),
with_controls(true),
with_osr(false),
with_extension(false),
initially_hidden(false),
url(HumanAppContext::Get()->GetMainURL()) {}
RootWindow::RootWindow() : delegate_(nullptr) {}
RootWindow::~RootWindow() {}
// static
scoped_refptr<RootWindow> RootWindow::GetForBrowser(int browser_id) {
RootWindowManager* rootWindowManager = HumanAppContext::Get()->GetRootWindowManager();
return rootWindowManager->GetWindowForBrowser(browser_id);
}
void RootWindow::OnExtensionsChanged(const ExtensionSet& extensions) {
REQUIRE_MAIN_THREAD();
DCHECK(delegate_);
DCHECK(!WithExtension());
if (extensions.empty())
return;
ExtensionSet::const_iterator it = extensions.begin();
for (; it != extensions.end(); ++it) {
delegate_->CreateExtensionWindow(*it, CefRect(), nullptr, base::DoNothing(),
WithWindowlessRendering());
}
}

194
src/CEF/RootWindow.h Normal file
View File

@ -0,0 +1,194 @@
// 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 <set>
#include <string>
#include "include/base/cef_callback_forward.h"
#include "include/base/cef_ref_counted.h"
#include "include/cef_browser.h"
#include "include/views/cef_window.h"
#include "CEF/HumanApptypes.h"
#include "CEF/ImageCache.h"
#include "CEF/MainMessageLoop.h"
// Used to configure how a RootWindow is created.
struct RootWindowConfig {
RootWindowConfig();
// If true the window will always display above other windows.
bool always_on_top;
// If true the window will show controls.
bool with_controls;
// If true the window will use off-screen rendering.
bool with_osr;
// If true the window is hosting an extension app.
bool with_extension;
// If true the window will be created initially hidden.
bool initially_hidden;
// Requested window position. If |bounds| and |source_bounds| are empty the
// default window size and location will be used.
CefRect bounds;
// Position of the UI element that triggered the window creation. If |bounds|
// is empty and |source_bounds| is non-empty the new window will be positioned
// relative to |source_bounds|. This is currently only implemented for Views-
// based windows when |initially_hidden| is also true.
CefRect source_bounds;
// Parent window. Only used for Views-based windows.
CefRefPtr<CefWindow> parent_window;
// Callback to be executed when the window is closed. Will be executed on the
// main thread. This is currently only implemented for Views-based windows.
base::OnceClosure close_callback;
// Initial URL to load.
std::string url;
};
typedef std::set<CefRefPtr<CefExtension>> ExtensionSet;
// Represents a top-level native window in the browser process. While references
// to this object are thread-safe the methods must be called on the main thread
// unless otherwise indicated.
class RootWindow
: public base::RefCountedThreadSafe<RootWindow, DeleteOnMainThread> {
public:
// This interface is implemented by the owner of the RootWindow. The methods
// of this class will be called on the main thread.
class Delegate {
public:
// Called to retrieve the CefRequestContext for browser. Only called for
// non-popup browsers. May return nullptr.
virtual CefRefPtr<CefRequestContext> GetRequestContext(
RootWindow* root_window) = 0;
// Returns the ImageCache.
virtual scoped_refptr<ImageCache> GetImageCache() = 0;
// Called to execute a test. See resource.h for |test_id| values.
virtual void OnTest(RootWindow* root_window, int test_id) = 0;
// Called to exit the application.
virtual void OnExit(RootWindow* root_window) = 0;
// Called when the RootWindow has been destroyed.
virtual void OnRootWindowDestroyed(RootWindow* root_window) = 0;
// Called when the RootWindow is activated (becomes the foreground window).
virtual void OnRootWindowActivated(RootWindow* root_window) = 0;
// Called when the browser is created for the RootWindow.
virtual void OnBrowserCreated(RootWindow* root_window,
CefRefPtr<CefBrowser> browser) = 0;
// Create a window for |extension|. |source_bounds| are the bounds of the
// UI element, like a button, that triggered the extension.
virtual void CreateExtensionWindow(CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
base::OnceClosure close_callback,
bool with_osr) = 0;
protected:
virtual ~Delegate() {}
};
// Create a new RootWindow object. This method may be called on any thread.
// Use RootWindowManager::CreateRootWindow() or CreateRootWindowAsPopup()
// instead of calling this method directly. |use_views| will be true if the
// Views framework should be used.
static scoped_refptr<RootWindow> Create(bool use_views);
// Returns the RootWindow associated with the specified |browser_id|. Must be
// called on the main thread.
static scoped_refptr<RootWindow> GetForBrowser(int browser_id);
// Initialize as a normal window. This will create and show a native window
// hosting a single browser instance. This method may be called on any thread.
// |delegate| must be non-nullptr and outlive this object.
// Use RootWindowManager::CreateRootWindow() instead of calling this method
// directly.
virtual void Init(RootWindow::Delegate* delegate,
std::unique_ptr<RootWindowConfig> config,
const CefBrowserSettings& settings) = 0;
// Initialize as a popup window. This is used to attach a new native window to
// a single browser instance that will be created later. The native window
// will be created and shown once the browser is available. This method may be
// called on any thread. |delegate| must be non-nullptr and outlive this
// object. Use RootWindowManager::CreateRootWindowAsPopup() instead of calling
// this method directly. Called on the UI thread.
virtual void InitAsPopup(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) = 0;
enum ShowMode {
ShowNormal,
ShowMinimized,
ShowMaximized,
ShowNoActivate,
};
// Show the window.
virtual void Show(ShowMode mode) = 0;
// Hide the window.
virtual void Hide() = 0;
// Set the window bounds in screen coordinates.
virtual void SetBounds(int x, int y, size_t width, size_t height) = 0;
// Close the window. If |force| is true onunload handlers will not be
// executed.
virtual void Close(bool force) = 0;
// Set the device scale factor. Only used in combination with off-screen
// rendering.
virtual void SetDeviceScaleFactor(float device_scale_factor) = 0;
// Returns the device scale factor. Only used in combination with off-screen
// rendering.
virtual float GetDeviceScaleFactor() const = 0;
// Returns the browser that this window contains, if any.
virtual CefRefPtr<CefBrowser> GetBrowser() const = 0;
// Returns the native handle for this window, if any.
virtual ClientWindowHandle GetWindowHandle() const = 0;
// Returns true if this window is using windowless rendering (osr).
virtual bool WithWindowlessRendering() const = 0;
// Returns true if this window is hosting an extension app.
virtual bool WithExtension() const = 0;
// Called when the set of loaded extensions changes. The default
// implementation will create a single window instance for each extension.
virtual void OnExtensionsChanged(const ExtensionSet& extensions);
protected:
// Allow deletion via scoped_refptr only.
friend struct DeleteOnMainThread;
friend class base::RefCountedThreadSafe<RootWindow, DeleteOnMainThread>;
RootWindow();
virtual ~RootWindow();
Delegate* delegate_;
};

24
src/CEF/TempWindow.h Normal file
View File

@ -0,0 +1,24 @@
// 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/HumanApptypes.h"
#if defined(OS_WIN)
#include "CEF/TempWindowWin.h"
#elif defined(OS_LINUX)
//#include "tests/cefclient/browser/temp_window_x11.h"
#elif defined(OS_MAC)
//#include "tests/cefclient/browser/temp_window_mac.h"
#endif
#if defined(OS_WIN)
typedef TempWindowWin TempWindow;
#elif defined(OS_LINUX)
typedef TempWindowX11 TempWindow;
#elif defined(OS_MAC)
typedef TempWindowMac TempWindow;
#endif

51
src/CEF/TempWindowWin.cpp Normal file
View File

@ -0,0 +1,51 @@
// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "CEF/TempWindowWin.h"
#include <windows.h>
#include "include/base/cef_logging.h"
const wchar_t kWndClass[] = L"Client_TempWindow";
// Create the temp window.
HWND CreateTempWindow() {
HINSTANCE hInstance = ::GetModuleHandle(nullptr);
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(wc);
wc.lpfnWndProc = DefWindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = kWndClass;
RegisterClassEx(&wc);
// Create a 1x1 pixel hidden window.
return CreateWindow(kWndClass, 0, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, 0, 0,
1, 1, nullptr, nullptr, hInstance, nullptr);
}
TempWindowWin* g_temp_window = nullptr;
TempWindowWin::TempWindowWin() : hwnd_(nullptr) {
DCHECK(!g_temp_window);
g_temp_window = this;
hwnd_ = CreateTempWindow();
CHECK(hwnd_);
}
TempWindowWin::~TempWindowWin() {
g_temp_window = nullptr;
DCHECK(hwnd_);
DestroyWindow(hwnd_);
}
// static
CefWindowHandle TempWindowWin::GetWindowHandle() {
DCHECK(g_temp_window);
return g_temp_window->hwnd_;
}

29
src/CEF/TempWindowWin.h Normal file
View File

@ -0,0 +1,29 @@
// 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_base.h"
// Represents a singleton hidden window that acts as a temporary parent for
// popup browsers. Only accessed on the UI thread.
class TempWindowWin {
public:
// Returns the singleton window handle.
static CefWindowHandle GetWindowHandle();
private:
// A single instance will be created/owned by RootWindowManager.
friend class RootWindowManager;
// Allow deletion via std::unique_ptr only.
friend std::default_delete<TempWindowWin>;
TempWindowWin();
~TempWindowWin();
CefWindowHandle hwnd_;
DISALLOW_COPY_AND_ASSIGN(TempWindowWin);
};

865
src/CEF/TestRunner.cpp Normal file
View File

@ -0,0 +1,865 @@
// 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/test_runner.h"
#include <algorithm>
#include <map>
#include <set>
#include <sstream>
#include "include/base/cef_callback.h"
#include "include/cef_parser.h"
#include "include/cef_task.h"
#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"
namespace client {
namespace test_runner {
namespace {
const char kTestHost[] = "tests";
const char kLocalHost[] = "localhost";
const char kTestOrigin[] = "http://tests/";
// Pages handled via StringResourceProvider.
const char kTestGetSourcePage[] = "get_source.html";
const char kTestGetTextPage[] = "get_text.html";
// Set page data and navigate the browser. Used in combination with
// StringResourceProvider.
void LoadStringResourcePage(CefRefPtr<CefBrowser> browser,
const std::string& page,
const std::string& data) {
CefRefPtr<CefClient> client = browser->GetHost()->GetClient();
ClientHandler* client_handler = static_cast<ClientHandler*>(client.get());
client_handler->SetStringResource(page, data);
browser->GetMainFrame()->LoadURL(kTestOrigin + page);
}
// Replace all instances of |from| with |to| in |str|.
std::string StringReplace(const std::string& str,
const std::string& from,
const std::string& to) {
std::string result = str;
std::string::size_type pos = 0;
std::string::size_type from_len = from.length();
std::string::size_type to_len = to.length();
do {
pos = result.find(from, pos);
if (pos != std::string::npos) {
result.replace(pos, from_len, to);
pos += to_len;
}
} while (pos != std::string::npos);
return result;
}
void RunGetSourceTest(CefRefPtr<CefBrowser> browser) {
class Visitor : public CefStringVisitor {
public:
explicit Visitor(CefRefPtr<CefBrowser> browser) : browser_(browser) {}
virtual void Visit(const CefString& string) override {
std::string source = StringReplace(string, "<", "&lt;");
source = StringReplace(source, ">", "&gt;");
std::stringstream ss;
ss << "<html><body bgcolor=\"white\">Source:<pre>" << source
<< "</pre></body></html>";
LoadStringResourcePage(browser_, kTestGetSourcePage, ss.str());
}
private:
CefRefPtr<CefBrowser> browser_;
IMPLEMENT_REFCOUNTING(Visitor);
};
browser->GetMainFrame()->GetSource(new Visitor(browser));
}
void RunGetTextTest(CefRefPtr<CefBrowser> browser) {
class Visitor : public CefStringVisitor {
public:
explicit Visitor(CefRefPtr<CefBrowser> browser) : browser_(browser) {}
virtual void Visit(const CefString& string) override {
std::string text = StringReplace(string, "<", "&lt;");
text = StringReplace(text, ">", "&gt;");
std::stringstream ss;
ss << "<html><body bgcolor=\"white\">Text:<pre>" << text
<< "</pre></body></html>";
LoadStringResourcePage(browser_, kTestGetTextPage, ss.str());
}
private:
CefRefPtr<CefBrowser> browser_;
IMPLEMENT_REFCOUNTING(Visitor);
};
browser->GetMainFrame()->GetText(new Visitor(browser));
}
void RunRequestTest(CefRefPtr<CefBrowser> browser) {
// Create a new request
CefRefPtr<CefRequest> request(CefRequest::Create());
if (browser->GetMainFrame()->GetURL().ToString().find("http://tests/") != 0) {
// The LoadRequest method will fail with "bad IPC message" reason
// INVALID_INITIATOR_ORIGIN (213) unless you first navigate to the
// request origin using some other mechanism (LoadURL, link click, etc).
Alert(browser,
"Please first navigate to a http://tests/ URL. "
"For example, first load Tests > Other Tests.");
return;
}
// Set the request URL
request->SetURL("http://tests/request");
// Add post data to the request. The correct method and content-
// type headers will be set by CEF.
CefRefPtr<CefPostDataElement> postDataElement(CefPostDataElement::Create());
std::string data = "arg1=val1&arg2=val2";
postDataElement->SetToBytes(data.length(), data.c_str());
CefRefPtr<CefPostData> postData(CefPostData::Create());
postData->AddElement(postDataElement);
request->SetPostData(postData);
// Add a custom header
CefRequest::HeaderMap headerMap;
headerMap.insert(std::make_pair("X-My-Header", "My Header Value"));
request->SetHeaderMap(headerMap);
// Load the request
browser->GetMainFrame()->LoadRequest(request);
}
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(
std::move(config));
}
void RunPopupWindowTest(CefRefPtr<CefBrowser> browser) {
browser->GetMainFrame()->ExecuteJavaScript(
"window.open('http://www.google.com');", "about:blank", 0);
}
void ModifyZoom(CefRefPtr<CefBrowser> browser, double delta) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute on the UI thread.
CefPostTask(TID_UI, base::BindOnce(&ModifyZoom, browser, delta));
return;
}
browser->GetHost()->SetZoomLevel(browser->GetHost()->GetZoomLevel() + delta);
}
const char kPrompt[] = "Prompt.";
const char kPromptFPS[] = "FPS";
const char kPromptDSF[] = "DSF";
// Handles execution of prompt results.
class PromptHandler : public CefMessageRouterBrowserSide::Handler {
public:
PromptHandler() {}
// Called due to cefQuery execution.
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) override {
// Parse |request| which takes the form "Prompt.[type]:[value]".
const std::string& request_str = request;
if (request_str.find(kPrompt) != 0)
return false;
std::string type = request_str.substr(sizeof(kPrompt) - 1);
size_t delim = type.find(':');
if (delim == std::string::npos)
return false;
const std::string& value = type.substr(delim + 1);
type = type.substr(0, delim);
// Canceling the prompt dialog returns a value of "null".
if (value != "null") {
if (type == kPromptFPS)
SetFPS(browser, atoi(value.c_str()));
else if (type == kPromptDSF)
SetDSF(browser, static_cast<float>(atof(value.c_str())));
}
// Nothing is done with the response.
callback->Success(CefString());
return true;
}
private:
void SetFPS(CefRefPtr<CefBrowser> browser, int fps) {
if (fps <= 0) {
// Reset to the default value.
CefBrowserSettings settings;
MainContext::Get()->PopulateBrowserSettings(&settings);
fps = settings.windowless_frame_rate;
}
browser->GetHost()->SetWindowlessFrameRate(fps);
}
void SetDSF(CefRefPtr<CefBrowser> browser, float dsf) {
MainMessageLoop::Get()->PostClosure(
base::BindOnce(&PromptHandler::SetDSFOnMainThread, browser, dsf));
}
static void SetDSFOnMainThread(CefRefPtr<CefBrowser> browser, float dsf) {
RootWindow::GetForBrowser(browser->GetIdentifier())
->SetDeviceScaleFactor(dsf);
}
};
void Prompt(CefRefPtr<CefBrowser> browser,
const std::string& type,
const std::string& label,
const std::string& default_value) {
// Prompt the user for a new value. Works as follows:
// 1. Show a prompt() dialog via JavaScript.
// 2. Pass the result to window.cefQuery().
// 3. Handle the result in PromptHandler::OnQuery.
const std::string& code = "window.cefQuery({'request': '" +
std::string(kPrompt) + type + ":' + prompt('" +
label + "', '" + default_value + "')});";
browser->GetMainFrame()->ExecuteJavaScript(
code, browser->GetMainFrame()->GetURL(), 0);
}
void PromptFPS(CefRefPtr<CefBrowser> browser) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute on the UI thread.
CefPostTask(TID_UI, base::BindOnce(&PromptFPS, browser));
return;
}
// Format the default value string.
std::stringstream ss;
ss << browser->GetHost()->GetWindowlessFrameRate();
Prompt(browser, kPromptFPS, "Enter FPS", ss.str());
}
void PromptDSF(CefRefPtr<CefBrowser> browser) {
if (!MainMessageLoop::Get()->RunsTasksOnCurrentThread()) {
// Execute on the main thread.
MainMessageLoop::Get()->PostClosure(base::BindOnce(&PromptDSF, browser));
return;
}
// Format the default value string.
std::stringstream ss;
ss << RootWindow::GetForBrowser(browser->GetIdentifier())
->GetDeviceScaleFactor();
Prompt(browser, kPromptDSF, "Enter Device Scale Factor", ss.str());
}
void BeginTracing() {
if (!CefCurrentlyOn(TID_UI)) {
// Execute on the UI thread.
CefPostTask(TID_UI, base::BindOnce(&BeginTracing));
return;
}
CefBeginTracing(CefString(), nullptr);
}
void EndTracing(CefRefPtr<CefBrowser> browser) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute on the UI thread.
CefPostTask(TID_UI, base::BindOnce(&EndTracing, browser));
return;
}
class Client : public CefEndTracingCallback, public CefRunFileDialogCallback {
public:
explicit Client(CefRefPtr<CefBrowser> browser) : browser_(browser) {
RunDialog();
}
void RunDialog() {
static const char kDefaultFileName[] = "trace.txt";
std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName);
if (path.empty())
path = kDefaultFileName;
// Results in a call to OnFileDialogDismissed.
browser_->GetHost()->RunFileDialog(
FILE_DIALOG_SAVE,
/*title=*/CefString(), path,
/*accept_filters=*/std::vector<CefString>(), this);
}
void OnFileDialogDismissed(
const std::vector<CefString>& file_paths) override {
if (!file_paths.empty()) {
// File selected. Results in a call to OnEndTracingComplete.
CefEndTracing(file_paths.front(), this);
} else {
// No file selected. Discard the trace data.
CefEndTracing(CefString(), nullptr);
}
}
void OnEndTracingComplete(const CefString& tracing_file) override {
Alert(browser_,
"File \"" + tracing_file.ToString() + "\" saved successfully.");
}
private:
CefRefPtr<CefBrowser> browser_;
IMPLEMENT_REFCOUNTING(Client);
};
new Client(browser);
}
void PrintToPDF(CefRefPtr<CefBrowser> browser) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute on the UI thread.
CefPostTask(TID_UI, base::BindOnce(&PrintToPDF, browser));
return;
}
class Client : public CefPdfPrintCallback, public CefRunFileDialogCallback {
public:
explicit Client(CefRefPtr<CefBrowser> browser) : browser_(browser) {
RunDialog();
}
void RunDialog() {
static const char kDefaultFileName[] = "output.pdf";
std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName);
if (path.empty())
path = kDefaultFileName;
std::vector<CefString> accept_filters;
accept_filters.push_back(".pdf");
// Results in a call to OnFileDialogDismissed.
browser_->GetHost()->RunFileDialog(FILE_DIALOG_SAVE,
/*title=*/CefString(), path,
accept_filters, this);
}
void OnFileDialogDismissed(
const std::vector<CefString>& file_paths) override {
if (!file_paths.empty()) {
CefPdfPrintSettings settings;
// Show the URL in the footer.
settings.header_footer_enabled = true;
CefString(&settings.header_footer_url) =
browser_->GetMainFrame()->GetURL();
// Print to the selected PDF file.
browser_->GetHost()->PrintToPDF(file_paths[0], settings, this);
}
}
void OnPdfPrintFinished(const CefString& path, bool ok) override {
Alert(browser_, "File \"" + path.ToString() + "\" " +
(ok ? "saved successfully." : "failed to save."));
}
private:
CefRefPtr<CefBrowser> browser_;
IMPLEMENT_REFCOUNTING(Client);
};
new Client(browser);
}
void MuteAudio(CefRefPtr<CefBrowser> browser, bool mute) {
CefRefPtr<CefBrowserHost> host = browser->GetHost();
host->SetAudioMuted(mute);
}
void RunOtherTests(CefRefPtr<CefBrowser> browser) {
browser->GetMainFrame()->LoadURL("http://tests/other_tests");
}
// Provider that dumps the request contents.
class RequestDumpResourceProvider : public CefResourceManager::Provider {
public:
explicit RequestDumpResourceProvider(const std::string& url) : url_(url) {
DCHECK(!url.empty());
}
bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
CEF_REQUIRE_IO_THREAD();
const std::string& url = request->url();
if (url != url_) {
// Not handled by this provider.
return false;
}
CefResponse::HeaderMap response_headers;
CefRefPtr<CefStreamReader> response =
GetDumpResponse(request->request(), response_headers);
request->Continue(new CefStreamResourceHandler(200, "OK", "text/html",
response_headers, response));
return true;
}
private:
std::string url_;
DISALLOW_COPY_AND_ASSIGN(RequestDumpResourceProvider);
};
// Provider that returns string data for specific pages. Used in combination
// with LoadStringResourcePage().
class StringResourceProvider : public CefResourceManager::Provider {
public:
StringResourceProvider(const std::set<std::string>& pages,
StringResourceMap* string_resource_map)
: pages_(pages), string_resource_map_(string_resource_map) {
DCHECK(!pages.empty());
}
bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
CEF_REQUIRE_IO_THREAD();
const std::string& url = request->url();
if (url.find(kTestOrigin) != 0U) {
// Not handled by this provider.
return false;
}
const std::string& page = url.substr(strlen(kTestOrigin));
if (pages_.find(page) == pages_.end()) {
// Not handled by this provider.
return false;
}
std::string value;
StringResourceMap::const_iterator it = string_resource_map_->find(page);
if (it != string_resource_map_->end()) {
value = it->second;
} else {
value = "<html><body>No data available</body></html>";
}
CefRefPtr<CefStreamReader> response = CefStreamReader::CreateForData(
static_cast<void*>(const_cast<char*>(value.c_str())), value.size());
request->Continue(new CefStreamResourceHandler(
200, "OK", "text/html", CefResponse::HeaderMap(), response));
return true;
}
private:
const std::set<std::string> pages_;
// Only accessed on the IO thread.
StringResourceMap* string_resource_map_;
DISALLOW_COPY_AND_ASSIGN(StringResourceProvider);
};
// Add a file extension to |url| if none is currently specified.
std::string RequestUrlFilter(const std::string& url) {
if (url.find(kTestOrigin) != 0U) {
// Don't filter anything outside of the test origin.
return url;
}
// Identify where the query or fragment component, if any, begins.
size_t suffix_pos = url.find('?');
if (suffix_pos == std::string::npos)
suffix_pos = url.find('#');
std::string url_base, url_suffix;
if (suffix_pos == std::string::npos) {
url_base = url;
} else {
url_base = url.substr(0, suffix_pos);
url_suffix = url.substr(suffix_pos);
}
// Identify the last path component.
size_t path_pos = url_base.rfind('/');
if (path_pos == std::string::npos)
return url;
const std::string& path_component = url_base.substr(path_pos);
// Identify if a file extension is currently specified.
size_t ext_pos = path_component.rfind(".");
if (ext_pos != std::string::npos)
return url;
// Rebuild the URL with a file extension.
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;
}
}
std::string DumpRequestContents(CefRefPtr<CefRequest> request) {
std::stringstream ss;
ss << "URL: " << std::string(request->GetURL());
ss << "\nMethod: " << std::string(request->GetMethod());
CefRequest::HeaderMap headerMap;
request->GetHeaderMap(headerMap);
if (headerMap.size() > 0) {
ss << "\nHeaders:";
CefRequest::HeaderMap::const_iterator it = headerMap.begin();
for (; it != headerMap.end(); ++it) {
ss << "\n\t" << std::string((*it).first) << ": "
<< std::string((*it).second);
}
}
CefRefPtr<CefPostData> postData = request->GetPostData();
if (postData.get()) {
CefPostData::ElementVector elements;
postData->GetElements(elements);
if (elements.size() > 0) {
ss << "\nPost Data:";
CefRefPtr<CefPostDataElement> element;
CefPostData::ElementVector::const_iterator it = elements.begin();
for (; it != elements.end(); ++it) {
element = (*it);
if (element->GetType() == PDE_TYPE_BYTES) {
// the element is composed of bytes
ss << "\n\tBytes: ";
if (element->GetBytesCount() == 0) {
ss << "(empty)";
} else {
// retrieve the data.
size_t size = element->GetBytesCount();
char* bytes = new char[size];
element->GetBytes(size, bytes);
ss << std::string(bytes, size);
delete[] bytes;
}
} else if (element->GetType() == PDE_TYPE_FILE) {
ss << "\n\tFile: " << std::string(element->GetFile());
}
}
}
}
return ss.str();
}
CefRefPtr<CefStreamReader> GetDumpResponse(
CefRefPtr<CefRequest> request,
CefResponse::HeaderMap& response_headers) {
std::string origin;
// Extract the origin request header, if any. It will be specified for
// cross-origin requests.
{
CefRequest::HeaderMap requestMap;
request->GetHeaderMap(requestMap);
CefRequest::HeaderMap::const_iterator it = requestMap.begin();
for (; it != requestMap.end(); ++it) {
std::string key = it->first;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
if (key == "origin") {
origin = it->second;
break;
}
}
}
if (!origin.empty() &&
(origin.find("http://" + std::string(kTestHost)) == 0 ||
origin.find("http://" + std::string(kLocalHost)) == 0)) {
// Allow cross-origin XMLHttpRequests from test origins.
response_headers.insert(
std::make_pair("Access-Control-Allow-Origin", origin));
// Allow the custom header from the xmlhttprequest.html example.
response_headers.insert(
std::make_pair("Access-Control-Allow-Headers", "My-Custom-Header"));
}
const std::string& dump = DumpRequestContents(request);
std::string str =
"<html><body bgcolor=\"white\"><pre>" + dump + "</pre></body></html>";
CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
static_cast<void*>(const_cast<char*>(str.c_str())), str.size());
DCHECK(stream);
return stream;
}
std::string GetDataURI(const std::string& data, const std::string& mime_type) {
return "data:" + mime_type + ";base64," +
CefURIEncode(CefBase64Encode(data.data(), data.size()), false)
.ToString();
}
std::string GetErrorString(cef_errorcode_t code) {
// Case condition that returns |code| as a string.
#define CASE(code) \
case code: \
return #code
switch (code) {
CASE(ERR_NONE);
CASE(ERR_FAILED);
CASE(ERR_ABORTED);
CASE(ERR_INVALID_ARGUMENT);
CASE(ERR_INVALID_HANDLE);
CASE(ERR_FILE_NOT_FOUND);
CASE(ERR_TIMED_OUT);
CASE(ERR_FILE_TOO_BIG);
CASE(ERR_UNEXPECTED);
CASE(ERR_ACCESS_DENIED);
CASE(ERR_NOT_IMPLEMENTED);
CASE(ERR_CONNECTION_CLOSED);
CASE(ERR_CONNECTION_RESET);
CASE(ERR_CONNECTION_REFUSED);
CASE(ERR_CONNECTION_ABORTED);
CASE(ERR_CONNECTION_FAILED);
CASE(ERR_NAME_NOT_RESOLVED);
CASE(ERR_INTERNET_DISCONNECTED);
CASE(ERR_SSL_PROTOCOL_ERROR);
CASE(ERR_ADDRESS_INVALID);
CASE(ERR_ADDRESS_UNREACHABLE);
CASE(ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
CASE(ERR_TUNNEL_CONNECTION_FAILED);
CASE(ERR_NO_SSL_VERSIONS_ENABLED);
CASE(ERR_SSL_VERSION_OR_CIPHER_MISMATCH);
CASE(ERR_SSL_RENEGOTIATION_REQUESTED);
CASE(ERR_CERT_COMMON_NAME_INVALID);
CASE(ERR_CERT_DATE_INVALID);
CASE(ERR_CERT_AUTHORITY_INVALID);
CASE(ERR_CERT_CONTAINS_ERRORS);
CASE(ERR_CERT_NO_REVOCATION_MECHANISM);
CASE(ERR_CERT_UNABLE_TO_CHECK_REVOCATION);
CASE(ERR_CERT_REVOKED);
CASE(ERR_CERT_INVALID);
CASE(ERR_CERT_END);
CASE(ERR_INVALID_URL);
CASE(ERR_DISALLOWED_URL_SCHEME);
CASE(ERR_UNKNOWN_URL_SCHEME);
CASE(ERR_TOO_MANY_REDIRECTS);
CASE(ERR_UNSAFE_REDIRECT);
CASE(ERR_UNSAFE_PORT);
CASE(ERR_INVALID_RESPONSE);
CASE(ERR_INVALID_CHUNKED_ENCODING);
CASE(ERR_METHOD_NOT_SUPPORTED);
CASE(ERR_UNEXPECTED_PROXY_AUTH);
CASE(ERR_EMPTY_RESPONSE);
CASE(ERR_RESPONSE_HEADERS_TOO_BIG);
CASE(ERR_CACHE_MISS);
CASE(ERR_INSECURE_RESPONSE);
default:
return "UNKNOWN";
}
}
void SetupResourceManager(CefRefPtr<CefResourceManager> resource_manager,
StringResourceMap* string_resource_map) {
if (!CefCurrentlyOn(TID_IO)) {
// Execute on the browser IO thread.
CefPostTask(TID_IO, base::BindOnce(SetupResourceManager, resource_manager,
string_resource_map));
return;
}
const std::string& test_origin = kTestOrigin;
// Add the URL filter.
resource_manager->SetUrlFilter(base::BindRepeating(RequestUrlFilter));
// Add provider for resource dumps.
resource_manager->AddProvider(
new RequestDumpResourceProvider(test_origin + "request.html"), 0,
std::string());
// Set of supported string pages.
std::set<std::string> string_pages;
string_pages.insert(kTestGetSourcePage);
string_pages.insert(kTestGetTextPage);
// Add provider for string resources.
resource_manager->AddProvider(
new StringResourceProvider(string_pages, string_resource_map), 0,
std::string());
// Add provider for bundled resource files.
#if defined(OS_WIN)
// Read resources from the binary.
resource_manager->AddProvider(
CreateBinaryResourceProvider(test_origin, std::string()), 100,
std::string());
#elif defined(OS_POSIX)
// Read resources from a directory on disk.
std::string resource_dir;
if (GetResourceDir(resource_dir)) {
resource_manager->AddDirectoryProvider(test_origin, resource_dir, 100,
std::string());
}
#endif
}
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();
if (!browser)
return;
}
// Escape special characters in the message.
std::string msg = StringReplace(message, "\\", "\\\\");
msg = StringReplace(msg, "'", "\\'");
// Execute a JavaScript alert().
CefRefPtr<CefFrame> frame = browser->GetMainFrame();
frame->ExecuteJavaScript("alert('" + msg + "');", frame->GetURL(), 0);
}
bool IsTestURL(const std::string& url, const std::string& path) {
CefURLParts parts;
CefParseURL(url, parts);
const std::string& url_host = CefString(&parts.host);
if (url_host != kTestHost && url_host != kLocalHost)
return false;
const std::string& url_path = CefString(&parts.path);
return url_path.find(path) == 0;
}
void CreateMessageHandlers(MessageHandlerSet& handlers) {
handlers.insert(new PromptHandler);
// Create the binding test handlers.
binding_test::CreateMessageHandlers(handlers);
// Create the dialog test handlers.
dialog_test::CreateMessageHandlers(handlers);
// Create the media router test handlers.
media_router_test::CreateMessageHandlers(handlers);
// Create the preferences test handlers.
preferences_test::CreateMessageHandlers(handlers);
// Create the server test handlers.
server_test::CreateMessageHandlers(handlers);
// Create the urlrequest test handlers.
urlrequest_test::CreateMessageHandlers(handlers);
// Create the window test handlers.
window_test::CreateMessageHandlers(handlers);
}
void RegisterSchemeHandlers() {
// Register the scheme handler.
scheme_test::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,
request, response);
}
} // namespace test_runner
} // namespace client

69
src/CEF/TestRunner.h Normal file
View File

@ -0,0 +1,69 @@
// 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_TEST_RUNNER_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_TEST_RUNNER_H_
#pragma once
#include <set>
#include <string>
#include "include/cef_browser.h"
#include "include/cef_request.h"
#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);
// Returns the contents of the CefRequest as a string.
std::string DumpRequestContents(CefRefPtr<CefRequest> request);
// Returns the dump response as a stream. |request| is the request.
// |response_headers| will be populated with extra response headers, if any.
CefRefPtr<CefStreamReader> GetDumpResponse(
CefRefPtr<CefRequest> request,
CefResponse::HeaderMap& response_headers);
// Returns a data: URI with the specified contents.
std::string GetDataURI(const std::string& data, const std::string& mime_type);
// Returns the string representation of the specified error code.
std::string GetErrorString(cef_errorcode_t code);
typedef std::map<std::string, std::string> StringResourceMap;
// Set up the resource manager for tests.
void SetupResourceManager(CefRefPtr<CefResourceManager> resource_manager,
StringResourceMap* string_resource_map);
// Show a JS alert message.
void Alert(CefRefPtr<CefBrowser> browser, const std::string& message);
// Returns true if |url| is a test URL with the specified |path|. This matches
// both http://tests/<path> and http://localhost:xxxx/<path>.
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;
void CreateMessageHandlers(MessageHandlerSet& handlers);
// Register scheme handlers for tests.
void RegisterSchemeHandlers();
// Create a resource response filter for tests.
CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response);
} // namespace test_runner
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_TEST_RUNNER_H_