modify cef
This commit is contained in:
parent
e3175def71
commit
79f86c0931
1357
src/CEF/ClientHandler.cpp
Normal file
1357
src/CEF/ClientHandler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
439
src/CEF/ClientHandler.h
Normal file
439
src/CEF/ClientHandler.h
Normal 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);
|
||||
};
|
||||
|
186
src/CEF/ClientHandlerOSR.cpp
Normal file
186
src/CEF/ClientHandlerOSR.cpp
Normal 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
152
src/CEF/ClientHandlerOSR.h
Normal 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_
|
14
src/CEF/ClientHandlerStd.cpp
Normal file
14
src/CEF/ClientHandlerStd.cpp
Normal 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
|
29
src/CEF/ClientHandlerStd.h
Normal file
29
src/CEF/ClientHandlerStd.h
Normal 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
247
src/CEF/ExtensionUtil.cpp
Normal 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
71
src/CEF/ExtensionUtil.h
Normal 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
112
src/CEF/FileUtil.cpp
Normal 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
38
src/CEF/FileUtil.h
Normal 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);
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
25
src/CEF/HumanAppContext.cpp
Normal file
25
src/CEF/HumanAppContext.cpp
Normal 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
69
src/CEF/HumanAppContext.h
Normal 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);
|
||||
};
|
267
src/CEF/HumanAppContextImpl.cpp
Normal file
267
src/CEF/HumanAppContextImpl.cpp
Normal 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;
|
||||
}
|
87
src/CEF/HumanAppContextImpl.h
Normal file
87
src/CEF/HumanAppContextImpl.h
Normal 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
29
src/CEF/HumanApptypes.h
Normal 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
304
src/CEF/ImageCache.cpp
Normal 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
121
src/CEF/ImageCache.h
Normal 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_;
|
||||
};
|
||||
|
41
src/CEF/MainMessageLoop.cpp
Normal file
41
src/CEF/MainMessageLoop.cpp
Normal 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
103
src/CEF/MainMessageLoop.h
Normal 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)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
107
src/CEF/MainMessageLoopExternalPump.cpp
Normal file
107
src/CEF/MainMessageLoopExternalPump.cpp
Normal 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
|
70
src/CEF/MainMessageLoopExternalPump.h
Normal file
70
src/CEF/MainMessageLoopExternalPump.h
Normal 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_
|
154
src/CEF/MainMessageLoopExternalPumpWin.cpp
Normal file
154
src/CEF/MainMessageLoopExternalPumpWin.cpp
Normal 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
|
37
src/CEF/MainMessageLoopStd.cpp
Normal file
37
src/CEF/MainMessageLoopStd.cpp
Normal 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
|
35
src/CEF/MainMessageLoopStd.h
Normal file
35
src/CEF/MainMessageLoopStd.h
Normal 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_
|
30
src/CEF/OsrRendererSettings.h
Normal file
30
src/CEF/OsrRendererSettings.h
Normal 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
33
src/CEF/ResourceUtil.h
Normal 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
121
src/CEF/ResourceUtilWin.cpp
Normal 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);
|
||||
}
|
441
src/CEF/RootWindoManager.cpp
Normal file
441
src/CEF/RootWindoManager.cpp
Normal 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
139
src/CEF/RootWindoManager.h
Normal file
@ -0,0 +1,139 @@
|
||||
// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <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
43
src/CEF/RootWindow.cpp
Normal 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
194
src/CEF/RootWindow.h
Normal 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
24
src/CEF/TempWindow.h
Normal 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
51
src/CEF/TempWindowWin.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#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
29
src/CEF/TempWindowWin.h
Normal 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
865
src/CEF/TestRunner.cpp
Normal 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, "<", "<");
|
||||
source = StringReplace(source, ">", ">");
|
||||
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, "<", "<");
|
||||
text = StringReplace(text, ">", ">");
|
||||
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
69
src/CEF/TestRunner.h
Normal 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_
|
Loading…
Reference in New Issue
Block a user