- Factor platform-specific code out of CefBrowserHostImpl (issue #1749).

- Introduce native/ and osr/ folders for native (non-platform-agnostic) and
    osr (windowless) code respectively.
  - Introduce CefBrowserPlatformDelegate for abstracting platform-specific
    implementations of browser host functionality.
  - Move dialog and menu code to separate manager and platform-specific runner
    implementations exposed via CefBrowserPlatformDelegate.
  - Standardize focus-handling behavior between windowed and windowless
    implementations. CefFocusHandler::OnSetFocus() will now also be called for
    osr focus changes.
- Support multiple simultaneous popups (issue #1289).
This commit is contained in:
Marshall Greenblatt
2015-11-17 13:20:13 -05:00
parent 4b5f052e13
commit 6cccc3b8a7
93 changed files with 6870 additions and 4569 deletions

89
cef.gyp
View File

@ -958,12 +958,17 @@
'libcef/browser/browser_host_impl.h',
'libcef/browser/browser_info.cc',
'libcef/browser/browser_info.h',
'libcef/browser/browser_info_manager.cc',
'libcef/browser/browser_info_manager.h',
'libcef/browser/browser_main.cc',
'libcef/browser/browser_main.h',
'libcef/browser/browser_message_filter.cc',
'libcef/browser/browser_message_filter.h',
'libcef/browser/browser_message_loop.cc',
'libcef/browser/browser_message_loop.h',
'libcef/browser/browser_platform_delegate.cc',
'libcef/browser/browser_platform_delegate.h',
'libcef/browser/browser_platform_delegate_create.cc',
'libcef/browser/browser_urlrequest_impl.cc',
'libcef/browser/browser_urlrequest_impl.h',
'libcef/browser/chrome_browser_process_stub.cc',
@ -1022,26 +1027,42 @@
'libcef/browser/extensions/pdf_web_contents_helper_client.h',
'libcef/browser/extensions/url_request_util.cc',
'libcef/browser/extensions/url_request_util.h',
'libcef/browser/file_dialog_runner.h',
'libcef/browser/file_dialog_manager.cc',
'libcef/browser/file_dialog_manager.h',
'libcef/browser/frame_host_impl.cc',
'libcef/browser/frame_host_impl.h',
'libcef/browser/geolocation_impl.cc',
'libcef/browser/internal_scheme_handler.cc',
'libcef/browser/internal_scheme_handler.h',
'libcef/browser/javascript_dialog.h',
'libcef/browser/javascript_dialog_runner.h',
'libcef/browser/javascript_dialog_manager.cc',
'libcef/browser/javascript_dialog_manager.h',
'libcef/browser/media_capture_devices_dispatcher.cc',
'libcef/browser/media_capture_devices_dispatcher.h',
'libcef/browser/menu_creator.cc',
'libcef/browser/menu_creator.h',
'libcef/browser/menu_manager.cc',
'libcef/browser/menu_manager.h',
'libcef/browser/menu_model_impl.cc',
'libcef/browser/menu_model_impl.h',
'libcef/browser/menu_runner.h',
'libcef/browser/native/browser_platform_delegate_native.cc',
'libcef/browser/native/browser_platform_delegate_native.h',
'libcef/browser/navigate_params.cc',
'libcef/browser/navigate_params.h',
'libcef/browser/navigation_entry_impl.cc',
'libcef/browser/navigation_entry_impl.h',
'libcef/browser/origin_whitelist_impl.cc',
'libcef/browser/origin_whitelist_impl.h',
'libcef/browser/osr/browser_platform_delegate_osr.cc',
'libcef/browser/osr/browser_platform_delegate_osr.h',
'libcef/browser/osr/osr_util.cc',
'libcef/browser/osr/osr_util.h',
'libcef/browser/osr/render_widget_host_view_osr.cc',
'libcef/browser/osr/render_widget_host_view_osr.h',
'libcef/browser/osr/software_output_device_osr.cc',
'libcef/browser/osr/software_output_device_osr.h',
'libcef/browser/osr/web_contents_view_osr.cc',
'libcef/browser/osr/web_contents_view_osr.h',
'libcef/browser/path_util_impl.cc',
'libcef/browser/pepper/browser_pepper_host_factory.cc',
'libcef/browser/pepper/browser_pepper_host_factory.h',
@ -1074,8 +1095,6 @@
'libcef/browser/printing/print_view_manager_base.h',
'libcef/browser/process_util_impl.cc',
'libcef/browser/proxy_stubs.cc',
'libcef/browser/render_widget_host_view_osr.cc',
'libcef/browser/render_widget_host_view_osr.h',
'libcef/browser/resource_context.cc',
'libcef/browser/resource_context.h',
'libcef/browser/resource_dispatcher_host_delegate.cc',
@ -1087,8 +1106,6 @@
'libcef/browser/scheme_handler.cc',
'libcef/browser/scheme_handler.h',
'libcef/browser/scheme_impl.cc',
'libcef/browser/software_output_device_osr.cc',
'libcef/browser/software_output_device_osr.h',
'libcef/browser/speech_recognition_manager_delegate.cc',
'libcef/browser/speech_recognition_manager_delegate.h',
'libcef/browser/ssl_cert_principal_impl.cc',
@ -1121,8 +1138,6 @@
'libcef/browser/url_request_interceptor.h',
'libcef/browser/url_request_user_data.cc',
'libcef/browser/url_request_user_data.h',
'libcef/browser/web_contents_view_osr.cc',
'libcef/browser/web_contents_view_osr.h',
'libcef/browser/web_plugin_impl.cc',
'libcef/browser/web_plugin_impl.h',
'libcef/browser/xml_reader_impl.cc',
@ -1398,12 +1413,18 @@
['OS=="win"', {
'sources': [
'<@(includes_win)',
'libcef/browser/browser_host_impl_win.cc',
'libcef/browser/browser_main_win.cc',
'libcef/browser/javascript_dialog_win.cc',
'libcef/browser/menu_creator_runner_win.cc',
'libcef/browser/menu_creator_runner_win.h',
'libcef/browser/render_widget_host_view_osr_win.cc',
'libcef/browser/native/browser_platform_delegate_native_win.cc',
'libcef/browser/native/browser_platform_delegate_native_win.h',
'libcef/browser/native/file_dialog_runner_win.cc',
'libcef/browser/native/file_dialog_runner_win.h',
'libcef/browser/native/javascript_dialog_runner_win.cc',
'libcef/browser/native/javascript_dialog_runner_win.h',
'libcef/browser/native/menu_runner_win.cc',
'libcef/browser/native/menu_runner_win.h',
'libcef/browser/osr/browser_platform_delegate_osr_win.cc',
'libcef/browser/osr/browser_platform_delegate_osr_win.h',
'libcef/browser/osr/render_widget_host_view_osr_win.cc',
# Include sources for printing using PDF.
'libcef/utility/printing_handler.cc',
'libcef/utility/printing_handler.h',
@ -1418,13 +1439,19 @@
[ 'OS=="mac"', {
'sources': [
'<@(includes_mac)',
'libcef/browser/browser_host_impl_mac.mm',
'libcef/browser/javascript_dialog_mac.mm',
'libcef/browser/menu_creator_runner_mac.h',
'libcef/browser/menu_creator_runner_mac.mm',
'libcef/browser/render_widget_host_view_osr_mac.mm',
'libcef/browser/text_input_client_osr_mac.mm',
'libcef/browser/text_input_client_osr_mac.h',
'libcef/browser/native/browser_platform_delegate_native_mac.h',
'libcef/browser/native/browser_platform_delegate_native_mac.mm',
'libcef/browser/native/file_dialog_runner_mac.h',
'libcef/browser/native/file_dialog_runner_mac.mm',
'libcef/browser/native/javascript_dialog_runner_mac.h',
'libcef/browser/native/javascript_dialog_runner_mac.mm',
'libcef/browser/native/menu_runner_mac.h',
'libcef/browser/native/menu_runner_mac.mm',
'libcef/browser/osr/browser_platform_delegate_osr_mac.h',
'libcef/browser/osr/browser_platform_delegate_osr_mac.mm',
'libcef/browser/osr/render_widget_host_view_osr_mac.mm',
'libcef/browser/osr/text_input_client_osr_mac.mm',
'libcef/browser/osr/text_input_client_osr_mac.h',
'libcef/common/util_mac.h',
'libcef/common/util_mac.mm',
# Include sources for spell checking support.
@ -1442,15 +1469,17 @@
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
'sources': [
'<@(includes_linux)',
'libcef/browser/browser_host_impl_linux.cc',
'libcef/browser/javascript_dialog_linux.cc',
'libcef/browser/menu_creator_runner_linux.cc',
'libcef/browser/menu_creator_runner_linux.h',
'libcef/browser/native/browser_platform_delegate_native_linux.cc',
'libcef/browser/native/browser_platform_delegate_native_linux.h',
'libcef/browser/native/menu_runner_linux.cc',
'libcef/browser/native/menu_runner_linux.h',
'libcef/browser/osr/browser_platform_delegate_osr_linux.cc',
'libcef/browser/osr/browser_platform_delegate_osr_linux.h',
'libcef/browser/osr/render_widget_host_view_osr_linux.cc',
'libcef/browser/printing/print_dialog_linux.cc',
'libcef/browser/printing/print_dialog_linux.h',
'libcef/browser/render_widget_host_view_osr_linux.cc',
'libcef/browser/window_x11.cc',
'libcef/browser/window_x11.h',
'libcef/browser/native/window_x11.cc',
'libcef/browser/native/window_x11.h',
],
}],
['os_posix == 1 and OS != "mac"', {
@ -1469,8 +1498,8 @@
'<(DEPTH)/ui/views/views.gyp:views',
],
'sources': [
'libcef/browser/window_delegate_view.cc',
'libcef/browser/window_delegate_view.h',
'libcef/browser/native/window_delegate_view.cc',
'libcef/browser/native/window_delegate_view.h',
'<(DEPTH)/ui/views/test/desktop_test_views_delegate.h',
'<(DEPTH)/ui/views/test/desktop_test_views_delegate_aura.cc',
'<(DEPTH)/ui/views/test/test_views_delegate.h',

File diff suppressed because it is too large Load Diff

View File

@ -16,9 +16,11 @@
#include "include/cef_client.h"
#include "include/cef_frame.h"
#include "libcef/browser/browser_info.h"
#include "libcef/browser/browser_platform_delegate.h"
#include "libcef/browser/file_dialog_manager.h"
#include "libcef/browser/frame_host_impl.h"
#include "libcef/browser/javascript_dialog_manager.h"
#include "libcef/browser/menu_creator.h"
#include "libcef/browser/menu_manager.h"
#include "libcef/common/response_manager.h"
#include "base/memory/scoped_ptr.h"
@ -29,42 +31,11 @@
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/file_chooser_params.h"
#if defined(USE_AURA)
#include "third_party/WebKit/public/platform/WebCursorInfo.h"
#include "ui/base/cursor/cursor.h"
#endif
#if defined(USE_X11)
#include "ui/base/x/x11_util.h"
#endif
namespace content {
struct NativeWebKeyboardEvent;
}
namespace blink {
class WebMouseEvent;
class WebMouseWheelEvent;
class WebInputEvent;
}
namespace net {
class DirectoryLister;
class URLRequest;
}
#if defined(USE_AURA)
namespace views {
class Widget;
}
#endif
#if defined(USE_X11)
class CefWindowX11;
#endif
struct Cef_DraggableRegion_Params;
struct Cef_Request_Params;
struct Cef_Response_Params;
@ -100,18 +71,6 @@ class CefBrowserHostImpl : public CefBrowserHost,
virtual void OnResponse(const std::string& response) =0;
};
// Extend content::FileChooserParams with some options unique to CEF.
struct FileChooserParams : public content::FileChooserParams {
// 0-based index of the selected value in |accept_types|.
int selected_accept_filter = 0;
// True if the Save dialog should prompt before overwriting files.
bool overwriteprompt = true;
// True if read-only files should be hidden.
bool hidereadonly = true;
};
~CefBrowserHostImpl() override;
// Create a new CefBrowserHostImpl instance.
@ -120,7 +79,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
CefRefPtr<CefClient> client,
const CefString& url,
const CefBrowserSettings& settings,
CefWindowHandle opener,
CefRefPtr<CefBrowserHostImpl> opener,
bool is_popup,
CefRefPtr<CefRequestContext> request_context);
@ -239,8 +198,6 @@ class CefBrowserHostImpl : public CefBrowserHost,
// Returns true if windowless rendering is enabled.
bool IsWindowless() const;
// Returns true if transparent painting is enabled.
bool IsTransparent() const;
// Called when the OS window hosting the browser is destroyed.
void WindowDestroyed();
@ -252,11 +209,11 @@ class CefBrowserHostImpl : public CefBrowserHost,
// Cancel display of the context menu, if any.
void CancelContextMenu();
// Returns the native view for the WebContents.
gfx::NativeView GetContentView() const;
// Returns a pointer to the WebContents.
content::WebContents* GetWebContents() const;
#if defined(USE_AURA)
// Returns the Widget owner for the browser window. Only used with windowed
// rendering.
views::Widget* GetWindowWidget() const;
#endif
// Returns the frame associated with the specified URLRequest.
CefRefPtr<CefFrame> GetFrameForRequest(net::URLRequest* request);
@ -293,7 +250,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
bool user_initiated);
// Open the specified text in the default text editor.
bool ViewText(const std::string& text);
void ViewText(const std::string& text);
// Handler for URLs involving external protocols.
void HandleExternalProtocol(const GURL& url);
@ -301,39 +258,23 @@ class CefBrowserHostImpl : public CefBrowserHost,
// Set the frame that currently has focus.
void SetFocusedFrame(int64 frame_id);
// Convert from view coordinates to screen coordinates.
gfx::Point GetScreenPoint(const gfx::Point& view) const;
// Thread safe accessors.
const CefBrowserSettings& settings() const { return settings_; }
CefRefPtr<CefClient> client() const { return client_; }
scoped_refptr<CefBrowserInfo> browser_info() const { return browser_info_; }
int browser_id() const;
#if defined(USE_AURA)
views::Widget* window_widget() const { return window_widget_; }
#endif
#if defined(USE_X11)
CefWindowX11* window_x11() const { return window_x11_; }
#endif
#if defined(OS_WIN)
static void RegisterWindowClass();
#endif
#if defined(USE_AURA)
ui::PlatformCursor GetPlatformCursor(blink::WebCursorInfo::Type type);
#endif
void OnSetFocus(cef_focus_source_t source);
// The argument vector will be empty if the dialog was cancelled.
typedef base::Callback<void(int, const std::vector<base::FilePath>&)>
RunFileChooserCallback;
// Run the file chooser dialog specified by |params|. Only a single dialog may
// be pending at any given time. |callback| will be executed asynchronously
// after the dialog is dismissed or if another dialog is already pending.
void RunFileChooser(const FileChooserParams& params,
const RunFileChooserCallback& callback);
void RunFileChooser(
const CefFileDialogRunner::FileChooserParams& params,
const CefFileDialogRunner::RunFileChooserCallback& callback);
bool HandleContextMenu(
content::WebContents* web_contents,
@ -345,15 +286,6 @@ class CefBrowserHostImpl : public CefBrowserHost,
// Otherwise, the browser's WebContents will be returned.
content::WebContents* GetActionableWebContents();
// Used when creating a new popup window.
struct PendingPopupInfo {
CefWindowInfo window_info;
CefBrowserSettings settings;
CefRefPtr<CefClient> client;
};
// Returns false if a popup is already pending.
bool SetPendingPopupInfo(scoped_ptr<PendingPopupInfo> info);
enum DestructionState {
DESTRUCTION_STATE_NONE = 0,
DESTRUCTION_STATE_PENDING,
@ -488,13 +420,13 @@ class CefBrowserHostImpl : public CefBrowserHost,
class DevToolsWebContentsObserver;
static CefRefPtr<CefBrowserHostImpl> CreateInternal(
const CefWindowInfo& window_info,
const CefBrowserSettings& settings,
CefRefPtr<CefClient> client,
content::WebContents* web_contents,
scoped_refptr<CefBrowserInfo> browser_info,
CefWindowHandle opener,
CefRefPtr<CefRequestContext> request_context);
CefRefPtr<CefBrowserHostImpl> opener,
CefRefPtr<CefRequestContext> request_context,
scoped_ptr<CefBrowserPlatformDelegate> platform_delegate);
// content::WebContentsObserver::OnMessageReceived() message handlers.
void OnFrameIdentified(int64 frame_id,
@ -516,13 +448,16 @@ class CefBrowserHostImpl : public CefBrowserHost,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
CefBrowserHostImpl(const CefWindowInfo& window_info,
const CefBrowserSettings& settings,
CefBrowserHostImpl(const CefBrowserSettings& settings,
CefRefPtr<CefClient> client,
content::WebContents* web_contents,
scoped_refptr<CefBrowserInfo> browser_info,
CefWindowHandle opener,
CefRefPtr<CefRequestContext> request_context);
CefRefPtr<CefBrowserHostImpl> opener,
CefRefPtr<CefRequestContext> request_context,
scoped_ptr<CefBrowserPlatformDelegate> platform_delegate);
// Give the platform delegate an opportunity to create the host window.
bool CreateHostWindow();
// Updates and returns an existing frame or creates a new frame. Pass
// CefFrameHostImpl::kUnspecifiedFrameId for |parent_frame_id| if unknown.
@ -534,59 +469,6 @@ class CefBrowserHostImpl : public CefBrowserHost,
// Remove the references to all frames and mark them as detached.
void DetachAllFrames();
#if defined(OS_WIN)
static LPCTSTR GetWndClass();
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam);
#endif
// Create the window.
bool PlatformCreateWindow();
// Sends a message via the OS to close the native browser window.
// DestroyBrowser will be called after the native window has closed.
void PlatformCloseWindow();
// Resize the window to the given dimensions.
void PlatformSizeTo(int width, int height);
// Set or remove focus from the window.
void PlatformSetFocus(bool focus);
#if defined(OS_MACOSX)
// Set or remove window visibility.
void PlatformSetWindowVisibility(bool visible);
#endif
// Return the handle for this window.
CefWindowHandle PlatformGetWindowHandle();
// Open the specified text in the default text editor.
bool PlatformViewText(const std::string& text);
// Forward the keyboard event to the application or frame window to allow
// processing of shortcut keys.
void PlatformHandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event);
// Invoke platform specific handling for the external protocol.
void PlatformHandleExternalProtocol(const GURL& url);
// Invoke platform specific file chooser dialog.
void PlatformRunFileChooser(const FileChooserParams& params,
RunFileChooserCallback callback);
void PlatformTranslateKeyEvent(content::NativeWebKeyboardEvent& native_event,
const CefKeyEvent& key_event);
void PlatformTranslateClickEvent(blink::WebMouseEvent& web_event,
const CefMouseEvent& mouse_event,
CefBrowserHost::MouseButtonType type,
bool mouseUp, int clickCount);
void PlatformTranslateMoveEvent(blink::WebMouseEvent& web_event,
const CefMouseEvent& mouse_event,
bool mouseLeave);
void PlatformTranslateWheelEvent(blink::WebMouseWheelEvent& web_event,
const CefMouseEvent& mouse_event,
int deltaX, int deltaY);
void PlatformTranslateMouseEvent(blink::WebMouseEvent& web_event,
const CefMouseEvent& mouse_event);
void PlatformNotifyMoveOrResizeStarted();
int TranslateModifiers(uint32 cefKeyStates);
void SendMouseEvent(const blink::WebMouseEvent& web_event);
void OnAddressChange(CefRefPtr<CefFrame> frame,
const GURL& url);
void OnLoadStart(CefRefPtr<CefFrame> frame,
@ -602,44 +484,18 @@ class CefBrowserHostImpl : public CefBrowserHost,
void OnFullscreenModeChange(bool fullscreen);
void OnTitleChange(const base::string16& title);
// Continuation from RunFileChooser.
void RunFileChooserOnUIThread(const FileChooserParams& params,
const RunFileChooserCallback& callback);
// Used with RunFileChooser to clear the |file_chooser_pending_| flag.
void OnRunFileChooserCallback(const RunFileChooserCallback& callback,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths);
// Used with WebContentsDelegate::RunFileChooser when mode is
// content::FileChooserParams::UploadFolder.
void OnRunFileChooserUploadFolderDelegateCallback(
content::WebContents* web_contents,
const content::FileChooserParams::Mode mode,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths);
// Used with WebContentsDelegate::RunFileChooser to notify the WebContents.
void OnRunFileChooserDelegateCallback(
content::WebContents* web_contents,
content::FileChooserParams::Mode mode,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths);
void OnDevToolsWebContentsDestroyed();
CefWindowInfo window_info_;
// Create the CefFileDialogManager if it doesn't already exist.
void EnsureFileDialogManager();
CefBrowserSettings settings_;
CefRefPtr<CefClient> client_;
scoped_ptr<content::WebContents> web_contents_;
scoped_refptr<CefBrowserInfo> browser_info_;
CefWindowHandle opener_;
CefRefPtr<CefRequestContext> request_context_;
// Pending popup information. Access must be protected by
// |pending_popup_info_lock_|.
base::Lock pending_popup_info_lock_;
scoped_ptr<PendingPopupInfo> pending_popup_info_;
scoped_ptr<CefBrowserPlatformDelegate> platform_delegate_;
// Volatile state information. All access must be protected by the state lock.
base::Lock state_lock_;
@ -694,11 +550,14 @@ class CefBrowserHostImpl : public CefBrowserHost,
// Manages response registrations.
scoped_ptr<CefResponseManager> response_manager_;
// Used for creating and managing file dialogs.
scoped_ptr<CefFileDialogManager> file_dialog_manager_;
// Used for creating and managing JavaScript dialogs.
scoped_ptr<CefJavaScriptDialogManager> dialog_manager_;
scoped_ptr<CefJavaScriptDialogManager> javascript_dialog_manager_;
// Used for creating and managing context menus.
scoped_ptr<CefMenuCreator> menu_creator_;
scoped_ptr<CefMenuManager> menu_manager_;
// Track the lifespan of the frontend WebContents associated with this
// browser.
@ -707,24 +566,8 @@ class CefBrowserHostImpl : public CefBrowserHost,
// destroyed.
CefDevToolsFrontend* devtools_frontend_;
// True if a file chooser is currently pending.
bool file_chooser_pending_;
// Used for asynchronously listing directory contents.
scoped_ptr<net::DirectoryLister> lister_;
#if defined(USE_AURA)
// Widget hosting the web contents. It will be deleted automatically when the
// associated root window is destroyed.
views::Widget* window_widget_;
#endif // defined(USE_AURA)
#if defined(USE_X11)
CefWindowX11* window_x11_;
scoped_ptr<ui::XScopedCursor> invisible_cursor_;
#endif // defined(USE_X11)
IMPLEMENT_REFCOUNTING(CefBrowserHostImpl);
DISALLOW_EVIL_CONSTRUCTORS(CefBrowserHostImpl);
DISALLOW_COPY_AND_ASSIGN(CefBrowserHostImpl);
};
#endif // CEF_LIBCEF_BROWSER_BROWSER_HOST_IMPL_H_

View File

@ -1,946 +0,0 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2011 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 "libcef/browser/browser_host_impl.h"
#import <Cocoa/Cocoa.h>
#import <CoreServices/CoreServices.h>
#include "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/browser/text_input_client_osr_mac.h"
#include "libcef/browser/thread_util.h"
#include "base/files/file_util.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/file_chooser_params.h"
#include "grit/cef_strings.h"
#include "grit/ui_strings.h"
#include "net/base/mime_util.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/events/keycodes/keyboard_codes_posix.h"
#include "ui/gfx/geometry/rect.h"
// Wrapper NSView for the native view. Necessary to destroy the browser when
// the view is deleted.
@interface CefBrowserHostView : NSView {
@private
CefBrowserHostImpl* browser_; // weak
}
@property (nonatomic, assign) CefBrowserHostImpl* browser;
@end
@implementation CefBrowserHostView
@synthesize browser = browser_;
- (void) dealloc {
if (browser_) {
// Force the browser to be destroyed and release the reference added in
// PlatformCreateWindow().
browser_->WindowDestroyed();
}
[super dealloc];
}
@end
// Receives notifications from the browser window. Will delete itself when done.
@interface CefWindowDelegate : NSObject <NSWindowDelegate> {
@private
CefBrowserHostImpl* browser_; // weak
NSWindow* window_;
}
- (id)initWithWindow:(NSWindow*)window andBrowser:(CefBrowserHostImpl*)browser;
@end
@implementation CefWindowDelegate
- (id)initWithWindow:(NSWindow*)window andBrowser:(CefBrowserHostImpl*)browser {
if (self = [super init]) {
window_ = window;
browser_ = browser;
[window_ setDelegate:self];
// Register for application hide/unhide notifications.
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationDidHide:)
name:NSApplicationDidHideNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationDidUnhide:)
name:NSApplicationDidUnhideNotification
object:nil];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
// Called when we are activated (when we gain focus).
- (void)windowDidBecomeKey:(NSNotification*)notification {
if (browser_)
browser_->SetFocus(true);
}
// Called when we are deactivated (when we lose focus).
- (void)windowDidResignKey:(NSNotification*)notification {
if (browser_)
browser_->SetFocus(false);
}
// Called when we have been minimized.
- (void)windowDidMiniaturize:(NSNotification *)notification {
if (browser_)
browser_->SetWindowVisibility(false);
}
// Called when we have been unminimized.
- (void)windowDidDeminiaturize:(NSNotification *)notification {
if (browser_)
browser_->SetWindowVisibility(true);
}
// Called when the application has been hidden.
- (void)applicationDidHide:(NSNotification *)notification {
// If the window is miniaturized then nothing has really changed.
if (![window_ isMiniaturized]) {
if (browser_)
browser_->SetWindowVisibility(false);
}
}
// Called when the application has been unhidden.
- (void)applicationDidUnhide:(NSNotification *)notification {
// If the window is miniaturized then nothing has really changed.
if (![window_ isMiniaturized]) {
if (browser_)
browser_->SetWindowVisibility(true);
}
}
- (BOOL)windowShouldClose:(id)window {
// Protect against multiple requests to close while the close is pending.
if (browser_ && browser_->destruction_state() <=
CefBrowserHostImpl::DESTRUCTION_STATE_PENDING) {
if (browser_->destruction_state() ==
CefBrowserHostImpl::DESTRUCTION_STATE_NONE) {
// Request that the browser close.
browser_->CloseBrowser(false);
}
// Cancel the close.
return NO;
}
// Clean ourselves up after clearing the stack of anything that might have the
// window on it.
[self performSelectorOnMainThread:@selector(cleanup:)
withObject:window
waitUntilDone:NO];
// Allow the close.
return YES;
}
- (void)cleanup:(id)window {
[self release];
}
@end
namespace {
base::string16 GetDescriptionFromMimeType(const std::string& mime_type) {
// Check for wild card mime types and return an appropriate description.
static const struct {
const char* mime_type;
int string_id;
} kWildCardMimeTypes[] = {
{ "audio", IDS_APP_AUDIO_FILES },
{ "image", IDS_APP_IMAGE_FILES },
{ "text", IDS_APP_TEXT_FILES },
{ "video", IDS_APP_VIDEO_FILES },
};
for (size_t i = 0; i < arraysize(kWildCardMimeTypes); ++i) {
if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*")
return l10n_util::GetStringUTF16(kWildCardMimeTypes[i].string_id);
}
return base::string16();
}
void AddFilters(NSPopUpButton *button,
const std::vector<base::string16>& accept_filters,
bool include_all_files,
std::vector<std::vector<base::string16> >* all_extensions) {
for (size_t i = 0; i < accept_filters.size(); ++i) {
const base::string16& filter = accept_filters[i];
if (filter.empty())
continue;
std::vector<base::string16> extensions;
base::string16 description;
size_t sep_index = filter.find('|');
if (sep_index != std::string::npos) {
// Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3".
description = filter.substr(0, sep_index);
const std::vector<base::string16>& ext =
base::SplitString(filter.substr(sep_index + 1),
base::ASCIIToUTF16(";"),
base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
for (size_t x = 0; x < ext.size(); ++x) {
const base::string16& file_ext = ext[x];
if (!file_ext.empty() && file_ext[0] == '.')
extensions.push_back(file_ext);
}
} else if (filter[0] == '.') {
// Treat as an extension beginning with the '.' character.
extensions.push_back(filter);
} else {
// Otherwise convert mime type to one or more extensions.
const std::string& ascii = base::UTF16ToASCII(filter);
std::vector<base::FilePath::StringType> ext;
net::GetExtensionsForMimeType(ascii, &ext);
if (!ext.empty()) {
for (size_t x = 0; x < ext.size(); ++x)
extensions.push_back(base::ASCIIToUTF16("." + ext[x]));
description = GetDescriptionFromMimeType(ascii);
}
}
if (extensions.empty())
continue;
// Don't display a crazy number of extensions since the NSPopUpButton width
// will keep growing.
const size_t kMaxExtensions = 10;
base::string16 ext_str;
for (size_t x = 0; x < std::min(kMaxExtensions, extensions.size()); ++x) {
const base::string16& pattern = base::ASCIIToUTF16("*") + extensions[x];
if (x != 0)
ext_str += base::ASCIIToUTF16(";");
ext_str += pattern;
}
if (extensions.size() > kMaxExtensions)
ext_str += base::ASCIIToUTF16(";...");
if (description.empty()) {
description = ext_str;
} else {
description +=
base::ASCIIToUTF16(" (") + ext_str + base::ASCIIToUTF16(")");
}
[button addItemWithTitle:base::SysUTF16ToNSString(description)];
all_extensions->push_back(extensions);
}
// Add the *.* filter, but only if we have added other filters (otherwise it
// is implied).
if (include_all_files && !all_extensions->empty()) {
[button addItemWithTitle:base::SysUTF8ToNSString("All Files (*)")];
all_extensions->push_back(std::vector<base::string16>());
}
}
} // namespace
// Used to manage the file type filter in the NSSavePanel/NSOpenPanel.
@interface CefFilterDelegate : NSObject {
@private
NSSavePanel* panel_;
std::vector<std::vector<base::string16> > extensions_;
int selected_index_;
}
- (id)initWithPanel:(NSSavePanel*)panel
andAcceptFilters:(const std::vector<base::string16>&)accept_filters
andFilterIndex:(int)index;
- (void)setFilter:(int)index;
- (int)filter;
- (void)filterSelectionChanged:(id)sender;
- (void)setFileExtension;
@end
@implementation CefFilterDelegate
- (id)initWithPanel:(NSSavePanel*)panel
andAcceptFilters:(const std::vector<base::string16>&)accept_filters
andFilterIndex:(int)index {
if (self = [super init]) {
DCHECK(panel);
panel_ = panel;
selected_index_ = 0;
NSPopUpButton *button = [[NSPopUpButton alloc] init];
AddFilters(button, accept_filters, true, &extensions_);
[button sizeToFit];
[button setTarget:self];
[button setAction:@selector(filterSelectionChanged:)];
if (index < static_cast<int>(extensions_.size())) {
[button selectItemAtIndex:index];
[self setFilter:index];
}
[panel_ setAccessoryView:button];
}
return self;
}
// Set the current filter index.
- (void)setFilter:(int)index {
DCHECK(index >= 0 && index < static_cast<int>(extensions_.size()));
selected_index_ = index;
// Set the selectable file types. For open panels this limits the files that
// can be selected. For save panels this applies a default file extenion when
// the dialog is dismissed if none is already provided.
NSMutableArray* acceptArray = nil;
if (!extensions_[index].empty()) {
acceptArray = [[NSMutableArray alloc] init];
for (size_t i = 0; i < extensions_[index].size(); ++i) {
[acceptArray addObject:
base::SysUTF16ToNSString(extensions_[index][i].substr(1))];
}
}
[panel_ setAllowedFileTypes:acceptArray];
if (![panel_ isKindOfClass:[NSOpenPanel class]]) {
// For save panels set the file extension.
[self setFileExtension];
}
}
// Returns the current filter index.
- (int)filter {
return selected_index_;
}
// Called when the selected filter is changed via the NSPopUpButton.
- (void)filterSelectionChanged:(id)sender {
NSPopUpButton *button = (NSPopUpButton*)sender;
[self setFilter:[button indexOfSelectedItem]];
}
// Set the extension on the currently selected file name.
- (void)setFileExtension {
const std::vector<base::string16>& filter = extensions_[selected_index_];
if (filter.empty()) {
// All extensions are allowed so don't change anything.
return;
}
base::FilePath path(base::SysNSStringToUTF8([panel_ nameFieldStringValue]));
// If the file name currently includes an extension from |filter| then don't
// change anything.
base::string16 extension = base::UTF8ToUTF16(path.Extension());
if (!extension.empty()) {
for (size_t i = 0; i < filter.size(); ++i) {
if (filter[i] == extension)
return;
}
}
// Change the extension to the first value in |filter|.
path = path.ReplaceExtension(base::UTF16ToUTF8(filter[0]));
[panel_ setNameFieldStringValue:base::SysUTF8ToNSString(path.value())];
}
@end
namespace {
void RunOpenFileDialog(const CefBrowserHostImpl::FileChooserParams& params,
NSView* view,
int* filter_index,
std::vector<base::FilePath>* files) {
NSOpenPanel* openPanel = [NSOpenPanel openPanel];
base::string16 title;
if (!params.title.empty()) {
title = params.title;
} else {
title = l10n_util::GetStringUTF16(
params.mode == content::FileChooserParams::Open ?
IDS_OPEN_FILE_DIALOG_TITLE :
(params.mode == content::FileChooserParams::OpenMultiple ?
IDS_OPEN_FILES_DIALOG_TITLE : IDS_SELECT_FOLDER_DIALOG_TITLE));
}
[openPanel setTitle:base::SysUTF16ToNSString(title)];
std::string filename, directory;
if (!params.default_file_name.empty()) {
if (params.mode == content::FileChooserParams::UploadFolder ||
params.default_file_name.EndsWithSeparator()) {
// The value is only a directory.
directory = params.default_file_name.value();
} else {
// The value is a file name and possibly a directory.
filename = params.default_file_name.BaseName().value();
directory = params.default_file_name.DirName().value();
}
}
if (!filename.empty()) {
[openPanel setNameFieldStringValue:base::SysUTF8ToNSString(filename)];
}
if (!directory.empty()) {
[openPanel setDirectoryURL:
[NSURL fileURLWithPath:base::SysUTF8ToNSString(directory)]];
}
CefFilterDelegate* filter_delegate = nil;
if (params.mode != content::FileChooserParams::UploadFolder &&
!params.accept_types.empty()) {
// Add the file filter control.
filter_delegate =
[[CefFilterDelegate alloc] initWithPanel:openPanel
andAcceptFilters:params.accept_types
andFilterIndex:*filter_index];
}
// Further panel configuration.
[openPanel setAllowsOtherFileTypes:YES];
[openPanel setAllowsMultipleSelection:
(params.mode == content::FileChooserParams::OpenMultiple)];
[openPanel setCanChooseFiles:
(params.mode != content::FileChooserParams::UploadFolder)];
[openPanel setCanChooseDirectories:
(params.mode == content::FileChooserParams::UploadFolder)];
[openPanel setShowsHiddenFiles:!params.hidereadonly];
// Show panel.
[openPanel beginSheetModalForWindow:[view window]
completionHandler:^(NSInteger returnCode) {
[NSApp stopModalWithCode:returnCode];
}];
NSInteger result = [NSApp runModalForWindow:[view window]];
if (result == NSFileHandlingPanelOKButton) {
NSArray *urls = [openPanel URLs];
int i, count = [urls count];
for (i=0; i<count; i++) {
NSURL* url = [urls objectAtIndex:i];
if ([url isFileURL])
files->push_back(base::FilePath(base::SysNSStringToUTF8([url path])));
}
}
if (filter_delegate != nil)
*filter_index = [filter_delegate filter];
}
bool RunSaveFileDialog(const CefBrowserHostImpl::FileChooserParams& params,
NSView* view,
int* filter_index,
base::FilePath* file) {
NSSavePanel* savePanel = [NSSavePanel savePanel];
base::string16 title;
if (!params.title.empty())
title = params.title;
else
title = l10n_util::GetStringUTF16(IDS_SAVE_AS_DIALOG_TITLE);
[savePanel setTitle:base::SysUTF16ToNSString(title)];
std::string filename, directory;
if (!params.default_file_name.empty()) {
if (params.default_file_name.EndsWithSeparator()) {
// The value is only a directory.
directory = params.default_file_name.value();
} else {
// The value is a file name and possibly a directory.
filename = params.default_file_name.BaseName().value();
directory = params.default_file_name.DirName().value();
}
}
if (!filename.empty()) {
[savePanel setNameFieldStringValue:base::SysUTF8ToNSString(filename)];
}
if (!directory.empty()) {
[savePanel setDirectoryURL:
[NSURL fileURLWithPath:base::SysUTF8ToNSString(directory)]];
}
CefFilterDelegate* filter_delegate = nil;
if (!params.accept_types.empty()) {
// Add the file filter control.
filter_delegate =
[[CefFilterDelegate alloc] initWithPanel:savePanel
andAcceptFilters:params.accept_types
andFilterIndex:*filter_index];
}
[savePanel setAllowsOtherFileTypes:YES];
[savePanel setShowsHiddenFiles:!params.hidereadonly];
bool success = false;
// Show panel.
[savePanel beginSheetModalForWindow:[view window]
completionHandler:^(NSInteger resultCode) {
[NSApp stopModalWithCode:resultCode];
}];
NSInteger result = [NSApp runModalForWindow:[view window]];
if (result == NSFileHandlingPanelOKButton) {
NSURL* url = [savePanel URL];
NSString* path = [url path];
*file = base::FilePath([path UTF8String]);
success = true;
}
if (filter_delegate != nil)
*filter_index = [filter_delegate filter];
return success;
}
} // namespace
bool CefBrowserHostImpl::PlatformViewText(const std::string& text) {
NOTIMPLEMENTED();
return false;
}
CefTextInputContext CefBrowserHostImpl::GetNSTextInputContext() {
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return NULL;
}
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "Called on invalid thread";
return NULL;
}
CefRenderWidgetHostViewOSR* rwhv = static_cast<CefRenderWidgetHostViewOSR*>(
GetWebContents()->GetRenderWidgetHostView());
return rwhv->GetNSTextInputContext();
}
void CefBrowserHostImpl::HandleKeyEventBeforeTextInputClient(
CefEventHandle keyEvent) {
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "Called on invalid thread";
return;
}
CefRenderWidgetHostViewOSR* rwhv = static_cast<CefRenderWidgetHostViewOSR*>(
GetWebContents()->GetRenderWidgetHostView());
rwhv->HandleKeyEventBeforeTextInputClient(keyEvent);
}
void CefBrowserHostImpl::HandleKeyEventAfterTextInputClient(
CefEventHandle keyEvent) {
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "Called on invalid thread";
return;
}
CefRenderWidgetHostViewOSR* rwhv = static_cast<CefRenderWidgetHostViewOSR*>(
GetWebContents()->GetRenderWidgetHostView());
rwhv->HandleKeyEventAfterTextInputClient(keyEvent);
}
bool CefBrowserHostImpl::PlatformCreateWindow() {
base::mac::ScopedNSAutoreleasePool autorelease_pool;
NSWindow* newWnd = nil;
NSView* parentView = window_info_.parent_view;
NSRect contentRect = {{window_info_.x, window_info_.y},
{window_info_.width, window_info_.height}};
if (parentView == nil) {
// Create a new window.
NSRect screen_rect = [[NSScreen mainScreen] visibleFrame];
NSRect window_rect = {{window_info_.x,
screen_rect.size.height - window_info_.y},
{window_info_.width, window_info_.height}};
if (window_rect.size.width == 0)
window_rect.size.width = 750;
if (window_rect.size.height == 0)
window_rect.size.height = 750;
contentRect.origin.x = 0;
contentRect.origin.y = 0;
contentRect.size.width = window_rect.size.width;
contentRect.size.height = window_rect.size.height;
newWnd = [[UnderlayOpenGLHostingWindow alloc]
initWithContentRect:window_rect
styleMask:(NSTitledWindowMask |
NSClosableWindowMask |
NSMiniaturizableWindowMask |
NSResizableWindowMask |
NSUnifiedTitleAndToolbarWindowMask )
backing:NSBackingStoreBuffered
defer:NO];
// Create the delegate for control and browser window events.
[[CefWindowDelegate alloc] initWithWindow:newWnd andBrowser:this];
parentView = [newWnd contentView];
window_info_.parent_view = parentView;
}
// Make the content view for the window have a layer. This will make all
// sub-views have layers. This is necessary to ensure correct layer
// ordering of all child views and their layers.
[[[parentView window] contentView] setWantsLayer:YES];
// Add a reference that will be released in the dealloc handler.
AddRef();
// Create the browser view.
CefBrowserHostView* browser_view =
[[CefBrowserHostView alloc] initWithFrame:contentRect];
browser_view.browser = this;
[parentView addSubview:browser_view];
[browser_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[browser_view setNeedsDisplay:YES];
[browser_view release];
// Parent the TabContents to the browser view.
const NSRect bounds = [browser_view bounds];
NSView* native_view = web_contents_->GetNativeView();
[browser_view addSubview:native_view];
[native_view setFrame:bounds];
[native_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[native_view setNeedsDisplay:YES];
window_info_.view = browser_view;
if (newWnd != nil && !window_info_.hidden) {
// Show the window.
[newWnd makeKeyAndOrderFront: nil];
}
return true;
}
void CefBrowserHostImpl::PlatformCloseWindow() {
if (window_info_.view != nil) {
[[window_info_.view window]
performSelectorOnMainThread:@selector(performClose:)
withObject:nil
waitUntilDone:NO];
}
}
void CefBrowserHostImpl::PlatformSizeTo(int width, int height) {
// Not needed; subviews are bound.
}
void CefBrowserHostImpl::PlatformSetFocus(bool focus) {
if (web_contents_) {
if (content::RenderWidgetHostView* view =
web_contents_->GetRenderWidgetHostView()) {
view->SetActive(focus);
if (focus && !IsWindowless()) {
// Give keyboard focus to the native view.
NSView* view = web_contents_->GetContentNativeView();
DCHECK([view canBecomeKeyView]);
[[view window] makeFirstResponder:view];
}
}
}
}
void CefBrowserHostImpl::PlatformSetWindowVisibility(bool visible) {
if (web_contents_) {
if (content::RenderWidgetHostView* view =
web_contents_->GetRenderWidgetHostView()) {
view->SetWindowVisibility(visible);
}
}
}
CefWindowHandle CefBrowserHostImpl::PlatformGetWindowHandle() {
return IsWindowless() ? window_info_.parent_view : window_info_.view;
}
void CefBrowserHostImpl::PlatformHandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) {
// Give the top level menu equivalents a chance to handle the event.
if ([event.os_event type] == NSKeyDown)
[[NSApp mainMenu] performKeyEquivalent:event.os_event];
}
void CefBrowserHostImpl::PlatformRunFileChooser(
const FileChooserParams& params,
RunFileChooserCallback callback) {
std::vector<base::FilePath> files;
int filter_index = params.selected_accept_filter;
NSView* owner = PlatformGetWindowHandle();
if (params.mode == content::FileChooserParams::Open ||
params.mode == content::FileChooserParams::OpenMultiple ||
params.mode == content::FileChooserParams::UploadFolder) {
RunOpenFileDialog(params, owner, &filter_index, &files);
} else if (params.mode == content::FileChooserParams::Save) {
base::FilePath file;
if (RunSaveFileDialog(params, owner, &filter_index, &file)) {
files.push_back(file);
}
} else {
NOTIMPLEMENTED();
}
callback.Run(filter_index, files);
}
void CefBrowserHostImpl::PlatformHandleExternalProtocol(const GURL& url) {
}
static NSTimeInterval currentEventTimestamp() {
NSEvent* currentEvent = [NSApp currentEvent];
if (currentEvent)
return [currentEvent timestamp];
else {
// FIXME(API): In case there is no current event, the timestamp could be
// obtained by getting the time since the application started. This involves
// taking some more static functions from Chromium code.
// Another option is to have the timestamp as a field in CefEvent structures
// and let the client provide it.
return 0;
}
}
static NSUInteger NativeModifiers(int cef_modifiers) {
NSUInteger native_modifiers = 0;
if (cef_modifiers & EVENTFLAG_SHIFT_DOWN)
native_modifiers |= NSShiftKeyMask;
if (cef_modifiers & EVENTFLAG_CONTROL_DOWN)
native_modifiers |= NSControlKeyMask;
if (cef_modifiers & EVENTFLAG_ALT_DOWN)
native_modifiers |= NSAlternateKeyMask;
if (cef_modifiers & EVENTFLAG_COMMAND_DOWN)
native_modifiers |= NSCommandKeyMask;
if (cef_modifiers & EVENTFLAG_CAPS_LOCK_ON)
native_modifiers |= NSAlphaShiftKeyMask;
if (cef_modifiers & EVENTFLAG_NUM_LOCK_ON)
native_modifiers |= NSNumericPadKeyMask;
return native_modifiers;
}
void CefBrowserHostImpl::PlatformTranslateKeyEvent(
content::NativeWebKeyboardEvent& native_event,
const CefKeyEvent& key_event) {
// Use a synthetic NSEvent in order to obtain the windowsKeyCode member from
// the NativeWebKeyboardEvent constructor. This is the only member which can
// not be easily translated (without hardcoding keyCodes)
// Determining whether a modifier key is left or right seems to be done
// through the key code as well.
NSEventType event_type;
if (key_event.character == 0 && key_event.unmodified_character == 0) {
// Check if both character and unmodified_characther are empty to determine
// if this was a NSFlagsChanged event.
// A dead key will have an empty character, but a non-empty unmodified
// character
event_type = NSFlagsChanged;
} else {
switch (key_event.type) {
case KEYEVENT_RAWKEYDOWN:
case KEYEVENT_KEYDOWN:
case KEYEVENT_CHAR:
event_type = NSKeyDown;
break;
case KEYEVENT_KEYUP:
event_type = NSKeyUp;
break;
}
}
NSString* charactersIgnoringModifiers = [[[NSString alloc]
initWithCharacters:&key_event.unmodified_character length:1]
autorelease];
NSString* characters = [[[NSString alloc]
initWithCharacters:&key_event.character length:1] autorelease];
NSEvent* synthetic_event =
[NSEvent keyEventWithType:event_type
location:NSMakePoint(0, 0)
modifierFlags:NativeModifiers(key_event.modifiers)
timestamp:currentEventTimestamp()
windowNumber:0
context:nil
characters:characters
charactersIgnoringModifiers:charactersIgnoringModifiers
isARepeat:NO
keyCode:key_event.native_key_code];
native_event = content::NativeWebKeyboardEvent(synthetic_event);
if (key_event.type == KEYEVENT_CHAR)
native_event.type = blink::WebInputEvent::Char;
native_event.isSystemKey = key_event.is_system_key;
}
void CefBrowserHostImpl::PlatformTranslateClickEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
MouseButtonType type,
bool mouseUp, int clickCount) {
PlatformTranslateMouseEvent(result, mouse_event);
switch (type) {
case MBT_LEFT:
result.type = mouseUp ? blink::WebInputEvent::MouseUp :
blink::WebInputEvent::MouseDown;
result.button = blink::WebMouseEvent::ButtonLeft;
break;
case MBT_MIDDLE:
result.type = mouseUp ? blink::WebInputEvent::MouseUp :
blink::WebInputEvent::MouseDown;
result.button = blink::WebMouseEvent::ButtonMiddle;
break;
case MBT_RIGHT:
result.type = mouseUp ? blink::WebInputEvent::MouseUp :
blink::WebInputEvent::MouseDown;
result.button = blink::WebMouseEvent::ButtonRight;
break;
default:
NOTREACHED();
}
result.clickCount = clickCount;
}
void CefBrowserHostImpl::PlatformTranslateMoveEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) {
PlatformTranslateMouseEvent(result, mouse_event);
if (!mouseLeave) {
result.type = blink::WebInputEvent::MouseMove;
if (mouse_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonLeft;
else if (mouse_event.modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonMiddle;
else if (mouse_event.modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonRight;
else
result.button = blink::WebMouseEvent::ButtonNone;
} else {
result.type = blink::WebInputEvent::MouseLeave;
result.button = blink::WebMouseEvent::ButtonNone;
}
result.clickCount = 0;
}
void CefBrowserHostImpl::PlatformTranslateWheelEvent(
blink::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX, int deltaY) {
result = blink::WebMouseWheelEvent();
PlatformTranslateMouseEvent(result, mouse_event);
result.type = blink::WebInputEvent::MouseWheel;
static const double scrollbarPixelsPerCocoaTick = 40.0;
result.deltaX = deltaX;
result.deltaY = deltaY;
result.wheelTicksX = result.deltaX / scrollbarPixelsPerCocoaTick;
result.wheelTicksY = result.deltaY / scrollbarPixelsPerCocoaTick;
result.hasPreciseScrollingDeltas = true;
// Unless the phase and momentumPhase are passed in as parameters to this
// function, there is no way to know them
result.phase = blink::WebMouseWheelEvent::PhaseNone;
result.momentumPhase = blink::WebMouseWheelEvent::PhaseNone;
if (mouse_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonLeft;
else if (mouse_event.modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonMiddle;
else if (mouse_event.modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonRight;
else
result.button = blink::WebMouseEvent::ButtonNone;
}
void CefBrowserHostImpl::PlatformTranslateMouseEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event) {
// position
result.x = mouse_event.x;
result.y = mouse_event.y;
result.windowX = result.x;
result.windowY = result.y;
result.globalX = result.x;
result.globalY = result.y;
if (IsWindowless()) {
CefRefPtr<CefRenderHandler> handler = client_->GetRenderHandler();
if (handler.get()) {
handler->GetScreenPoint(this, result.x, result.y, result.globalX,
result.globalY);
}
} else {
NSView* view = window_info_.parent_view;
if (view) {
NSRect bounds = [view bounds];
NSPoint view_pt = {result.x, bounds.size.height - result.y};
NSPoint window_pt = [view convertPoint:view_pt toView:nil];
NSPoint screen_pt = [[view window] convertBaseToScreen:window_pt];
result.globalX = screen_pt.x;
result.globalY = screen_pt.y;
}
}
// modifiers
result.modifiers |= TranslateModifiers(mouse_event.modifiers);
// timestamp - Mac OSX specific
result.timeStampSeconds = currentEventTimestamp();
}
void CefBrowserHostImpl::PlatformNotifyMoveOrResizeStarted() {
}

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@
#include "libcef/browser/browser_info.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/thread_util.h"
#include "ipc/ipc_message.h"
@ -36,14 +37,14 @@ void CefBrowserInfo::RenderIDManager::remove_render_frame_id(
}
bool CefBrowserInfo::RenderIDManager::is_render_view_id_match(
int render_process_id, int render_routing_id) {
int render_process_id, int render_routing_id) const {
return is_render_id_match(&render_view_id_set_,
render_process_id,
render_routing_id);
}
bool CefBrowserInfo::RenderIDManager::is_render_frame_id_match(
int render_process_id, int render_routing_id) {
int render_process_id, int render_routing_id) const {
return is_render_id_match(&render_frame_id_set_,
render_process_id,
render_routing_id);
@ -87,7 +88,7 @@ void CefBrowserInfo::RenderIDManager::remove_render_id(RenderIdSet* id_set,
bool CefBrowserInfo::RenderIDManager::is_render_id_match(
const RenderIdSet* id_set,
int render_process_id,
int render_routing_id) {
int render_routing_id) const {
base::AutoLock lock_scope(*lock_);
if (id_set->empty())
@ -117,7 +118,7 @@ void CefBrowserInfo::set_windowless(bool windowless) {
is_windowless_ = windowless;
}
CefRefPtr<CefBrowserHostImpl> CefBrowserInfo::browser() {
CefRefPtr<CefBrowserHostImpl> CefBrowserInfo::browser() const {
base::AutoLock lock_scope(lock_);
return browser_;
}

View File

@ -36,8 +36,10 @@ class CefBrowserInfo : public base::RefCountedThreadSafe<CefBrowserInfo> {
void remove_render_frame_id(int render_process_id, int render_routing_id);
// Returns true if this browser matches the specified ID pair.
bool is_render_view_id_match(int render_process_id, int render_routing_id);
bool is_render_frame_id_match(int render_process_id, int render_routing_id);
bool is_render_view_id_match(int render_process_id,
int render_routing_id) const;
bool is_render_frame_id_match(int render_process_id,
int render_routing_id)const ;
private:
typedef std::set<std::pair<int, int> > RenderIdSet;
@ -50,9 +52,9 @@ class CefBrowserInfo : public base::RefCountedThreadSafe<CefBrowserInfo> {
int render_routing_id);
bool is_render_id_match(const RenderIdSet* id_set,
int render_process_id,
int render_routing_id);
int render_routing_id) const;
base::Lock* lock_;
mutable base::Lock* lock_;
// The below members must be protected by |lock_|.
@ -88,7 +90,7 @@ class CefBrowserInfo : public base::RefCountedThreadSafe<CefBrowserInfo> {
return &guest_render_id_manager_;
}
CefRefPtr<CefBrowserHostImpl> browser();
CefRefPtr<CefBrowserHostImpl> browser() const;
void set_browser(CefRefPtr<CefBrowserHostImpl> browser);
private:
@ -100,7 +102,7 @@ class CefBrowserInfo : public base::RefCountedThreadSafe<CefBrowserInfo> {
bool is_popup_;
bool is_windowless_;
base::Lock lock_;
mutable base::Lock lock_;
// The below members must be protected by |lock_|.

View File

@ -0,0 +1,556 @@
// Copyright 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 "libcef/browser/browser_info_manager.h"
#include "libcef/browser/browser_platform_delegate.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/cef_messages.h"
#include "libcef/common/extensions/extensions_util.h"
#include "libcef/browser/extensions/browser_extensions_util.h"
#include "base/logging.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/common/view_messages.h"
namespace {
void TranslatePopupFeatures(const blink::WebWindowFeatures& webKitFeatures,
CefPopupFeatures& features) {
features.x = static_cast<int>(webKitFeatures.x);
features.xSet = webKitFeatures.xSet;
features.y = static_cast<int>(webKitFeatures.y);
features.ySet = webKitFeatures.ySet;
features.width = static_cast<int>(webKitFeatures.width);
features.widthSet = webKitFeatures.widthSet;
features.height = static_cast<int>(webKitFeatures.height);
features.heightSet = webKitFeatures.heightSet;
features.menuBarVisible = webKitFeatures.menuBarVisible;
features.statusBarVisible = webKitFeatures.statusBarVisible;
features.toolBarVisible = webKitFeatures.toolBarVisible;
features.locationBarVisible = webKitFeatures.locationBarVisible;
features.scrollbarsVisible = webKitFeatures.scrollbarsVisible;
features.resizable = webKitFeatures.resizable;
features.fullscreen = webKitFeatures.fullscreen;
features.dialog = webKitFeatures.dialog;
features.additionalFeatures = NULL;
if (webKitFeatures.additionalFeatures.size() > 0)
features.additionalFeatures = cef_string_list_alloc();
CefString str;
for (unsigned int i = 0; i < webKitFeatures.additionalFeatures.size(); ++i) {
str = base::string16(webKitFeatures.additionalFeatures[i]);
cef_string_list_append(features.additionalFeatures, str.GetStruct());
}
}
CefBrowserInfoManager* g_info_manager = nullptr;
} // namespace
CefBrowserInfoManager::CefBrowserInfoManager()
: next_browser_id_(0) {
DCHECK(!g_info_manager);
g_info_manager = this;
}
CefBrowserInfoManager::~CefBrowserInfoManager() {
DCHECK(browser_info_list_.empty());
g_info_manager = nullptr;
}
// static
CefBrowserInfoManager* CefBrowserInfoManager::GetInstance() {
return g_info_manager;
}
scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::CreateBrowserInfo(
bool is_popup,
bool is_windowless) {
base::AutoLock lock_scope(browser_info_lock_);
scoped_refptr<CefBrowserInfo> browser_info =
new CefBrowserInfo(++next_browser_id_, is_popup);
browser_info_list_.push_back(browser_info);
if (is_windowless)
browser_info->set_windowless(true);
return browser_info;
}
scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::CreatePopupBrowserInfo(
content::WebContents* new_contents,
bool is_windowless) {
base::AutoLock lock_scope(browser_info_lock_);
content::RenderViewHost* view_host = new_contents->GetRenderViewHost();
content::RenderFrameHost* main_frame_host = new_contents->GetMainFrame();
content::RenderProcessHost* host = view_host->GetProcess();
// The host processes may be different in the future with OOP iframes. When
// that happens re-visit the implementation of this class.
DCHECK_EQ(host, main_frame_host->GetProcess());
const int render_process_routing_id = host->GetID();
const int render_view_routing_id = view_host->GetRoutingID();
const int render_frame_routing_id = main_frame_host->GetRoutingID();
scoped_refptr<CefBrowserInfo> browser_info =
new CefBrowserInfo(++next_browser_id_, true);
browser_info->render_id_manager()->add_render_view_id(
render_process_routing_id, render_view_routing_id);
browser_info->render_id_manager()->add_render_frame_id(
render_process_routing_id, render_frame_routing_id);
browser_info_list_.push_back(browser_info);
if (is_windowless)
browser_info->set_windowless(true);
// Continue any pending NewBrowserInfo requests.
PendingNewBrowserInfoList::iterator it =
pending_new_browser_info_list_.begin();
for (; it != pending_new_browser_info_list_.end(); ++it) {
PendingNewBrowserInfo* info = *it;
if (info->host == host &&
info->render_view_routing_id == render_view_routing_id &&
info->render_frame_routing_id == render_frame_routing_id) {
SendNewBrowserInfoResponse(host, browser_info.get(), false,
info->reply_msg);
pending_new_browser_info_list_.erase(it);
break;
}
}
return browser_info;
}
void CefBrowserInfoManager::OnCreateWindow(
content::RenderProcessHost* host,
const ViewHostMsg_CreateWindow_Params& params) {
DCHECK_GT(params.opener_id, 0);
DCHECK_GT(params.opener_render_frame_id, 0);
DCHECK(!params.target_url.is_empty());
scoped_ptr<CefBrowserInfoManager::PendingPopup> pending_popup(
new CefBrowserInfoManager::PendingPopup);
pending_popup->step = CefBrowserInfoManager::PendingPopup::ON_CREATE_WINDOW;
pending_popup->opener_process_id = host->GetID();
pending_popup->opener_view_id = params.opener_id;
pending_popup->opener_frame_id = params.opener_render_frame_id;
pending_popup->target_url = params.target_url;
pending_popup->target_frame_name = params.frame_name;
PushPendingPopup(pending_popup.Pass());
}
bool CefBrowserInfoManager::CanCreateWindow(
const GURL& target_url,
const content::Referrer& referrer,
WindowOpenDisposition disposition,
const blink::WebWindowFeatures& features,
bool user_gesture,
bool opener_suppressed,
int render_process_id,
int opener_render_view_id,
int opener_render_frame_id,
bool* no_javascript_access) {
scoped_ptr<CefBrowserInfoManager::PendingPopup> pending_popup =
PopPendingPopup(CefBrowserInfoManager::PendingPopup::ON_CREATE_WINDOW,
render_process_id, opener_render_view_id, target_url);
DCHECK(pending_popup.get());
DCHECK(!pending_popup->platform_delegate.get());
bool is_guest_view = false;
CefRefPtr<CefBrowserHostImpl> browser =
extensions::GetOwnerBrowserForView(
pending_popup->opener_process_id,
pending_popup->opener_view_id,
&is_guest_view);
DCHECK(browser.get());
if (!browser.get()) {
// Cancel the popup.
return false;
}
if (is_guest_view) {
content::OpenURLParams params(target_url,
referrer,
disposition,
ui::PAGE_TRANSITION_LINK,
true);
params.user_gesture = user_gesture;
// Pass navigation to the owner browser.
CEF_POST_TASK(CEF_UIT,
base::Bind(base::IgnoreResult(&CefBrowserHostImpl::OpenURLFromTab),
browser.get(), nullptr, params));
// Cancel the popup.
return false;
}
CefRefPtr<CefClient> client = browser->GetClient();
bool allow = true;
#if defined(OS_WIN)
pending_popup->window_info.SetAsPopup(NULL, CefString());
#endif
// Start with the current browser's settings.
pending_popup->client = client;
pending_popup->settings = browser->settings();
if (client.get()) {
CefRefPtr<CefLifeSpanHandler> handler = client->GetLifeSpanHandler();
if (handler.get()) {
CefRefPtr<CefFrame> frame =
browser->GetFrame(pending_popup->opener_frame_id);
CefPopupFeatures cef_features;
TranslatePopupFeatures(features, cef_features);
#if (defined(OS_WIN) || defined(OS_MACOSX))
// Default to the size from the popup features.
if (cef_features.xSet)
pending_popup->window_info.x = cef_features.x;
if (cef_features.ySet)
pending_popup->window_info.y = cef_features.y;
if (cef_features.widthSet)
pending_popup->window_info.width = cef_features.width;
if (cef_features.heightSet)
pending_popup->window_info.height = cef_features.height;
#endif
allow = !handler->OnBeforePopup(browser.get(),
frame,
pending_popup->target_url.spec(),
pending_popup->target_frame_name,
static_cast<cef_window_open_disposition_t>(disposition),
user_gesture,
cef_features,
pending_popup->window_info,
pending_popup->client,
pending_popup->settings,
no_javascript_access);
}
}
if (allow) {
pending_popup->platform_delegate =
CefBrowserPlatformDelegate::Create(pending_popup->window_info,
pending_popup->settings,
pending_popup->client);
CHECK(pending_popup->platform_delegate.get());
pending_popup->step =
CefBrowserInfoManager::PendingPopup::CAN_CREATE_WINDOW;
// Filtering needs to be done on the UI thread.
CEF_POST_TASK(CEF_UIT,
base::Bind(FilterPendingPopupURL, render_process_id,
base::Passed(&pending_popup)));
}
return allow;
}
void CefBrowserInfoManager::ShouldCreateWebContents(
content::WebContents* web_contents,
const GURL& target_url,
content::WebContentsView** view,
content::RenderViewHostDelegateView** delegate_view) {
scoped_ptr<CefBrowserInfoManager::PendingPopup> pending_popup =
PopPendingPopup(CefBrowserInfoManager::PendingPopup::CAN_CREATE_WINDOW,
web_contents->GetRenderViewHost()->GetProcess()->GetID(),
web_contents->GetRenderViewHost()->GetRoutingID(),
target_url);
DCHECK(pending_popup.get());
DCHECK(pending_popup->platform_delegate.get());
if (pending_popup->platform_delegate->IsWindowless()) {
pending_popup->platform_delegate->CreateViewForWebContents(view,
delegate_view);
}
pending_popup->step =
CefBrowserInfoManager::PendingPopup::SHOULD_CREATE_WEB_CONTENTS;
PushPendingPopup(pending_popup.Pass());
}
void CefBrowserInfoManager::WebContentsCreated(
content::WebContents* source_contents,
const GURL& target_url,
content::WebContents* new_contents,
CefBrowserSettings& settings,
CefRefPtr<CefClient>& client,
scoped_ptr<CefBrowserPlatformDelegate>& platform_delegate) {
DCHECK(source_contents);
DCHECK(new_contents);
scoped_ptr<CefBrowserInfoManager::PendingPopup> pending_popup =
PopPendingPopup(
CefBrowserInfoManager::PendingPopup::SHOULD_CREATE_WEB_CONTENTS,
source_contents->GetRenderViewHost()->GetProcess()->GetID(),
source_contents->GetRenderViewHost()->GetRoutingID(),
target_url);
DCHECK(pending_popup.get());
DCHECK(pending_popup->platform_delegate.get());
settings = pending_popup->settings;
client = pending_popup->client;
platform_delegate = pending_popup->platform_delegate.Pass();
}
void CefBrowserInfoManager::OnGetNewBrowserInfo(
content::RenderProcessHost* host,
int render_view_routing_id,
int render_frame_routing_id,
IPC::Message* reply_msg) {
DCHECK(host);
DCHECK_GT(render_view_routing_id, 0);
DCHECK_GT(render_frame_routing_id, 0);
DCHECK(reply_msg);
base::AutoLock lock_scope(browser_info_lock_);
const int render_process_routing_id = host->GetID();
bool is_guest_view = false;
scoped_refptr<CefBrowserInfo> browser_info = GetBrowserInfo(
render_process_routing_id, render_view_routing_id,
render_process_routing_id, render_frame_routing_id,
&is_guest_view);
if (browser_info.get()) {
// Send the response immediately.
SendNewBrowserInfoResponse(host, browser_info.get(), is_guest_view,
reply_msg);
return;
}
#ifndef NDEBUG
// Verify that no request for the same route is currently queued.
{
PendingNewBrowserInfoList::const_iterator it =
pending_new_browser_info_list_.begin();
for (; it != pending_new_browser_info_list_.end(); ++it) {
PendingNewBrowserInfo* info = *it;
if (info->host == host &&
info->render_view_routing_id == render_view_routing_id &&
info->render_frame_routing_id == render_frame_routing_id) {
NOTREACHED();
}
}
}
#endif
// Queue the request.
scoped_ptr<PendingNewBrowserInfo> pending(new PendingNewBrowserInfo());
pending->host = host;
pending->render_view_routing_id = render_view_routing_id;
pending->render_frame_routing_id = render_frame_routing_id;
pending->reply_msg = reply_msg;
pending_new_browser_info_list_.push_back(pending.Pass());
}
void CefBrowserInfoManager::RemoveBrowserInfo(
scoped_refptr<CefBrowserInfo> browser_info) {
base::AutoLock lock_scope(browser_info_lock_);
BrowserInfoList::iterator it = browser_info_list_.begin();
for (; it != browser_info_list_.end(); ++it) {
if (*it == browser_info) {
browser_info_list_.erase(it);
return;
}
}
NOTREACHED();
}
void CefBrowserInfoManager::DestroyAllBrowsers() {
BrowserInfoList list;
{
base::AutoLock lock_scope(browser_info_lock_);
list = browser_info_list_;
}
// Destroy any remaining browser windows.
if (!list.empty()) {
BrowserInfoList::iterator it = list.begin();
for (; it != list.end(); ++it) {
CefRefPtr<CefBrowserHostImpl> browser = (*it)->browser();
DCHECK(browser.get());
if (browser.get()) {
// DestroyBrowser will call RemoveBrowserInfo.
browser->DestroyBrowser();
}
}
}
#ifndef NDEBUG
{
// Verify that all browser windows have been destroyed.
base::AutoLock lock_scope(browser_info_lock_);
DCHECK(browser_info_list_.empty());
}
#endif
}
scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::GetBrowserInfoForView(
int render_process_id,
int render_routing_id,
bool* is_guest_view) {
base::AutoLock lock_scope(browser_info_lock_);
return GetBrowserInfo(render_process_id, render_routing_id, 0, 0,
is_guest_view);
}
scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::GetBrowserInfoForFrame(
int render_process_id,
int render_routing_id,
bool* is_guest_view) {
base::AutoLock lock_scope(browser_info_lock_);
return GetBrowserInfo(0, 0, render_process_id, render_routing_id,
is_guest_view);
}
void CefBrowserInfoManager::RenderProcessHostDestroyed(
content::RenderProcessHost* host) {
base::AutoLock lock_scope(browser_info_lock_);
// Remove all pending requests that reference the destroyed host.
PendingNewBrowserInfoList::iterator it =
pending_new_browser_info_list_.begin();
while (it != pending_new_browser_info_list_.end()) {
PendingNewBrowserInfo* info = *it;
if (info->host == host)
it = pending_new_browser_info_list_.erase(it);
else
++it;
}
}
void CefBrowserInfoManager::FilterPendingPopupURL(
int render_process_id,
scoped_ptr<CefBrowserInfoManager::PendingPopup> pending_popup) {
content::RenderProcessHost* rph =
content::RenderProcessHost::FromID(render_process_id);
DCHECK(rph);
rph->FilterURL(false, &pending_popup->target_url);
GetInstance()->PushPendingPopup(pending_popup.Pass());
}
void CefBrowserInfoManager::PushPendingPopup(scoped_ptr<PendingPopup> popup) {
base::AutoLock lock_scope(pending_popup_lock_);
pending_popup_list_.push_back(popup.Pass());
}
scoped_ptr<CefBrowserInfoManager::PendingPopup>
CefBrowserInfoManager::PopPendingPopup(
PendingPopup::Step step,
int opener_process_id,
int opener_view_id,
const GURL& target_url) {
DCHECK_GT(opener_process_id, 0);
DCHECK_GT(opener_view_id, 0);
DCHECK(!target_url.is_empty());
base::AutoLock lock_scope(pending_popup_lock_);
PendingPopupList::iterator it = pending_popup_list_.begin();
for (; it != pending_popup_list_.end(); ++it) {
PendingPopup* popup = *it;
if (popup->step == step &&
popup->opener_process_id == opener_process_id &&
popup->opener_view_id == opener_view_id &&
popup->target_url == target_url) {
pending_popup_list_.weak_erase(it);
return make_scoped_ptr(popup);
}
}
return nullptr;
}
scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::GetBrowserInfo(
int render_view_process_id,
int render_view_routing_id,
int render_frame_process_id,
int render_frame_routing_id,
bool* is_guest_view) {
browser_info_lock_.AssertAcquired();
if (is_guest_view)
*is_guest_view = false;
const bool valid_view_ids = render_view_process_id > 0 &&
render_view_routing_id > 0;
const bool valid_frame_ids = render_frame_process_id > 0 &&
render_frame_routing_id > 0;
BrowserInfoList::const_iterator it = browser_info_list_.begin();
for (; it != browser_info_list_.end(); ++it) {
const scoped_refptr<CefBrowserInfo>& browser_info = *it;
if (valid_view_ids &&
browser_info->render_id_manager()->is_render_view_id_match(
render_view_process_id, render_view_routing_id)) {
if (valid_frame_ids) {
// Make sure the frame id is also registered.
browser_info->render_id_manager()->add_render_frame_id(
render_frame_process_id, render_frame_routing_id);
}
return browser_info;
}
if (valid_frame_ids &&
browser_info->render_id_manager()->is_render_frame_id_match(
render_frame_process_id, render_frame_routing_id)) {
if (valid_view_ids) {
// Make sure the view id is also registered.
browser_info->render_id_manager()->add_render_view_id(
render_view_process_id, render_view_routing_id);
}
return browser_info;
}
if (extensions::ExtensionsEnabled() &&
((valid_view_ids &&
browser_info->guest_render_id_manager()->is_render_view_id_match(
render_view_process_id, render_view_routing_id)) ||
(valid_frame_ids &&
browser_info->guest_render_id_manager()->is_render_frame_id_match(
render_frame_process_id, render_frame_routing_id)))) {
if (is_guest_view)
*is_guest_view = true;
return browser_info;
}
}
return nullptr;
}
// static
void CefBrowserInfoManager::SendNewBrowserInfoResponse(
content::RenderProcessHost* host,
CefBrowserInfo* browser_info,
bool is_guest_view,
IPC::Message* reply_msg) {
CefProcessHostMsg_GetNewBrowserInfo_Params params;
params.browser_id = browser_info->browser_id();
params.is_windowless = browser_info->is_windowless();
params.is_popup = browser_info->is_popup();
params.is_guest_view = is_guest_view;
CefProcessHostMsg_GetNewBrowserInfo::WriteReplyParams(reply_msg, params);
host->Send(reply_msg);
}

View File

@ -0,0 +1,239 @@
// Copyright 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_LIBCEF_BROWSER_BROWSER_INFO_MANAGER_H_
#define CEF_LIBCEF_BROWSER_BROWSER_INFO_MANAGER_H_
#pragma once
#include "include/cef_client.h"
#include <list>
#include "libcef/browser/browser_info.h"
#include "base/memory/scoped_vector.h"
#include "base/synchronization/lock.h"
#include "content/public/browser/render_process_host_observer.h"
#include "ui/base/window_open_disposition.h"
#include "url/gurl.h"
namespace blink {
struct WebWindowFeatures;
}
namespace content {
struct Referrer;
class RenderViewHostDelegateView;
class WebContents;
class WebContentsView;
}
namespace IPC {
class Message;
}
class CefBrowserPlatformDelegate;
struct ViewHostMsg_CreateWindow_Params;
// Singleton object for managing BrowserInfo instances.
class CefBrowserInfoManager : public content::RenderProcessHostObserver {
public:
CefBrowserInfoManager();
~CefBrowserInfoManager() override;
// Returns this singleton instance of this class.
static CefBrowserInfoManager* GetInstance();
// Called from CefBrowserHostImpl::Create when a new browser is being created
// directly. In this case |is_popup| will be true only for DevTools browsers.
scoped_refptr<CefBrowserInfo> CreateBrowserInfo(bool is_popup,
bool is_windowless);
// Called from CefBrowserHostImpl::WebContentsCreated when a new browser is
// being created for a traditional popup (e.g. window.open() or targeted
// link). If any OnGetNewBrowserInfo requests are pending for the popup the
// response will be sent when this method is called.
scoped_refptr<CefBrowserInfo> CreatePopupBrowserInfo(
content::WebContents* new_contents,
bool is_windowless);
// Called from CefBrowserMessageFilter::OnCreateWindow. See comments on
// PendingPopup for more information.
void OnCreateWindow(content::RenderProcessHost* host,
const ViewHostMsg_CreateWindow_Params& params);
// Called from CefContentBrowserClient::CanCreateWindow. See comments on
// PendingPopup for more information.
bool CanCreateWindow(
const GURL& target_url,
const content::Referrer& referrer,
WindowOpenDisposition disposition,
const blink::WebWindowFeatures& features,
bool user_gesture,
bool opener_suppressed,
int render_process_id,
int opener_render_view_id,
int opener_render_frame_id,
bool* no_javascript_access);
// Called from CefBrowserHostImpl::ShouldCreateWebContents. See comments on
// PendingPopup for more information.
void ShouldCreateWebContents(
content::WebContents* web_contents,
const GURL& target_url,
content::WebContentsView** view,
content::RenderViewHostDelegateView** delegate_view);
// Called from CefBrowserHostImpl::WebContentsCreated. See comments on
// PendingPopup for more information.
void WebContentsCreated(
content::WebContents* source_contents,
const GURL& target_url,
content::WebContents* new_contents,
CefBrowserSettings& settings,
CefRefPtr<CefClient>& client,
scoped_ptr<CefBrowserPlatformDelegate>& platform_delegate);
// Called from CefBrowserMessageFilter::OnGetNewBrowserInfo for delivering
// browser info to the renderer process. If the browser info already exists
// the response will be sent immediately. Otherwise, the response will be sent
// when CreatePopupBrowserInfo creates the browser info. The info will already
// exist for explicitly created browsers and guest views. It may sometimes
// already exist for traditional popup browsers depending on timing. See
// comments on PendingPopup for more information.
void OnGetNewBrowserInfo(
content::RenderProcessHost* host,
int render_view_routing_id,
int render_frame_routing_id,
IPC::Message* reply_msg);
// Called from CefBrowserHostImpl::DestroyBrowser() when a browser is
// destroyed.
void RemoveBrowserInfo(scoped_refptr<CefBrowserInfo> browser_info);
// Called from CefContext::FinishShutdownOnUIThread() to destroy all browsers.
void DestroyAllBrowsers();
// Retrieves the CefBrowserInfo matching the specified IDs or an empty
// pointer if no match is found. It is allowed to add new callers of this
// method but consider using CefBrowserHostImpl::GetBrowserFor[View|Frame]()
// or extensions::GetOwnerBrowserForView() instead.
// |is_guest_view| will be set to true if the IDs match a guest view
// associated with the returned browser info instead of the browser itself.
scoped_refptr<CefBrowserInfo> GetBrowserInfoForView(int render_process_id,
int render_routing_id,
bool* is_guest_view);
scoped_refptr<CefBrowserInfo> GetBrowserInfoForFrame(int render_process_id,
int render_routing_id,
bool* is_guest_view);
private:
// RenderProcessHostObserver methods:
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
// Store state information about pending popups. Call order is:
// - CefBrowserMessageFilter::OnCreateWindow (IOT)
// Intercepts the ViewHostMsg_CreateWindow message to gather information
// about the opener (parent browser) and target URL/frame.
// - CefContentBrowserClient::CanCreateWindow (IOT)
// Provides an opportunity to cancel the popup (calls OnBeforePopup) and
// creates the new platform delegate for the popup. If the popup owner is
// an extension guest view then the popup is canceled and
// CefBrowserHostImpl::OpenURLFromTab is called.
// And then the following calls may occur at the same time:
// - CefBrowserHostImpl::ShouldCreateWebContents (UIT)
// Creates the OSR views for windowless popups.
// - CefBrowserHostImpl::WebContentsCreated (UIT)
// Creates the CefBrowserHostImpl representation for the popup.
// - CefBrowserMessageFilter::OnGetNewBrowserInfo (IOT)
// Passes information about the popup to the renderer process.
struct PendingPopup {
// Track the last method that modified this PendingPopup instance. There may
// be multiple pending popups with the same identifiers and this allows us
// to differentiate between them at different processing steps.
enum Step {
ON_CREATE_WINDOW,
CAN_CREATE_WINDOW,
SHOULD_CREATE_WEB_CONTENTS
} step;
// Initial state from ViewHostMsg_CreateWindow.
int opener_process_id;
int opener_view_id;
int64 opener_frame_id;
GURL target_url;
std::string target_frame_name;
// Values specified by OnBeforePopup.
CefWindowInfo window_info;
CefBrowserSettings settings;
CefRefPtr<CefClient> client;
// Platform delegate specific to the new popup.
scoped_ptr<CefBrowserPlatformDelegate> platform_delegate;
};
// Between the calls to CanCreateWindow and ShouldCreateWebContents
// RenderViewHostImpl::CreateNewWindow() will call
// RenderProcessHostImpl::FilterURL() which, in the case of "javascript:"
// URIs, rewrites the URL to "about:blank". We need to apply the same filter
// otherwise ShouldCreateWebContents will fail to retrieve the PopupInfo.
static void FilterPendingPopupURL(
int render_process_id,
scoped_ptr<PendingPopup> pending_popup);
// Manage pending popups.
void PushPendingPopup(scoped_ptr<PendingPopup> popup);
scoped_ptr<PendingPopup> PopPendingPopup(
PendingPopup::Step step,
int opener_process_id,
int opener_view_id,
const GURL& target_url);
// Retrieves the BrowserInfo matching the specified IDs. If both sets are
// valid then this method makes sure both sets have been registered.
scoped_refptr<CefBrowserInfo> GetBrowserInfo(
int render_view_process_id,
int render_view_routing_id,
int render_frame_process_id,
int render_frame_routing_id,
bool* is_guest_view);
// Send the response for a pending OnGetNewBrowserInfo request.
static void SendNewBrowserInfoResponse(
content::RenderProcessHost* host,
CefBrowserInfo* browser_info,
bool is_guest_view,
IPC::Message* reply_msg);
// Pending request for OnGetNewBrowserInfo.
struct PendingNewBrowserInfo {
content::RenderProcessHost* host;
int render_view_routing_id;
int render_frame_routing_id;
IPC::Message* reply_msg;
};
mutable base::Lock browser_info_lock_;
// Access to the below members must be protected by |browser_info_lock_|.
typedef std::list<scoped_refptr<CefBrowserInfo> > BrowserInfoList;
BrowserInfoList browser_info_list_;
int next_browser_id_;
typedef ScopedVector<PendingNewBrowserInfo> PendingNewBrowserInfoList;
PendingNewBrowserInfoList pending_new_browser_info_list_;
base::Lock pending_popup_lock_;
// Access to the below members must be protected by |pending_popup_lock_|.
typedef ScopedVector<PendingPopup> PendingPopupList;
PendingPopupList pending_popup_list_;
DISALLOW_COPY_AND_ASSIGN(CefBrowserInfoManager);
};
#endif // CEF_LIBCEF_BROWSER_BROWSER_INFO_H_

View File

@ -6,7 +6,6 @@
#include <commctrl.h>
#include <Objbase.h>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/browser_main.h"
#include "chrome/common/chrome_utility_messages.h"
@ -45,9 +44,6 @@ void CefBrowserMainParts::PlatformInitialize() {
// Start COM stuff.
res = OleInitialize(NULL);
DCHECK(SUCCEEDED(res));
// Register the browser window class.
CefBrowserHostImpl::RegisterWindowClass();
}
void CefBrowserMainParts::PlatformPreMainMessageLoopRun() {

View File

@ -6,8 +6,7 @@
#include "libcef/browser/browser_message_filter.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/browser_info.h"
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/browser_info_manager.h"
#include "libcef/browser/context.h"
#include "libcef/browser/origin_whitelist_impl.h"
#include "libcef/browser/thread_util.h"
@ -55,7 +54,7 @@ bool CefBrowserMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(CefBrowserMessageFilter, message)
IPC_MESSAGE_HANDLER(CefProcessHostMsg_GetNewRenderThreadInfo,
OnGetNewRenderThreadInfo)
IPC_MESSAGE_HANDLER(CefProcessHostMsg_GetNewBrowserInfo,
IPC_MESSAGE_HANDLER_DELAY_REPLY(CefProcessHostMsg_GetNewBrowserInfo,
OnGetNewBrowserInfo)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_CreateWindow, OnCreateWindow)
IPC_MESSAGE_UNHANDLED(handled = false)
@ -87,33 +86,18 @@ void CefBrowserMessageFilter::OnGetNewRenderThreadInfo(
void CefBrowserMessageFilter::OnGetNewBrowserInfo(
int render_view_routing_id,
int render_frame_routing_id,
CefProcessHostMsg_GetNewBrowserInfo_Params* params) {
DCHECK_GT(render_view_routing_id, 0);
DCHECK_GT(render_frame_routing_id, 0);
// Popup windows may not have info yet.
scoped_refptr<CefBrowserInfo> info =
CefContentBrowserClient::Get()->GetOrCreateBrowserInfo(
host_->GetID(),
IPC::Message* reply_msg) {
CefBrowserInfoManager::GetInstance()->OnGetNewBrowserInfo(
host_,
render_view_routing_id,
host_->GetID(),
render_frame_routing_id,
&params->is_guest_view);
params->browser_id = info->browser_id();
params->is_popup = info->is_popup();
params->is_windowless = info->is_windowless();
reply_msg);
}
void CefBrowserMessageFilter::OnCreateWindow(
const ViewHostMsg_CreateWindow_Params& params,
IPC::Message* reply_msg) {
CefContentBrowserClient::LastCreateWindowParams lcwp;
lcwp.opener_process_id = host_->GetID();
lcwp.opener_view_id = params.opener_id;
lcwp.opener_frame_id = params.opener_render_frame_id;
lcwp.target_url = params.target_url;
lcwp.target_frame_name = params.frame_name;
CefContentBrowserClient::Get()->set_last_create_window_params(lcwp);
CefBrowserInfoManager::GetInstance()->OnCreateWindow(host_, params);
// Reply message is not used.
delete reply_msg;

View File

@ -38,7 +38,7 @@ class CefBrowserMessageFilter : public IPC::MessageFilter {
void OnGetNewBrowserInfo(
int render_view_routing_id,
int render_frame_routing_id,
CefProcessHostMsg_GetNewBrowserInfo_Params* params);
IPC::Message* reply_msg);
void OnCreateWindow(const ViewHostMsg_CreateWindow_Params& params,
IPC::Message* reply_msg);
void OnFrameFocused(int32 render_frame_routing_id);

View File

@ -0,0 +1,199 @@
// Copyright 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 "libcef/browser/browser_platform_delegate.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/osr/browser_platform_delegate_osr.h"
#include "base/logging.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
CefBrowserPlatformDelegate::CefBrowserPlatformDelegate()
: browser_(nullptr) {
}
CefBrowserPlatformDelegate::~CefBrowserPlatformDelegate() {
DCHECK(!browser_);
}
void CefBrowserPlatformDelegate::CreateViewForWebContents(
content::WebContentsView** view,
content::RenderViewHostDelegateView** delegate_view) {
NOTREACHED();
}
void CefBrowserPlatformDelegate::WebContentsCreated(
content::WebContents* web_contents) {
}
void CefBrowserPlatformDelegate::RenderViewCreated(
content::RenderViewHost* render_view_host) {
// Indicate that the view has an external parent (namely us). This changes the
// default view behavior in some cases (e.g. focus handling on Linux).
if (render_view_host->GetWidget()->GetView())
render_view_host->GetWidget()->GetView()->SetHasExternalParent(true);
}
void CefBrowserPlatformDelegate::BrowserCreated(CefBrowserHostImpl* browser) {
DCHECK(!browser_);
browser_ = browser;
}
void CefBrowserPlatformDelegate::BrowserDestroyed(CefBrowserHostImpl* browser) {
DCHECK(browser_ && browser_ == browser);
browser_ = nullptr;
}
bool CefBrowserPlatformDelegate::CreateHostWindow() {
NOTREACHED();
return true;
}
void CefBrowserPlatformDelegate::CloseHostWindow() {
NOTREACHED();
}
#if defined(USE_AURA)
views::Widget* CefBrowserPlatformDelegate::GetWindowWidget() const {
NOTREACHED();
return nullptr;
}
#endif
void CefBrowserPlatformDelegate::SendCaptureLostEvent() {
content::RenderWidgetHostImpl* widget =
content::RenderWidgetHostImpl::From(
browser_->web_contents()->GetRenderViewHost()->GetWidget());
if (widget)
widget->LostCapture();
}
#if defined(OS_WIN) || (defined(OS_POSIX) && !defined(OS_MACOSX))
void CefBrowserPlatformDelegate::NotifyMoveOrResizeStarted() {
// Dismiss any existing popups.
content::RenderViewHost* host = browser_->web_contents()->GetRenderViewHost();
if (host)
host->NotifyMoveOrResizeStarted();
}
void CefBrowserPlatformDelegate::SizeTo(int width, int height) {
}
#endif
#if defined(OS_MACOSX)
void CefBrowserPlatformDelegate::SetWindowVisibility(bool visible) {
content::RenderWidgetHostView* view =
browser_->web_contents()->GetRenderWidgetHostView();
if (view)
view->SetWindowVisibility(visible);
}
#endif
scoped_ptr<CefFileDialogRunner>
CefBrowserPlatformDelegate::CreateFileDialogRunner() {
return nullptr;
}
scoped_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegate::CreateJavaScriptDialogRunner() {
return nullptr;
}
void CefBrowserPlatformDelegate::WasHidden(bool hidden) {
NOTREACHED();
}
void CefBrowserPlatformDelegate::NotifyScreenInfoChanged() {
NOTREACHED();
}
void CefBrowserPlatformDelegate::Invalidate(cef_paint_element_type_t type) {
NOTREACHED();
}
void CefBrowserPlatformDelegate::SetWindowlessFrameRate(int frame_rate) {
NOTREACHED();
}
#if defined(OS_MACOSX)
CefTextInputContext CefBrowserPlatformDelegate::GetNSTextInputContext() {
NOTREACHED();
return nullptr;
}
void CefBrowserPlatformDelegate::HandleKeyEventBeforeTextInputClient(
CefEventHandle keyEvent) {
NOTREACHED();
}
void CefBrowserPlatformDelegate::HandleKeyEventAfterTextInputClient(
CefEventHandle keyEvent) {
NOTREACHED();
}
#endif
void CefBrowserPlatformDelegate::DragTargetDragEnter(
CefRefPtr<CefDragData> drag_data,
const CefMouseEvent& event,
cef_drag_operations_mask_t allowed_ops) {
NOTREACHED();
}
void CefBrowserPlatformDelegate::DragTargetDragOver(
const CefMouseEvent& event,
cef_drag_operations_mask_t allowed_ops) {
NOTREACHED();
}
void CefBrowserPlatformDelegate::DragTargetDragLeave() {
NOTREACHED();
}
void CefBrowserPlatformDelegate::DragTargetDrop(const CefMouseEvent& event) {
NOTREACHED();
}
void CefBrowserPlatformDelegate::DragSourceEndedAt(
int x, int y,
cef_drag_operations_mask_t op) {
NOTREACHED();
}
void CefBrowserPlatformDelegate::DragSourceSystemDragEnded() {
NOTREACHED();
}
// static
int CefBrowserPlatformDelegate::TranslateModifiers(uint32 cef_modifiers) {
int webkit_modifiers = 0;
// Set modifiers based on key state.
if (cef_modifiers & EVENTFLAG_SHIFT_DOWN)
webkit_modifiers |= blink::WebInputEvent::ShiftKey;
if (cef_modifiers & EVENTFLAG_CONTROL_DOWN)
webkit_modifiers |= blink::WebInputEvent::ControlKey;
if (cef_modifiers & EVENTFLAG_ALT_DOWN)
webkit_modifiers |= blink::WebInputEvent::AltKey;
if (cef_modifiers & EVENTFLAG_COMMAND_DOWN)
webkit_modifiers |= blink::WebInputEvent::MetaKey;
if (cef_modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON)
webkit_modifiers |= blink::WebInputEvent::LeftButtonDown;
if (cef_modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON)
webkit_modifiers |= blink::WebInputEvent::MiddleButtonDown;
if (cef_modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON)
webkit_modifiers |= blink::WebInputEvent::RightButtonDown;
if (cef_modifiers & EVENTFLAG_CAPS_LOCK_ON)
webkit_modifiers |= blink::WebInputEvent::CapsLockOn;
if (cef_modifiers & EVENTFLAG_NUM_LOCK_ON)
webkit_modifiers |= blink::WebInputEvent::NumLockOn;
if (cef_modifiers & EVENTFLAG_IS_LEFT)
webkit_modifiers |= blink::WebInputEvent::IsLeft;
if (cef_modifiers & EVENTFLAG_IS_RIGHT)
webkit_modifiers |= blink::WebInputEvent::IsRight;
if (cef_modifiers & EVENTFLAG_IS_KEY_PAD)
webkit_modifiers |= blink::WebInputEvent::IsKeyPad;
return webkit_modifiers;
}

View File

@ -0,0 +1,225 @@
// Copyright (c) 2015 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_BROWSER_PLATFORM_DELEGATE_H_
#define CEF_LIBCEF_BROWSER_BROWSER_PLATFORM_DELEGATE_H_
#include <string>
#include <vector>
#include "include/cef_client.h"
#include "include/cef_drag_data.h"
#include "include/internal/cef_types.h"
#include "base/callback.h"
#include "content/public/browser/web_contents.h"
namespace blink {
class WebMouseEvent;
class WebMouseWheelEvent;
class WebInputEvent;
}
namespace content {
struct NativeWebKeyboardEvent;
class RenderViewHost;
class RenderViewHostDelegateView;
class WebContentsView;
}
#if defined(USE_AURA)
namespace views {
class Widget;
}
#endif
class CefBrowserHostImpl;
class CefBrowserInfo;
class CefFileDialogRunner;
class CefJavaScriptDialogRunner;
class CefMenuRunner;
// Provides platform-specific implementations of browser functionality. All
// methods are called on the browser process UI thread unless otherwise
// indicated.
class CefBrowserPlatformDelegate {
public:
// Create a new CefBrowserPlatformDelegate instance. May be called on multiple
// threads.
static scoped_ptr<CefBrowserPlatformDelegate> Create(
const CefWindowInfo& window_info,
const CefBrowserSettings& settings,
CefRefPtr<CefClient> client);
// Called to create the view objects for a new WebContents. Will only be
// called a single time per instance. May be called on multiple threads. Only
// used with windowless rendering.
virtual void CreateViewForWebContents(
content::WebContentsView** view,
content::RenderViewHostDelegateView** delegate_view);
// Called after the WebContents for the browser is created. Will only be
// called a single time per instance.
virtual void WebContentsCreated(content::WebContents* web_contents);
// Called after the RenderViewHost is created.
virtual void RenderViewCreated(
content::RenderViewHost* render_view_host);
// Called after the owning CefBrowserHostImpl is created. Will only be called
// a single time per instance.
virtual void BrowserCreated(CefBrowserHostImpl* browser);
// Called before the owning CefBrowserHostImpl is destroyed. Will only be
// called a single time per instance. All references to the CefBrowserHostImpl
// and WebContents should be cleared when this method is called.
virtual void BrowserDestroyed(CefBrowserHostImpl* browser);
// Create the window that hosts the browser. Will only be called a single time
// per instance. Only used with windowed rendering.
virtual bool CreateHostWindow();
// Sends a message to close the window that hosts the browser. On native
// platforms this will be done via the OS. DestroyBrowser will be called after
// the native window has closed. Only used with windowed rendering.
virtual void CloseHostWindow();
// Return the OS handle for the window that hosts the browser. For windowed
// rendering this will return the most immediate parent window handle. For
// windowless rendering this will return the parent window handle specified by
// the client, which may be NULL. May be called on multiple threads.
virtual CefWindowHandle GetHostWindowHandle() const = 0;
#if defined(USE_AURA)
// Returns the Widget owner for the browser window. Only used with windowed
// rendering.
virtual views::Widget* GetWindowWidget() const;
#endif
// Notify the window that it was resized.
virtual void WasResized() = 0;
// Send input events.
virtual void SendKeyEvent(const content::NativeWebKeyboardEvent& event) = 0;
virtual void SendMouseEvent(const blink::WebMouseEvent& event) = 0;
virtual void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event) = 0;
// Send focus event. The browser's WebContents may be NULL when this method is
// called.
virtual void SendFocusEvent(bool setFocus) = 0;
// Send capture lost event.
virtual void SendCaptureLostEvent();
#if defined(OS_WIN) || (defined(OS_POSIX) && !defined(OS_MACOSX))
// The window hosting the browser is about to be moved or resized. Only used
// on Windows and Linux.
virtual void NotifyMoveOrResizeStarted();
// Resize the host window to the given dimensions. Only used with windowed
// rendering on Windows and Linux.
virtual void SizeTo(int width, int height);
#endif
#if defined(OS_MACOSX)
// Set or remove host window visibility. Only used on OS X.
virtual void SetWindowVisibility(bool visible);
#endif
// Convert from view coordinates to screen coordinates.
virtual gfx::Point GetScreenPoint(const gfx::Point& view) const = 0;
// Open the specified text in the default text editor.
virtual void ViewText(const std::string& text) = 0;
// Forward the keyboard event to the application or frame window to allow
// processing of shortcut keys.
virtual void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) = 0;
// Invoke platform specific handling for the external protocol.
virtual void HandleExternalProtocol(const GURL& url) = 0;
// Translate CEF events to Chromium/Blink events.
virtual void TranslateKeyEvent(content::NativeWebKeyboardEvent& result,
const CefKeyEvent& key_event) const = 0;
virtual void TranslateClickEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
CefBrowserHost::MouseButtonType type,
bool mouseUp, int clickCount) const = 0;
virtual void TranslateMoveEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) const = 0;
virtual void TranslateWheelEvent(blink::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX, int deltaY) const = 0;
// Returns the OS event handle, if any, associated with |event|.
virtual CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const = 0;
// Create the platform-specific file dialog runner.
virtual scoped_ptr<CefFileDialogRunner> CreateFileDialogRunner();
// Create the platform-specific JavaScript dialog runner.
virtual scoped_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner();
// Create the platform-specific menu runner.
virtual scoped_ptr<CefMenuRunner> CreateMenuRunner() = 0;
// Returns true if this delegate implements windowless rendering. May be
// called on multiple threads.
virtual bool IsWindowless() const = 0;
// Notify the browser that it was hidden. Only used with windowless rendering.
virtual void WasHidden(bool hidden);
// Notify the browser that screen information has changed. Only used with
// windowless rendering.
virtual void NotifyScreenInfoChanged();
// Invalidate the view. Only used with windowless rendering.
virtual void Invalidate(cef_paint_element_type_t type);
// Set the windowless frame rate. Only used with windowless rendering.
virtual void SetWindowlessFrameRate(int frame_rate);
#if defined(OS_MACOSX)
// IME-related callbacks. See documentation in CefRenderHandler. Only used
// with windowless rendering on OS X.
virtual CefTextInputContext GetNSTextInputContext();
virtual void HandleKeyEventBeforeTextInputClient(CefEventHandle keyEvent);
virtual void HandleKeyEventAfterTextInputClient(CefEventHandle keyEvent);
#endif
// Drag/drop-related callbacks. See documentation in CefRenderHandler. Only
// used with windowless rendering.
virtual void DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,
const CefMouseEvent& event,
cef_drag_operations_mask_t allowed_ops);
virtual void DragTargetDragOver(const CefMouseEvent& event,
cef_drag_operations_mask_t allowed_ops);
virtual void DragTargetDragLeave();
virtual void DragTargetDrop(const CefMouseEvent& event);
virtual void DragSourceEndedAt(int x, int y,
cef_drag_operations_mask_t op);
virtual void DragSourceSystemDragEnded();
protected:
// Allow deletion via scoped_ptr only.
friend struct base::DefaultDeleter<CefBrowserPlatformDelegate>;
CefBrowserPlatformDelegate();
virtual ~CefBrowserPlatformDelegate();
static int TranslateModifiers(uint32 cef_modifiers);
CefBrowserHostImpl *browser_; // Not owned by this object.
private:
DISALLOW_COPY_AND_ASSIGN(CefBrowserPlatformDelegate);
};
#endif // CEF_LIBCEF_BROWSER_BROWSER_PLATFORM_DELEGATE_H_

View File

@ -0,0 +1,62 @@
// Copyright 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 "libcef/browser/browser_platform_delegate.h"
#if defined(OS_WIN)
#include "libcef/browser/native/browser_platform_delegate_native_win.h"
#include "libcef/browser/osr/browser_platform_delegate_osr_win.h"
#elif defined(OS_MACOSX)
#include "libcef/browser/native/browser_platform_delegate_native_mac.h"
#include "libcef/browser/osr/browser_platform_delegate_osr_mac.h"
#elif defined(OS_LINUX)
#include "libcef/browser/native/browser_platform_delegate_native_linux.h"
#include "libcef/browser/osr/browser_platform_delegate_osr_linux.h"
#else
#error A delegate implementation is not available for your platform.
#endif
namespace {
scoped_ptr<CefBrowserPlatformDelegateNative> CreateNativeDelegate(
const CefWindowInfo& window_info) {
#if defined(OS_WIN)
return make_scoped_ptr(new CefBrowserPlatformDelegateNativeWin(window_info));
#elif defined(OS_MACOSX)
return make_scoped_ptr(new CefBrowserPlatformDelegateNativeMac(window_info));
#elif defined(OS_LINUX)
return make_scoped_ptr(
new CefBrowserPlatformDelegateNativeLinux(window_info));
#endif
}
scoped_ptr<CefBrowserPlatformDelegateOsr> CreateOSRDelegate(
scoped_ptr<CefBrowserPlatformDelegateNative> native_delegate) {
#if defined(OS_WIN)
return make_scoped_ptr(
new CefBrowserPlatformDelegateOsrWin(native_delegate.Pass()));
#elif defined(OS_MACOSX)
return make_scoped_ptr(
new CefBrowserPlatformDelegateOsrMac(native_delegate.Pass()));
#elif defined(OS_LINUX)
return make_scoped_ptr(
new CefBrowserPlatformDelegateOsrLinux(native_delegate.Pass()));
#endif
}
} // namespace
// static
scoped_ptr<CefBrowserPlatformDelegate> CefBrowserPlatformDelegate::Create(
const CefWindowInfo& window_info,
const CefBrowserSettings& settings,
CefRefPtr<CefClient> client) {
scoped_ptr<CefBrowserPlatformDelegateNative> native_delegate =
CreateNativeDelegate(window_info);
if (window_info.windowless_rendering_enabled &&
client->GetRenderHandler().get()) {
return CreateOSRDelegate(native_delegate.Pass());
}
return native_delegate.Pass();
}

View File

@ -7,13 +7,14 @@
#include <algorithm>
#include "libcef/browser/browser_info.h"
#include "libcef/browser/browser_info_manager.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/browser_main.h"
#include "libcef/browser/browser_message_filter.h"
#include "libcef/browser/browser_platform_delegate.h"
#include "libcef/browser/chrome_scheme_handler.h"
#include "libcef/browser/context.h"
#include "libcef/browser/devtools_delegate.h"
#include "libcef/browser/extensions/browser_extensions_util.h"
#include "libcef/browser/extensions/extension_system.h"
#include "libcef/browser/media_capture_devices_dispatcher.h"
#include "libcef/browser/pepper/browser_pepper_host_factory.h"
@ -277,37 +278,6 @@ class CefQuotaPermissionContext : public content::QuotaPermissionContext {
DISALLOW_COPY_AND_ASSIGN(CefQuotaPermissionContext);
};
void TranslatePopupFeatures(const blink::WebWindowFeatures& webKitFeatures,
CefPopupFeatures& features) {
features.x = static_cast<int>(webKitFeatures.x);
features.xSet = webKitFeatures.xSet;
features.y = static_cast<int>(webKitFeatures.y);
features.ySet = webKitFeatures.ySet;
features.width = static_cast<int>(webKitFeatures.width);
features.widthSet = webKitFeatures.widthSet;
features.height = static_cast<int>(webKitFeatures.height);
features.heightSet = webKitFeatures.heightSet;
features.menuBarVisible = webKitFeatures.menuBarVisible;
features.statusBarVisible = webKitFeatures.statusBarVisible;
features.toolBarVisible = webKitFeatures.toolBarVisible;
features.locationBarVisible = webKitFeatures.locationBarVisible;
features.scrollbarsVisible = webKitFeatures.scrollbarsVisible;
features.resizable = webKitFeatures.resizable;
features.fullscreen = webKitFeatures.fullscreen;
features.dialog = webKitFeatures.dialog;
features.additionalFeatures = NULL;
if (webKitFeatures.additionalFeatures.size() > 0)
features.additionalFeatures = cef_string_list_alloc();
CefString str;
for (unsigned int i = 0; i < webKitFeatures.additionalFeatures.size(); ++i) {
str = base::string16(webKitFeatures.additionalFeatures[i]);
cef_string_list_append(features.additionalFeatures, str.GetStruct());
}
}
#if defined(OS_POSIX) && !defined(OS_MACOSX)
breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
const std::string& process_type) {
@ -436,13 +406,10 @@ void FindFrameHostForNavigationHandle(
CefContentBrowserClient::CefContentBrowserClient()
: browser_main_parts_(NULL),
next_browser_id_(0) {
: browser_main_parts_(NULL) {
plugin_service_filter_.reset(new CefPluginServiceFilter);
content::PluginServiceImpl::GetInstance()->SetFilter(
plugin_service_filter_.get());
last_create_window_params_.opener_process_id = MSG_ROUTING_NONE;
}
CefContentBrowserClient::~CefContentBrowserClient() {
@ -454,178 +421,6 @@ CefContentBrowserClient* CefContentBrowserClient::Get() {
CefContentClient::Get()->browser());
}
scoped_refptr<CefBrowserInfo> CefContentBrowserClient::CreateBrowserInfo(
bool is_popup) {
base::AutoLock lock_scope(browser_info_lock_);
scoped_refptr<CefBrowserInfo> browser_info =
new CefBrowserInfo(++next_browser_id_, is_popup);
browser_info_list_.push_back(browser_info);
return browser_info;
}
scoped_refptr<CefBrowserInfo>
CefContentBrowserClient::GetOrCreateBrowserInfo(
int render_view_process_id,
int render_view_routing_id,
int render_frame_process_id,
int render_frame_routing_id,
bool* is_guest_view) {
base::AutoLock lock_scope(browser_info_lock_);
if (is_guest_view)
*is_guest_view = false;
BrowserInfoList::const_iterator it = browser_info_list_.begin();
for (; it != browser_info_list_.end(); ++it) {
const scoped_refptr<CefBrowserInfo>& browser_info = *it;
if (browser_info->render_id_manager()->is_render_view_id_match(
render_view_process_id, render_view_routing_id)) {
// Make sure the frame id is also registered.
browser_info->render_id_manager()->add_render_frame_id(
render_frame_process_id, render_frame_routing_id);
return browser_info;
}
if (browser_info->render_id_manager()->is_render_frame_id_match(
render_frame_process_id, render_frame_routing_id)) {
// Make sure the view id is also registered.
browser_info->render_id_manager()->add_render_view_id(
render_view_process_id, render_view_routing_id);
return browser_info;
}
if (extensions::ExtensionsEnabled() &&
(browser_info->guest_render_id_manager()->is_render_view_id_match(
render_view_process_id, render_view_routing_id) ||
browser_info->guest_render_id_manager()->is_render_frame_id_match(
render_frame_process_id, render_frame_routing_id))) {
if (is_guest_view)
*is_guest_view = true;
return browser_info;
}
}
// Must be a popup if it hasn't already been created.
scoped_refptr<CefBrowserInfo> browser_info =
new CefBrowserInfo(++next_browser_id_, true);
browser_info->render_id_manager()->add_render_view_id(
render_view_process_id, render_view_routing_id);
browser_info->render_id_manager()->add_render_frame_id(
render_frame_process_id, render_frame_routing_id);
browser_info_list_.push_back(browser_info);
return browser_info;
}
void CefContentBrowserClient::RemoveBrowserInfo(
scoped_refptr<CefBrowserInfo> browser_info) {
base::AutoLock lock_scope(browser_info_lock_);
BrowserInfoList::iterator it = browser_info_list_.begin();
for (; it != browser_info_list_.end(); ++it) {
if (*it == browser_info) {
browser_info_list_.erase(it);
return;
}
}
NOTREACHED();
}
void CefContentBrowserClient::DestroyAllBrowsers() {
BrowserInfoList list;
{
base::AutoLock lock_scope(browser_info_lock_);
list = browser_info_list_;
}
// Destroy any remaining browser windows.
if (!list.empty()) {
BrowserInfoList::iterator it = list.begin();
for (; it != list.end(); ++it) {
CefRefPtr<CefBrowserHostImpl> browser = (*it)->browser();
if (browser.get()) {
// DestroyBrowser will call RemoveBrowserInfo.
browser->DestroyBrowser();
} else {
// Canceled popup windows may have browser info but no browser because
// CefBrowserMessageFilter::OnGetNewBrowserInfo is still called.
DCHECK((*it)->is_popup());
RemoveBrowserInfo(*it);
}
}
}
#ifndef NDEBUG
{
// Verify that all browser windows have been destroyed.
base::AutoLock lock_scope(browser_info_lock_);
DCHECK(browser_info_list_.empty());
}
#endif
}
scoped_refptr<CefBrowserInfo> CefContentBrowserClient::GetBrowserInfoForView(
int render_process_id,
int render_routing_id,
bool* is_guest_view) {
base::AutoLock lock_scope(browser_info_lock_);
if (is_guest_view)
*is_guest_view = false;
BrowserInfoList::const_iterator it = browser_info_list_.begin();
for (; it != browser_info_list_.end(); ++it) {
const scoped_refptr<CefBrowserInfo>& browser_info = *it;
if (browser_info->render_id_manager()->is_render_view_id_match(
render_process_id, render_routing_id)) {
return browser_info;
}
if (extensions::ExtensionsEnabled() &&
browser_info->guest_render_id_manager()->is_render_view_id_match(
render_process_id, render_routing_id)) {
if (is_guest_view)
*is_guest_view = true;
return browser_info;
}
}
LOG(WARNING) << "No browser info matching view process id " <<
render_process_id << " and routing id " << render_routing_id;
return scoped_refptr<CefBrowserInfo>();
}
scoped_refptr<CefBrowserInfo> CefContentBrowserClient::GetBrowserInfoForFrame(
int render_process_id,
int render_routing_id,
bool* is_guest_view) {
base::AutoLock lock_scope(browser_info_lock_);
if (is_guest_view)
*is_guest_view = false;
BrowserInfoList::const_iterator it = browser_info_list_.begin();
for (; it != browser_info_list_.end(); ++it) {
const scoped_refptr<CefBrowserInfo>& browser_info = *it;
if (browser_info->render_id_manager()->is_render_frame_id_match(
render_process_id, render_routing_id)) {
return browser_info;
}
if (extensions::ExtensionsEnabled() &&
browser_info->guest_render_id_manager()->is_render_frame_id_match(
render_process_id, render_routing_id)) {
if (is_guest_view)
*is_guest_view = true;
return browser_info;
}
}
LOG(WARNING) << "No browser info matching frame process id " <<
render_process_id << " and routing id " << render_routing_id;
return scoped_refptr<CefBrowserInfo>();
}
content::BrowserMainParts* CefContentBrowserClient::CreateBrowserMainParts(
const content::MainFunctionParams& parameters) {
browser_main_parts_ = new CefBrowserMainParts(parameters);
@ -662,6 +457,8 @@ void CefContentBrowserClient::RenderProcessWillLaunch(
new extensions::ExtensionsGuestViewMessageFilter(id, browser_context));
}
host->AddObserver(CefBrowserInfoManager::GetInstance());
host->Send(new CefProcessMsg_SetIsIncognitoProcess(
browser_context->IsOffTheRecord()));
}
@ -959,102 +756,10 @@ bool CefContentBrowserClient::CanCreateWindow(
CEF_REQUIRE_IOT();
*no_javascript_access = false;
DCHECK_NE(last_create_window_params_.opener_process_id, MSG_ROUTING_NONE);
if (last_create_window_params_.opener_process_id == MSG_ROUTING_NONE)
return false;
bool is_guest_view = false;
CefRefPtr<CefBrowserHostImpl> browser =
extensions::GetOwnerBrowserForView(
last_create_window_params_.opener_process_id,
last_create_window_params_.opener_view_id,
&is_guest_view);
DCHECK(browser.get());
if (!browser.get()) {
// Cancel the popup.
last_create_window_params_.opener_process_id = MSG_ROUTING_NONE;
return false;
}
if (is_guest_view) {
content::OpenURLParams params(target_url,
referrer,
disposition,
ui::PAGE_TRANSITION_LINK,
true);
params.user_gesture = user_gesture;
// Pass navigation to the owner browser.
CEF_POST_TASK(CEF_UIT,
base::Bind(base::IgnoreResult(&CefBrowserHostImpl::OpenURLFromTab),
browser.get(), nullptr, params));
// Cancel the popup.
last_create_window_params_.opener_process_id = MSG_ROUTING_NONE;
return false;
}
CefRefPtr<CefClient> client = browser->GetClient();
bool allow = true;
scoped_ptr<CefBrowserHostImpl::PendingPopupInfo> pending_info;
pending_info.reset(new CefBrowserHostImpl::PendingPopupInfo);
#if defined(OS_WIN)
pending_info->window_info.SetAsPopup(NULL, CefString());
#endif
// Start with the current browser's settings.
pending_info->client = client;
pending_info->settings = browser->settings();
if (client.get()) {
CefRefPtr<CefLifeSpanHandler> handler = client->GetLifeSpanHandler();
if (handler.get()) {
CefRefPtr<CefFrame> frame =
browser->GetFrame(last_create_window_params_.opener_frame_id);
CefPopupFeatures cef_features;
TranslatePopupFeatures(features, cef_features);
#if (defined(OS_WIN) || defined(OS_MACOSX))
// Default to the size from the popup features.
if (cef_features.xSet)
pending_info->window_info.x = cef_features.x;
if (cef_features.ySet)
pending_info->window_info.y = cef_features.y;
if (cef_features.widthSet)
pending_info->window_info.width = cef_features.width;
if (cef_features.heightSet)
pending_info->window_info.height = cef_features.height;
#endif
allow = !handler->OnBeforePopup(browser.get(),
frame,
last_create_window_params_.target_url.spec(),
last_create_window_params_.target_frame_name,
static_cast<cef_window_open_disposition_t>(disposition),
user_gesture,
cef_features,
pending_info->window_info,
pending_info->client,
pending_info->settings,
no_javascript_access);
}
}
if (allow) {
CefRefPtr<CefClient> pending_client = pending_info->client;
allow = browser->SetPendingPopupInfo(pending_info.Pass());
if (!allow) {
LOG(WARNING) << "Creation of popup window denied because one is already "
"pending.";
}
}
last_create_window_params_.opener_process_id = MSG_ROUTING_NONE;
return allow;
return CefBrowserInfoManager::GetInstance()->CanCreateWindow(
target_url, referrer, disposition, features, user_gesture,
opener_suppressed, render_process_id, opener_render_view_id,
opener_render_frame_id, no_javascript_access);
}
void CefContentBrowserClient::ResourceDispatcherHostCreated() {
@ -1198,12 +903,6 @@ void CefContentBrowserClient::RegisterCustomScheme(const std::string& scheme) {
policy->RegisterWebSafeScheme(scheme);
}
void CefContentBrowserClient::set_last_create_window_params(
const LastCreateWindowParams& params) {
CEF_REQUIRE_IOT();
last_create_window_params_ = params;
}
scoped_refptr<CefBrowserContextImpl>
CefContentBrowserClient::browser_context() const {
return browser_main_parts_->browser_context();

View File

@ -6,9 +6,6 @@
#define CEF_LIBCEF_BROWSER_CONTENT_BROWSER_CLIENT_H_
#pragma once
#include <list>
#include <map>
#include <set>
#include <string>
#include <utility>
@ -19,13 +16,9 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "content/public/browser/content_browser_client.h"
#include "third_party/skia/include/core/SkColor.h"
#include "url/gurl.h"
class CefBrowserHostImpl;
class CefBrowserInfo;
class CefBrowserMainParts;
class CefDevToolsDelegate;
class CefResourceDispatcherHostDelegate;
@ -43,38 +36,6 @@ class CefContentBrowserClient : public content::ContentBrowserClient {
// Returns the singleton CefContentBrowserClient instance.
static CefContentBrowserClient* Get();
// Methods for managing CefBrowserInfo life span. Do not add new callers of
// these methods.
// During popup window creation there is a race between the call to
// CefBrowserMessageFilter::OnGetNewBrowserInfo on the IO thread and the call
// to CefBrowserHostImpl::ShouldCreateWebContents on the UI thread. To resolve
// this race CefBrowserInfo may be created when requested for the first time
// and before the associated CefBrowserHostImpl is created.
// |is_guest_view| will be set to true if the IDs match a guest view
// associated with the returned browser info instead of the browser itself.
scoped_refptr<CefBrowserInfo> CreateBrowserInfo(bool is_popup);
scoped_refptr<CefBrowserInfo> GetOrCreateBrowserInfo(
int render_view_process_id,
int render_view_routing_id,
int render_frame_process_id,
int render_frame_routing_id,
bool* is_guest_view);
void RemoveBrowserInfo(scoped_refptr<CefBrowserInfo> browser_info);
void DestroyAllBrowsers();
// Retrieves the CefBrowserInfo matching the specified IDs or an empty
// pointer if no match is found. It is allowed to add new callers of this
// method but consider using CefBrowserHostImpl::GetBrowserFor[View|Frame]()
// or extensions::GetOwnerBrowserForView() instead.
// |is_guest_view| will be set to true if the IDs match a guest view
// associated with the returned browser info instead of the browser itself.
scoped_refptr<CefBrowserInfo> GetBrowserInfoForView(int render_process_id,
int render_routing_id,
bool* is_guest_view);
scoped_refptr<CefBrowserInfo> GetBrowserInfoForFrame(int render_process_id,
int render_routing_id,
bool* is_guest_view);
// ContentBrowserClient implementation.
content::BrowserMainParts* CreateBrowserMainParts(
const content::MainFunctionParams& parameters) override;
@ -162,17 +123,6 @@ class CefContentBrowserClient : public content::ContentBrowserClient {
// Perform browser process registration for the custom scheme.
void RegisterCustomScheme(const std::string& scheme);
// Store additional state from the ViewHostMsg_CreateWindow message that will
// be used when CanCreateWindow() is called.
struct LastCreateWindowParams {
int opener_process_id;
int opener_view_id;
int64 opener_frame_id;
GURL target_url;
std::string target_frame_name;
};
void set_last_create_window_params(const LastCreateWindowParams& params);
scoped_refptr<CefBrowserContextImpl> browser_context() const;
CefDevToolsDelegate* devtools_delegate() const;
@ -182,16 +132,6 @@ class CefContentBrowserClient : public content::ContentBrowserClient {
scoped_ptr<content::PluginServiceFilter> plugin_service_filter_;
scoped_ptr<CefResourceDispatcherHostDelegate>
resource_dispatcher_host_delegate_;
base::Lock browser_info_lock_;
// Access must be protected by |browser_info_lock_|.
typedef std::list<scoped_refptr<CefBrowserInfo> > BrowserInfoList;
BrowserInfoList browser_info_list_;
int next_browser_id_;
// Only accessed on the IO thread.
LastCreateWindowParams last_create_window_params_;
};
#endif // CEF_LIBCEF_BROWSER_CONTENT_BROWSER_CLIENT_H_

View File

@ -6,6 +6,7 @@
#include "libcef/browser/browser_context.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/browser_info.h"
#include "libcef/browser/browser_info_manager.h"
#include "libcef/browser/browser_main.h"
#include "libcef/browser/browser_message_loop.h"
#include "libcef/browser/chrome_browser_process_stub.h"
@ -246,6 +247,7 @@ bool CefContext::Initialize(const CefMainArgs& args,
main_delegate_.reset(new CefMainDelegate(application));
main_runner_.reset(content::ContentMainRunner::Create());
browser_info_manager_.reset(new CefBrowserInfoManager);
int exit_code;
@ -415,7 +417,7 @@ void CefContext::FinishShutdownOnUIThread(
print_job_manager_->Shutdown();
print_job_manager_.reset(NULL);
CefContentBrowserClient::Get()->DestroyAllBrowsers();
browser_info_manager_->DestroyAllBrowsers();
if (trace_subscriber_.get())
trace_subscriber_.reset(NULL);
@ -436,6 +438,7 @@ void CefContext::FinalizeShutdown() {
// Shut down the content runner.
main_runner_->Shutdown();
browser_info_manager_.reset(NULL);
main_runner_.reset(NULL);
main_delegate_.reset(NULL);
}

View File

@ -32,6 +32,7 @@ class PrintJobManager;
}
class CefBrowserHostImpl;
class CefBrowserInfoManager;
class CefMainDelegate;
class CefTraceSubscriber;
@ -97,6 +98,7 @@ class CefContext {
scoped_ptr<CefMainDelegate> main_delegate_;
scoped_ptr<content::ContentMainRunner> main_runner_;
scoped_ptr<CefTraceSubscriber> trace_subscriber_;
scoped_ptr<CefBrowserInfoManager> browser_info_manager_;
// Only accessed on the UI Thread.
scoped_ptr<printing::PrintJobManager> print_job_manager_;

View File

@ -109,11 +109,10 @@ CefDevToolsFrontend* CefDevToolsFrontend::Show(
CefRefPtr<CefBrowserHostImpl> frontend_browser =
CefBrowserHostImpl::Create(windowInfo, client, CefString(),
new_settings,
inspected_browser->GetWindowHandle(), true,
inspected_browser, true,
inspected_browser->GetRequestContext());
content::WebContents* inspected_contents =
inspected_browser->GetWebContents();
content::WebContents* inspected_contents = inspected_browser->web_contents();
if (!inspect_element_at.IsEmpty()) {
scoped_refptr<content::DevToolsAgentHost> agent_host =
content::DevToolsAgentHost::GetOrCreateFor(inspected_contents);
@ -166,7 +165,7 @@ void CefDevToolsFrontend::DisconnectFromTarget() {
CefDevToolsFrontend::CefDevToolsFrontend(
CefRefPtr<CefBrowserHostImpl> frontend_browser,
content::WebContents* inspected_contents)
: WebContentsObserver(frontend_browser->GetWebContents()),
: WebContentsObserver(frontend_browser->web_contents()),
frontend_browser_(frontend_browser),
inspected_contents_(inspected_contents),
weak_factory_(this) {

View File

@ -142,7 +142,7 @@ class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
if (browser.get()) {
handled = true;
CefBrowserHostImpl::FileChooserParams params;
CefFileDialogRunner::FileChooserParams params;
params.mode = content::FileChooserParams::Save;
if (!suggested_path.empty()) {
params.default_file_name = suggested_path;

View File

@ -4,7 +4,7 @@
#include "libcef/browser/extensions/browser_extensions_util.h"
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/browser_info_manager.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/extensions/extensions_util.h"
@ -72,7 +72,7 @@ CefRefPtr<CefBrowserHostImpl> GetOwnerBrowserForView(int render_process_id,
} else {
// Use the thread-safe approach.
scoped_refptr<CefBrowserInfo> info =
CefContentBrowserClient::Get()->GetBrowserInfoForView(
CefBrowserInfoManager::GetInstance()->GetBrowserInfoForView(
render_process_id, render_routing_id, is_guest_view);
if (info.get()) {
CefRefPtr<CefBrowserHostImpl> browser = info->browser();

View File

@ -8,7 +8,7 @@
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/browser_info.h"
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/web_contents_view_osr.h"
#include "libcef/browser/osr/web_contents_view_osr.h"
#include "content/browser/browser_plugin/browser_plugin_guest.h"
#include "content/browser/web_contents/web_contents_impl.h"
@ -43,7 +43,7 @@ void CefMimeHandlerViewGuestDelegate::OverrideWebContentsCreateParams(
CefRefPtr<CefBrowserHostImpl> owner_browser = GetOwnerBrowser(guest_);
if (owner_browser->IsWindowless()) {
CefWebContentsViewOSR* view_osr = new CefWebContentsViewOSR();
CefWebContentsViewOSR* view_osr = new CefWebContentsViewOSR(false);
params->view = view_osr;
params->delegate_view = view_osr;
}

View File

@ -0,0 +1,396 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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 "libcef/browser/file_dialog_manager.h"
#include "include/cef_dialog_handler.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/thread_util.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/common/file_chooser_file_info.h"
#include "net/base/directory_lister.h"
namespace {
class CefFileDialogCallbackImpl : public CefFileDialogCallback {
public:
explicit CefFileDialogCallbackImpl(
const CefFileDialogRunner::RunFileChooserCallback& callback)
: callback_(callback) {
}
~CefFileDialogCallbackImpl() override {
if (!callback_.is_null()) {
// The callback is still pending. Cancel it now.
if (CEF_CURRENTLY_ON_UIT()) {
CancelNow(callback_);
} else {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefFileDialogCallbackImpl::CancelNow, callback_));
}
}
}
void Continue(int selected_accept_filter,
const std::vector<CefString>& file_paths) override {
if (CEF_CURRENTLY_ON_UIT()) {
if (!callback_.is_null()) {
std::vector<base::FilePath> vec;
if (!file_paths.empty()) {
std::vector<CefString>::const_iterator it = file_paths.begin();
for (; it != file_paths.end(); ++it)
vec.push_back(base::FilePath(*it));
}
callback_.Run(selected_accept_filter, vec);
callback_.Reset();
}
} else {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefFileDialogCallbackImpl::Continue, this,
selected_accept_filter, file_paths));
}
}
void Cancel() override {
if (CEF_CURRENTLY_ON_UIT()) {
if (!callback_.is_null()) {
CancelNow(callback_);
callback_.Reset();
}
} else {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefFileDialogCallbackImpl::Cancel, this));
}
}
bool IsConnected() {
return !callback_.is_null();
}
void Disconnect() {
callback_.Reset();
}
private:
static void CancelNow(
const CefFileDialogRunner::RunFileChooserCallback& callback) {
CEF_REQUIRE_UIT();
std::vector<base::FilePath> file_paths;
callback.Run(0, file_paths);
}
CefFileDialogRunner::RunFileChooserCallback callback_;
IMPLEMENT_REFCOUNTING(CefFileDialogCallbackImpl);
};
void RunFileDialogDismissed(
CefRefPtr<CefRunFileDialogCallback> callback,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths) {
std::vector<CefString> paths;
if (file_paths.size() > 0) {
for (size_t i = 0; i < file_paths.size(); ++i)
paths.push_back(file_paths[i].value());
}
callback->OnFileDialogDismissed(selected_accept_filter, paths);
}
class UploadFolderHelper :
public net::DirectoryLister::DirectoryListerDelegate {
public:
explicit UploadFolderHelper(
const CefFileDialogRunner::RunFileChooserCallback& callback)
: callback_(callback) {
}
~UploadFolderHelper() override {
if (!callback_.is_null()) {
if (CEF_CURRENTLY_ON_UIT()) {
CancelNow(callback_);
} else {
CEF_POST_TASK(CEF_UIT,
base::Bind(&UploadFolderHelper::CancelNow, callback_));
}
}
}
void OnListFile(
const net::DirectoryLister::DirectoryListerData& data) override {
CEF_REQUIRE_UIT();
if (!data.info.IsDirectory())
select_files_.push_back(data.path);
}
void OnListDone(int error) override {
CEF_REQUIRE_UIT();
if (!callback_.is_null()) {
callback_.Run(0, select_files_);
callback_.Reset();
}
}
private:
static void CancelNow(
const CefFileDialogRunner::RunFileChooserCallback& callback) {
CEF_REQUIRE_UIT();
std::vector<base::FilePath> file_paths;
callback.Run(0, file_paths);
}
CefFileDialogRunner::RunFileChooserCallback callback_;
std::vector<base::FilePath> select_files_;
DISALLOW_COPY_AND_ASSIGN(UploadFolderHelper);
};
} // namespace
CefFileDialogManager::CefFileDialogManager(
CefBrowserHostImpl* browser,
scoped_ptr<CefFileDialogRunner> runner)
: content::WebContentsObserver(browser->web_contents()),
browser_(browser),
runner_(runner.Pass()),
file_chooser_pending_(false),
weak_ptr_factory_(this) {
DCHECK(web_contents());
}
CefFileDialogManager::~CefFileDialogManager() {
}
void CefFileDialogManager::Destroy() {
DCHECK(!file_chooser_pending_);
runner_.reset(NULL);
}
void CefFileDialogManager::RunFileDialog(
cef_file_dialog_mode_t mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefRunFileDialogCallback> callback) {
DCHECK(callback.get());
if (!callback.get())
return;
CefFileDialogRunner::FileChooserParams params;
switch (mode & FILE_DIALOG_TYPE_MASK) {
case FILE_DIALOG_OPEN:
params.mode = content::FileChooserParams::Open;
break;
case FILE_DIALOG_OPEN_MULTIPLE:
params.mode = content::FileChooserParams::OpenMultiple;
break;
case FILE_DIALOG_OPEN_FOLDER:
params.mode = content::FileChooserParams::UploadFolder;
break;
case FILE_DIALOG_SAVE:
params.mode = content::FileChooserParams::Save;
break;
}
DCHECK_GE(selected_accept_filter, 0);
params.selected_accept_filter = selected_accept_filter;
params.overwriteprompt = !!(mode & FILE_DIALOG_OVERWRITEPROMPT_FLAG);
params.hidereadonly = !!(mode & FILE_DIALOG_HIDEREADONLY_FLAG);
params.title = title;
if (!default_file_path.empty())
params.default_file_name = base::FilePath(default_file_path);
if (!accept_filters.empty()) {
std::vector<CefString>::const_iterator it = accept_filters.begin();
for (; it != accept_filters.end(); ++it)
params.accept_types.push_back(*it);
}
RunFileChooser(params, base::Bind(RunFileDialogDismissed, callback));
}
void CefFileDialogManager::RunFileChooser(
content::WebContents* web_contents,
const content::FileChooserParams& params) {
CEF_REQUIRE_UIT();
DCHECK_EQ(web_contents, this->web_contents());
content::RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
if (!render_view_host)
return;
CefFileDialogRunner::FileChooserParams cef_params;
static_cast<content::FileChooserParams&>(cef_params) = params;
if (lister_) {
// Cancel the previous upload folder run.
lister_->Cancel();
lister_.reset();
}
if (params.mode == content::FileChooserParams::UploadFolder) {
RunFileChooser(cef_params,
base::Bind(
&CefFileDialogManager::OnRunFileChooserUploadFolderDelegateCallback,
weak_ptr_factory_.GetWeakPtr(), params.mode));
return;
}
RunFileChooser(cef_params,
base::Bind(&CefFileDialogManager::OnRunFileChooserDelegateCallback,
weak_ptr_factory_.GetWeakPtr(), params.mode));
}
void CefFileDialogManager::RunFileChooser(
const CefFileDialogRunner::FileChooserParams& params,
const CefFileDialogRunner::RunFileChooserCallback& callback) {
CEF_REQUIRE_UIT();
if (file_chooser_pending_) {
// Dismiss the new dialog immediately.
callback.Run(0, std::vector<base::FilePath>());
return;
}
file_chooser_pending_ = true;
// Ensure that the |file_chooser_pending_| flag is cleared.
const CefFileDialogRunner::RunFileChooserCallback& host_callback =
base::Bind(&CefFileDialogManager::OnRunFileChooserCallback,
weak_ptr_factory_.GetWeakPtr(), callback);
bool handled = false;
if (browser_->client().get()) {
CefRefPtr<CefDialogHandler> handler =
browser_->client()->GetDialogHandler();
if (handler.get()) {
int mode = FILE_DIALOG_OPEN;
switch (params.mode) {
case content::FileChooserParams::Open:
mode = FILE_DIALOG_OPEN;
break;
case content::FileChooserParams::OpenMultiple:
mode = FILE_DIALOG_OPEN_MULTIPLE;
break;
case content::FileChooserParams::UploadFolder:
mode = FILE_DIALOG_OPEN_FOLDER;
break;
case content::FileChooserParams::Save:
mode = FILE_DIALOG_SAVE;
break;
default:
NOTREACHED();
break;
}
if (params.overwriteprompt)
mode |= FILE_DIALOG_OVERWRITEPROMPT_FLAG;
if (params.hidereadonly)
mode |= FILE_DIALOG_HIDEREADONLY_FLAG;
std::vector<base::string16>::const_iterator it;
std::vector<CefString> accept_filters;
it = params.accept_types.begin();
for (; it != params.accept_types.end(); ++it)
accept_filters.push_back(*it);
CefRefPtr<CefFileDialogCallbackImpl> callbackImpl(
new CefFileDialogCallbackImpl(host_callback));
handled = handler->OnFileDialog(
browser_,
static_cast<cef_file_dialog_mode_t>(mode),
params.title,
params.default_file_name.value(),
accept_filters,
params.selected_accept_filter,
callbackImpl.get());
if (!handled) {
if (callbackImpl->IsConnected()) {
callbackImpl->Disconnect();
} else {
// User executed the callback even though they returned false.
NOTREACHED();
handled = true;
}
}
}
}
if (!handled) {
if (runner_.get()) {
runner_->Run(browser_, params, host_callback);
} else {
LOG(WARNING) << "No file dialog runner available for this platform";
host_callback.Run(0, std::vector<base::FilePath>());
}
}
}
void CefFileDialogManager::OnRunFileChooserCallback(
const CefFileDialogRunner::RunFileChooserCallback& callback,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths) {
CEF_REQUIRE_UIT();
file_chooser_pending_ = false;
// Execute the callback asynchronously.
CEF_POST_TASK(CEF_UIT,
base::Bind(callback, selected_accept_filter, file_paths));
}
void CefFileDialogManager::OnRunFileChooserUploadFolderDelegateCallback(
const content::FileChooserParams::Mode mode,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths) {
CEF_REQUIRE_UIT();
DCHECK_EQ(mode, content::FileChooserParams::UploadFolder);
if (file_paths.size() == 0) {
// Client canceled the file chooser.
OnRunFileChooserDelegateCallback(mode, selected_accept_filter, file_paths);
} else {
lister_.reset(new net::DirectoryLister(
file_paths[0],
net::DirectoryLister::NO_SORT,
new UploadFolderHelper(
base::Bind(&CefFileDialogManager::OnRunFileChooserDelegateCallback,
weak_ptr_factory_.GetWeakPtr(), mode))));
lister_->Start();
}
}
void CefFileDialogManager::OnRunFileChooserDelegateCallback(
content::FileChooserParams::Mode mode,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths) {
CEF_REQUIRE_UIT();
if (lister_.get())
lister_.reset();
if (!web_contents())
return;
content::RenderViewHost* render_view_host =
web_contents()->GetRenderViewHost();
if (!render_view_host)
return;
// Convert FilePath list to SelectedFileInfo list.
std::vector<content::FileChooserFileInfo> selected_files;
for (size_t i = 0; i < file_paths.size(); ++i) {
content::FileChooserFileInfo info;
info.file_path = file_paths[i];
selected_files.push_back(info);
}
// Notify our RenderViewHost in all cases.
render_view_host->FilesSelectedInChooser(selected_files, mode);
}

View File

@ -0,0 +1,99 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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.
#ifndef CEF_LIBCEF_BROWSER_FILE_DIALOG_MANAGER_H_
#define CEF_LIBCEF_BROWSER_FILE_DIALOG_MANAGER_H_
#pragma once
#include "include/cef_browser.h"
#include "libcef/browser/file_dialog_runner.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/web_contents_observer.h"
namespace content {
class WebContents;
}
namespace net {
class DirectoryLister;
}
class CefBrowserHostImpl;
class CefFileDialogManager : public content::WebContentsObserver {
public:
// |runner| may be NULL if the platform doesn't implement dialogs.
CefFileDialogManager(
CefBrowserHostImpl* browser,
scoped_ptr<CefFileDialogRunner> runner);
~CefFileDialogManager() override;
// Delete the runner to free any platform constructs.
void Destroy();
// Called from CefBrowserHostImpl::RunFileChooser.
// See CefBrowserHost::RunFileDialog documentation.
void RunFileDialog(
cef_file_dialog_mode_t mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefRunFileDialogCallback> callback);
// Called from CefBrowserHostImpl::RunFileChooser.
// See WebContentsDelegate::RunFileChooser documentation.
void RunFileChooser(
content::WebContents* web_contents,
const content::FileChooserParams& params);
// Run the file chooser dialog specified by |params|. Only a single dialog may
// be pending at any given time. |callback| will be executed asynchronously
// after the dialog is dismissed or if another dialog is already pending.
void RunFileChooser(
const CefFileDialogRunner::FileChooserParams& params,
const CefFileDialogRunner::RunFileChooserCallback& callback);
private:
// Used with RunFileChooser to clear the |file_chooser_pending_| flag.
void OnRunFileChooserCallback(
const CefFileDialogRunner::RunFileChooserCallback& callback,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths);
// Used with WebContentsDelegate::RunFileChooser when mode is
// content::FileChooserParams::UploadFolder.
void OnRunFileChooserUploadFolderDelegateCallback(
const content::FileChooserParams::Mode mode,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths);
// Used with WebContentsDelegate::RunFileChooser to notify the WebContents.
void OnRunFileChooserDelegateCallback(
content::FileChooserParams::Mode mode,
int selected_accept_filter,
const std::vector<base::FilePath>& file_paths);
// CefBrowserHostImpl pointer is guaranteed to outlive this object.
CefBrowserHostImpl* browser_;
scoped_ptr<CefFileDialogRunner> runner_;
// True if a file chooser is currently pending.
bool file_chooser_pending_;
// Used for asynchronously listing directory contents.
scoped_ptr<net::DirectoryLister> lister_;
// Must be the last member.
base::WeakPtrFactory<CefFileDialogManager> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CefFileDialogManager);
};
#endif // CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_MANAGER_H_

View File

@ -0,0 +1,53 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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.
#ifndef CEF_LIBCEF_BROWSER_FILE_DIALOG_RUNNER_H_
#define CEF_LIBCEF_BROWSER_FILE_DIALOG_RUNNER_H_
#pragma once
#include <vector>
#include "base/files/file_path.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "content/public/common/file_chooser_params.h"
class CefBrowserHostImpl;
class CefFileDialogRunner {
public:
// Extend content::FileChooserParams with some options unique to CEF.
struct FileChooserParams : public content::FileChooserParams {
// 0-based index of the selected value in |accept_types|.
int selected_accept_filter = 0;
// True if the Save dialog should prompt before overwriting files.
bool overwriteprompt = true;
// True if read-only files should be hidden.
bool hidereadonly = true;
};
// The argument vector will be empty if the dialog was canceled.
typedef base::Callback<void(int, const std::vector<base::FilePath>&)>
RunFileChooserCallback;
// Display the file chooser dialog. Execute |callback| on completion.
virtual void Run(CefBrowserHostImpl* browser,
const FileChooserParams& params,
RunFileChooserCallback callback) = 0;
protected:
// Allow deletion via scoped_ptr only.
friend struct base::DefaultDeleter<CefFileDialogRunner>;
CefFileDialogRunner() {}
virtual ~CefFileDialogRunner() {}
private:
DISALLOW_COPY_AND_ASSIGN(CefFileDialogRunner);
};
#endif // CEF_LIBCEF_BROWSER_FILE_DIALOG_RUNNER_H_

View File

@ -1,28 +0,0 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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 "libcef/browser/javascript_dialog.h"
#include "libcef/browser/javascript_dialog_manager.h"
CefJavaScriptDialog::CefJavaScriptDialog(
CefJavaScriptDialogManager* creator,
content::JavaScriptMessageType message_type,
const base::string16& display_url,
const base::string16& message_text,
const base::string16& default_prompt_text,
const content::JavaScriptDialogManager::DialogClosedCallback& callback)
: creator_(creator),
callback_(callback) {
NOTIMPLEMENTED();
callback_.Run(false, base::string16());
creator_->DialogClosed(this);
}
CefJavaScriptDialog::~CefJavaScriptDialog() {
}
void CefJavaScriptDialog::Cancel() {
}

View File

@ -5,7 +5,6 @@
#include "libcef/browser/javascript_dialog_manager.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/javascript_dialog.h"
#include "libcef/browser/thread_util.h"
#include "base/bind.h"
@ -68,13 +67,24 @@ class CefJSDialogCallbackImpl : public CefJSDialogCallback {
CefJavaScriptDialogManager::CefJavaScriptDialogManager(
CefBrowserHostImpl* browser)
: browser_(browser) {
CefBrowserHostImpl* browser,
scoped_ptr<CefJavaScriptDialogRunner> runner)
: browser_(browser),
runner_(runner.Pass()),
dialog_running_(false),
weak_ptr_factory_(this) {
}
CefJavaScriptDialogManager::~CefJavaScriptDialogManager() {
}
void CefJavaScriptDialogManager::Destroy() {
if (runner_.get()) {
DCHECK(!dialog_running_);
runner_.reset(NULL);
}
}
void CefJavaScriptDialogManager::RunJavaScriptDialog(
content::WebContents* web_contents,
const GURL& origin_url,
@ -111,29 +121,26 @@ void CefJavaScriptDialogManager::RunJavaScriptDialog(
}
}
#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
*did_suppress_message = false;
if (dialog_.get()) {
// One dialog at a time, please.
if (!runner_.get() || dialog_running_) {
// Suppress the dialog if there is no platform runner or if the dialog is
// currently running.
if (!runner_.get())
LOG(WARNING) << "No javascript dialog runner available for this platform";
*did_suppress_message = true;
return;
}
dialog_running_ = true;
base::string16 display_url =
url_formatter::FormatUrlForSecurityDisplay(origin_url, accept_lang);
dialog_.reset(new CefJavaScriptDialog(this,
message_type,
display_url,
message_text,
runner_->Run(browser_, message_type, display_url, message_text,
default_prompt_text,
callback));
#else
// TODO(port): implement CefJavaScriptDialog for other platforms.
*did_suppress_message = true;
return;
#endif
base::Bind(&CefJavaScriptDialogManager::DialogClosed,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void CefJavaScriptDialogManager::RunBeforeUnloadDialog(
@ -166,29 +173,28 @@ void CefJavaScriptDialogManager::RunBeforeUnloadDialog(
}
}
#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
if (dialog_.get()) {
// Seriously!?
if (!runner_.get() || dialog_running_) {
if (!runner_.get())
LOG(WARNING) << "No javascript dialog runner available for this platform";
// Suppress the dialog if there is no platform runner or if the dialog is
// currently running.
callback.Run(true, base::string16());
return;
}
dialog_running_ = true;
base::string16 new_message_text =
message_text +
base::ASCIIToUTF16("\n\nIs it OK to leave/reload this page?");
dialog_.reset(
new CefJavaScriptDialog(this,
runner_->Run(browser_,
content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM,
base::string16(), // display_url
new_message_text,
base::string16(), // default_prompt_text
callback));
#else
// TODO(port): implement CefJavaScriptDialog for other platforms.
callback.Run(true, base::string16());
return;
#endif
base::Bind(&CefJavaScriptDialogManager::DialogClosed,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void CefJavaScriptDialogManager::CancelActiveAndPendingDialogs(
@ -202,27 +208,31 @@ void CefJavaScriptDialogManager::CancelActiveAndPendingDialogs(
}
}
#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
if (dialog_.get()) {
dialog_->Cancel();
dialog_.reset();
if (runner_.get() && dialog_running_) {
runner_->Cancel();
dialog_running_ = false;
}
#endif
}
void CefJavaScriptDialogManager::ResetDialogState(
content::WebContents* web_contents) {
}
void CefJavaScriptDialogManager::DialogClosed(CefJavaScriptDialog* dialog) {
#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
DCHECK_EQ(dialog, dialog_.get());
dialog_.reset();
void CefJavaScriptDialogManager::DialogClosed(
const DialogClosedCallback& callback,
bool success,
const base::string16& user_input) {
CefRefPtr<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefJSDialogHandler> handler = client->GetJSDialogHandler();
if (handler.get())
handler->OnDialogClosed(browser_);
}
#endif
DCHECK(runner_.get());
DCHECK(dialog_running_);
dialog_running_ = false;
callback.Run(success, user_input);
}

View File

@ -9,18 +9,26 @@
#include <string>
#include "libcef/browser/javascript_dialog_runner.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/javascript_dialog_manager.h"
class CefBrowserHostImpl;
class CefJavaScriptDialog;
class CefJavaScriptDialogManager : public content::JavaScriptDialogManager {
public:
explicit CefJavaScriptDialogManager(CefBrowserHostImpl* browser);
// |runner| may be NULL if the platform doesn't implement dialogs.
CefJavaScriptDialogManager(
CefBrowserHostImpl* browser,
scoped_ptr<CefJavaScriptDialogRunner> runner);
~CefJavaScriptDialogManager() override;
// Delete the runner to free any platform constructs.
void Destroy();
// JavaScriptDialogManager methods.
void RunJavaScriptDialog(
content::WebContents* web_contents,
@ -31,32 +39,32 @@ class CefJavaScriptDialogManager : public content::JavaScriptDialogManager {
const base::string16& default_prompt_text,
const DialogClosedCallback& callback,
bool* did_suppress_message) override;
void RunBeforeUnloadDialog(
content::WebContents* web_contents,
const base::string16& message_text,
bool is_reload,
const DialogClosedCallback& callback) override;
void CancelActiveAndPendingDialogs(
content::WebContents* web_contents) override;
void ResetDialogState(
content::WebContents* web_contents) override;
// Called by the CefJavaScriptDialog when it closes.
void DialogClosed(CefJavaScriptDialog* dialog);
CefBrowserHostImpl* browser() const { return browser_; }
private:
// This pointer is guaranteed to outlive the CefJavaScriptDialogManager.
// Method executed by the callback passed to CefJavaScriptDialogRunner::Run.
void DialogClosed(const DialogClosedCallback& callback,
bool success,
const base::string16& user_input);
// CefBrowserHostImpl pointer is guaranteed to outlive this object.
CefBrowserHostImpl* browser_;
#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
// The dialog being shown. No queueing.
scoped_ptr<CefJavaScriptDialog> dialog_;
#endif
scoped_ptr<CefJavaScriptDialogRunner> runner_;
// True if a dialog is currently running.
bool dialog_running_;
// Must be the last member.
base::WeakPtrFactory<CefJavaScriptDialogManager> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CefJavaScriptDialogManager);
};

View File

@ -0,0 +1,46 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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.
#ifndef CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_RUNNER_H_
#define CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_RUNNER_H_
#pragma once
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "content/public/common/javascript_message_type.h"
class CefBrowserHostImpl;
class CefJavaScriptDialogRunner {
public:
typedef base::Callback<void(bool /* success */,
const base::string16& /* user_input */)>
DialogClosedCallback;
// Run the dialog. Execute |callback| on completion.
virtual void Run(
CefBrowserHostImpl* browser,
content::JavaScriptMessageType message_type,
const base::string16& display_url,
const base::string16& message_text,
const base::string16& default_prompt_text,
const DialogClosedCallback& callback) = 0;
// Cancel a dialog mid-flight.
virtual void Cancel() = 0;
protected:
// Allow deletion via scoped_ptr only.
friend struct base::DefaultDeleter<CefJavaScriptDialogRunner>;
CefJavaScriptDialogRunner() {}
virtual ~CefJavaScriptDialogRunner() {}
private:
DISALLOW_COPY_AND_ASSIGN(CefJavaScriptDialogRunner);
};
#endif // CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_RUNNER_H_

View File

@ -1,72 +0,0 @@
// Copyright 2014 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 "libcef/browser/menu_creator_runner_linux.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/window_x11.h"
#include "base/compiler_specific.h"
#include "base/strings/string_util.h"
#include "ui/aura/window.h"
#include "ui/gfx/geometry/point.h"
CefMenuCreatorRunnerLinux::CefMenuCreatorRunnerLinux() {
}
CefMenuCreatorRunnerLinux::~CefMenuCreatorRunnerLinux() {
}
bool CefMenuCreatorRunnerLinux::RunContextMenu(CefMenuCreator* manager) {
menu_.reset(
new views::MenuRunner(manager->model(), views::MenuRunner::CONTEXT_MENU));
gfx::Point screen_point;
if (manager->browser()->IsWindowless()) {
CefRefPtr<CefClient> client = manager->browser()->GetClient();
if (!client.get())
return false;
CefRefPtr<CefRenderHandler> handler = client->GetRenderHandler();
if (!handler.get())
return false;
int screenX = 0, screenY = 0;
if (!handler->GetScreenPoint(manager->browser(),
manager->params().x, manager->params().y,
screenX, screenY)) {
return false;
}
screen_point = gfx::Point(screenX, screenY);
} else {
// We can't use aura::Window::GetBoundsInScreen on Linux because it will
// return bounds from DesktopWindowTreeHostX11 which in our case is relative
// to the parent window instead of the root window (screen).
const gfx::Rect& bounds_in_screen =
manager->browser()->window_x11()->GetBoundsInScreen();
screen_point = gfx::Point(bounds_in_screen.x() + manager->params().x,
bounds_in_screen.y() + manager->params().y);
}
views::MenuRunner::RunResult result =
menu_->RunMenuAt(manager->browser()->window_widget(),
NULL, gfx::Rect(screen_point, gfx::Size()),
views::MENU_ANCHOR_TOPRIGHT,
ui::MENU_SOURCE_NONE);
ALLOW_UNUSED_LOCAL(result);
return true;
}
void CefMenuCreatorRunnerLinux::CancelContextMenu() {
if (menu_)
menu_->Cancel();
}
bool CefMenuCreatorRunnerLinux::FormatLabel(base::string16& label) {
// Remove the accelerator indicator (&) from label strings.
const char16 replace[] = {L'&', 0};
return base::ReplaceChars(label, replace, base::string16(), &label);
}

View File

@ -1,28 +0,0 @@
// 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.
#ifndef CEF_LIBCEF_BROWSER_MENU_MANAGER_RUNNER_LINUX_H_
#define CEF_LIBCEF_BROWSER_MENU_MANAGER_RUNNER_LINUX_H_
#pragma once
#include "libcef/browser/menu_creator.h"
#include "base/memory/scoped_ptr.h"
#include "ui/views/controls/menu/menu_runner.h"
class CefMenuCreatorRunnerLinux: public CefMenuCreator::Runner {
public:
CefMenuCreatorRunnerLinux();
~CefMenuCreatorRunnerLinux() override;
// CefMemoryManager::Runner methods.
bool RunContextMenu(CefMenuCreator* manager) override;
void CancelContextMenu() override;
bool FormatLabel(base::string16& label) override;
private:
scoped_ptr<views::MenuRunner> menu_;
};
#endif // CEF_LIBCEF_BROWSER_MENU_MANAGER_RUNNER_LINUX_H_

View File

@ -1,29 +0,0 @@
// 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.
#ifndef CEF_LIBCEF_BROWSER_MENU_MANAGER_RUNNER_MAC_H_
#define CEF_LIBCEF_BROWSER_MENU_MANAGER_RUNNER_MAC_H_
#pragma once
#include "libcef/browser/menu_creator.h"
#if __OBJC__
@class MenuController;
#else
class MenuController;
#endif
class CefMenuCreatorRunnerMac : public CefMenuCreator::Runner {
public:
CefMenuCreatorRunnerMac();
~CefMenuCreatorRunnerMac() override;
// CefMemoryManager::Runner methods.
bool RunContextMenu(CefMenuCreator* manager) override;
private:
MenuController* menu_controller_;
};
#endif // CEF_LIBCEF_BROWSER_MENU_MANAGER_RUNNER_MAC_H_

View File

@ -1,94 +0,0 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
#include "libcef/browser/menu_creator_runner_mac.h"
#include "libcef/browser/browser_host_impl.h"
#include "base/message_loop/message_loop.h"
#include "base/compiler_specific.h"
#import "base/mac/scoped_sending_event.h"
#import "ui/base/cocoa/menu_controller.h"
CefMenuCreatorRunnerMac::CefMenuCreatorRunnerMac()
: menu_controller_(nil) {
}
CefMenuCreatorRunnerMac::~CefMenuCreatorRunnerMac() {
if (menu_controller_ != nil)
[menu_controller_ release];
}
bool CefMenuCreatorRunnerMac::RunContextMenu(CefMenuCreator* manager) {
// Create a menu controller based on the model.
if (menu_controller_ != nil)
[menu_controller_ release];
menu_controller_ =
[[MenuController alloc] initWithModel:manager->model()
useWithPopUpButtonCell:NO];
NSView* parent_view =
manager->browser()->GetWebContents()->GetContentNativeView();
// Synthesize an event for the click, as there is no certainty that
// [NSApp currentEvent] will return a valid event.
NSEvent* currentEvent = [NSApp currentEvent];
NSWindow* window = [parent_view window];
NSPoint position = [window mouseLocationOutsideOfEventStream];
NSTimeInterval eventTime = [currentEvent timestamp];
NSEvent* clickEvent = [NSEvent mouseEventWithType:NSRightMouseDown
location:position
modifierFlags:NSRightMouseDownMask
timestamp:eventTime
windowNumber:[window windowNumber]
context:nil
eventNumber:0
clickCount:1
pressure:1.0];
{
// Make sure events can be pumped while the menu is up.
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
// One of the events that could be pumped is |window.close()|.
// User-initiated event-tracking loops protect against this by
// setting flags in -[CrApplication sendEvent:], but since
// web-content menus are initiated by IPC message the setup has to
// be done manually.
base::mac::ScopedSendingEvent sendingEventScoper;
// Show the menu. Blocks until the menu is dismissed.
if (manager->browser()->IsWindowless()) {
// Showing the menu in OSR is pretty much self contained, only using
// the initialized menu_controller_ in this function, and the scoped
// variables in this block.
int screenX = 0, screenY = 0;
CefRefPtr<CefRenderHandler> handler =
manager->browser()->GetClient()->GetRenderHandler();
if (!handler->GetScreenPoint(manager->browser(),
manager->params().x, manager->params().y,
screenX, screenY)) {
return false;
}
// Don't show the menu unless there is a parent native window to tie it to
if (!manager->browser()->GetWindowHandle())
return false;
NSPoint screen_position =
NSPointFromCGPoint(gfx::Point(screenX, screenY).ToCGPoint());
[[menu_controller_ menu] popUpMenuPositioningItem:nil
atLocation:screen_position
inView:nil];
} else {
[NSMenu popUpContextMenu:[menu_controller_ menu]
withEvent:clickEvent
forView:parent_view];
}
}
return true;
}

View File

@ -1,63 +0,0 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
#include "libcef/browser/menu_creator_runner_win.h"
#include "libcef/browser/browser_host_impl.h"
#include "base/message_loop/message_loop.h"
#include "ui/aura/window.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/menu/menu_2.h"
CefMenuCreatorRunnerWin::CefMenuCreatorRunnerWin() {
}
bool CefMenuCreatorRunnerWin::RunContextMenu(CefMenuCreator* manager) {
// Create a menu based on the model.
menu_.reset(new views::NativeMenuWin(manager->model(), NULL));
menu_->Rebuild(NULL);
// Make sure events can be pumped while the menu is up.
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
gfx::Point screen_point;
if (manager->browser()->IsWindowless()) {
CefRefPtr<CefClient> client = manager->browser()->GetClient();
if (!client.get())
return false;
CefRefPtr<CefRenderHandler> handler = client->GetRenderHandler();
if (!handler.get())
return false;
int screenX = 0, screenY = 0;
if (!handler->GetScreenPoint(manager->browser(),
manager->params().x, manager->params().y,
screenX, screenY)) {
return false;
}
screen_point = gfx::Point(screenX, screenY);
} else {
aura::Window* window = manager->browser()->GetContentView();
const gfx::Rect& bounds_in_screen = window->GetBoundsInScreen();
screen_point = gfx::Point(bounds_in_screen.x() + manager->params().x,
bounds_in_screen.y() + manager->params().y);
// Adjust for potential display scaling.
float scale = gfx::Screen::GetScreenFor(window)->
GetDisplayNearestWindow(window).device_scale_factor();
screen_point = gfx::ToFlooredPoint(
gfx::ScalePoint(gfx::PointF(screen_point), scale));
}
// Show the menu. Blocks until the menu is dismissed.
menu_->RunMenuAt(screen_point, views::Menu2::ALIGN_TOPLEFT);
return true;
}

View File

@ -1,25 +0,0 @@
// 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.
#ifndef CEF_LIBCEF_BROWSER_MENU_MANAGER_RUNNER_WIN_H_
#define CEF_LIBCEF_BROWSER_MENU_MANAGER_RUNNER_WIN_H_
#pragma once
#include "libcef/browser/menu_creator.h"
#include "base/memory/scoped_ptr.h"
#include "ui/views/controls/menu/native_menu_win.h"
class CefMenuCreatorRunnerWin : public CefMenuCreator::Runner {
public:
CefMenuCreatorRunnerWin();
// CefMemoryManager::Runner methods.
bool RunContextMenu(CefMenuCreator* manager) override;
private:
scoped_ptr<views::NativeMenuWin> menu_;
};
#endif // CEF_LIBCEF_BROWSER_MENU_MANAGER_RUNNER_WIN_H_

View File

@ -2,9 +2,11 @@
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
#include "libcef/browser/menu_creator.h"
#include "libcef/browser/menu_manager.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/context_menu_params_impl.h"
#include "libcef/browser/menu_runner.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/content_client.h"
@ -15,14 +17,6 @@
#include "content/public/browser/render_widget_host_view.h"
#include "grit/cef_strings.h"
#if defined(OS_WIN)
#include "libcef/browser/menu_creator_runner_win.h"
#elif defined(OS_MACOSX)
#include "libcef/browser/menu_creator_runner_mac.h"
#elif defined(OS_LINUX)
#include "libcef/browser/menu_creator_runner_linux.h"
#endif
namespace {
CefString GetLabel(int message_id) {
@ -93,24 +87,30 @@ class CefRunContextMenuCallbackImpl : public CefRunContextMenuCallback {
} // namespace
CefMenuCreator::CefMenuCreator(content::WebContents* web_contents,
CefBrowserHostImpl* browser)
: content::WebContentsObserver(web_contents),
CefMenuManager::CefMenuManager(CefBrowserHostImpl* browser,
scoped_ptr<CefMenuRunner> runner)
: content::WebContentsObserver(browser->web_contents()),
browser_(browser),
runner_(runner.Pass()),
custom_menu_callback_(NULL),
weak_ptr_factory_(this) {
DCHECK(web_contents);
DCHECK(browser_);
DCHECK(web_contents());
DCHECK(runner_.get());
model_ = new CefMenuModelImpl(this);
}
CefMenuCreator::~CefMenuCreator() {
CefMenuManager::~CefMenuManager() {
// The model may outlive the delegate if the context menu is visible when the
// application is closed.
model_->set_delegate(NULL);
}
bool CefMenuCreator::IsShowingContextMenu() {
void CefMenuManager::Destroy() {
CancelContextMenu();
runner_.reset(NULL);
}
bool CefMenuManager::IsShowingContextMenu() {
if (!web_contents())
return false;
content::RenderWidgetHostView* view =
@ -118,11 +118,8 @@ bool CefMenuCreator::IsShowingContextMenu() {
return (view && view->IsShowingContextMenu());
}
bool CefMenuCreator::CreateContextMenu(
bool CefMenuManager::CreateContextMenu(
const content::ContextMenuParams& params) {
if (!CreateRunner())
return true;
// The renderer may send the "show context menu" message multiple times, one
// for each right click mouse event it receives. Normally, this doesn't happen
// because mouse events are not forwarded once the context menu is showing.
@ -162,7 +159,7 @@ bool CefMenuCreator::CreateContextMenu(
if (model_->GetCount() > 0) {
CefRefPtr<CefRunContextMenuCallbackImpl> callbackImpl(
new CefRunContextMenuCallbackImpl(
base::Bind(&CefMenuCreator::ExecuteCommandCallback,
base::Bind(&CefMenuManager::ExecuteCommandCallback,
weak_ptr_factory_.GetWeakPtr())));
// This reference will be cleared when the callback is executed or
@ -198,10 +195,10 @@ bool CefMenuCreator::CreateContextMenu(
if (custom_menu)
return true;
return runner_->RunContextMenu(this);
return runner_->RunContextMenu(browser_, model_->model(), params_);
}
void CefMenuCreator::CancelContextMenu() {
void CefMenuManager::CancelContextMenu() {
if (IsShowingContextMenu()) {
if (custom_menu_callback_)
custom_menu_callback_->Cancel();
@ -210,24 +207,7 @@ void CefMenuCreator::CancelContextMenu() {
}
}
bool CefMenuCreator::CreateRunner() {
if (!runner_.get()) {
// Create the menu runner.
#if defined(OS_WIN)
runner_.reset(new CefMenuCreatorRunnerWin);
#elif defined(OS_MACOSX)
runner_.reset(new CefMenuCreatorRunnerMac);
#elif defined(OS_LINUX)
runner_.reset(new CefMenuCreatorRunnerLinux);
#else
// Need an implementation.
NOTREACHED();
#endif
}
return (runner_.get() != NULL);
}
void CefMenuCreator::ExecuteCommand(CefRefPtr<CefMenuModelImpl> source,
void CefMenuManager::ExecuteCommand(CefRefPtr<CefMenuModelImpl> source,
int command_id,
cef_event_flags_t event_flags) {
// Give the client a chance to handle the command.
@ -259,7 +239,7 @@ void CefMenuCreator::ExecuteCommand(CefRefPtr<CefMenuModelImpl> source,
ExecuteDefaultCommand(command_id);
}
void CefMenuCreator::MenuWillShow(CefRefPtr<CefMenuModelImpl> source) {
void CefMenuManager::MenuWillShow(CefRefPtr<CefMenuModelImpl> source) {
// May be called for sub-menus as well.
if (source.get() != model_.get())
return;
@ -278,7 +258,7 @@ void CefMenuCreator::MenuWillShow(CefRefPtr<CefMenuModelImpl> source) {
view->SetShowingContextMenu(true);
}
void CefMenuCreator::MenuClosed(CefRefPtr<CefMenuModelImpl> source) {
void CefMenuManager::MenuClosed(CefRefPtr<CefMenuModelImpl> source) {
// May be called for sub-menus as well.
if (source.get() != model_.get())
return;
@ -306,11 +286,11 @@ void CefMenuCreator::MenuClosed(CefRefPtr<CefMenuModelImpl> source) {
web_contents()->NotifyContextMenuClosed(params_.custom_context);
}
bool CefMenuCreator::FormatLabel(base::string16& label) {
bool CefMenuManager::FormatLabel(base::string16& label) {
return runner_->FormatLabel(label);
}
void CefMenuCreator::ExecuteCommandCallback(int command_id,
void CefMenuManager::ExecuteCommandCallback(int command_id,
cef_event_flags_t event_flags) {
DCHECK(IsShowingContextMenu());
DCHECK(custom_menu_callback_);
@ -320,7 +300,7 @@ void CefMenuCreator::ExecuteCommandCallback(int command_id,
custom_menu_callback_ = NULL;
}
void CefMenuCreator::CreateDefaultModel() {
void CefMenuManager::CreateDefaultModel() {
if (!params_.custom_items.empty()) {
// Custom menu items originating from the renderer process. For example,
// plugin placeholder menu items or Flash menu items.
@ -410,7 +390,7 @@ void CefMenuCreator::CreateDefaultModel() {
}
}
void CefMenuCreator::ExecuteDefaultCommand(int command_id) {
void CefMenuManager::ExecuteDefaultCommand(int command_id) {
if (IsCustomContextMenuCommand(command_id)) {
if (web_contents()) {
web_contents()->ExecuteCustomContextMenuCommand(
@ -494,7 +474,7 @@ void CefMenuCreator::ExecuteDefaultCommand(int command_id) {
}
}
bool CefMenuCreator::IsCustomContextMenuCommand(int command_id) {
bool CefMenuManager::IsCustomContextMenuCommand(int command_id) {
// Verify that the command ID is in the correct range.
if (command_id < MENU_ID_CUSTOM_FIRST || command_id > MENU_ID_CUSTOM_LAST)
return false;

View File

@ -8,6 +8,8 @@
#include "libcef/browser/menu_model_impl.h"
#include "libcef/browser/menu_runner.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/web_contents_observer.h"
@ -18,24 +20,18 @@ class RenderFrameHost;
class WebContents;
};
class CefRunContextMenuCallback;
class CefBrowserHostImpl;
class CefRunContextMenuCallback;
class CefMenuCreator : public CefMenuModelImpl::Delegate,
class CefMenuManager : public CefMenuModelImpl::Delegate,
public content::WebContentsObserver {
public:
// Used for OS-specific menu implementations.
class Runner {
public:
virtual ~Runner() {}
virtual bool RunContextMenu(CefMenuCreator* manager) =0;
virtual void CancelContextMenu() {}
virtual bool FormatLabel(base::string16& label) { return false; }
};
CefMenuManager(CefBrowserHostImpl* browser,
scoped_ptr<CefMenuRunner> runner);
~CefMenuManager() override;
CefMenuCreator(content::WebContents* web_contents,
CefBrowserHostImpl* browser);
~CefMenuCreator() override;
// Delete the runner to free any platform constructs.
void Destroy();
// Returns true if the context menu is currently showing.
bool IsShowingContextMenu();
@ -44,14 +40,7 @@ class CefMenuCreator : public CefMenuModelImpl::Delegate,
bool CreateContextMenu(const content::ContextMenuParams& params);
void CancelContextMenu();
CefBrowserHostImpl* browser() { return browser_; }
ui::MenuModel* model() { return model_->model(); }
const content::ContextMenuParams& params() const { return params_; }
private:
// Create the menu runner if it doesn't already exist.
bool CreateRunner();
// CefMenuModelImpl::Delegate methods.
void ExecuteCommand(CefRefPtr<CefMenuModelImpl> source,
int command_id,
@ -74,17 +63,18 @@ class CefMenuCreator : public CefMenuModelImpl::Delegate,
// CefBrowserHostImpl pointer is guaranteed to outlive this object.
CefBrowserHostImpl* browser_;
scoped_ptr<CefMenuRunner> runner_;
CefRefPtr<CefMenuModelImpl> model_;
content::ContextMenuParams params_;
scoped_ptr<Runner> runner_;
// Not owned by this class.
CefRunContextMenuCallback* custom_menu_callback_;
// Must be the last member.
base::WeakPtrFactory<CefMenuCreator> weak_ptr_factory_;
base::WeakPtrFactory<CefMenuManager> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CefMenuCreator);
DISALLOW_COPY_AND_ASSIGN(CefMenuManager);
};
#endif // CEF_LIBCEF_BROWSER_MENU_MANAGER_H_

View File

@ -0,0 +1,40 @@
// 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.
#ifndef CEF_LIBCEF_BROWSER_MENU_RUNNER_H_
#define CEF_LIBCEF_BROWSER_MENU_RUNNER_H_
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
namespace content {
struct ContextMenuParams;
}
namespace ui {
class MenuModel;
}
class CefBrowserHostImpl;
// Provides platform-specific menu implementations for CefMenuCreator.
class CefMenuRunner {
public:
virtual bool RunContextMenu(CefBrowserHostImpl* browser,
ui::MenuModel* model,
const content::ContextMenuParams& params) = 0;
virtual void CancelContextMenu() {}
virtual bool FormatLabel(base::string16& label) { return false; }
protected:
// Allow deletion via scoped_ptr only.
friend struct base::DefaultDeleter<CefMenuRunner>;
CefMenuRunner() {}
virtual ~CefMenuRunner() {}
DISALLOW_COPY_AND_ASSIGN(CefMenuRunner);
};
#endif // CEF_LIBCEF_BROWSER_MENU_RUNNER_H_

View File

@ -0,0 +1,47 @@
// Copyright 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 "libcef/browser/native/browser_platform_delegate_native.h"
#include "libcef/browser/browser_host_impl.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
CefBrowserPlatformDelegateNative::CefBrowserPlatformDelegateNative(
const CefWindowInfo& window_info)
: window_info_(window_info),
windowless_handler_(nullptr) {
}
void CefBrowserPlatformDelegateNative::WasResized() {
content::RenderViewHost* host = browser_->web_contents()->GetRenderViewHost();
if (host)
host->GetWidget()->WasResized();
}
void CefBrowserPlatformDelegateNative::SendKeyEvent(
const content::NativeWebKeyboardEvent& event) {
content::RenderViewHost* host = browser_->web_contents()->GetRenderViewHost();
if (host)
host->GetWidget()->ForwardKeyboardEvent(event);
}
void CefBrowserPlatformDelegateNative::SendMouseEvent(
const blink::WebMouseEvent& event) {
content::RenderViewHost* host = browser_->web_contents()->GetRenderViewHost();
if (host)
host->GetWidget()->ForwardMouseEvent(event);
}
void CefBrowserPlatformDelegateNative::SendMouseWheelEvent(
const blink::WebMouseWheelEvent& event) {
content::RenderViewHost* host = browser_->web_contents()->GetRenderViewHost();
if (host)
host->GetWidget()->ForwardWheelEvent(event);
}
bool CefBrowserPlatformDelegateNative::IsWindowless() const {
return false;
}

View File

@ -0,0 +1,48 @@
// Copyright 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_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_H_
#define CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_H_
#include "libcef/browser/browser_platform_delegate.h"
// Base implementation of native browser functionality.
class CefBrowserPlatformDelegateNative : public CefBrowserPlatformDelegate {
public:
// Used by the windowless implementation to override specific functionality
// when delegating to the native implementation.
class WindowlessHandler {
public:
// Returns the parent window handle.
virtual CefWindowHandle GetParentWindowHandle() const = 0;
// Convert from view coordinates to screen coordinates.
virtual gfx::Point GetParentScreenPoint(const gfx::Point& view) const = 0;
protected:
virtual ~WindowlessHandler() {}
};
// CefBrowserPlatformDelegate methods:
void WasResized() override;
void SendKeyEvent(const content::NativeWebKeyboardEvent& event) override;
void SendMouseEvent(const blink::WebMouseEvent& event) override;
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event) override;
bool IsWindowless() const override;
const CefWindowInfo& window_info() const { return window_info_; }
void set_windowless_handler(WindowlessHandler* handler) {
windowless_handler_ = handler;
}
protected:
explicit CefBrowserPlatformDelegateNative(const CefWindowInfo& window_info);
CefWindowInfo window_info_;
WindowlessHandler* windowless_handler_; // Not owned by this object.
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_H_

View File

@ -1,29 +1,27 @@
// Copyright (c) 2014 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
// Copyright 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 "libcef/browser/browser_host_impl.h"
#include "libcef/browser/native/browser_platform_delegate_native_linux.h"
// Include this first to avoid type conflict errors.
#include "base/tracked_objects.h"
#undef Status
#include <sys/sysinfo.h>
#include <X11/cursorfont.h>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/context.h"
#include "libcef/browser/window_delegate_view.h"
#include "libcef/browser/window_x11.h"
#include "libcef/browser/native/menu_runner_linux.h"
#include "libcef/browser/native/window_delegate_view.h"
#include "libcef/browser/native/window_x11.h"
#include "libcef/browser/thread_util.h"
#include "base/bind.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/common/file_chooser_params.h"
#include "content/public/common/renderer_preferences.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/gfx/font_render_params.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
#include "ui/views/widget/widget.h"
@ -37,121 +35,27 @@ long GetSystemUptime() {
return 0;
}
// Based on ui/base/cursor/cursor_loader_x11.cc.
using blink::WebCursorInfo;
int ToCursorID(WebCursorInfo::Type type) {
switch (type) {
case WebCursorInfo::TypePointer:
return XC_left_ptr;
case WebCursorInfo::TypeCross:
return XC_crosshair;
case WebCursorInfo::TypeHand:
return XC_hand2;
case WebCursorInfo::TypeIBeam:
return XC_xterm;
case WebCursorInfo::TypeWait:
return XC_watch;
case WebCursorInfo::TypeHelp:
return XC_question_arrow;
case WebCursorInfo::TypeEastResize:
return XC_right_side;
case WebCursorInfo::TypeNorthResize:
return XC_top_side;
case WebCursorInfo::TypeNorthEastResize:
return XC_top_right_corner;
case WebCursorInfo::TypeNorthWestResize:
return XC_top_left_corner;
case WebCursorInfo::TypeSouthResize:
return XC_bottom_side;
case WebCursorInfo::TypeSouthEastResize:
return XC_bottom_right_corner;
case WebCursorInfo::TypeSouthWestResize:
return XC_bottom_left_corner;
case WebCursorInfo::TypeWestResize:
return XC_left_side;
case WebCursorInfo::TypeNorthSouthResize:
return XC_sb_v_double_arrow;
case WebCursorInfo::TypeEastWestResize:
return XC_sb_h_double_arrow;
case WebCursorInfo::TypeNorthEastSouthWestResize:
return XC_left_ptr;
case WebCursorInfo::TypeNorthWestSouthEastResize:
return XC_left_ptr;
case WebCursorInfo::TypeColumnResize:
return XC_sb_h_double_arrow;
case WebCursorInfo::TypeRowResize:
return XC_sb_v_double_arrow;
case WebCursorInfo::TypeMiddlePanning:
return XC_fleur;
case WebCursorInfo::TypeEastPanning:
return XC_sb_right_arrow;
case WebCursorInfo::TypeNorthPanning:
return XC_sb_up_arrow;
case WebCursorInfo::TypeNorthEastPanning:
return XC_top_right_corner;
case WebCursorInfo::TypeNorthWestPanning:
return XC_top_left_corner;
case WebCursorInfo::TypeSouthPanning:
return XC_sb_down_arrow;
case WebCursorInfo::TypeSouthEastPanning:
return XC_bottom_right_corner;
case WebCursorInfo::TypeSouthWestPanning:
return XC_bottom_left_corner;
case WebCursorInfo::TypeWestPanning:
return XC_sb_left_arrow;
case WebCursorInfo::TypeMove:
return XC_fleur;
case WebCursorInfo::TypeVerticalText:
return XC_left_ptr;
case WebCursorInfo::TypeCell:
return XC_left_ptr;
case WebCursorInfo::TypeContextMenu:
return XC_left_ptr;
case WebCursorInfo::TypeAlias:
return XC_left_ptr;
case WebCursorInfo::TypeProgress:
return XC_left_ptr;
case WebCursorInfo::TypeNoDrop:
return XC_left_ptr;
case WebCursorInfo::TypeCopy:
return XC_left_ptr;
case WebCursorInfo::TypeNotAllowed:
return XC_left_ptr;
case WebCursorInfo::TypeZoomIn:
return XC_left_ptr;
case WebCursorInfo::TypeZoomOut:
return XC_left_ptr;
case WebCursorInfo::TypeGrab:
return XC_left_ptr;
case WebCursorInfo::TypeGrabbing:
return XC_left_ptr;
case WebCursorInfo::TypeCustom:
case WebCursorInfo::TypeNone:
break;
}
NOTREACHED();
return 0;
}
} // namespace
ui::PlatformCursor CefBrowserHostImpl::GetPlatformCursor(
blink::WebCursorInfo::Type type) {
if (type == WebCursorInfo::TypeNone) {
if (!invisible_cursor_) {
invisible_cursor_.reset(
new ui::XScopedCursor(ui::CreateInvisibleCursor(),
gfx::GetXDisplay()));
CefBrowserPlatformDelegateNativeLinux::CefBrowserPlatformDelegateNativeLinux(
const CefWindowInfo& window_info)
: CefBrowserPlatformDelegateNative(window_info),
host_window_created_(false),
window_widget_(nullptr),
window_x11_(nullptr) {
}
return invisible_cursor_->get();
} else {
return ui::GetXCursor(ToCursorID(type));
void CefBrowserPlatformDelegateNativeLinux::BrowserDestroyed(
CefBrowserHostImpl* browser) {
CefBrowserPlatformDelegate::BrowserDestroyed(browser);
if (host_window_created_) {
// Release the reference added in CreateHostWindow().
browser->Release();
}
}
bool CefBrowserHostImpl::PlatformCreateWindow() {
bool CefBrowserPlatformDelegateNativeLinux::CreateHostWindow() {
DCHECK(!window_x11_);
DCHECK(!window_widget_);
@ -165,11 +69,13 @@ bool CefBrowserHostImpl::PlatformCreateWindow() {
// Create a new window object. It will delete itself when the associated X11
// window is destroyed.
window_x11_ = new CefWindowX11(this, window_info_.parent_window, rect);
window_x11_ = new CefWindowX11(browser_, window_info_.parent_window, rect);
window_info_.window = window_x11_->xwindow();
// Add a reference that will be released in the destroy handler.
AddRef();
host_window_created_ = true;
// Add a reference that will be released in BrowserDestroyed().
browser_->AddRef();
SkColor background_color = SK_ColorWHITE;
const CefSettings& settings = CefContext::Get()->settings();
@ -183,7 +89,7 @@ bool CefBrowserHostImpl::PlatformCreateWindow() {
CefWindowDelegateView* delegate_view =
new CefWindowDelegateView(background_color);
delegate_view->Init(window_info_.window,
web_contents(),
browser_->web_contents(),
gfx::Rect(gfx::Point(), rect.size()));
window_widget_ = delegate_view->GetWidget();
@ -194,7 +100,7 @@ bool CefBrowserHostImpl::PlatformCreateWindow() {
// As an additional requirement on Linux, we must set the colors for the
// render widgets in webkit.
content::RendererPreferences* prefs =
web_contents_->GetMutableRendererPrefs();
browser_->web_contents()->GetMutableRendererPrefs();
prefs->focus_ring_color = SkColorSetARGB(255, 229, 151, 0);
prefs->thumb_active_color = SkColorSetRGB(244, 244, 244);
prefs->thumb_inactive_color = SkColorSetRGB(234, 234, 234);
@ -205,29 +111,45 @@ bool CefBrowserHostImpl::PlatformCreateWindow() {
prefs->inactive_selection_bg_color = SkColorSetRGB(200, 200, 200);
prefs->inactive_selection_fg_color = SkColorSetRGB(50, 50, 50);
// Set font-related attributes.
CR_DEFINE_STATIC_LOCAL(const gfx::FontRenderParams, params,
(gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), NULL)));
prefs->should_antialias_text = params.antialiasing;
prefs->use_subpixel_positioning = params.subpixel_positioning;
prefs->hinting = params.hinting;
prefs->use_autohinter = params.autohinter;
prefs->use_bitmaps = params.use_bitmaps;
prefs->subpixel_rendering = params.subpixel_rendering;
browser_->web_contents()->GetRenderViewHost()->SyncRendererPrefs();
return true;
}
void CefBrowserHostImpl::PlatformCloseWindow() {
void CefBrowserPlatformDelegateNativeLinux::CloseHostWindow() {
if (window_x11_)
window_x11_->Close();
}
void CefBrowserHostImpl::PlatformSizeTo(int width, int height) {
if (window_x11_) {
window_x11_->SetBounds(
gfx::Rect(window_x11_->bounds().origin(), gfx::Size(width, height)));
}
CefWindowHandle
CefBrowserPlatformDelegateNativeLinux::GetHostWindowHandle() const {
if (windowless_handler_)
return windowless_handler_->GetParentWindowHandle();
return window_info_.window;
}
void CefBrowserHostImpl::PlatformSetFocus(bool focus) {
if (!focus)
views::Widget* CefBrowserPlatformDelegateNativeLinux::GetWindowWidget() const {
return window_widget_;
}
void CefBrowserPlatformDelegateNativeLinux::SendFocusEvent(bool setFocus) {
if (!setFocus)
return;
if (web_contents_) {
if (browser_->web_contents()) {
// Give logical focus to the RenderWidgetHostViewAura in the views
// hierarchy. This does not change the native keyboard focus.
web_contents_->Focus();
browser_->web_contents()->Focus();
}
if (window_x11_) {
@ -238,26 +160,66 @@ void CefBrowserHostImpl::PlatformSetFocus(bool focus) {
}
}
CefWindowHandle CefBrowserHostImpl::PlatformGetWindowHandle() {
return IsWindowless() ? window_info_.parent_window : window_info_.window;
void CefBrowserPlatformDelegateNativeLinux::NotifyMoveOrResizeStarted() {
// Call the parent method to dismiss any existing popups.
CefBrowserPlatformDelegate::NotifyMoveOrResizeStarted();
if (!window_x11_)
return;
views::DesktopWindowTreeHostX11* tree_host = window_x11_->GetHost();
if (!tree_host)
return;
// Explicitly set the screen bounds so that WindowTreeHost::*Screen()
// methods return the correct results.
const gfx::Rect& bounds = window_x11_->GetBoundsInScreen();
tree_host->set_screen_bounds(bounds);
// Send updated screen rectangle information to the renderer process so that
// popups are displayed in the correct location.
content::RenderWidgetHostImpl::From(
browser_->web_contents()->GetRenderViewHost()->GetWidget())->
SendScreenRects();
}
bool CefBrowserHostImpl::PlatformViewText(const std::string& text) {
CEF_REQUIRE_UIT();
void CefBrowserPlatformDelegateNativeLinux::SizeTo(int width, int height) {
if (window_x11_) {
window_x11_->SetBounds(
gfx::Rect(window_x11_->bounds().origin(), gfx::Size(width, height)));
}
}
gfx::Point CefBrowserPlatformDelegateNativeLinux::GetScreenPoint(
const gfx::Point& view) const {
if (windowless_handler_)
return windowless_handler_->GetParentScreenPoint(view);
if (!window_x11_)
return view;
// We can't use aura::Window::GetBoundsInScreen on Linux because it will
// return bounds from DesktopWindowTreeHostX11 which in our case is relative
// to the parent window instead of the root window (screen).
const gfx::Rect& bounds_in_screen = window_x11_->GetBoundsInScreen();
return gfx::Point(bounds_in_screen.x() + view.x(),
bounds_in_screen.y() + view.y());
}
void CefBrowserPlatformDelegateNativeLinux::ViewText(const std::string& text) {
char buff[] = "/tmp/CEFSourceXXXXXX";
int fd = mkstemp(buff);
if (fd == -1)
return false;
return;
FILE* srcOutput = fdopen(fd, "w+");
if (!srcOutput)
return false;
return;
if (fputs(text.c_str(), srcOutput) < 0) {
fclose(srcOutput);
return false;
return;
}
fclose(srcOutput);
@ -265,35 +227,26 @@ bool CefBrowserHostImpl::PlatformViewText(const std::string& text) {
std::string newName(buff);
newName.append(".txt");
if (rename(buff, newName.c_str()) != 0)
return false;
return;
std::string openCommand("xdg-open ");
openCommand += newName;
if (system(openCommand.c_str()) != 0)
return false;
return true;
system(openCommand.c_str());
}
void CefBrowserHostImpl::PlatformHandleKeyboardEvent(
void CefBrowserPlatformDelegateNativeLinux::HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) {
// TODO(cef): Is something required here to handle shortcut keys?
}
void CefBrowserHostImpl::PlatformRunFileChooser(
const FileChooserParams& params,
RunFileChooserCallback callback) {
NOTIMPLEMENTED();
callback.Run(0, std::vector<base::FilePath>());
void CefBrowserPlatformDelegateNativeLinux::HandleExternalProtocol(
const GURL& url) {
}
void CefBrowserHostImpl::PlatformHandleExternalProtocol(const GURL& url) {
}
void CefBrowserHostImpl::PlatformTranslateKeyEvent(
void CefBrowserPlatformDelegateNativeLinux::TranslateKeyEvent(
content::NativeWebKeyboardEvent& result,
const CefKeyEvent& key_event) {
const CefKeyEvent& key_event) const {
result.timeStampSeconds = GetSystemUptime();
result.windowsKeyCode = key_event.windows_key_code;
@ -322,12 +275,12 @@ void CefBrowserHostImpl::PlatformTranslateKeyEvent(
result.modifiers |= TranslateModifiers(key_event.modifiers);
}
void CefBrowserHostImpl::PlatformTranslateClickEvent(
void CefBrowserPlatformDelegateNativeLinux::TranslateClickEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
MouseButtonType type,
bool mouseUp, int clickCount) {
PlatformTranslateMouseEvent(result, mouse_event);
CefBrowserHost::MouseButtonType type,
bool mouseUp, int clickCount) const {
TranslateMouseEvent(result, mouse_event);
switch (type) {
case MBT_LEFT:
@ -352,11 +305,11 @@ void CefBrowserHostImpl::PlatformTranslateClickEvent(
result.clickCount = clickCount;
}
void CefBrowserHostImpl::PlatformTranslateMoveEvent(
void CefBrowserPlatformDelegateNativeLinux::TranslateMoveEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) {
PlatformTranslateMouseEvent(result, mouse_event);
bool mouseLeave) const {
TranslateMouseEvent(result, mouse_event);
if (!mouseLeave) {
result.type = blink::WebInputEvent::MouseMove;
@ -376,12 +329,12 @@ void CefBrowserHostImpl::PlatformTranslateMoveEvent(
result.clickCount = 0;
}
void CefBrowserHostImpl::PlatformTranslateWheelEvent(
void CefBrowserPlatformDelegateNativeLinux::TranslateWheelEvent(
blink::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX, int deltaY) {
int deltaX, int deltaY) const {
result = blink::WebMouseWheelEvent();
PlatformTranslateMouseEvent(result, mouse_event);
TranslateMouseEvent(result, mouse_event);
result.type = blink::WebInputEvent::MouseWheel;
@ -407,28 +360,30 @@ void CefBrowserHostImpl::PlatformTranslateWheelEvent(
result.button = blink::WebMouseEvent::ButtonNone;
}
void CefBrowserHostImpl::PlatformTranslateMouseEvent(
CefEventHandle CefBrowserPlatformDelegateNativeLinux::GetEventHandle(
const content::NativeWebKeyboardEvent& event) const {
if (!event.os_event)
return NULL;
return const_cast<CefEventHandle>(event.os_event->native_event());
}
scoped_ptr<CefMenuRunner>
CefBrowserPlatformDelegateNativeLinux::CreateMenuRunner() {
return make_scoped_ptr(new CefMenuRunnerLinux);
}
void CefBrowserPlatformDelegateNativeLinux::TranslateMouseEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event) {
const CefMouseEvent& mouse_event) const {
// position
result.x = mouse_event.x;
result.y = mouse_event.y;
result.windowX = result.x;
result.windowY = result.y;
result.globalX = result.x;
result.globalY = result.y;
if (IsWindowless()) {
CefRefPtr<CefRenderHandler> handler = client_->GetRenderHandler();
if (handler.get()) {
handler->GetScreenPoint(this, result.x, result.y, result.globalX,
result.globalY);
}
} else if (window_x11_) {
const gfx::Point& origin = window_x11_->bounds().origin();
result.globalX += origin.x();
result.globalY += origin.y();
}
const gfx::Point& screen_pt = GetScreenPoint(gfx::Point(result.x, result.y));
result.globalX = screen_pt.x();
result.globalY = screen_pt.y();
// modifiers
result.modifiers |= TranslateModifiers(mouse_event.modifiers);
@ -437,25 +392,3 @@ void CefBrowserHostImpl::PlatformTranslateMouseEvent(
result.timeStampSeconds = GetSystemUptime();
}
void CefBrowserHostImpl::PlatformNotifyMoveOrResizeStarted() {
if (IsWindowless())
return;
if (!window_x11_)
return;
views::DesktopWindowTreeHostX11* tree_host = window_x11_->GetHost();
if (!tree_host)
return;
// Explicitly set the screen bounds so that WindowTreeHost::*Screen()
// methods return the correct results.
const gfx::Rect& bounds = window_x11_->GetBoundsInScreen();
tree_host->set_screen_bounds(bounds);
// Send updated screen rectangle information to the renderer process so that
// popups are displayed in the correct location.
content::RenderWidgetHostImpl::From(
web_contents()->GetRenderViewHost()->GetWidget())->SendScreenRects();
}

View File

@ -0,0 +1,63 @@
// Copyright 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_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_LINUX_H_
#define CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_LINUX_H_
#include "libcef/browser/native/browser_platform_delegate_native.h"
class CefWindowX11;
// Windowed browser implementation for Linux.
class CefBrowserPlatformDelegateNativeLinux :
public CefBrowserPlatformDelegateNative {
public:
explicit CefBrowserPlatformDelegateNativeLinux(
const CefWindowInfo& window_info);
// CefBrowserPlatformDelegate methods:
void BrowserDestroyed(CefBrowserHostImpl* browser) override;
bool CreateHostWindow() override;
void CloseHostWindow() override;
CefWindowHandle GetHostWindowHandle() const override;
views::Widget* GetWindowWidget() const override;
void SendFocusEvent(bool setFocus) override;
void NotifyMoveOrResizeStarted() override;
void SizeTo(int width, int height) override;
gfx::Point GetScreenPoint(const gfx::Point& view) const override;
void ViewText(const std::string& text) override;
void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) override;
void HandleExternalProtocol(const GURL& url) override;
void TranslateKeyEvent(content::NativeWebKeyboardEvent& result,
const CefKeyEvent& key_event) const override;
void TranslateClickEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
CefBrowserHost::MouseButtonType type,
bool mouseUp, int clickCount) const override;
void TranslateMoveEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) const override;
void TranslateWheelEvent(blink::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX, int deltaY) const override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
scoped_ptr<CefMenuRunner> CreateMenuRunner() override;
private:
void TranslateMouseEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event) const;
// True if the host window has been created.
bool host_window_created_;
// Widget hosting the web contents. It will be deleted automatically when the
// associated root window is destroyed.
views::Widget* window_widget_;
CefWindowX11* window_x11_;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_LINUX_H_

View File

@ -0,0 +1,54 @@
// Copyright 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_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_MAC_H_
#define CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_MAC_H_
#include "libcef/browser/native/browser_platform_delegate_native.h"
// Windowed browser implementation for Mac OS X.
class CefBrowserPlatformDelegateNativeMac :
public CefBrowserPlatformDelegateNative {
public:
explicit CefBrowserPlatformDelegateNativeMac(
const CefWindowInfo& window_info);
// CefBrowserPlatformDelegate methods:
void BrowserDestroyed(CefBrowserHostImpl* browser) override;
bool CreateHostWindow() override;
void CloseHostWindow() override;
CefWindowHandle GetHostWindowHandle() const override;
void SendFocusEvent(bool setFocus) override;
gfx::Point GetScreenPoint(const gfx::Point& view) const override;
void ViewText(const std::string& text) override;
void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) override;
void HandleExternalProtocol(const GURL& url) override;
void TranslateKeyEvent(content::NativeWebKeyboardEvent& result,
const CefKeyEvent& key_event) const override;
void TranslateClickEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
CefBrowserHost::MouseButtonType type,
bool mouseUp, int clickCount) const override;
void TranslateMoveEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) const override;
void TranslateWheelEvent(blink::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX, int deltaY) const override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
scoped_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
scoped_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner() override;
scoped_ptr<CefMenuRunner> CreateMenuRunner() override;
private:
void TranslateMouseEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event) const;
// True if the host window has been created.
bool host_window_created_;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_MAC_H_

View File

@ -0,0 +1,536 @@
// Copyright 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 "libcef/browser/native/browser_platform_delegate_native_mac.h"
#import <Cocoa/Cocoa.h>
#import <CoreServices/CoreServices.h>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/context.h"
#include "libcef/browser/native/file_dialog_runner_mac.h"
#include "libcef/browser/native/javascript_dialog_runner_mac.h"
#include "libcef/browser/native/menu_runner_mac.h"
#include "libcef/browser/thread_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
#include "ui/events/keycodes/keyboard_codes_posix.h"
#include "ui/gfx/geometry/rect.h"
// Wrapper NSView for the native view. Necessary to destroy the browser when
// the view is deleted.
@interface CefBrowserHostView : NSView {
@private
CefBrowserHostImpl* browser_; // weak
}
@property (nonatomic, assign) CefBrowserHostImpl* browser;
@end
@implementation CefBrowserHostView
@synthesize browser = browser_;
- (void) dealloc {
if (browser_) {
// Force the browser to be destroyed and release the reference added in
// PlatformCreateWindow().
browser_->WindowDestroyed();
}
[super dealloc];
}
@end
// Receives notifications from the browser window. Will delete itself when done.
@interface CefWindowDelegate : NSObject <NSWindowDelegate> {
@private
CefBrowserHostImpl* browser_; // weak
NSWindow* window_;
}
- (id)initWithWindow:(NSWindow*)window andBrowser:(CefBrowserHostImpl*)browser;
@end
@implementation CefWindowDelegate
- (id)initWithWindow:(NSWindow*)window andBrowser:(CefBrowserHostImpl*)browser {
if (self = [super init]) {
window_ = window;
browser_ = browser;
[window_ setDelegate:self];
// Register for application hide/unhide notifications.
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationDidHide:)
name:NSApplicationDidHideNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationDidUnhide:)
name:NSApplicationDidUnhideNotification
object:nil];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
// Called when we are activated (when we gain focus).
- (void)windowDidBecomeKey:(NSNotification*)notification {
if (browser_)
browser_->SetFocus(true);
}
// Called when we are deactivated (when we lose focus).
- (void)windowDidResignKey:(NSNotification*)notification {
if (browser_)
browser_->SetFocus(false);
}
// Called when we have been minimized.
- (void)windowDidMiniaturize:(NSNotification *)notification {
if (browser_)
browser_->SetWindowVisibility(false);
}
// Called when we have been unminimized.
- (void)windowDidDeminiaturize:(NSNotification *)notification {
if (browser_)
browser_->SetWindowVisibility(true);
}
// Called when the application has been hidden.
- (void)applicationDidHide:(NSNotification *)notification {
// If the window is miniaturized then nothing has really changed.
if (![window_ isMiniaturized]) {
if (browser_)
browser_->SetWindowVisibility(false);
}
}
// Called when the application has been unhidden.
- (void)applicationDidUnhide:(NSNotification *)notification {
// If the window is miniaturized then nothing has really changed.
if (![window_ isMiniaturized]) {
if (browser_)
browser_->SetWindowVisibility(true);
}
}
- (BOOL)windowShouldClose:(id)window {
// Protect against multiple requests to close while the close is pending.
if (browser_ && browser_->destruction_state() <=
CefBrowserHostImpl::DESTRUCTION_STATE_PENDING) {
if (browser_->destruction_state() ==
CefBrowserHostImpl::DESTRUCTION_STATE_NONE) {
// Request that the browser close.
browser_->CloseBrowser(false);
}
// Cancel the close.
return NO;
}
// Clean ourselves up after clearing the stack of anything that might have the
// window on it.
[self performSelectorOnMainThread:@selector(cleanup:)
withObject:window
waitUntilDone:NO];
// Allow the close.
return YES;
}
- (void)cleanup:(id)window {
[self release];
}
@end
namespace {
NSTimeInterval currentEventTimestamp() {
NSEvent* currentEvent = [NSApp currentEvent];
if (currentEvent)
return [currentEvent timestamp];
else {
// FIXME(API): In case there is no current event, the timestamp could be
// obtained by getting the time since the application started. This involves
// taking some more static functions from Chromium code.
// Another option is to have the timestamp as a field in CefEvent structures
// and let the client provide it.
return 0;
}
}
NSUInteger NativeModifiers(int cef_modifiers) {
NSUInteger native_modifiers = 0;
if (cef_modifiers & EVENTFLAG_SHIFT_DOWN)
native_modifiers |= NSShiftKeyMask;
if (cef_modifiers & EVENTFLAG_CONTROL_DOWN)
native_modifiers |= NSControlKeyMask;
if (cef_modifiers & EVENTFLAG_ALT_DOWN)
native_modifiers |= NSAlternateKeyMask;
if (cef_modifiers & EVENTFLAG_COMMAND_DOWN)
native_modifiers |= NSCommandKeyMask;
if (cef_modifiers & EVENTFLAG_CAPS_LOCK_ON)
native_modifiers |= NSAlphaShiftKeyMask;
if (cef_modifiers & EVENTFLAG_NUM_LOCK_ON)
native_modifiers |= NSNumericPadKeyMask;
return native_modifiers;
}
} // namespace
CefBrowserPlatformDelegateNativeMac::CefBrowserPlatformDelegateNativeMac(
const CefWindowInfo& window_info)
: CefBrowserPlatformDelegateNative(window_info),
host_window_created_(false) {
}
void CefBrowserPlatformDelegateNativeMac::BrowserDestroyed(
CefBrowserHostImpl* browser) {
CefBrowserPlatformDelegate::BrowserDestroyed(browser);
if (host_window_created_) {
// Release the reference added in CreateHostWindow().
browser->Release();
}
}
bool CefBrowserPlatformDelegateNativeMac::CreateHostWindow() {
base::mac::ScopedNSAutoreleasePool autorelease_pool;
NSWindow* newWnd = nil;
NSView* parentView = window_info_.parent_view;
NSRect contentRect = {{window_info_.x, window_info_.y},
{window_info_.width, window_info_.height}};
if (parentView == nil) {
// Create a new window.
NSRect screen_rect = [[NSScreen mainScreen] visibleFrame];
NSRect window_rect = {{window_info_.x,
screen_rect.size.height - window_info_.y},
{window_info_.width, window_info_.height}};
if (window_rect.size.width == 0)
window_rect.size.width = 750;
if (window_rect.size.height == 0)
window_rect.size.height = 750;
contentRect.origin.x = 0;
contentRect.origin.y = 0;
contentRect.size.width = window_rect.size.width;
contentRect.size.height = window_rect.size.height;
newWnd = [[UnderlayOpenGLHostingWindow alloc]
initWithContentRect:window_rect
styleMask:(NSTitledWindowMask |
NSClosableWindowMask |
NSMiniaturizableWindowMask |
NSResizableWindowMask |
NSUnifiedTitleAndToolbarWindowMask )
backing:NSBackingStoreBuffered
defer:NO];
// Create the delegate for control and browser window events.
[[CefWindowDelegate alloc] initWithWindow:newWnd andBrowser:browser_];
parentView = [newWnd contentView];
window_info_.parent_view = parentView;
}
// Make the content view for the window have a layer. This will make all
// sub-views have layers. This is necessary to ensure correct layer
// ordering of all child views and their layers.
[[[parentView window] contentView] setWantsLayer:YES];
host_window_created_ = true;
// Add a reference that will be released in BrowserDestroyed().
browser_->AddRef();
// Create the browser view.
CefBrowserHostView* browser_view =
[[CefBrowserHostView alloc] initWithFrame:contentRect];
browser_view.browser = browser_;
[parentView addSubview:browser_view];
[browser_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[browser_view setNeedsDisplay:YES];
[browser_view release];
// Parent the TabContents to the browser view.
const NSRect bounds = [browser_view bounds];
NSView* native_view = browser_->web_contents()->GetNativeView();
[browser_view addSubview:native_view];
[native_view setFrame:bounds];
[native_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[native_view setNeedsDisplay:YES];
window_info_.view = browser_view;
if (newWnd != nil && !window_info_.hidden) {
// Show the window.
[newWnd makeKeyAndOrderFront: nil];
}
return true;
}
void CefBrowserPlatformDelegateNativeMac::CloseHostWindow() {
if (window_info_.view != nil) {
[[window_info_.view window]
performSelectorOnMainThread:@selector(performClose:)
withObject:nil
waitUntilDone:NO];
}
}
CefWindowHandle
CefBrowserPlatformDelegateNativeMac::GetHostWindowHandle() const {
if (windowless_handler_)
return windowless_handler_->GetParentWindowHandle();
return window_info_.view;
}
void CefBrowserPlatformDelegateNativeMac::SendFocusEvent(bool setFocus) {
content::RenderWidgetHostView* view =
browser_->web_contents()->GetRenderWidgetHostView();
if (view) {
view->SetActive(setFocus);
if (setFocus) {
// Give keyboard focus to the native view.
NSView* view = browser_->web_contents()->GetContentNativeView();
DCHECK([view canBecomeKeyView]);
[[view window] makeFirstResponder:view];
}
}
}
gfx::Point CefBrowserPlatformDelegateNativeMac::GetScreenPoint(
const gfx::Point& view) const {
if (windowless_handler_)
return windowless_handler_->GetParentScreenPoint(view);
NSView* nsview = window_info_.parent_view;
if (nsview) {
NSRect bounds = [nsview bounds];
NSPoint view_pt = {view.x(), bounds.size.height - view.y()};
NSPoint window_pt = [nsview convertPoint:view_pt toView:nil];
NSPoint screen_pt = [[nsview window] convertBaseToScreen:window_pt];
return gfx::Point(screen_pt.x, screen_pt.y);
}
return gfx::Point();
}
void CefBrowserPlatformDelegateNativeMac::ViewText(const std::string& text) {
// TODO(cef): Implement this functionality.
NOTIMPLEMENTED();
}
void CefBrowserPlatformDelegateNativeMac::HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) {
// Give the top level menu equivalents a chance to handle the event.
if ([event.os_event type] == NSKeyDown)
[[NSApp mainMenu] performKeyEquivalent:event.os_event];
}
void CefBrowserPlatformDelegateNativeMac::HandleExternalProtocol(
const GURL& url) {
}
void CefBrowserPlatformDelegateNativeMac::TranslateKeyEvent(
content::NativeWebKeyboardEvent& result,
const CefKeyEvent& key_event) const {
// Use a synthetic NSEvent in order to obtain the windowsKeyCode member from
// the NativeWebKeyboardEvent constructor. This is the only member which can
// not be easily translated (without hardcoding keyCodes)
// Determining whether a modifier key is left or right seems to be done
// through the key code as well.
NSEventType event_type;
if (key_event.character == 0 && key_event.unmodified_character == 0) {
// Check if both character and unmodified_characther are empty to determine
// if this was a NSFlagsChanged event.
// A dead key will have an empty character, but a non-empty unmodified
// character
event_type = NSFlagsChanged;
} else {
switch (key_event.type) {
case KEYEVENT_RAWKEYDOWN:
case KEYEVENT_KEYDOWN:
case KEYEVENT_CHAR:
event_type = NSKeyDown;
break;
case KEYEVENT_KEYUP:
event_type = NSKeyUp;
break;
}
}
NSString* charactersIgnoringModifiers = [[[NSString alloc]
initWithCharacters:&key_event.unmodified_character length:1]
autorelease];
NSString* characters = [[[NSString alloc]
initWithCharacters:&key_event.character length:1] autorelease];
NSEvent* synthetic_event =
[NSEvent keyEventWithType:event_type
location:NSMakePoint(0, 0)
modifierFlags:NativeModifiers(key_event.modifiers)
timestamp:currentEventTimestamp()
windowNumber:0
context:nil
characters:characters
charactersIgnoringModifiers:charactersIgnoringModifiers
isARepeat:NO
keyCode:key_event.native_key_code];
result = content::NativeWebKeyboardEvent(synthetic_event);
if (key_event.type == KEYEVENT_CHAR)
result.type = blink::WebInputEvent::Char;
result.isSystemKey = key_event.is_system_key;
}
void CefBrowserPlatformDelegateNativeMac::TranslateClickEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
CefBrowserHost::MouseButtonType type,
bool mouseUp, int clickCount) const {
TranslateMouseEvent(result, mouse_event);
switch (type) {
case MBT_LEFT:
result.type = mouseUp ? blink::WebInputEvent::MouseUp :
blink::WebInputEvent::MouseDown;
result.button = blink::WebMouseEvent::ButtonLeft;
break;
case MBT_MIDDLE:
result.type = mouseUp ? blink::WebInputEvent::MouseUp :
blink::WebInputEvent::MouseDown;
result.button = blink::WebMouseEvent::ButtonMiddle;
break;
case MBT_RIGHT:
result.type = mouseUp ? blink::WebInputEvent::MouseUp :
blink::WebInputEvent::MouseDown;
result.button = blink::WebMouseEvent::ButtonRight;
break;
default:
NOTREACHED();
}
result.clickCount = clickCount;
}
void CefBrowserPlatformDelegateNativeMac::TranslateMoveEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) const {
TranslateMouseEvent(result, mouse_event);
if (!mouseLeave) {
result.type = blink::WebInputEvent::MouseMove;
if (mouse_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonLeft;
else if (mouse_event.modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonMiddle;
else if (mouse_event.modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonRight;
else
result.button = blink::WebMouseEvent::ButtonNone;
} else {
result.type = blink::WebInputEvent::MouseLeave;
result.button = blink::WebMouseEvent::ButtonNone;
}
result.clickCount = 0;
}
void CefBrowserPlatformDelegateNativeMac::TranslateWheelEvent(
blink::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX, int deltaY) const {
result = blink::WebMouseWheelEvent();
TranslateMouseEvent(result, mouse_event);
result.type = blink::WebInputEvent::MouseWheel;
static const double scrollbarPixelsPerCocoaTick = 40.0;
result.deltaX = deltaX;
result.deltaY = deltaY;
result.wheelTicksX = result.deltaX / scrollbarPixelsPerCocoaTick;
result.wheelTicksY = result.deltaY / scrollbarPixelsPerCocoaTick;
result.hasPreciseScrollingDeltas = true;
// Unless the phase and momentumPhase are passed in as parameters to this
// function, there is no way to know them
result.phase = blink::WebMouseWheelEvent::PhaseNone;
result.momentumPhase = blink::WebMouseWheelEvent::PhaseNone;
if (mouse_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonLeft;
else if (mouse_event.modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonMiddle;
else if (mouse_event.modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonRight;
else
result.button = blink::WebMouseEvent::ButtonNone;
}
CefEventHandle CefBrowserPlatformDelegateNativeMac::GetEventHandle(
const content::NativeWebKeyboardEvent& event) const {
return event.os_event;
}
scoped_ptr<CefFileDialogRunner>
CefBrowserPlatformDelegateNativeMac::CreateFileDialogRunner() {
return make_scoped_ptr(new CefFileDialogRunnerMac);
}
scoped_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegateNativeMac::CreateJavaScriptDialogRunner() {
return make_scoped_ptr(new CefJavaScriptDialogRunnerMac);
}
scoped_ptr<CefMenuRunner>
CefBrowserPlatformDelegateNativeMac::CreateMenuRunner() {
return make_scoped_ptr(new CefMenuRunnerMac);
}
void CefBrowserPlatformDelegateNativeMac::TranslateMouseEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event) const {
// position
result.x = mouse_event.x;
result.y = mouse_event.y;
result.windowX = result.x;
result.windowY = result.y;
const gfx::Point& screen_pt = GetScreenPoint(gfx::Point(result.x, result.y));
result.globalX = screen_pt.x();
result.globalY = screen_pt.y();
// modifiers
result.modifiers |= TranslateModifiers(mouse_event.modifiers);
// timestamp - Mac OSX specific
result.timeStampSeconds = currentEventTimestamp();
}

View File

@ -0,0 +1,637 @@
// Copyright 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 "libcef/browser/native/browser_platform_delegate_native_win.h"
#include <shellapi.h>
#include <wininet.h>
#include <winspool.h>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/context.h"
#include "libcef/browser/native/file_dialog_runner_win.h"
#include "libcef/browser/native/javascript_dialog_runner_win.h"
#include "libcef/browser/native/menu_runner_win.h"
#include "libcef/browser/native/window_delegate_view.h"
#include "libcef/browser/thread_util.h"
#include "base/files/file_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "ui/aura/window.h"
#include "ui/base/win/shell.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
#include "ui/views/widget/widget.h"
#include "ui/views/win/hwnd_util.h"
#pragma comment(lib, "dwmapi.lib")
namespace {
void WriteTempFileAndView(scoped_refptr<base::RefCountedString> str) {
CEF_REQUIRE_FILET();
base::FilePath tmp_file;
if (!base::CreateTemporaryFile(&tmp_file))
return;
// The shell command will look at the file extension to identify the correct
// program to open.
tmp_file = tmp_file.AddExtension(L"txt");
const std::string& data = str->data();
int write_ct = base::WriteFile(tmp_file, data.c_str(), data.size());
DCHECK_EQ(static_cast<int>(data.size()), write_ct);
ui::win::OpenFileViaShell(tmp_file);
}
// According to Mozilla in uriloader/exthandler/win/nsOSHelperAppService.cpp:
// "Some versions of windows (Win2k before SP3, Win XP before SP1) crash in
// ShellExecute on long URLs (bug 161357 on bugzilla.mozilla.org). IE 5 and 6
// support URLS of 2083 chars in length, 2K is safe."
const int kMaxAddressLengthChars = 2048;
bool HasExternalHandler(const std::string& scheme) {
base::win::RegKey key;
const std::wstring registry_path =
base::ASCIIToUTF16(scheme + "\\shell\\open\\command");
key.Open(HKEY_CLASSES_ROOT, registry_path.c_str(), KEY_READ);
if (key.Valid()) {
DWORD size = 0;
key.ReadValue(NULL, NULL, &size, NULL);
if (size > 2) {
// ShellExecute crashes the process when the command is empty.
// We check for "2" because it always returns the trailing NULL.
return true;
}
}
return false;
}
void ExecuteExternalProtocol(const GURL& url) {
CEF_REQUIRE_FILET();
if (!HasExternalHandler(url.scheme()))
return;
const std::string& address = url.spec();
if (address.length() > kMaxAddressLengthChars)
return;
ShellExecuteA(NULL, "open", address.c_str(), NULL, NULL, SW_SHOWNORMAL);
}
WORD KeyStatesToWord() {
static const USHORT kHighBitMaskShort = 0x8000;
WORD result = 0;
if (GetKeyState(VK_CONTROL) & kHighBitMaskShort)
result |= MK_CONTROL;
if (GetKeyState(VK_SHIFT) & kHighBitMaskShort)
result |= MK_SHIFT;
if (GetKeyState(VK_LBUTTON) & kHighBitMaskShort)
result |= MK_LBUTTON;
if (GetKeyState(VK_MBUTTON) & kHighBitMaskShort)
result |= MK_MBUTTON;
if (GetKeyState(VK_RBUTTON) & kHighBitMaskShort)
result |= MK_RBUTTON;
return result;
}
} // namespace
CefBrowserPlatformDelegateNativeWin::CefBrowserPlatformDelegateNativeWin(
const CefWindowInfo& window_info)
: CefBrowserPlatformDelegateNative(window_info),
host_window_created_(false),
window_widget_(nullptr) {
}
void CefBrowserPlatformDelegateNativeWin::BrowserDestroyed(
CefBrowserHostImpl* browser) {
CefBrowserPlatformDelegate::BrowserDestroyed(browser);
if (host_window_created_) {
// Release the reference added in CreateHostWindow().
browser->Release();
}
}
bool CefBrowserPlatformDelegateNativeWin::CreateHostWindow() {
RegisterWindowClass();
std::wstring windowName(CefString(&window_info_.window_name));
// Create the new browser window.
window_info_.window = CreateWindowEx(window_info_.ex_style,
GetWndClass(), windowName.c_str(), window_info_.style,
window_info_.x, window_info_.y, window_info_.width,
window_info_.height, window_info_.parent_window, window_info_.menu,
::GetModuleHandle(NULL), NULL);
// It's possible for CreateWindowEx to fail if the parent window was
// destroyed between the call to CreateBrowser and the above one.
DCHECK(window_info_.window != NULL);
if (!window_info_.window)
return false;
host_window_created_ = true;
// Set window user data to this object for future reference from the window
// procedure.
gfx::SetWindowUserData(window_info_.window, this);
// Add a reference that will later be released in DestroyBrowser().
browser_->AddRef();
RECT cr;
GetClientRect(window_info_.window, &cr);
DCHECK(!window_widget_);
SkColor background_color = SK_ColorWHITE;
const CefSettings& settings = CefContext::Get()->settings();
if (CefColorGetA(settings.background_color) > 0) {
background_color = SkColorSetRGB(
CefColorGetR(settings.background_color),
CefColorGetG(settings.background_color),
CefColorGetB(settings.background_color));
}
// Adjust for potential display scaling.
gfx::Point point = gfx::Point(cr.right, cr.bottom);
float scale = gfx::Screen::GetNativeScreen()->
GetDisplayNearestPoint(point).device_scale_factor();
point = gfx::ToFlooredPoint(
gfx::ScalePoint(gfx::PointF(point), 1.0f / scale));
CefWindowDelegateView* delegate_view =
new CefWindowDelegateView(background_color);
delegate_view->Init(window_info_.window,
browser_->web_contents(),
gfx::Rect(0, 0, point.x(), point.y()));
window_widget_ = delegate_view->GetWidget();
window_widget_->Show();
return true;
}
void CefBrowserPlatformDelegateNativeWin::CloseHostWindow() {
if (window_info_.window != NULL) {
HWND frameWnd = GetAncestor(window_info_.window, GA_ROOT);
PostMessage(frameWnd, WM_CLOSE, 0, 0);
}
}
CefWindowHandle
CefBrowserPlatformDelegateNativeWin::GetHostWindowHandle() const {
if (windowless_handler_)
return windowless_handler_->GetParentWindowHandle();
return window_info_.window;
}
views::Widget* CefBrowserPlatformDelegateNativeWin::GetWindowWidget() const {
return window_widget_;
}
void CefBrowserPlatformDelegateNativeWin::SendFocusEvent(bool setFocus) {
if (!setFocus)
return;
if (browser_->web_contents()) {
// Give logical focus to the RenderWidgetHostViewAura in the views
// hierarchy. This does not change the native keyboard focus.
browser_->web_contents()->Focus();
}
if (window_widget_) {
// Give native focus to the DesktopWindowTreeHostWin associated with the
// root window.
//
// The DesktopWindowTreeHostWin HandleNativeFocus/HandleNativeBlur methods
// are called in response to WM_SETFOCUS/WM_KILLFOCUS respectively. The
// implementation has been patched to call HandleActivationChanged which
// results in the following behaviors:
// 1. Update focus/activation state of the aura::Window indirectly via
// wm::FocusController. This allows focus-related behaviors (e.g. focus
// rings, flashing caret, onFocus/onBlur JS events, etc.) to work as
// expected (see issue #1677).
// 2. Update focus state of the ui::InputMethod. If this does not occur
// then InputMethodBase::GetTextInputClient will return NULL and
// InputMethodWin::OnChar will fail to sent character events to the
// renderer (see issue #1700).
//
// This differs from activation in Chrome which is handled via
// HWNDMessageHandler::PostProcessActivateMessage (Widget::Show indirectly
// calls HWNDMessageHandler::Activate which calls ::SetForegroundWindow
// resulting in a WM_ACTIVATE message being sent to the window). The Chrome
// code path doesn't work for CEF because IsTopLevelWindow in
// hwnd_message_handler.cc will return false and consequently
// HWNDMessageHandler::PostProcessActivateMessage will not be called.
//
// Activation events are usually reserved for the top-level window so
// triggering activation based on focus events may be incorrect in some
// circumstances. Revisit this implementation if additional problems are
// discovered.
::SetFocus(HWNDForWidget(window_widget_));
}
}
void CefBrowserPlatformDelegateNativeWin::NotifyMoveOrResizeStarted() {
// Call the parent method to dismiss any existing popups.
CefBrowserPlatformDelegate::NotifyMoveOrResizeStarted();
if (!window_widget_)
return;
// Notify DesktopWindowTreeHostWin of move events so that screen rectangle
// information is communicated to the renderer process and popups are
// displayed in the correct location.
views::DesktopWindowTreeHostWin* tree_host =
static_cast<views::DesktopWindowTreeHostWin*>(
aura::WindowTreeHost::GetForAcceleratedWidget(
HWNDForWidget(window_widget_)));
DCHECK(tree_host);
if (tree_host) {
// Cast to HWNDMessageHandlerDelegate so we can access HandleMove().
static_cast<views::HWNDMessageHandlerDelegate*>(tree_host)->HandleMove();
}
}
void CefBrowserPlatformDelegateNativeWin::SizeTo(int width, int height) {
HWND window = window_info_.window;
RECT rect = {0, 0, width, height};
DWORD style = GetWindowLong(window, GWL_STYLE);
DWORD ex_style = GetWindowLong(window, GWL_EXSTYLE);
bool has_menu = !(style & WS_CHILD) && (GetMenu(window) != NULL);
// The size value is for the client area. Calculate the whole window size
// based on the current style.
AdjustWindowRectEx(&rect, style, has_menu, ex_style);
// Size the window.
SetWindowPos(window, NULL, 0, 0, rect.right,
rect.bottom, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
}
gfx::Point CefBrowserPlatformDelegateNativeWin::GetScreenPoint(
const gfx::Point& view) const {
if (windowless_handler_)
return windowless_handler_->GetParentScreenPoint(view);
if (!window_widget_)
return view;
aura::Window* window = window_widget_->GetNativeView();
const gfx::Rect& bounds_in_screen = window->GetBoundsInScreen();
const gfx::Point& screen_point = gfx::Point(bounds_in_screen.x() + view.x(),
bounds_in_screen.y() + view.y());
// Adjust for potential display scaling.
float scale = gfx::Screen::GetScreenFor(window)->
GetDisplayNearestWindow(window).device_scale_factor();
return gfx::ToFlooredPoint(
gfx::ScalePoint(gfx::PointF(screen_point), scale));
}
void CefBrowserPlatformDelegateNativeWin::ViewText(const std::string& text) {
std::string str = text;
scoped_refptr<base::RefCountedString> str_ref =
base::RefCountedString::TakeString(&str);
CEF_POST_TASK(CEF_FILET, base::Bind(WriteTempFileAndView, str_ref));
}
void CefBrowserPlatformDelegateNativeWin::HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) {
// Any unhandled keyboard/character messages are sent to DefWindowProc so that
// shortcut keys work correctly.
if (event.os_event) {
const MSG& msg = event.os_event->native_event();
DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
} else {
MSG msg = {};
msg.hwnd = GetHostWindowHandle();
if (!msg.hwnd)
return;
switch (event.type) {
case blink::WebInputEvent::RawKeyDown:
msg.message = event.isSystemKey ? WM_SYSKEYDOWN : WM_KEYDOWN;
break;
case blink::WebInputEvent::KeyUp:
msg.message = event.isSystemKey ? WM_SYSKEYUP : WM_KEYUP;
break;
case blink::WebInputEvent::Char:
msg.message = event.isSystemKey ? WM_SYSCHAR: WM_CHAR;
break;
default:
NOTREACHED();
return;
}
msg.wParam = event.windowsKeyCode;
UINT scan_code = ::MapVirtualKeyW(event.windowsKeyCode, MAPVK_VK_TO_VSC);
msg.lParam = (scan_code << 16) | // key scan code
1; // key repeat count
if (event.modifiers & content::NativeWebKeyboardEvent::AltKey)
msg.lParam |= (1 << 29);
DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
}
void CefBrowserPlatformDelegateNativeWin::HandleExternalProtocol(
const GURL& url) {
// Execute on the FILE thread.
CEF_POST_TASK(CEF_FILET,
base::Bind(ExecuteExternalProtocol, url));
}
void CefBrowserPlatformDelegateNativeWin::TranslateKeyEvent(
content::NativeWebKeyboardEvent& result,
const CefKeyEvent& key_event) const {
result.timeStampSeconds = GetMessageTime() / 1000.0;
result.windowsKeyCode = key_event.windows_key_code;
result.nativeKeyCode = key_event.native_key_code;
result.isSystemKey = key_event.is_system_key ? 1 : 0;
switch (key_event.type) {
case KEYEVENT_RAWKEYDOWN:
case KEYEVENT_KEYDOWN:
result.type = blink::WebInputEvent::RawKeyDown;
break;
case KEYEVENT_KEYUP:
result.type = blink::WebInputEvent::KeyUp;
break;
case KEYEVENT_CHAR:
result.type = blink::WebInputEvent::Char;
break;
default:
NOTREACHED();
}
if (result.type == blink::WebInputEvent::Char ||
result.type == blink::WebInputEvent::RawKeyDown) {
result.text[0] = result.windowsKeyCode;
result.unmodifiedText[0] = result.windowsKeyCode;
}
if (result.type != blink::WebInputEvent::Char)
result.setKeyIdentifierFromWindowsKeyCode();
result.modifiers |= TranslateModifiers(key_event.modifiers);
}
void CefBrowserPlatformDelegateNativeWin::TranslateClickEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
CefBrowserHost::MouseButtonType type,
bool mouseUp, int clickCount) const {
TranslateMouseEvent(result, mouse_event);
switch (type) {
case MBT_LEFT:
result.type = mouseUp ? blink::WebInputEvent::MouseUp :
blink::WebInputEvent::MouseDown;
result.button = blink::WebMouseEvent::ButtonLeft;
break;
case MBT_MIDDLE:
result.type = mouseUp ? blink::WebInputEvent::MouseUp :
blink::WebInputEvent::MouseDown;
result.button = blink::WebMouseEvent::ButtonMiddle;
break;
case MBT_RIGHT:
result.type = mouseUp ? blink::WebInputEvent::MouseUp :
blink::WebInputEvent::MouseDown;
result.button = blink::WebMouseEvent::ButtonRight;
break;
default:
NOTREACHED();
}
result.clickCount = clickCount;
}
void CefBrowserPlatformDelegateNativeWin::TranslateMoveEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) const {
TranslateMouseEvent(result, mouse_event);
if (!mouseLeave) {
result.type = blink::WebInputEvent::MouseMove;
if (mouse_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonLeft;
else if (mouse_event.modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonMiddle;
else if (mouse_event.modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON)
result.button = blink::WebMouseEvent::ButtonRight;
else
result.button = blink::WebMouseEvent::ButtonNone;
} else {
result.type = blink::WebInputEvent::MouseLeave;
result.button = blink::WebMouseEvent::ButtonNone;
}
result.clickCount = 0;
}
void CefBrowserPlatformDelegateNativeWin::TranslateWheelEvent(
blink::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX, int deltaY) const {
TranslateMouseEvent(result, mouse_event);
result.type = blink::WebInputEvent::MouseWheel;
result.button = blink::WebMouseEvent::ButtonNone;
float wheelDelta;
bool horizontalScroll = false;
wheelDelta = static_cast<float>(deltaY ? deltaY : deltaX);
horizontalScroll = (deltaY == 0);
static const ULONG defaultScrollCharsPerWheelDelta = 1;
static const FLOAT scrollbarPixelsPerLine = 100.0f / 3.0f;
static const ULONG defaultScrollLinesPerWheelDelta = 3;
wheelDelta /= WHEEL_DELTA;
float scrollDelta = wheelDelta;
if (horizontalScroll) {
ULONG scrollChars = defaultScrollCharsPerWheelDelta;
SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &scrollChars, 0);
scrollDelta *= static_cast<FLOAT>(scrollChars) * scrollbarPixelsPerLine;
} else {
ULONG scrollLines = defaultScrollLinesPerWheelDelta;
SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0);
if (scrollLines == WHEEL_PAGESCROLL)
result.scrollByPage = true;
if (!result.scrollByPage)
scrollDelta *= static_cast<FLOAT>(scrollLines) * scrollbarPixelsPerLine;
}
// Set scroll amount based on above calculations. WebKit expects positive
// deltaY to mean "scroll up" and positive deltaX to mean "scroll left".
if (horizontalScroll) {
result.deltaX = scrollDelta;
result.wheelTicksX = wheelDelta;
} else {
result.deltaY = scrollDelta;
result.wheelTicksY = wheelDelta;
}
}
CefEventHandle CefBrowserPlatformDelegateNativeWin::GetEventHandle(
const content::NativeWebKeyboardEvent& event) const {
if (!event.os_event)
return NULL;
return const_cast<CefEventHandle>(&event.os_event->native_event());
}
scoped_ptr<CefFileDialogRunner>
CefBrowserPlatformDelegateNativeWin::CreateFileDialogRunner() {
return make_scoped_ptr(new CefFileDialogRunnerWin);
}
scoped_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegateNativeWin::CreateJavaScriptDialogRunner() {
return make_scoped_ptr(new CefJavaScriptDialogRunnerWin);
}
scoped_ptr<CefMenuRunner>
CefBrowserPlatformDelegateNativeWin::CreateMenuRunner() {
return make_scoped_ptr(new CefMenuRunnerWin);
}
void CefBrowserPlatformDelegateNativeWin::TranslateMouseEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event) const {
// position
result.x = mouse_event.x;
result.y = mouse_event.y;
result.windowX = result.x;
result.windowY = result.y;
const gfx::Point& screen_pt = GetScreenPoint(gfx::Point(result.x, result.y));
result.globalX = screen_pt.x();
result.globalY = screen_pt.y();
// modifiers
result.modifiers |= TranslateModifiers(mouse_event.modifiers);
// timestamp
result.timeStampSeconds = GetMessageTime() / 1000.0;
}
// static
void CefBrowserPlatformDelegateNativeWin::RegisterWindowClass() {
static bool registered = false;
if (registered)
return;
// Register the window class
WNDCLASSEX wcex = {
/* cbSize = */ sizeof(WNDCLASSEX),
/* style = */ CS_HREDRAW | CS_VREDRAW,
/* lpfnWndProc = */ CefBrowserPlatformDelegateNativeWin::WndProc,
/* cbClsExtra = */ 0,
/* cbWndExtra = */ 0,
/* hInstance = */ ::GetModuleHandle(NULL),
/* hIcon = */ NULL,
/* hCursor = */ LoadCursor(NULL, IDC_ARROW),
/* hbrBackground = */ 0,
/* lpszMenuName = */ NULL,
/* lpszClassName = */ CefBrowserPlatformDelegateNativeWin::GetWndClass(),
/* hIconSm = */ NULL,
};
RegisterClassEx(&wcex);
registered = true;
}
// static
LPCTSTR CefBrowserPlatformDelegateNativeWin::GetWndClass() {
return L"CefBrowserWindow";
}
// static
LRESULT CALLBACK CefBrowserPlatformDelegateNativeWin::WndProc(
HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam) {
CefBrowserPlatformDelegateNativeWin* platform_delegate =
static_cast<CefBrowserPlatformDelegateNativeWin*>(
gfx::GetWindowUserData(hwnd));
CefBrowserHostImpl* browser = nullptr;
if (platform_delegate)
browser = platform_delegate->browser_;
switch (message) {
case WM_CLOSE:
// Protect against multiple requests to close while the close is pending.
if (browser &&
browser->destruction_state() <=
CefBrowserHostImpl::DESTRUCTION_STATE_PENDING) {
if (browser->destruction_state() ==
CefBrowserHostImpl::DESTRUCTION_STATE_NONE) {
// Request that the browser close.
browser->CloseBrowser(false);
}
// Cancel the close.
return 0;
}
// Allow the close.
break;
case WM_DESTROY:
if (platform_delegate) {
// Clear the user data pointer.
gfx::SetWindowUserData(hwnd, NULL);
// Force the browser to be destroyed. This will result in a call to
// BrowserDestroyed() that will release the reference added in
// CreateHostWindow().
browser->WindowDestroyed();
}
return 0;
case WM_SIZE:
if (platform_delegate && platform_delegate->window_widget_) {
// Pass window resize events to the HWND for the DesktopNativeWidgetAura
// root window. Passing size 0x0 (wParam == SIZE_MINIMIZED, for example)
// will cause the widget to be hidden which reduces resource usage.
RECT rc;
GetClientRect(hwnd, &rc);
SetWindowPos(HWNDForWidget(platform_delegate->window_widget_), NULL,
rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
SWP_NOZORDER);
}
return 0;
case WM_MOVING:
case WM_MOVE:
if (browser)
browser->NotifyMoveOrResizeStarted();
return 0;
case WM_SETFOCUS:
if (browser)
browser->SetFocus(true);
return 0;
case WM_ERASEBKGND:
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}

View File

@ -0,0 +1,68 @@
// Copyright 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_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_WIN_H_
#define CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_WIN_H_
#include <windows.h>
#include "libcef/browser/native/browser_platform_delegate_native.h"
// Windowed browser implementation for Windows.
class CefBrowserPlatformDelegateNativeWin :
public CefBrowserPlatformDelegateNative {
public:
explicit CefBrowserPlatformDelegateNativeWin(
const CefWindowInfo& window_info);
// CefBrowserPlatformDelegate methods:
void BrowserDestroyed(CefBrowserHostImpl* browser) override;
bool CreateHostWindow() override;
void CloseHostWindow() override;
CefWindowHandle GetHostWindowHandle() const override;
views::Widget* GetWindowWidget() const override;
void SendFocusEvent(bool setFocus) override;
void NotifyMoveOrResizeStarted() override;
void SizeTo(int width, int height) override;
gfx::Point GetScreenPoint(const gfx::Point& view) const override;
void ViewText(const std::string& text) override;
void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) override;
void HandleExternalProtocol(const GURL& url) override;
void TranslateKeyEvent(content::NativeWebKeyboardEvent& result,
const CefKeyEvent& key_event) const override;
void TranslateClickEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
CefBrowserHost::MouseButtonType type,
bool mouseUp, int clickCount) const override;
void TranslateMoveEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) const override;
void TranslateWheelEvent(blink::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX, int deltaY) const override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
scoped_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
scoped_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner() override;
scoped_ptr<CefMenuRunner> CreateMenuRunner() override;
private:
void TranslateMouseEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event) const;
static void RegisterWindowClass();
static LPCTSTR GetWndClass();
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam);
// True if the host window has been created.
bool host_window_created_;
// Widget hosting the web contents. It will be deleted automatically when the
// associated root window is destroyed.
views::Widget* window_widget_;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_WIN_H_

View File

@ -0,0 +1,22 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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.
#ifndef CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_MAC_H_
#define CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_MAC_H_
#pragma once
#include "libcef/browser/file_dialog_runner.h"
class CefFileDialogRunnerMac : public CefFileDialogRunner {
public:
CefFileDialogRunnerMac();
// CefFileDialogRunner methods:
void Run(CefBrowserHostImpl* browser,
const FileChooserParams& params,
RunFileChooserCallback callback) override;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_MAC_H_

View File

@ -0,0 +1,406 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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 "libcef/browser/native/file_dialog_runner_mac.h"
#import <Cocoa/Cocoa.h>
#import <CoreServices/CoreServices.h>
#include "libcef/browser/browser_host_impl.h"
#include "base/mac/mac_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/common/file_chooser_params.h"
#include "grit/cef_strings.h"
#include "grit/ui_strings.h"
#include "net/base/mime_util.h"
#include "ui/base/l10n/l10n_util.h"
namespace {
base::string16 GetDescriptionFromMimeType(const std::string& mime_type) {
// Check for wild card mime types and return an appropriate description.
static const struct {
const char* mime_type;
int string_id;
} kWildCardMimeTypes[] = {
{ "audio", IDS_APP_AUDIO_FILES },
{ "image", IDS_APP_IMAGE_FILES },
{ "text", IDS_APP_TEXT_FILES },
{ "video", IDS_APP_VIDEO_FILES },
};
for (size_t i = 0; i < arraysize(kWildCardMimeTypes); ++i) {
if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*")
return l10n_util::GetStringUTF16(kWildCardMimeTypes[i].string_id);
}
return base::string16();
}
void AddFilters(NSPopUpButton *button,
const std::vector<base::string16>& accept_filters,
bool include_all_files,
std::vector<std::vector<base::string16> >* all_extensions) {
for (size_t i = 0; i < accept_filters.size(); ++i) {
const base::string16& filter = accept_filters[i];
if (filter.empty())
continue;
std::vector<base::string16> extensions;
base::string16 description;
size_t sep_index = filter.find('|');
if (sep_index != std::string::npos) {
// Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3".
description = filter.substr(0, sep_index);
const std::vector<base::string16>& ext =
base::SplitString(filter.substr(sep_index + 1),
base::ASCIIToUTF16(";"),
base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
for (size_t x = 0; x < ext.size(); ++x) {
const base::string16& file_ext = ext[x];
if (!file_ext.empty() && file_ext[0] == '.')
extensions.push_back(file_ext);
}
} else if (filter[0] == '.') {
// Treat as an extension beginning with the '.' character.
extensions.push_back(filter);
} else {
// Otherwise convert mime type to one or more extensions.
const std::string& ascii = base::UTF16ToASCII(filter);
std::vector<base::FilePath::StringType> ext;
net::GetExtensionsForMimeType(ascii, &ext);
if (!ext.empty()) {
for (size_t x = 0; x < ext.size(); ++x)
extensions.push_back(base::ASCIIToUTF16("." + ext[x]));
description = GetDescriptionFromMimeType(ascii);
}
}
if (extensions.empty())
continue;
// Don't display a crazy number of extensions since the NSPopUpButton width
// will keep growing.
const size_t kMaxExtensions = 10;
base::string16 ext_str;
for (size_t x = 0; x < std::min(kMaxExtensions, extensions.size()); ++x) {
const base::string16& pattern = base::ASCIIToUTF16("*") + extensions[x];
if (x != 0)
ext_str += base::ASCIIToUTF16(";");
ext_str += pattern;
}
if (extensions.size() > kMaxExtensions)
ext_str += base::ASCIIToUTF16(";...");
if (description.empty()) {
description = ext_str;
} else {
description +=
base::ASCIIToUTF16(" (") + ext_str + base::ASCIIToUTF16(")");
}
[button addItemWithTitle:base::SysUTF16ToNSString(description)];
all_extensions->push_back(extensions);
}
// Add the *.* filter, but only if we have added other filters (otherwise it
// is implied).
if (include_all_files && !all_extensions->empty()) {
[button addItemWithTitle:base::SysUTF8ToNSString("All Files (*)")];
all_extensions->push_back(std::vector<base::string16>());
}
}
} // namespace
// Used to manage the file type filter in the NSSavePanel/NSOpenPanel.
@interface CefFilterDelegate : NSObject {
@private
NSSavePanel* panel_;
std::vector<std::vector<base::string16> > extensions_;
int selected_index_;
}
- (id)initWithPanel:(NSSavePanel*)panel
andAcceptFilters:(const std::vector<base::string16>&)accept_filters
andFilterIndex:(int)index;
- (void)setFilter:(int)index;
- (int)filter;
- (void)filterSelectionChanged:(id)sender;
- (void)setFileExtension;
@end
@implementation CefFilterDelegate
- (id)initWithPanel:(NSSavePanel*)panel
andAcceptFilters:(const std::vector<base::string16>&)accept_filters
andFilterIndex:(int)index {
if (self = [super init]) {
DCHECK(panel);
panel_ = panel;
selected_index_ = 0;
NSPopUpButton *button = [[NSPopUpButton alloc] init];
AddFilters(button, accept_filters, true, &extensions_);
[button sizeToFit];
[button setTarget:self];
[button setAction:@selector(filterSelectionChanged:)];
if (index < static_cast<int>(extensions_.size())) {
[button selectItemAtIndex:index];
[self setFilter:index];
}
[panel_ setAccessoryView:button];
}
return self;
}
// Set the current filter index.
- (void)setFilter:(int)index {
DCHECK(index >= 0 && index < static_cast<int>(extensions_.size()));
selected_index_ = index;
// Set the selectable file types. For open panels this limits the files that
// can be selected. For save panels this applies a default file extenion when
// the dialog is dismissed if none is already provided.
NSMutableArray* acceptArray = nil;
if (!extensions_[index].empty()) {
acceptArray = [[NSMutableArray alloc] init];
for (size_t i = 0; i < extensions_[index].size(); ++i) {
[acceptArray addObject:
base::SysUTF16ToNSString(extensions_[index][i].substr(1))];
}
}
[panel_ setAllowedFileTypes:acceptArray];
if (![panel_ isKindOfClass:[NSOpenPanel class]]) {
// For save panels set the file extension.
[self setFileExtension];
}
}
// Returns the current filter index.
- (int)filter {
return selected_index_;
}
// Called when the selected filter is changed via the NSPopUpButton.
- (void)filterSelectionChanged:(id)sender {
NSPopUpButton *button = (NSPopUpButton*)sender;
[self setFilter:[button indexOfSelectedItem]];
}
// Set the extension on the currently selected file name.
- (void)setFileExtension {
const std::vector<base::string16>& filter = extensions_[selected_index_];
if (filter.empty()) {
// All extensions are allowed so don't change anything.
return;
}
base::FilePath path(base::SysNSStringToUTF8([panel_ nameFieldStringValue]));
// If the file name currently includes an extension from |filter| then don't
// change anything.
base::string16 extension = base::UTF8ToUTF16(path.Extension());
if (!extension.empty()) {
for (size_t i = 0; i < filter.size(); ++i) {
if (filter[i] == extension)
return;
}
}
// Change the extension to the first value in |filter|.
path = path.ReplaceExtension(base::UTF16ToUTF8(filter[0]));
[panel_ setNameFieldStringValue:base::SysUTF8ToNSString(path.value())];
}
@end
namespace {
void RunOpenFileDialog(
const CefFileDialogRunner::FileChooserParams& params,
NSView* view,
int* filter_index,
std::vector<base::FilePath>* files) {
NSOpenPanel* openPanel = [NSOpenPanel openPanel];
base::string16 title;
if (!params.title.empty()) {
title = params.title;
} else {
title = l10n_util::GetStringUTF16(
params.mode == content::FileChooserParams::Open ?
IDS_OPEN_FILE_DIALOG_TITLE :
(params.mode == content::FileChooserParams::OpenMultiple ?
IDS_OPEN_FILES_DIALOG_TITLE : IDS_SELECT_FOLDER_DIALOG_TITLE));
}
[openPanel setTitle:base::SysUTF16ToNSString(title)];
std::string filename, directory;
if (!params.default_file_name.empty()) {
if (params.mode == content::FileChooserParams::UploadFolder ||
params.default_file_name.EndsWithSeparator()) {
// The value is only a directory.
directory = params.default_file_name.value();
} else {
// The value is a file name and possibly a directory.
filename = params.default_file_name.BaseName().value();
directory = params.default_file_name.DirName().value();
}
}
if (!filename.empty()) {
[openPanel setNameFieldStringValue:base::SysUTF8ToNSString(filename)];
}
if (!directory.empty()) {
[openPanel setDirectoryURL:
[NSURL fileURLWithPath:base::SysUTF8ToNSString(directory)]];
}
CefFilterDelegate* filter_delegate = nil;
if (params.mode != content::FileChooserParams::UploadFolder &&
!params.accept_types.empty()) {
// Add the file filter control.
filter_delegate =
[[CefFilterDelegate alloc] initWithPanel:openPanel
andAcceptFilters:params.accept_types
andFilterIndex:*filter_index];
}
// Further panel configuration.
[openPanel setAllowsOtherFileTypes:YES];
[openPanel setAllowsMultipleSelection:
(params.mode == content::FileChooserParams::OpenMultiple)];
[openPanel setCanChooseFiles:
(params.mode != content::FileChooserParams::UploadFolder)];
[openPanel setCanChooseDirectories:
(params.mode == content::FileChooserParams::UploadFolder)];
[openPanel setShowsHiddenFiles:!params.hidereadonly];
// Show panel.
[openPanel beginSheetModalForWindow:[view window]
completionHandler:^(NSInteger returnCode) {
[NSApp stopModalWithCode:returnCode];
}];
NSInteger result = [NSApp runModalForWindow:[view window]];
if (result == NSFileHandlingPanelOKButton) {
NSArray *urls = [openPanel URLs];
int i, count = [urls count];
for (i=0; i<count; i++) {
NSURL* url = [urls objectAtIndex:i];
if ([url isFileURL])
files->push_back(base::FilePath(base::SysNSStringToUTF8([url path])));
}
}
if (filter_delegate != nil)
*filter_index = [filter_delegate filter];
}
bool RunSaveFileDialog(
const CefFileDialogRunner::FileChooserParams& params,
NSView* view,
int* filter_index,
base::FilePath* file) {
NSSavePanel* savePanel = [NSSavePanel savePanel];
base::string16 title;
if (!params.title.empty())
title = params.title;
else
title = l10n_util::GetStringUTF16(IDS_SAVE_AS_DIALOG_TITLE);
[savePanel setTitle:base::SysUTF16ToNSString(title)];
std::string filename, directory;
if (!params.default_file_name.empty()) {
if (params.default_file_name.EndsWithSeparator()) {
// The value is only a directory.
directory = params.default_file_name.value();
} else {
// The value is a file name and possibly a directory.
filename = params.default_file_name.BaseName().value();
directory = params.default_file_name.DirName().value();
}
}
if (!filename.empty()) {
[savePanel setNameFieldStringValue:base::SysUTF8ToNSString(filename)];
}
if (!directory.empty()) {
[savePanel setDirectoryURL:
[NSURL fileURLWithPath:base::SysUTF8ToNSString(directory)]];
}
CefFilterDelegate* filter_delegate = nil;
if (!params.accept_types.empty()) {
// Add the file filter control.
filter_delegate =
[[CefFilterDelegate alloc] initWithPanel:savePanel
andAcceptFilters:params.accept_types
andFilterIndex:*filter_index];
}
[savePanel setAllowsOtherFileTypes:YES];
[savePanel setShowsHiddenFiles:!params.hidereadonly];
bool success = false;
// Show panel.
[savePanel beginSheetModalForWindow:[view window]
completionHandler:^(NSInteger resultCode) {
[NSApp stopModalWithCode:resultCode];
}];
NSInteger result = [NSApp runModalForWindow:[view window]];
if (result == NSFileHandlingPanelOKButton) {
NSURL* url = [savePanel URL];
NSString* path = [url path];
*file = base::FilePath([path UTF8String]);
success = true;
}
if (filter_delegate != nil)
*filter_index = [filter_delegate filter];
return success;
}
} // namespace
CefFileDialogRunnerMac::CefFileDialogRunnerMac() {
}
void CefFileDialogRunnerMac::Run(CefBrowserHostImpl* browser,
const FileChooserParams& params,
RunFileChooserCallback callback) {
std::vector<base::FilePath> files;
int filter_index = params.selected_accept_filter;
NSView* owner = browser->GetWindowHandle();
if (params.mode == content::FileChooserParams::Open ||
params.mode == content::FileChooserParams::OpenMultiple ||
params.mode == content::FileChooserParams::UploadFolder) {
RunOpenFileDialog(params, owner, &filter_index, &files);
} else if (params.mode == content::FileChooserParams::Save) {
base::FilePath file;
if (RunSaveFileDialog(params, owner, &filter_index, &file)) {
files.push_back(file);
}
} else {
NOTIMPLEMENTED();
}
callback.Run(filter_index, files);
}

View File

@ -0,0 +1,525 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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 "libcef/browser/native/file_dialog_runner_win.h"
#include <commdlg.h>
#include <shlobj.h>
#include "libcef/browser/browser_host_impl.h"
#include "base/files/file_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
#include "base/win/scoped_comptr.h"
#include "grit/cef_strings.h"
#include "grit/ui_strings.h"
#include "net/base/mime_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/win/shell.h"
namespace {
// From ui/base/dialogs/select_file_dialog_win.cc.
// Get the file type description from the registry. This will be "Text Document"
// for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't
// have an entry for the file type, we return false, true if the description was
// found. 'file_ext' must be in form ".txt".
static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
std::wstring* reg_description) {
DCHECK(reg_description);
base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ);
std::wstring reg_app;
if (reg_ext.ReadValue(NULL, &reg_app) == ERROR_SUCCESS && !reg_app.empty()) {
base::win::RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ);
if (reg_link.ReadValue(NULL, reg_description) == ERROR_SUCCESS)
return true;
}
return false;
}
// Set up a filter for a Save/Open dialog, which will consist of |file_ext| file
// extensions (internally separated by semicolons), |ext_desc| as the text
// descriptions of the |file_ext| types (optional), and (optionally) the default
// 'All Files' view. The purpose of the filter is to show only files of a
// particular type in a Windows Save/Open dialog box. The resulting filter is
// returned. The filters created here are:
// 1. only files that have 'file_ext' as their extension
// 2. all files (only added if 'include_all_files' is true)
// Example:
// file_ext: { "*.txt", "*.htm;*.html" }
// ext_desc: { "Text Document" }
// returned: "Text Document\0*.txt\0HTML Document\0*.htm;*.html\0"
// "All Files\0*.*\0\0" (in one big string)
// If a description is not provided for a file extension, it will be retrieved
// from the registry. If the file extension does not exist in the registry, it
// will be omitted from the filter, as it is likely a bogus extension.
std::wstring FormatFilterForExtensions(
const std::vector<std::wstring>& file_ext,
const std::vector<std::wstring>& ext_desc,
bool include_all_files) {
const std::wstring all_ext = L"*.*";
const std::wstring all_desc =
l10n_util::GetStringUTF16(IDS_APP_SAVEAS_ALL_FILES) +
L" (" + all_ext + L")";
DCHECK(file_ext.size() >= ext_desc.size());
if (file_ext.empty())
include_all_files = true;
std::wstring result;
for (size_t i = 0; i < file_ext.size(); ++i) {
std::wstring ext = file_ext[i];
std::wstring desc;
if (i < ext_desc.size())
desc = ext_desc[i];
if (ext.empty()) {
// Force something reasonable to appear in the dialog box if there is no
// extension provided.
include_all_files = true;
continue;
}
if (desc.empty()) {
DCHECK(ext.find(L'.') != std::wstring::npos);
std::wstring first_extension = ext.substr(ext.find(L'.'));
size_t first_separator_index = first_extension.find(L';');
if (first_separator_index != std::wstring::npos)
first_extension = first_extension.substr(0, first_separator_index);
// Find the extension name without the preceeding '.' character.
std::wstring ext_name = first_extension;
size_t ext_index = ext_name.find_first_not_of(L'.');
if (ext_index != std::wstring::npos)
ext_name = ext_name.substr(ext_index);
if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) {
// The extension doesn't exist in the registry.
include_all_files = true;
}
}
if (!desc.empty())
desc += L" (" + ext + L")";
else
desc = ext;
result.append(desc.c_str(), desc.size() + 1); // Append NULL too.
result.append(ext.c_str(), ext.size() + 1);
}
if (include_all_files) {
result.append(all_desc.c_str(), all_desc.size() + 1);
result.append(all_ext.c_str(), all_ext.size() + 1);
}
result.append(1, '\0'); // Double NULL required.
return result;
}
std::wstring GetDescriptionFromMimeType(const std::string& mime_type) {
// Check for wild card mime types and return an appropriate description.
static const struct {
const char* mime_type;
int string_id;
} kWildCardMimeTypes[] = {
{ "audio", IDS_APP_AUDIO_FILES },
{ "image", IDS_APP_IMAGE_FILES },
{ "text", IDS_APP_TEXT_FILES },
{ "video", IDS_APP_VIDEO_FILES },
};
for (size_t i = 0; i < arraysize(kWildCardMimeTypes); ++i) {
if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*")
return l10n_util::GetStringUTF16(kWildCardMimeTypes[i].string_id);
}
return std::wstring();
}
std::wstring GetFilterString(
const std::vector<base::string16>& accept_filters) {
std::vector<std::wstring> extensions;
std::vector<std::wstring> descriptions;
for (size_t i = 0; i < accept_filters.size(); ++i) {
const base::string16& filter = accept_filters[i];
if (filter.empty())
continue;
size_t sep_index = filter.find('|');
if (sep_index != base::string16::npos) {
// Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3".
const base::string16& desc = filter.substr(0, sep_index);
const std::vector<base::string16>& ext =
base::SplitString(filter.substr(sep_index + 1),
base::ASCIIToUTF16(";"),
base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
std::wstring ext_str;
for (size_t x = 0; x < ext.size(); ++x) {
const base::string16& file_ext = ext[x];
if (!file_ext.empty() && file_ext[0] == '.') {
if (!ext_str.empty())
ext_str += L";";
ext_str += L"*" + file_ext;
}
}
if (!ext_str.empty()) {
extensions.push_back(ext_str);
descriptions.push_back(desc);
}
} else if (filter[0] == L'.') {
// Treat as an extension beginning with the '.' character.
extensions.push_back(L"*" + filter);
descriptions.push_back(std::wstring());
} else {
// Otherwise convert mime type to one or more extensions.
const std::string& ascii = base::UTF16ToASCII(filter);
std::vector<base::FilePath::StringType> ext;
std::wstring ext_str;
net::GetExtensionsForMimeType(ascii, &ext);
if (!ext.empty()) {
for (size_t x = 0; x < ext.size(); ++x) {
if (x != 0)
ext_str += L";";
ext_str += L"*." + ext[x];
}
extensions.push_back(ext_str);
descriptions.push_back(GetDescriptionFromMimeType(ascii));
}
}
}
return FormatFilterForExtensions(extensions, descriptions, true);
}
// From chrome/browser/views/shell_dialogs_win.cc
bool RunOpenFileDialog(
const CefFileDialogRunner::FileChooserParams& params,
HWND owner,
int* filter_index,
base::FilePath* path) {
OPENFILENAME ofn;
// We must do this otherwise the ofn's FlagsEx may be initialized to random
// junk in release builds which can cause the Places Bar not to show up!
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = owner;
wchar_t filename[MAX_PATH] = {0};
ofn.lpstrFile = filename;
ofn.nMaxFile = MAX_PATH;
std::wstring directory;
if (!params.default_file_name.empty()) {
if (params.default_file_name.EndsWithSeparator()) {
// The value is only a directory.
directory = params.default_file_name.value();
} else {
// The value is a file name and possibly a directory.
base::wcslcpy(filename, params.default_file_name.value().c_str(),
arraysize(filename));
directory = params.default_file_name.DirName().value();
}
}
if (!directory.empty())
ofn.lpstrInitialDir = directory.c_str();
std::wstring title;
if (!params.title.empty())
title = params.title;
else
title = l10n_util::GetStringUTF16(IDS_OPEN_FILE_DIALOG_TITLE);
if (!title.empty())
ofn.lpstrTitle = title.c_str();
// We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
// without having to close Chrome first.
ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER |
OFN_ENABLESIZING;
if (params.hidereadonly)
ofn.Flags |= OFN_HIDEREADONLY;
const std::wstring& filter = GetFilterString(params.accept_types);
if (!filter.empty()) {
ofn.lpstrFilter = filter.c_str();
// Indices into |lpstrFilter| start at 1.
ofn.nFilterIndex = *filter_index + 1;
}
bool success = !!GetOpenFileName(&ofn);
if (success) {
*filter_index = ofn.nFilterIndex == 0 ? 0 : ofn.nFilterIndex - 1;
*path = base::FilePath(filename);
}
return success;
}
bool RunOpenMultiFileDialog(
const CefFileDialogRunner::FileChooserParams& params,
HWND owner,
int* filter_index,
std::vector<base::FilePath>* paths) {
OPENFILENAME ofn;
// We must do this otherwise the ofn's FlagsEx may be initialized to random
// junk in release builds which can cause the Places Bar not to show up!
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = owner;
scoped_ptr<wchar_t[]> filename(new wchar_t[UNICODE_STRING_MAX_CHARS]);
filename[0] = 0;
ofn.lpstrFile = filename.get();
ofn.nMaxFile = UNICODE_STRING_MAX_CHARS;
std::wstring directory;
if (!params.default_file_name.empty()) {
if (params.default_file_name.EndsWithSeparator()) {
// The value is only a directory.
directory = params.default_file_name.value();
} else {
// The value is a file name and possibly a directory.
directory = params.default_file_name.DirName().value();
}
}
if (!directory.empty())
ofn.lpstrInitialDir = directory.c_str();
std::wstring title;
if (!params.title.empty())
title = params.title;
else
title = l10n_util::GetStringUTF16(IDS_OPEN_FILES_DIALOG_TITLE);
if (!title.empty())
ofn.lpstrTitle = title.c_str();
// We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
// without having to close Chrome first.
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER |
OFN_ALLOWMULTISELECT | OFN_ENABLESIZING;
if (params.hidereadonly)
ofn.Flags |= OFN_HIDEREADONLY;
const std::wstring& filter = GetFilterString(params.accept_types);
if (!filter.empty()) {
ofn.lpstrFilter = filter.c_str();
// Indices into |lpstrFilter| start at 1.
ofn.nFilterIndex = *filter_index + 1;
}
bool success = !!GetOpenFileName(&ofn);
if (success) {
std::vector<base::FilePath> files;
const wchar_t* selection = ofn.lpstrFile;
while (*selection) { // Empty string indicates end of list.
files.push_back(base::FilePath(selection));
// Skip over filename and null-terminator.
selection += files.back().value().length() + 1;
}
if (files.empty()) {
success = false;
} else if (files.size() == 1) {
// When there is one file, it contains the path and filename.
paths->swap(files);
} else {
// Otherwise, the first string is the path, and the remainder are
// filenames.
std::vector<base::FilePath>::iterator path = files.begin();
for (std::vector<base::FilePath>::iterator file = path + 1;
file != files.end(); ++file) {
paths->push_back(path->Append(*file));
}
}
}
if (success)
*filter_index = ofn.nFilterIndex == 0 ? 0 : ofn.nFilterIndex - 1;
return success;
}
// The callback function for when the select folder dialog is opened.
int CALLBACK BrowseCallbackProc(HWND window,
UINT message,
LPARAM parameter,
LPARAM data)
{
if (message == BFFM_INITIALIZED) {
// WParam is TRUE since passing a path.
// data lParam member of the BROWSEINFO structure.
SendMessage(window, BFFM_SETSELECTION, TRUE, (LPARAM)data);
}
return 0;
}
bool RunOpenFolderDialog(
const CefFileDialogRunner::FileChooserParams& params,
HWND owner,
base::FilePath* path) {
wchar_t dir_buffer[MAX_PATH + 1] = {0};
bool result = false;
BROWSEINFO browse_info = {0};
browse_info.hwndOwner = owner;
browse_info.pszDisplayName = dir_buffer;
browse_info.ulFlags = BIF_USENEWUI | BIF_RETURNONLYFSDIRS;
std::wstring title;
if (!params.title.empty())
title = params.title;
else
title = l10n_util::GetStringUTF16(IDS_SELECT_FOLDER_DIALOG_TITLE);
if (!title.empty())
browse_info.lpszTitle = title.c_str();
const std::wstring& file_path = params.default_file_name.value();
if (!file_path.empty()) {
// Highlight the current value.
browse_info.lParam = (LPARAM)file_path.c_str();
browse_info.lpfn = &BrowseCallbackProc;
}
LPITEMIDLIST list = SHBrowseForFolder(&browse_info);
if (list) {
STRRET out_dir_buffer;
ZeroMemory(&out_dir_buffer, sizeof(out_dir_buffer));
out_dir_buffer.uType = STRRET_WSTR;
base::win::ScopedComPtr<IShellFolder> shell_folder;
if (SHGetDesktopFolder(shell_folder.Receive()) == NOERROR) {
HRESULT hr = shell_folder->GetDisplayNameOf(list, SHGDN_FORPARSING,
&out_dir_buffer);
if (SUCCEEDED(hr) && out_dir_buffer.uType == STRRET_WSTR) {
*path = base::FilePath(out_dir_buffer.pOleStr);
CoTaskMemFree(out_dir_buffer.pOleStr);
result = true;
} else {
// Use old way if we don't get what we want.
wchar_t old_out_dir_buffer[MAX_PATH + 1];
if (SHGetPathFromIDList(list, old_out_dir_buffer)) {
*path = base::FilePath(old_out_dir_buffer);
result = true;
}
}
}
CoTaskMemFree(list);
}
return result;
}
bool RunSaveFileDialog(
const CefFileDialogRunner::FileChooserParams& params,
HWND owner,
int* filter_index,
base::FilePath* path) {
OPENFILENAME ofn;
// We must do this otherwise the ofn's FlagsEx may be initialized to random
// junk in release builds which can cause the Places Bar not to show up!
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = owner;
wchar_t filename[MAX_PATH] = {0};
ofn.lpstrFile = filename;
ofn.nMaxFile = MAX_PATH;
std::wstring directory;
if (!params.default_file_name.empty()) {
if (params.default_file_name.EndsWithSeparator()) {
// The value is only a directory.
directory = params.default_file_name.value();
} else {
// The value is a file name and possibly a directory.
base::wcslcpy(filename, params.default_file_name.value().c_str(),
arraysize(filename));
directory = params.default_file_name.DirName().value();
}
}
if (!directory.empty())
ofn.lpstrInitialDir = directory.c_str();
std::wstring title;
if (!params.title.empty())
title = params.title;
else
title = l10n_util::GetStringUTF16(IDS_SAVE_AS_DIALOG_TITLE);
if (!title.empty())
ofn.lpstrTitle = title.c_str();
// We use OFN_NOCHANGEDIR so that the user can rename or delete the directory
// without having to close Chrome first.
ofn.Flags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_NOCHANGEDIR |
OFN_PATHMUSTEXIST;
if (params.hidereadonly)
ofn.Flags |= OFN_HIDEREADONLY;
if (params.overwriteprompt)
ofn.Flags |= OFN_OVERWRITEPROMPT;
const std::wstring& filter = GetFilterString(params.accept_types);
if (!filter.empty()) {
ofn.lpstrFilter = filter.c_str();
// Indices into |lpstrFilter| start at 1.
ofn.nFilterIndex = *filter_index + 1;
// If a filter is specified and the default file name is changed then append
// a file extension to the new name.
ofn.lpstrDefExt = L"";
}
bool success = !!GetSaveFileName(&ofn);
if (success) {
*filter_index = ofn.nFilterIndex == 0 ? 0 : ofn.nFilterIndex - 1;
*path = base::FilePath(filename);
}
return success;
}
} // namespace
CefFileDialogRunnerWin::CefFileDialogRunnerWin() {
}
void CefFileDialogRunnerWin::Run(CefBrowserHostImpl* browser,
const FileChooserParams& params,
RunFileChooserCallback callback) {
int filter_index = params.selected_accept_filter;
std::vector<base::FilePath> files;
HWND owner = browser->GetWindowHandle();
if (params.mode == content::FileChooserParams::Open) {
base::FilePath file;
if (RunOpenFileDialog(params, owner, &filter_index, &file))
files.push_back(file);
} else if (params.mode == content::FileChooserParams::OpenMultiple) {
RunOpenMultiFileDialog(params, owner, &filter_index, &files);
} else if (params.mode == content::FileChooserParams::UploadFolder) {
base::FilePath file;
if (RunOpenFolderDialog(params, owner, &file))
files.push_back(file);
} else if (params.mode == content::FileChooserParams::Save) {
base::FilePath file;
if (RunSaveFileDialog(params, owner, &filter_index, &file))
files.push_back(file);
} else {
NOTIMPLEMENTED();
}
callback.Run(filter_index, files);
}

View File

@ -0,0 +1,22 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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.
#ifndef CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_WIN_H_
#define CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_WIN_H_
#pragma once
#include "libcef/browser/file_dialog_runner.h"
class CefFileDialogRunnerWin : public CefFileDialogRunner {
public:
CefFileDialogRunnerWin();
// CefFileDialogRunner methods:
void Run(CefBrowserHostImpl* browser,
const FileChooserParams& params,
RunFileChooserCallback callback) override;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_FILE_DIALOG_RUNNER_WIN_H_

View File

@ -0,0 +1,49 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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.
#ifndef CEF_LIBCEF_BROWSER_NATIVE_JAVASCRIPT_DIALOG_RUNNER_MAC_H_
#define CEF_LIBCEF_BROWSER_NATIVE_JAVASCRIPT_DIALOG_RUNNER_MAC_H_
#pragma once
#include "libcef/browser/javascript_dialog_runner.h"
#include "base/mac/scoped_nsobject.h"
#include "base/memory/weak_ptr.h"
#if __OBJC__
@class CefJavaScriptDialogHelper;
#else
class CefJavaScriptDialogHelper;
#endif // __OBJC__
class CefJavaScriptDialogRunnerMac : public CefJavaScriptDialogRunner {
public:
CefJavaScriptDialogRunnerMac();
~CefJavaScriptDialogRunnerMac() override;
// CefJavaScriptDialogRunner methods:
void Run(
CefBrowserHostImpl* browser,
content::JavaScriptMessageType message_type,
const base::string16& display_url,
const base::string16& message_text,
const base::string16& default_prompt_text,
const DialogClosedCallback& callback) override;
void Cancel() override;
// Callback from CefJavaScriptDialogHelper when the dialog is closed.
void DialogClosed(bool success,
const base::string16& user_input);
private:
DialogClosedCallback callback_;
base::scoped_nsobject<CefJavaScriptDialogHelper> helper_;
// Must be the last member.
base::WeakPtrFactory<CefJavaScriptDialogRunnerMac> weak_ptr_factory_;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_JAVASCRIPT_DIALOG_RUNNER_MAC_H_

View File

@ -3,12 +3,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/javascript_dialog.h"
#include "libcef/browser/javascript_dialog_manager.h"
#include "libcef/browser/native/javascript_dialog_runner_mac.h"
#import <Cocoa/Cocoa.h>
#import "base/mac/scoped_nsobject.h"
#include "base/bind.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
@ -20,12 +19,11 @@
NSTextField* textField_; // WEAK; owned by alert_
// Copies of the fields in CefJavaScriptDialog because they're private.
CefJavaScriptDialogManager* creator_;
content::JavaScriptDialogManager::DialogClosedCallback callback_;
CefJavaScriptDialogRunner::DialogClosedCallback callback_;
}
- (id)initHelperWithCreator:(CefJavaScriptDialogManager*)creator
andCallback:(content::JavaScriptDialogManager::DialogClosedCallback)callback;
- (id)initHelperWithCallback:
(CefJavaScriptDialogRunner::DialogClosedCallback)callback;
- (NSAlert*)alert;
- (NSTextField*)textField;
- (void)alertDidEnd:(NSAlert*)alert
@ -37,12 +35,10 @@
@implementation CefJavaScriptDialogHelper
- (id)initHelperWithCreator:(CefJavaScriptDialogManager*)creator
andCallback:(content::JavaScriptDialogManager::DialogClosedCallback)callback {
if (self = [super init]) {
creator_ = creator;
- (id)initHelperWithCallback:
(CefJavaScriptDialogRunner::DialogClosedCallback)callback {
if (self = [super init])
callback_ = callback;
}
return self;
}
@ -73,10 +69,7 @@
if (textField_)
input = base::SysNSStringToUTF16([textField_ stringValue]);
CefJavaScriptDialog* native_dialog =
reinterpret_cast<CefJavaScriptDialog*>(contextInfo);
callback_.Run(success, input);
creator_->DialogClosed(native_dialog);
}
- (void)cancel {
@ -86,23 +79,33 @@
@end
CefJavaScriptDialog::CefJavaScriptDialog(
CefJavaScriptDialogManager* creator,
CefJavaScriptDialogRunnerMac::CefJavaScriptDialogRunnerMac()
: weak_ptr_factory_(this) {
}
CefJavaScriptDialogRunnerMac::~CefJavaScriptDialogRunnerMac() {
Cancel();
}
void CefJavaScriptDialogRunnerMac::Run(
CefBrowserHostImpl* browser,
content::JavaScriptMessageType message_type,
const base::string16& display_url,
const base::string16& message_text,
const base::string16& default_prompt_text,
const content::JavaScriptDialogManager::DialogClosedCallback& callback)
: creator_(creator),
callback_(callback) {
const DialogClosedCallback& callback) {
DCHECK(!helper_.get());
callback_ = callback;
bool text_field =
message_type == content::JAVASCRIPT_MESSAGE_TYPE_PROMPT;
bool one_button =
message_type == content::JAVASCRIPT_MESSAGE_TYPE_ALERT;
helper_ =
[[CefJavaScriptDialogHelper alloc] initHelperWithCreator:creator
andCallback:callback];
helper_.reset(
[[CefJavaScriptDialogHelper alloc] initHelperWithCallback:
base::Bind(&CefJavaScriptDialogRunnerMac::DialogClosed,
weak_ptr_factory_.GetWeakPtr())]);
// Show the modal dialog.
NSAlert* alert = [helper_ alert];
@ -147,10 +150,17 @@ CefJavaScriptDialog::CefJavaScriptDialog(
[[alert window] makeFirstResponder:[alert accessoryView]];
}
CefJavaScriptDialog::~CefJavaScriptDialog() {
[helper_ release];
void CefJavaScriptDialogRunnerMac::Cancel() {
if (helper_.get()) {
[helper_ cancel];
helper_.reset(nil);
}
}
void CefJavaScriptDialog::Cancel() {
[helper_ cancel];
void CefJavaScriptDialogRunnerMac::DialogClosed(
bool success,
const base::string16& user_input) {
helper_.reset(nil);
callback_.Run(success, user_input);
}

View File

@ -3,8 +3,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/javascript_dialog.h"
#include "libcef/browser/javascript_dialog_manager.h"
#include "libcef/browser/native/javascript_dialog_runner_win.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef_dll/resource.h"
@ -13,20 +13,18 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
class CefJavaScriptDialog;
class CefJavaScriptDialogRunnerWin;
HHOOK CefJavaScriptDialog::msg_hook_ = NULL;
int CefJavaScriptDialog::msg_hook_user_count_ = 0;
HHOOK CefJavaScriptDialogRunnerWin::msg_hook_ = NULL;
int CefJavaScriptDialogRunnerWin::msg_hook_user_count_ = 0;
INT_PTR CALLBACK CefJavaScriptDialog::DialogProc(HWND dialog,
UINT message,
WPARAM wparam,
LPARAM lparam) {
INT_PTR CALLBACK CefJavaScriptDialogRunnerWin::DialogProc(
HWND dialog, UINT message, WPARAM wparam, LPARAM lparam) {
switch (message) {
case WM_INITDIALOG: {
SetWindowLongPtr(dialog, DWLP_USER, static_cast<LONG_PTR>(lparam));
CefJavaScriptDialog* owner =
reinterpret_cast<CefJavaScriptDialog*>(lparam);
CefJavaScriptDialogRunnerWin* owner =
reinterpret_cast<CefJavaScriptDialogRunnerWin*>(lparam);
owner->dialog_win_ = dialog;
SetDlgItemText(dialog, IDC_DIALOGTEXT, owner->message_text_.c_str());
if (owner->message_type_ == content::JAVASCRIPT_MESSAGE_TYPE_PROMPT)
@ -35,12 +33,12 @@ INT_PTR CALLBACK CefJavaScriptDialog::DialogProc(HWND dialog,
break;
}
case WM_CLOSE: {
CefJavaScriptDialog* owner = reinterpret_cast<CefJavaScriptDialog*>(
CefJavaScriptDialogRunnerWin* owner =
reinterpret_cast<CefJavaScriptDialogRunnerWin*>(
GetWindowLongPtr(dialog, DWLP_USER));
if (owner) {
owner->Cancel();
owner->callback_.Run(false, base::string16());
owner->creator_->DialogClosed(owner);
// No need for the system to call DestroyWindow() because it will be
// called by the Cancel() method.
@ -49,7 +47,8 @@ INT_PTR CALLBACK CefJavaScriptDialog::DialogProc(HWND dialog,
break;
}
case WM_COMMAND: {
CefJavaScriptDialog* owner = reinterpret_cast<CefJavaScriptDialog*>(
CefJavaScriptDialogRunnerWin* owner =
reinterpret_cast<CefJavaScriptDialogRunnerWin*>(
GetWindowLongPtr(dialog, DWLP_USER));
base::string16 user_input;
bool finish = false;
@ -75,7 +74,6 @@ INT_PTR CALLBACK CefJavaScriptDialog::DialogProc(HWND dialog,
if (finish) {
owner->Cancel();
owner->callback_.Run(result, user_input);
owner->creator_->DialogClosed(owner);
}
break;
}
@ -85,19 +83,32 @@ INT_PTR CALLBACK CefJavaScriptDialog::DialogProc(HWND dialog,
return 0;
}
CefJavaScriptDialog::CefJavaScriptDialog(
CefJavaScriptDialogManager* creator,
CefJavaScriptDialogRunnerWin::CefJavaScriptDialogRunnerWin()
: dialog_win_(NULL),
parent_win_(NULL),
hook_installed_(false) {
}
CefJavaScriptDialogRunnerWin::~CefJavaScriptDialogRunnerWin() {
Cancel();
}
void CefJavaScriptDialogRunnerWin::Run(
CefBrowserHostImpl* browser,
content::JavaScriptMessageType message_type,
const base::string16& display_url,
const base::string16& message_text,
const base::string16& default_prompt_text,
const content::JavaScriptDialogManager::DialogClosedCallback& callback)
: creator_(creator),
callback_(callback),
message_type_(message_type),
message_text_(message_text),
default_prompt_text_(default_prompt_text) {
const DialogClosedCallback& callback) {
DCHECK(!dialog_win_);
message_type_ = message_type;
message_text_ = message_text;
default_prompt_text_ = default_prompt_text;
callback_ = callback;
InstallMessageHook();
hook_installed_ = true;
int dialog_type;
if (message_type == content::JAVASCRIPT_MESSAGE_TYPE_ALERT)
@ -117,7 +128,7 @@ CefJavaScriptDialog::CefJavaScriptDialog(
hModule = ::GetModuleHandle(NULL);
DCHECK(hModule);
parent_win_ = GetAncestor(creator->browser()->GetWindowHandle(), GA_ROOT);
parent_win_ = GetAncestor(browser->GetWindowHandle(), GA_ROOT);
dialog_win_ = CreateDialogParam(hModule,
MAKEINTRESOURCE(dialog_type),
parent_win_,
@ -142,12 +153,7 @@ CefJavaScriptDialog::CefJavaScriptDialog(
ShowWindow(dialog_win_, SW_SHOWNORMAL);
}
CefJavaScriptDialog::~CefJavaScriptDialog() {
Cancel();
UninstallMessageHook();
}
void CefJavaScriptDialog::Cancel() {
void CefJavaScriptDialogRunnerWin::Cancel() {
HWND parent = NULL;
// Re-enable the parent before closing the popup to avoid focus/activation/
@ -167,11 +173,16 @@ void CefJavaScriptDialog::Cancel() {
// Return focus to the parent window.
if (parent)
SetFocus(parent);
if (hook_installed_) {
UninstallMessageHook();
hook_installed_ = false;
}
}
// static
LRESULT CALLBACK CefJavaScriptDialog::GetMsgProc(int code, WPARAM wparam,
LPARAM lparam) {
LRESULT CALLBACK CefJavaScriptDialogRunnerWin::GetMsgProc(
int code, WPARAM wparam, LPARAM lparam) {
// Mostly borrowed from http://support.microsoft.com/kb/q187988/
// and http://www.codeproject.com/KB/atl/cdialogmessagehook.aspx.
LPMSG msg = reinterpret_cast<LPMSG>(lparam);
@ -196,7 +207,7 @@ LRESULT CALLBACK CefJavaScriptDialog::GetMsgProc(int code, WPARAM wparam,
}
// static
bool CefJavaScriptDialog::InstallMessageHook() {
bool CefJavaScriptDialogRunnerWin::InstallMessageHook() {
msg_hook_user_count_++;
// Make sure we only call this once.
@ -204,7 +215,7 @@ bool CefJavaScriptDialog::InstallMessageHook() {
return true;
msg_hook_ = ::SetWindowsHookEx(WH_GETMESSAGE,
&CefJavaScriptDialog::GetMsgProc,
&CefJavaScriptDialogRunnerWin::GetMsgProc,
NULL,
GetCurrentThreadId());
DCHECK(msg_hook_ != NULL);
@ -212,7 +223,7 @@ bool CefJavaScriptDialog::InstallMessageHook() {
}
// static
bool CefJavaScriptDialog::UninstallMessageHook() {
bool CefJavaScriptDialogRunnerWin::UninstallMessageHook() {
msg_hook_user_count_--;
DCHECK_GE(msg_hook_user_count_, 0);

View File

@ -3,51 +3,38 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_H_
#define CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_H_
#ifndef CEF_LIBCEF_BROWSER_NATIVE_JAVASCRIPT_DIALOG_RUNNER_WIN_H_
#define CEF_LIBCEF_BROWSER_NATIVE_JAVASCRIPT_DIALOG_RUNNER_WIN_H_
#pragma once
#include "content/public/browser/javascript_dialog_manager.h"
#include "libcef/browser/javascript_dialog_runner.h"
#if defined(OS_MACOSX)
#if __OBJC__
@class CefJavaScriptDialogHelper;
#else
class CefJavaScriptDialogHelper;
#endif // __OBJC__
#endif // defined(OS_MACOSX)
class CefJavaScriptDialogManager;
class CefJavaScriptDialog {
class CefJavaScriptDialogRunnerWin : public CefJavaScriptDialogRunner {
public:
CefJavaScriptDialog(
CefJavaScriptDialogManager* creator,
CefJavaScriptDialogRunnerWin();
~CefJavaScriptDialogRunnerWin() override;
// CefJavaScriptDialogRunner methods:
void Run(
CefBrowserHostImpl* browser,
content::JavaScriptMessageType message_type,
const base::string16& display_url,
const base::string16& message_text,
const base::string16& default_prompt_text,
const content::JavaScriptDialogManager::DialogClosedCallback& callback);
~CefJavaScriptDialog();
// Called to cancel a dialog mid-flight.
void Cancel();
// Activate the dialog.
void Activate();
const DialogClosedCallback& callback) override;
void Cancel() override;
private:
CefJavaScriptDialogManager* creator_;
content::JavaScriptDialogManager::DialogClosedCallback callback_;
#if defined(OS_MACOSX)
CefJavaScriptDialogHelper* helper_; // owned
#elif defined(OS_WIN)
content::JavaScriptMessageType message_type_;
HWND dialog_win_;
HWND parent_win_;
content::JavaScriptMessageType message_type_;
base::string16 message_text_;
base::string16 default_prompt_text_;
DialogClosedCallback callback_;
bool hook_installed_;
static INT_PTR CALLBACK DialogProc(HWND dialog, UINT message, WPARAM wparam,
LPARAM lparam);
@ -59,9 +46,6 @@ class CefJavaScriptDialog {
static LRESULT CALLBACK GetMsgProc(int code, WPARAM wparam, LPARAM lparam);
static HHOOK msg_hook_;
static int msg_hook_user_count_;
#endif
DISALLOW_COPY_AND_ASSIGN(CefJavaScriptDialog);
};
#endif // CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_H_
#endif // CEF_LIBCEF_BROWSER_NATIVE_JAVASCRIPT_DIALOG_RUNNER_WIN_H_

View File

@ -0,0 +1,49 @@
// Copyright 2014 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 "libcef/browser/native/menu_runner_linux.h"
#include "libcef/browser/browser_host_impl.h"
#include "base/compiler_specific.h"
#include "base/strings/string_util.h"
#include "ui/gfx/geometry/point.h"
CefMenuRunnerLinux::CefMenuRunnerLinux() {
}
bool CefMenuRunnerLinux::RunContextMenu(
CefBrowserHostImpl* browser,
ui::MenuModel* model,
const content::ContextMenuParams& params) {
menu_.reset(
new views::MenuRunner(model, views::MenuRunner::CONTEXT_MENU));
const gfx::Point& screen_point =
browser->GetScreenPoint(gfx::Point(params.x, params.y));
views::Widget* parent_widget = nullptr;
if (!browser->IsWindowless())
parent_widget = browser->GetWindowWidget();
views::MenuRunner::RunResult result =
menu_->RunMenuAt(parent_widget,
NULL, gfx::Rect(screen_point, gfx::Size()),
views::MENU_ANCHOR_TOPRIGHT,
ui::MENU_SOURCE_NONE);
ALLOW_UNUSED_LOCAL(result);
return true;
}
void CefMenuRunnerLinux::CancelContextMenu() {
if (menu_)
menu_->Cancel();
}
bool CefMenuRunnerLinux::FormatLabel(base::string16& label) {
// Remove the accelerator indicator (&) from label strings.
const char16 replace[] = {L'&', 0};
return base::ReplaceChars(label, replace, base::string16(), &label);
}

View File

@ -0,0 +1,29 @@
// 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.
#ifndef CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_LINUX_H_
#define CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_LINUX_H_
#pragma once
#include "libcef/browser/menu_runner.h"
#include "base/memory/scoped_ptr.h"
#include "ui/views/controls/menu/menu_runner.h"
class CefMenuRunnerLinux: public CefMenuRunner {
public:
CefMenuRunnerLinux();
// CefMenuRunner methods.
bool RunContextMenu(CefBrowserHostImpl* browser,
ui::MenuModel* model,
const content::ContextMenuParams& params) override;
void CancelContextMenu() override;
bool FormatLabel(base::string16& label) override;
private:
scoped_ptr<views::MenuRunner> menu_;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_LINUX_H_

View File

@ -0,0 +1,34 @@
// 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.
#ifndef CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_MAC_H_
#define CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_MAC_H_
#pragma once
#include "libcef/browser/menu_runner.h"
#include "base/mac/scoped_nsobject.h"
#if __OBJC__
@class MenuController;
#else
class MenuController;
#endif
class CefMenuRunnerMac : public CefMenuRunner {
public:
CefMenuRunnerMac();
~CefMenuRunnerMac() override;
// CefMenuRunner methods.
bool RunContextMenu(CefBrowserHostImpl* browser,
ui::MenuModel* model,
const content::ContextMenuParams& params) override;
void CancelContextMenu() override;
private:
base::scoped_nsobject<MenuController> menu_controller_;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_MAC_H_

View File

@ -0,0 +1,91 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
#include "libcef/browser/native/menu_runner_mac.h"
#include "libcef/browser/browser_host_impl.h"
#include "base/message_loop/message_loop.h"
#include "base/compiler_specific.h"
#import "base/mac/scoped_sending_event.h"
#import "ui/base/cocoa/menu_controller.h"
#include "ui/gfx/geometry/point.h"
CefMenuRunnerMac::CefMenuRunnerMac() {
}
CefMenuRunnerMac::~CefMenuRunnerMac() {
}
bool CefMenuRunnerMac::RunContextMenu(
CefBrowserHostImpl* browser,
ui::MenuModel* model,
const content::ContextMenuParams& params) {
// Create a menu controller based on the model.
menu_controller_.reset([[MenuController alloc] initWithModel:model
useWithPopUpButtonCell:NO]);
// Keep the menu controller alive (by adding an additional retain) until after
// the menu has been dismissed. Otherwise it will crash if the browser is
// destroyed (and consequently the menu controller is destroyed) while the
// menu is still pending.
base::scoped_nsobject<MenuController> menu_controller_ref(menu_controller_);
// Make sure events can be pumped while the menu is up.
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
// One of the events that could be pumped is |window.close()|.
// User-initiated event-tracking loops protect against this by
// setting flags in -[CrApplication sendEvent:], but since
// web-content menus are initiated by IPC message the setup has to
// be done manually.
base::mac::ScopedSendingEvent sendingEventScoper;
// Show the menu. Blocks until the menu is dismissed.
if (browser->IsWindowless()) {
// Don't show the menu unless a native window handle exists.
if (!browser->GetWindowHandle())
return false;
const gfx::Point& screen_point =
browser->GetScreenPoint(gfx::Point(params.x, params.y));
NSPoint screen_position = NSPointFromCGPoint(screen_point.ToCGPoint());
[[menu_controller_ menu] popUpMenuPositioningItem:nil
atLocation:screen_position
inView:nil];
} else {
NSView* parent_view = browser->web_contents()->GetContentNativeView();
// Synthesize an event for the click, as there is no certainty that
// [NSApp currentEvent] will return a valid event.
NSEvent* currentEvent = [NSApp currentEvent];
NSWindow* window = [parent_view window];
NSPoint position = [window mouseLocationOutsideOfEventStream];
NSTimeInterval eventTime = [currentEvent timestamp];
NSEvent* clickEvent = [NSEvent mouseEventWithType:NSRightMouseDown
location:position
modifierFlags:NSRightMouseDownMask
timestamp:eventTime
windowNumber:[window windowNumber]
context:nil
eventNumber:0
clickCount:1
pressure:1.0];
[NSMenu popUpContextMenu:[menu_controller_ menu]
withEvent:clickEvent
forView:parent_view];
}
return true;
}
void CefMenuRunnerMac::CancelContextMenu() {
if (menu_controller_.get())
[menu_controller_ cancel];
}

View File

@ -0,0 +1,35 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
#include "libcef/browser/native/menu_runner_win.h"
#include "libcef/browser/browser_host_impl.h"
#include "base/message_loop/message_loop.h"
#include "ui/gfx/geometry/point.h"
#include "ui/views/controls/menu/menu_2.h"
CefMenuRunnerWin::CefMenuRunnerWin() {
}
bool CefMenuRunnerWin::RunContextMenu(
CefBrowserHostImpl* browser,
ui::MenuModel* model,
const content::ContextMenuParams& params) {
// Create a menu based on the model.
menu_.reset(new views::NativeMenuWin(model, NULL));
menu_->Rebuild(NULL);
// Make sure events can be pumped while the menu is up.
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
const gfx::Point& screen_point =
browser->GetScreenPoint(gfx::Point(params.x, params.y));
// Show the menu. Blocks until the menu is dismissed.
menu_->RunMenuAt(screen_point, views::Menu2::ALIGN_TOPLEFT);
return true;
}

View File

@ -0,0 +1,27 @@
// 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.
#ifndef CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_WIN_H_
#define CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_WIN_H_
#pragma once
#include "libcef/browser/menu_runner.h"
#include "base/memory/scoped_ptr.h"
#include "ui/views/controls/menu/native_menu_win.h"
class CefMenuRunnerWin : public CefMenuRunner {
public:
CefMenuRunnerWin();
// CefMenuRunner methods.
bool RunContextMenu(CefBrowserHostImpl* browser,
ui::MenuModel* model,
const content::ContextMenuParams& params) override;
private:
scoped_ptr<views::NativeMenuWin> menu_;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_WIN_H_

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
#include "libcef/browser/window_delegate_view.h"
#include "libcef/browser/native/window_delegate_view.h"
#include "content/public/browser/web_contents.h"
#include "ui/views/background.h"

View File

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_WINDOW_DELEGATE_VIEW_H_
#define CEF_LIBCEF_BROWSER_WINDOW_DELEGATE_VIEW_H_
#ifndef CEF_LIBCEF_BROWSER_NATIVE_WINDOW_DELEGATE_VIEW_H_
#define CEF_LIBCEF_BROWSER_NATIVE_WINDOW_DELEGATE_VIEW_H_
#pragma once
#include "ui/views/widget/widget_delegate.h"
@ -47,4 +47,4 @@ class CefWindowDelegateView : public views::WidgetDelegateView {
DISALLOW_COPY_AND_ASSIGN(CefWindowDelegateView);
};
#endif // CEF_LIBCEF_BROWSER_WINDOW_DELEGATE_VIEW_H_
#endif // CEF_LIBCEF_BROWSER_NATIVE_WINDOW_DELEGATE_VIEW_H_

View File

@ -3,7 +3,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/window_x11.h"
#include "libcef/browser/native/window_x11.h"
#include "libcef/browser/thread_util.h"
#include <X11/extensions/XInput2.h>

View File

@ -3,8 +3,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_WINDOW_X11_H_
#define CEF_LIBCEF_BROWSER_WINDOW_X11_H_
#ifndef CEF_LIBCEF_BROWSER_NATIVE_WINDOW_X11_H_
#define CEF_LIBCEF_BROWSER_NATIVE_WINDOW_X11_H_
#pragma once
#include <X11/Xlib.h>
@ -75,4 +75,4 @@ class CefWindowX11 : public ui::PlatformEventDispatcher {
DISALLOW_COPY_AND_ASSIGN(CefWindowX11);
};
#endif // CEF_LIBCEF_BROWSER_WINDOW_X11_H_
#endif // CEF_LIBCEF_BROWSER_NATIVE_WINDOW_X11_H_

View File

@ -0,0 +1,309 @@
// Copyright 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 "libcef/browser/osr/browser_platform_delegate_osr.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/osr/render_widget_host_view_osr.h"
#include "libcef/browser/osr/web_contents_view_osr.h"
#include "libcef/common/drag_data_impl.h"
#include "content/public/browser/render_view_host.h"
CefBrowserPlatformDelegateOsr::CefBrowserPlatformDelegateOsr(
scoped_ptr<CefBrowserPlatformDelegateNative> native_delegate)
: native_delegate_(native_delegate.Pass()),
view_osr_(nullptr) {
native_delegate_->set_windowless_handler(this);
}
void CefBrowserPlatformDelegateOsr::CreateViewForWebContents(
content::WebContentsView** view,
content::RenderViewHostDelegateView** delegate_view) {
DCHECK(!view_osr_);
// Use the OSR view instead of the default platform view.
view_osr_ = new CefWebContentsViewOSR(
!!native_delegate_->window_info().transparent_painting_enabled);
*view = view_osr_;
*delegate_view = view_osr_;
}
void CefBrowserPlatformDelegateOsr::WebContentsCreated(
content::WebContents* web_contents) {
DCHECK(view_osr_);
DCHECK(!view_osr_->web_contents());
// Associate the WebContents with the OSR view.
view_osr_->set_web_contents(web_contents);
}
void CefBrowserPlatformDelegateOsr::BrowserCreated(
CefBrowserHostImpl* browser) {
CefBrowserPlatformDelegate::BrowserCreated(browser);
if (browser->IsPopup()) {
// Associate the RenderWidget host view with the browser now because the
// browser wasn't known at the time that the host view was created.
content::RenderViewHost* host =
browser->web_contents()->GetRenderViewHost();
DCHECK(host);
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(host->GetWidget()->GetView());
// |view| will be null if the popup is a DevTools window.
if (view)
view->set_browser_impl(browser);
}
}
void CefBrowserPlatformDelegateOsr::BrowserDestroyed(
CefBrowserHostImpl* browser) {
CefBrowserPlatformDelegate::BrowserDestroyed(browser);
view_osr_ = nullptr;
}
void CefBrowserPlatformDelegateOsr::WasResized() {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->WasResized();
}
void CefBrowserPlatformDelegateOsr::SendKeyEvent(
const content::NativeWebKeyboardEvent& event) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->SendKeyEvent(event);
}
void CefBrowserPlatformDelegateOsr::SendMouseEvent(
const blink::WebMouseEvent& event) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->SendMouseEvent(event);
}
void CefBrowserPlatformDelegateOsr::SendMouseWheelEvent(
const blink::WebMouseWheelEvent& event) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->SendMouseWheelEvent(event);
}
void CefBrowserPlatformDelegateOsr::SendFocusEvent(bool setFocus) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->SendFocusEvent(setFocus);
}
gfx::Point CefBrowserPlatformDelegateOsr::GetScreenPoint(
const gfx::Point& view) const {
CefRefPtr<CefRenderHandler> handler = browser_->client()->GetRenderHandler();
if (handler.get()) {
int screenX = 0, screenY = 0;
if (handler->GetScreenPoint(browser_, view.x(), view.y(),
screenX, screenY)) {
return gfx::Point(screenX, screenY);
}
}
return view;
}
void CefBrowserPlatformDelegateOsr::ViewText(const std::string& text) {
native_delegate_->ViewText(text);
}
void CefBrowserPlatformDelegateOsr::HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) {
native_delegate_->HandleKeyboardEvent(event);
}
void CefBrowserPlatformDelegateOsr::HandleExternalProtocol(const GURL& url) {
native_delegate_->HandleExternalProtocol(url);
}
void CefBrowserPlatformDelegateOsr::TranslateKeyEvent(
content::NativeWebKeyboardEvent& result,
const CefKeyEvent& key_event) const {
native_delegate_->TranslateKeyEvent(result, key_event);
}
void CefBrowserPlatformDelegateOsr::TranslateClickEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
CefBrowserHost::MouseButtonType type,
bool mouseUp, int clickCount) const {
native_delegate_->TranslateClickEvent(result, mouse_event, type, mouseUp,
clickCount);
}
void CefBrowserPlatformDelegateOsr::TranslateMoveEvent(
blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) const {
native_delegate_->TranslateMoveEvent(result, mouse_event, mouseLeave);
}
void CefBrowserPlatformDelegateOsr::TranslateWheelEvent(
blink::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX, int deltaY) const {
native_delegate_->TranslateWheelEvent(result, mouse_event, deltaX, deltaY);
}
CefEventHandle CefBrowserPlatformDelegateOsr::GetEventHandle(
const content::NativeWebKeyboardEvent& event) const {
return native_delegate_->GetEventHandle(event);
}
scoped_ptr<CefFileDialogRunner>
CefBrowserPlatformDelegateOsr::CreateFileDialogRunner() {
return native_delegate_->CreateFileDialogRunner();
}
scoped_ptr<CefJavaScriptDialogRunner>
CefBrowserPlatformDelegateOsr::CreateJavaScriptDialogRunner() {
return native_delegate_->CreateJavaScriptDialogRunner();
}
scoped_ptr<CefMenuRunner> CefBrowserPlatformDelegateOsr::CreateMenuRunner() {
return native_delegate_->CreateMenuRunner();
}
bool CefBrowserPlatformDelegateOsr::IsWindowless() const {
return true;
}
void CefBrowserPlatformDelegateOsr::WasHidden(bool hidden) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view) {
if (hidden)
view->Hide();
else
view->Show();
}
}
void CefBrowserPlatformDelegateOsr::NotifyScreenInfoChanged() {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->OnScreenInfoChanged();
}
void CefBrowserPlatformDelegateOsr::Invalidate(cef_paint_element_type_t type) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->Invalidate(type);
}
void CefBrowserPlatformDelegateOsr::SetWindowlessFrameRate(int frame_rate) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->UpdateFrameRate();
}
void CefBrowserPlatformDelegateOsr::DragTargetDragEnter(
CefRefPtr<CefDragData> drag_data,
const CefMouseEvent& event,
cef_drag_operations_mask_t allowed_ops) {
content::RenderViewHost* rvh = browser_->web_contents()->GetRenderViewHost();
if (!rvh)
return;
CefDragDataImpl* data_impl = static_cast<CefDragDataImpl*>(drag_data.get());
base::AutoLock lock_scope(data_impl->lock());
const content::DropData& drop_data = data_impl->drop_data();
const gfx::Point client_pt(event.x, event.y);
const gfx::Point& screen_pt = GetScreenPoint(client_pt);
blink::WebDragOperationsMask ops =
static_cast<blink::WebDragOperationsMask>(allowed_ops);
int modifiers = TranslateModifiers(event.modifiers);
rvh->DragTargetDragEnter(drop_data, client_pt, screen_pt, ops, modifiers);
}
void CefBrowserPlatformDelegateOsr::DragTargetDragOver(
const CefMouseEvent& event,
cef_drag_operations_mask_t allowed_ops) {
content::RenderViewHost* rvh = browser_->web_contents()->GetRenderViewHost();
if (!rvh)
return;
const gfx::Point client_pt(event.x, event.y);
const gfx::Point& screen_pt = GetScreenPoint(client_pt);
blink::WebDragOperationsMask ops =
static_cast<blink::WebDragOperationsMask>(allowed_ops);
int modifiers = TranslateModifiers(event.modifiers);
rvh->DragTargetDragOver(client_pt, screen_pt, ops, modifiers);
}
void CefBrowserPlatformDelegateOsr::DragTargetDragLeave() {
content::RenderViewHost* rvh = browser_->web_contents()->GetRenderViewHost();
if (!rvh)
return;
rvh->DragTargetDragLeave();
}
void CefBrowserPlatformDelegateOsr::DragTargetDrop(const CefMouseEvent& event) {
content::RenderViewHost* rvh = browser_->web_contents()->GetRenderViewHost();
if (!rvh)
return;
const gfx::Point client_pt(event.x, event.y);
const gfx::Point& screen_pt = GetScreenPoint(client_pt);
int modifiers = TranslateModifiers(event.modifiers);
rvh->DragTargetDrop(client_pt, screen_pt, modifiers);
}
void CefBrowserPlatformDelegateOsr::DragSourceEndedAt(
int x, int y,
cef_drag_operations_mask_t op) {
content::RenderViewHost* rvh = browser_->web_contents()->GetRenderViewHost();
if (!rvh)
return;
const gfx::Point& screen_pt = GetScreenPoint(gfx::Point(x, y));
blink::WebDragOperation drag_op = static_cast<blink::WebDragOperation>(op);
rvh->DragSourceEndedAt(x, y, screen_pt.x(), screen_pt.y(), drag_op);
}
void CefBrowserPlatformDelegateOsr::DragSourceSystemDragEnded() {
content::RenderViewHost* rvh = browser_->web_contents()->GetRenderViewHost();
if (!rvh)
return;
rvh->DragSourceSystemDragEnded();
}
CefWindowHandle CefBrowserPlatformDelegateOsr::GetParentWindowHandle() const {
return GetHostWindowHandle();
}
gfx::Point CefBrowserPlatformDelegateOsr::GetParentScreenPoint(
const gfx::Point& view) const {
return GetScreenPoint(view);
}
CefRenderWidgetHostViewOSR*
CefBrowserPlatformDelegateOsr::GetOSRHostView() const {
content::WebContents* web_contents = browser_->web_contents();
CefRenderWidgetHostViewOSR* fs_view =
static_cast<CefRenderWidgetHostViewOSR*>(
web_contents->GetFullscreenRenderWidgetHostView());
if (fs_view)
return fs_view;
content::RenderViewHost* host = web_contents->GetRenderViewHost();
if (host) {
return static_cast<CefRenderWidgetHostViewOSR*>(
host->GetWidget()->GetView());
}
return nullptr;
}

View File

@ -0,0 +1,87 @@
// Copyright 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_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_H_
#define CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_H_
#include "libcef/browser/browser_platform_delegate.h"
#include "libcef/browser/native/browser_platform_delegate_native.h"
class CefRenderWidgetHostViewOSR;
class CefWebContentsViewOSR;
// Base implementation of windowless browser functionality.
class CefBrowserPlatformDelegateOsr :
public CefBrowserPlatformDelegate,
public CefBrowserPlatformDelegateNative::WindowlessHandler {
public:
// CefBrowserPlatformDelegate methods:
void CreateViewForWebContents(
content::WebContentsView** view,
content::RenderViewHostDelegateView** delegate_view) override;
void WebContentsCreated(content::WebContents* web_contents) override;
void BrowserCreated(CefBrowserHostImpl* browser) override;
void BrowserDestroyed(CefBrowserHostImpl* browser) override;
void WasResized() override;
void SendKeyEvent(const content::NativeWebKeyboardEvent& event) override;
void SendMouseEvent(const blink::WebMouseEvent& event) override;
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event) override;
void SendFocusEvent(bool setFocus) override;
gfx::Point GetScreenPoint(const gfx::Point& view) const override;
void ViewText(const std::string& text) override;
void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) override;
void HandleExternalProtocol(const GURL& url) override;
void TranslateKeyEvent(content::NativeWebKeyboardEvent& result,
const CefKeyEvent& key_event) const override;
void TranslateClickEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
CefBrowserHost::MouseButtonType type,
bool mouseUp, int clickCount) const override;
void TranslateMoveEvent(blink::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) const override;
void TranslateWheelEvent(blink::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX, int deltaY) const override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
scoped_ptr<CefFileDialogRunner> CreateFileDialogRunner() override;
scoped_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner() override;
scoped_ptr<CefMenuRunner> CreateMenuRunner() override;
bool IsWindowless() const override;
void WasHidden(bool hidden) override;
void NotifyScreenInfoChanged() override;
void Invalidate(cef_paint_element_type_t type) override;
void SetWindowlessFrameRate(int frame_rate) override;
void DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,
const CefMouseEvent& event,
cef_drag_operations_mask_t allowed_ops) override;
void DragTargetDragOver(const CefMouseEvent& event,
cef_drag_operations_mask_t allowed_ops) override;
void DragTargetDragLeave() override;
void DragTargetDrop(const CefMouseEvent& event) override;
void DragSourceEndedAt(int x, int y,
cef_drag_operations_mask_t op) override;
void DragSourceSystemDragEnded() override;
// CefBrowserPlatformDelegateNative::WindowlessHandler methods:
CefWindowHandle GetParentWindowHandle() const override;
gfx::Point GetParentScreenPoint(const gfx::Point& view) const override;
protected:
// Platform-specific behaviors will be delegated to |native_delegate|.
explicit CefBrowserPlatformDelegateOsr(
scoped_ptr<CefBrowserPlatformDelegateNative> native_delegate);
// Returns the primary OSR host view for the underlying browser. If a
// full-screen host view currently exists then it will be returned. Otherwise,
// the main host view will be returned.
CefRenderWidgetHostViewOSR* GetOSRHostView() const;
scoped_ptr<CefBrowserPlatformDelegateNative> native_delegate_;
CefWebContentsViewOSR* view_osr_; // Not owned by this class.
};
#endif // CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_H_

View File

@ -0,0 +1,18 @@
// Copyright 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 "libcef/browser/osr/browser_platform_delegate_osr_linux.h"
#include "libcef/browser/browser_host_impl.h"
CefBrowserPlatformDelegateOsrLinux::CefBrowserPlatformDelegateOsrLinux(
scoped_ptr<CefBrowserPlatformDelegateNative> native_delegate)
: CefBrowserPlatformDelegateOsr(native_delegate.Pass()) {
}
CefWindowHandle
CefBrowserPlatformDelegateOsrLinux::GetHostWindowHandle() const {
return native_delegate_->window_info().parent_window;
}

View File

@ -0,0 +1,21 @@
// Copyright 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_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_LINUX_H_
#define CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_LINUX_H_
#include "libcef/browser/osr/browser_platform_delegate_osr.h"
// Windowless browser implementation for Linux.
class CefBrowserPlatformDelegateOsrLinux :
public CefBrowserPlatformDelegateOsr {
public:
explicit CefBrowserPlatformDelegateOsrLinux(
scoped_ptr<CefBrowserPlatformDelegateNative> native_delegate);
// CefBrowserPlatformDelegate methods:
CefWindowHandle GetHostWindowHandle() const override;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_OSR_LINUX_H_

View File

@ -0,0 +1,23 @@
// Copyright 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_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_MAC_H_
#define CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_MAC_H_
#include "libcef/browser/osr/browser_platform_delegate_osr.h"
// Windowless browser implementation for Mac OS X.
class CefBrowserPlatformDelegateOsrMac : public CefBrowserPlatformDelegateOsr {
public:
explicit CefBrowserPlatformDelegateOsrMac(
scoped_ptr<CefBrowserPlatformDelegateNative> native_delegate);
// CefBrowserPlatformDelegate methods:
CefWindowHandle GetHostWindowHandle() const override;
CefTextInputContext GetNSTextInputContext() override;
void HandleKeyEventBeforeTextInputClient(CefEventHandle keyEvent) override;
void HandleKeyEventAfterTextInputClient(CefEventHandle keyEvent) override;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_OSR_MAC_H_

View File

@ -0,0 +1,38 @@
// Copyright 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 "libcef/browser/osr/browser_platform_delegate_osr_mac.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/osr/render_widget_host_view_osr.h"
CefBrowserPlatformDelegateOsrMac::CefBrowserPlatformDelegateOsrMac(
scoped_ptr<CefBrowserPlatformDelegateNative> native_delegate)
: CefBrowserPlatformDelegateOsr(native_delegate.Pass()) {
}
CefWindowHandle CefBrowserPlatformDelegateOsrMac::GetHostWindowHandle() const {
return native_delegate_->window_info().parent_view;
}
CefTextInputContext CefBrowserPlatformDelegateOsrMac::GetNSTextInputContext() {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
return view->GetNSTextInputContext();
return nullptr;
}
void CefBrowserPlatformDelegateOsrMac::HandleKeyEventBeforeTextInputClient(
CefEventHandle keyEvent) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->HandleKeyEventBeforeTextInputClient(keyEvent);
}
void CefBrowserPlatformDelegateOsrMac::HandleKeyEventAfterTextInputClient(
CefEventHandle keyEvent) {
CefRenderWidgetHostViewOSR* view = GetOSRHostView();
if (view)
view->HandleKeyEventAfterTextInputClient(keyEvent);
}

View File

@ -0,0 +1,16 @@
// Copyright 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 "libcef/browser/osr/browser_platform_delegate_osr_win.h"
#include "libcef/browser/browser_host_impl.h"
CefBrowserPlatformDelegateOsrWin::CefBrowserPlatformDelegateOsrWin(
scoped_ptr<CefBrowserPlatformDelegateNative> native_delegate)
: CefBrowserPlatformDelegateOsr(native_delegate.Pass()) {
}
CefWindowHandle CefBrowserPlatformDelegateOsrWin::GetHostWindowHandle() const {
return native_delegate_->window_info().parent_window;
}

View File

@ -0,0 +1,20 @@
// Copyright 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_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_WIN_H_
#define CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_WIN_H_
#include "libcef/browser/osr/browser_platform_delegate_osr.h"
// Windowless browser implementation for Windows.
class CefBrowserPlatformDelegateOsrWin : public CefBrowserPlatformDelegateOsr {
public:
explicit CefBrowserPlatformDelegateOsrWin(
scoped_ptr<CefBrowserPlatformDelegateNative> native_delegate);
// CefBrowserPlatformDelegate methods:
CefWindowHandle GetHostWindowHandle() const override;
};
#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_OSR_WIN_H_

View File

@ -0,0 +1,25 @@
// Copyright 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 "libcef/browser/osr/osr_util.h"
namespace osr_util {
namespace {
// The rate at which new calls to OnPaint will be generated.
const int kDefaultFrameRate = 30;
const int kMaximumFrameRate = 60;
} // namespace
int ClampFrameRate(int frame_rate) {
if (frame_rate < 1)
return kDefaultFrameRate;
else if (frame_rate > kMaximumFrameRate)
return kMaximumFrameRate;
return frame_rate;
}
} // namespace osr_util

View File

@ -0,0 +1,14 @@
// Copyright 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_LIBCEF_BROWSER_OSR_OSR_UTIL_H_
#define CEF_LIBCEF_BROWSER_OSR_OSR_UTIL_H_
namespace osr_util {
int ClampFrameRate(int frame_rate);
} // namespace osr_util
#endif // CEF_LIBCEF_BROWSER_OSR_OSR_UTIL_H_

View File

@ -3,9 +3,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/browser/osr/render_widget_host_view_osr.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/software_output_device_osr.h"
#include "libcef/browser/osr/osr_util.h"
#include "libcef/browser/osr/software_output_device_osr.h"
#include "libcef/browser/thread_util.h"
#include "base/callback_helpers.h"
@ -34,10 +36,6 @@ namespace {
const float kDefaultScaleFactor = 1.0;
// The rate at which new calls to OnPaint will be generated.
const int kDefaultFrameRate = 30;
const int kMaximumFrameRate = 60;
// The maximum number of retry counts if frame capture fails.
const int kFrameRetryLimit = 2;
@ -437,9 +435,11 @@ class CefBeginFrameTimer : public cc::DelayBasedTimeSourceClient {
CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR(
bool transparent,
content::RenderWidgetHost* widget,
CefRenderWidgetHostViewOSR* parent_host_view)
: scale_factor_(kDefaultScaleFactor),
: transparent_(transparent),
scale_factor_(kDefaultScaleFactor),
frame_rate_threshold_ms_(0),
delegated_frame_host_(new content::DelegatedFrameHost(this)),
compositor_widget_(gfx::kNullAcceleratedWidget),
@ -767,7 +767,7 @@ void CefRenderWidgetHostViewOSR::UpdateCursor(
// |web_cursor| owns the resulting |platform_cursor|.
platform_cursor = web_cursor.GetPlatformCursor();
} else {
platform_cursor = browser_impl_->GetPlatformCursor(cursor_info.type);
platform_cursor = GetPlatformCursor(cursor_info.type);
}
handler->OnCursorChange(browser_impl_.get(), platform_cursor, cursor_type,
@ -1003,8 +1003,7 @@ CefRenderWidgetHostViewOSR::CreateSoftwareOutputDevice(
DCHECK(!copy_frame_generator_);
DCHECK(!software_output_device_);
software_output_device_ = new CefSoftwareOutputDeviceOSR(
compositor,
browser_impl_.get() ? browser_impl_->IsTransparent() : false,
compositor, transparent_,
base::Bind(&CefRenderWidgetHostViewOSR::OnPaint,
weak_ptr_factory_.GetWeakPtr()));
return make_scoped_ptr<cc::SoftwareOutputDevice>(software_output_device_);
@ -1070,7 +1069,7 @@ void CefRenderWidgetHostViewOSR::DelegatedFrameHostUpdateVSyncParameters(
}
bool CefRenderWidgetHostViewOSR::InstallTransparency() {
if (browser_impl_.get() && browser_impl_->IsTransparent()) {
if (transparent_) {
SetBackgroundColor(SkColorSetARGB(SK_AlphaTRANSPARENT, 0, 0, 0));
compositor_->SetHostHasTransparentBackground(true);
return true;
@ -1284,15 +1283,6 @@ void CefRenderWidgetHostViewOSR::RemoveGuestHostView(
guest_host_views_.erase(guest_host);
}
// static
int CefRenderWidgetHostViewOSR::ClampFrameRate(int frame_rate) {
if (frame_rate < 1)
return kDefaultFrameRate;
else if (frame_rate > kMaximumFrameRate)
return kMaximumFrameRate;
return frame_rate;
}
void CefRenderWidgetHostViewOSR::SetFrameRate() {
CefRefPtr<CefBrowserHostImpl> browser;
if (parent_host_view_) {
@ -1308,7 +1298,7 @@ void CefRenderWidgetHostViewOSR::SetFrameRate() {
return;
const int frame_rate =
ClampFrameRate(browser->settings().windowless_frame_rate);
osr_util::ClampFrameRate(browser->settings().windowless_frame_rate);
frame_rate_threshold_ms_ = 1000 / frame_rate;
// Configure the VSync interval for the browser process.

View File

@ -3,8 +3,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_RENDER_WIDGET_HOST_VIEW_OSR_H_
#define CEF_LIBCEF_BROWSER_RENDER_WIDGET_HOST_VIEW_OSR_H_
#ifndef CEF_LIBCEF_BROWSER_OSR_RENDER_WIDGET_HOST_VIEW_OSR_H_
#define CEF_LIBCEF_BROWSER_OSR_RENDER_WIDGET_HOST_VIEW_OSR_H_
#pragma once
#include <set>
@ -18,6 +18,10 @@
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "ui/compositor/compositor.h"
#if defined(OS_LINUX)
#include "ui/base/x/x11_util.h"
#endif
#if defined(OS_MACOSX)
#include "content/browser/compositor/browser_compositor_view_mac.h"
#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
@ -79,7 +83,8 @@ class CefRenderWidgetHostViewOSR
public ui::CompositorDelegate,
public content::DelegatedFrameHostClient {
public:
CefRenderWidgetHostViewOSR(content::RenderWidgetHost* widget,
CefRenderWidgetHostViewOSR(const bool transparent,
content::RenderWidgetHost* widget,
CefRenderWidgetHostViewOSR* parent_host_view);
~CefRenderWidgetHostViewOSR() override;
@ -284,8 +289,6 @@ class CefRenderWidgetHostViewOSR
content::RenderWidgetHostImpl* render_widget_host() const
{ return render_widget_host_; }
static int ClampFrameRate(int frame_rate);
private:
void SetFrameRate();
void SetDeviceScaleFactor();
@ -328,6 +331,12 @@ class CefRenderWidgetHostViewOSR
void PlatformCreateCompositorWidget();
void PlatformDestroyCompositorWidget();
#if defined(USE_AURA)
ui::PlatformCursor GetPlatformCursor(blink::WebCursorInfo::Type type);
#endif
const bool transparent_;
float scale_factor_;
int frame_rate_threshold_ms_;
@ -344,6 +353,7 @@ class CefRenderWidgetHostViewOSR
scoped_ptr<content::BrowserCompositorMac> browser_compositor_;
#elif defined(USE_X11)
CefWindowX11* window_;
scoped_ptr<ui::XScopedCursor> invisible_cursor_;
#endif
// Used to control the VSync rate in subprocesses when BeginFrame scheduling
@ -403,5 +413,5 @@ class CefRenderWidgetHostViewOSR
DISALLOW_COPY_AND_ASSIGN(CefRenderWidgetHostViewOSR);
};
#endif // CEF_LIBCEF_BROWSER_RENDER_WIDGET_HOST_VIEW_OSR_H_
#endif // CEF_LIBCEF_BROWSER_OSR_RENDER_WIDGET_HOST_VIEW_OSR_H_

View File

@ -0,0 +1,144 @@
// Copyright (c) 2014 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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 "libcef/browser/osr/render_widget_host_view_osr.h"
#include <X11/cursorfont.h>
#include <X11/Xlib.h>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/native/window_x11.h"
#include "third_party/WebKit/public/platform/WebCursorInfo.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/x/x11_types.h"
namespace {
// Based on ui/base/cursor/cursor_loader_x11.cc.
using blink::WebCursorInfo;
int ToCursorID(WebCursorInfo::Type type) {
switch (type) {
case WebCursorInfo::TypePointer:
return XC_left_ptr;
case WebCursorInfo::TypeCross:
return XC_crosshair;
case WebCursorInfo::TypeHand:
return XC_hand2;
case WebCursorInfo::TypeIBeam:
return XC_xterm;
case WebCursorInfo::TypeWait:
return XC_watch;
case WebCursorInfo::TypeHelp:
return XC_question_arrow;
case WebCursorInfo::TypeEastResize:
return XC_right_side;
case WebCursorInfo::TypeNorthResize:
return XC_top_side;
case WebCursorInfo::TypeNorthEastResize:
return XC_top_right_corner;
case WebCursorInfo::TypeNorthWestResize:
return XC_top_left_corner;
case WebCursorInfo::TypeSouthResize:
return XC_bottom_side;
case WebCursorInfo::TypeSouthEastResize:
return XC_bottom_right_corner;
case WebCursorInfo::TypeSouthWestResize:
return XC_bottom_left_corner;
case WebCursorInfo::TypeWestResize:
return XC_left_side;
case WebCursorInfo::TypeNorthSouthResize:
return XC_sb_v_double_arrow;
case WebCursorInfo::TypeEastWestResize:
return XC_sb_h_double_arrow;
case WebCursorInfo::TypeNorthEastSouthWestResize:
return XC_left_ptr;
case WebCursorInfo::TypeNorthWestSouthEastResize:
return XC_left_ptr;
case WebCursorInfo::TypeColumnResize:
return XC_sb_h_double_arrow;
case WebCursorInfo::TypeRowResize:
return XC_sb_v_double_arrow;
case WebCursorInfo::TypeMiddlePanning:
return XC_fleur;
case WebCursorInfo::TypeEastPanning:
return XC_sb_right_arrow;
case WebCursorInfo::TypeNorthPanning:
return XC_sb_up_arrow;
case WebCursorInfo::TypeNorthEastPanning:
return XC_top_right_corner;
case WebCursorInfo::TypeNorthWestPanning:
return XC_top_left_corner;
case WebCursorInfo::TypeSouthPanning:
return XC_sb_down_arrow;
case WebCursorInfo::TypeSouthEastPanning:
return XC_bottom_right_corner;
case WebCursorInfo::TypeSouthWestPanning:
return XC_bottom_left_corner;
case WebCursorInfo::TypeWestPanning:
return XC_sb_left_arrow;
case WebCursorInfo::TypeMove:
return XC_fleur;
case WebCursorInfo::TypeVerticalText:
return XC_left_ptr;
case WebCursorInfo::TypeCell:
return XC_left_ptr;
case WebCursorInfo::TypeContextMenu:
return XC_left_ptr;
case WebCursorInfo::TypeAlias:
return XC_left_ptr;
case WebCursorInfo::TypeProgress:
return XC_left_ptr;
case WebCursorInfo::TypeNoDrop:
return XC_left_ptr;
case WebCursorInfo::TypeCopy:
return XC_left_ptr;
case WebCursorInfo::TypeNotAllowed:
return XC_left_ptr;
case WebCursorInfo::TypeZoomIn:
return XC_left_ptr;
case WebCursorInfo::TypeZoomOut:
return XC_left_ptr;
case WebCursorInfo::TypeGrab:
return XC_left_ptr;
case WebCursorInfo::TypeGrabbing:
return XC_left_ptr;
case WebCursorInfo::TypeCustom:
case WebCursorInfo::TypeNone:
break;
}
NOTREACHED();
return 0;
}
} // namespace
void CefRenderWidgetHostViewOSR::PlatformCreateCompositorWidget() {
// Create a hidden 1x1 window. It will delete itself on close.
window_ = new CefWindowX11(NULL, None, gfx::Rect(0, 0, 1, 1));
compositor_widget_ = window_->xwindow();
}
void CefRenderWidgetHostViewOSR::PlatformDestroyCompositorWidget() {
DCHECK(window_);
window_->Close();
compositor_widget_ = gfx::kNullAcceleratedWidget;
}
ui::PlatformCursor CefRenderWidgetHostViewOSR::GetPlatformCursor(
blink::WebCursorInfo::Type type) {
if (type == WebCursorInfo::TypeNone) {
if (!invisible_cursor_) {
invisible_cursor_.reset(
new ui::XScopedCursor(ui::CreateInvisibleCursor(),
gfx::GetXDisplay()));
}
return invisible_cursor_->get();
} else {
return ui::GetXCursor(ToCursorID(type));
}
}

View File

@ -3,12 +3,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/browser/osr/render_widget_host_view_osr.h"
#import <Cocoa/Cocoa.h>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/text_input_client_osr_mac.h"
#include "libcef/browser/osr/text_input_client_osr_mac.h"
#include "base/compiler_specific.h"
#include "base/strings/utf_string_conversions.h"

View File

@ -0,0 +1,182 @@
// Copyright (c) 2014 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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 "libcef/browser/osr/render_widget_host_view_osr.h"
#include <windows.h>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/content_browser_client.h"
#include "grit/ui_unscaled_resources.h"
#include "third_party/WebKit/public/platform/WebCursorInfo.h"
namespace {
class CefCompositorHostWin : public gfx::WindowImpl {
public:
CefCompositorHostWin() {
// Create a hidden 1x1 borderless window.
set_window_style(WS_POPUP | WS_SYSMENU);
Init(NULL, gfx::Rect(0, 0, 1, 1));
}
~CefCompositorHostWin() override {
DestroyWindow(hwnd());
}
private:
CR_BEGIN_MSG_MAP_EX(CompositorHostWin)
CR_MSG_WM_PAINT(OnPaint)
CR_END_MSG_MAP()
void OnPaint(HDC dc) {
ValidateRect(hwnd(), NULL);
}
DISALLOW_COPY_AND_ASSIGN(CefCompositorHostWin);
};
// From content/common/cursors/webcursor_win.cc.
using blink::WebCursorInfo;
LPCWSTR ToCursorID(WebCursorInfo::Type type) {
switch (type) {
case WebCursorInfo::TypePointer:
return IDC_ARROW;
case WebCursorInfo::TypeCross:
return IDC_CROSS;
case WebCursorInfo::TypeHand:
return IDC_HAND;
case WebCursorInfo::TypeIBeam:
return IDC_IBEAM;
case WebCursorInfo::TypeWait:
return IDC_WAIT;
case WebCursorInfo::TypeHelp:
return IDC_HELP;
case WebCursorInfo::TypeEastResize:
return IDC_SIZEWE;
case WebCursorInfo::TypeNorthResize:
return IDC_SIZENS;
case WebCursorInfo::TypeNorthEastResize:
return IDC_SIZENESW;
case WebCursorInfo::TypeNorthWestResize:
return IDC_SIZENWSE;
case WebCursorInfo::TypeSouthResize:
return IDC_SIZENS;
case WebCursorInfo::TypeSouthEastResize:
return IDC_SIZENWSE;
case WebCursorInfo::TypeSouthWestResize:
return IDC_SIZENESW;
case WebCursorInfo::TypeWestResize:
return IDC_SIZEWE;
case WebCursorInfo::TypeNorthSouthResize:
return IDC_SIZENS;
case WebCursorInfo::TypeEastWestResize:
return IDC_SIZEWE;
case WebCursorInfo::TypeNorthEastSouthWestResize:
return IDC_SIZENESW;
case WebCursorInfo::TypeNorthWestSouthEastResize:
return IDC_SIZENWSE;
case WebCursorInfo::TypeColumnResize:
return MAKEINTRESOURCE(IDC_COLRESIZE);
case WebCursorInfo::TypeRowResize:
return MAKEINTRESOURCE(IDC_ROWRESIZE);
case WebCursorInfo::TypeMiddlePanning:
return MAKEINTRESOURCE(IDC_PAN_MIDDLE);
case WebCursorInfo::TypeEastPanning:
return MAKEINTRESOURCE(IDC_PAN_EAST);
case WebCursorInfo::TypeNorthPanning:
return MAKEINTRESOURCE(IDC_PAN_NORTH);
case WebCursorInfo::TypeNorthEastPanning:
return MAKEINTRESOURCE(IDC_PAN_NORTH_EAST);
case WebCursorInfo::TypeNorthWestPanning:
return MAKEINTRESOURCE(IDC_PAN_NORTH_WEST);
case WebCursorInfo::TypeSouthPanning:
return MAKEINTRESOURCE(IDC_PAN_SOUTH);
case WebCursorInfo::TypeSouthEastPanning:
return MAKEINTRESOURCE(IDC_PAN_SOUTH_EAST);
case WebCursorInfo::TypeSouthWestPanning:
return MAKEINTRESOURCE(IDC_PAN_SOUTH_WEST);
case WebCursorInfo::TypeWestPanning:
return MAKEINTRESOURCE(IDC_PAN_WEST);
case WebCursorInfo::TypeMove:
return IDC_SIZEALL;
case WebCursorInfo::TypeVerticalText:
return MAKEINTRESOURCE(IDC_VERTICALTEXT);
case WebCursorInfo::TypeCell:
return MAKEINTRESOURCE(IDC_CELL);
case WebCursorInfo::TypeContextMenu:
return IDC_ARROW;
case WebCursorInfo::TypeAlias:
return MAKEINTRESOURCE(IDC_ALIAS);
case WebCursorInfo::TypeProgress:
return IDC_APPSTARTING;
case WebCursorInfo::TypeNoDrop:
return IDC_NO;
case WebCursorInfo::TypeCopy:
return MAKEINTRESOURCE(IDC_COPYCUR);
case WebCursorInfo::TypeNone:
return MAKEINTRESOURCE(IDC_CURSOR_NONE);
case WebCursorInfo::TypeNotAllowed:
return IDC_NO;
case WebCursorInfo::TypeZoomIn:
return MAKEINTRESOURCE(IDC_ZOOMIN);
case WebCursorInfo::TypeZoomOut:
return MAKEINTRESOURCE(IDC_ZOOMOUT);
case WebCursorInfo::TypeGrab:
return MAKEINTRESOURCE(IDC_HAND_GRAB);
case WebCursorInfo::TypeGrabbing:
return MAKEINTRESOURCE(IDC_HAND_GRABBING);
}
NOTREACHED();
return NULL;
}
bool IsSystemCursorID(LPCWSTR cursor_id) {
return cursor_id >= IDC_ARROW; // See WinUser.h
}
} // namespace
void CefRenderWidgetHostViewOSR::SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) {
}
gfx::NativeViewId
CefRenderWidgetHostViewOSR::GetParentForWindowlessPlugin() const {
if (browser_impl_.get()) {
return reinterpret_cast<gfx::NativeViewId>(
browser_impl_->GetWindowHandle());
}
return NULL;
}
void CefRenderWidgetHostViewOSR::PlatformCreateCompositorWidget() {
DCHECK(!window_);
window_.reset(new CefCompositorHostWin());
compositor_widget_ = window_->hwnd();
}
void CefRenderWidgetHostViewOSR::PlatformDestroyCompositorWidget() {
window_.reset(NULL);
compositor_widget_ = gfx::kNullAcceleratedWidget;
}
ui::PlatformCursor CefRenderWidgetHostViewOSR::GetPlatformCursor(
blink::WebCursorInfo::Type type) {
HMODULE module_handle = NULL;
const wchar_t* cursor_id = ToCursorID(type);
if (!IsSystemCursorID(cursor_id)) {
module_handle = ::GetModuleHandle(
CefContentBrowserClient::Get()->GetResourceDllName());
if (!module_handle)
module_handle = ::GetModuleHandle(NULL);
}
return LoadCursor(module_handle, cursor_id);
}

View File

@ -3,10 +3,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/software_output_device_osr.h"
#include "libcef/browser/osr/software_output_device_osr.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/browser/osr/render_widget_host_view_osr.h"
#include "libcef/browser/thread_util.h"
#include "third_party/skia/include/core/SkDevice.h"

View File

@ -3,8 +3,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_SOFTWARE_OUTPUT_DEVICE_OSR_H_
#define CEF_LIBCEF_BROWSER_SOFTWARE_OUTPUT_DEVICE_OSR_H_
#ifndef CEF_LIBCEF_BROWSER_OSR_SOFTWARE_OUTPUT_DEVICE_OSR_H_
#define CEF_LIBCEF_BROWSER_OSR_SOFTWARE_OUTPUT_DEVICE_OSR_H_
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
@ -52,4 +52,4 @@ class CefSoftwareOutputDeviceOSR : public cc::SoftwareOutputDevice {
DISALLOW_COPY_AND_ASSIGN(CefSoftwareOutputDeviceOSR);
};
#endif // CEF_LIBCEF_BROWSER_SOFTWARE_OUTPUT_DEVICE_OSR_H_
#endif // CEF_LIBCEF_BROWSER_OSR_SOFTWARE_OUTPUT_DEVICE_OSR_H_

View File

@ -2,14 +2,14 @@
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_TEXT_INPUT_CLIENT_OSR_MAC_H_
#define CEF_LIBCEF_BROWSER_TEXT_INPUT_CLIENT_OSR_MAC_H_
#ifndef CEF_LIBCEF_BROWSER_OSR_TEXT_INPUT_CLIENT_OSR_MAC_H_
#define CEF_LIBCEF_BROWSER_OSR_TEXT_INPUT_CLIENT_OSR_MAC_H_
#pragma once
#import <Cocoa/Cocoa.h>
#include <vector>
#include "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/browser/osr/render_widget_host_view_osr.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/string16.h"
@ -73,4 +73,4 @@
@end
#endif // CEF_LIBCEF_BROWSER_TEXT_INPUT_CLIENT_OSR_MAC_H_
#endif // CEF_LIBCEF_BROWSER_OSR_TEXT_INPUT_CLIENT_OSR_MAC_H_

View File

@ -2,7 +2,8 @@
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "libcef/browser/text_input_client_osr_mac.h"
#include "libcef/browser/osr/text_input_client_osr_mac.h"
#include "libcef/browser/browser_host_impl.h"
#include "base/numerics/safe_conversions.h"

View File

@ -3,9 +3,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/web_contents_view_osr.h"
#include "libcef/browser/osr/web_contents_view_osr.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/browser/osr/render_widget_host_view_osr.h"
#include "libcef/common/drag_data_impl.h"
#include "content/browser/browser_plugin/browser_plugin_embedder.h"
@ -15,8 +16,9 @@
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/user_metrics.h"
CefWebContentsViewOSR::CefWebContentsViewOSR()
: web_contents_(NULL),
CefWebContentsViewOSR::CefWebContentsViewOSR(bool transparent)
: transparent_(transparent),
web_contents_(NULL),
view_(NULL),
guest_(NULL) {
}
@ -126,7 +128,8 @@ content::RenderWidgetHostViewBase* CefWebContentsViewOSR::CreateViewForWidget(
embedder_web_contents->GetRenderViewHost()->GetWidget()->GetView());
CefRenderWidgetHostViewOSR* platform_widget =
new CefRenderWidgetHostViewOSR(render_widget_host, embedder_host_view);
new CefRenderWidgetHostViewOSR(transparent_, render_widget_host,
embedder_host_view);
embedder_host_view->AddGuestHostView(platform_widget);
return new content::RenderWidgetHostViewGuest(
@ -135,7 +138,8 @@ content::RenderWidgetHostViewBase* CefWebContentsViewOSR::CreateViewForWidget(
platform_widget->GetWeakPtr());
}
view_ = new CefRenderWidgetHostViewOSR(render_widget_host, NULL);
view_ = new CefRenderWidgetHostViewOSR(transparent_, render_widget_host,
NULL);
return view_;
}
@ -143,7 +147,8 @@ content::RenderWidgetHostViewBase* CefWebContentsViewOSR::CreateViewForWidget(
content::RenderWidgetHostViewBase*
CefWebContentsViewOSR::CreateViewForPopupWidget(
content::RenderWidgetHost* render_widget_host) {
return new CefRenderWidgetHostViewOSR(render_widget_host, view_);
return new CefRenderWidgetHostViewOSR(transparent_, render_widget_host,
view_);
}
void CefWebContentsViewOSR::SetPageTitle(const base::string16& title) {

View File

@ -3,8 +3,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_WEB_CONTENTS_VIEW_OSR_H_
#define CEF_LIBCEF_BROWSER_WEB_CONTENTS_VIEW_OSR_H_
#ifndef CEF_LIBCEF_BROWSER_OSR_WEB_CONTENTS_VIEW_OSR_H_
#define CEF_LIBCEF_BROWSER_OSR_WEB_CONTENTS_VIEW_OSR_H_
#include "content/browser/renderer_host/render_view_host_delegate_view.h"
#include "content/browser/web_contents/web_contents_view.h"
@ -21,10 +21,11 @@ class CefRenderWidgetHostViewOSR;
class CefWebContentsViewOSR : public content::WebContentsView,
public content::RenderViewHostDelegateView {
public:
CefWebContentsViewOSR();
explicit CefWebContentsViewOSR(bool transparent);
~CefWebContentsViewOSR() override;
void set_web_contents(content::WebContents* web_contents);
content::WebContents* web_contents() const { return web_contents_; }
void set_guest(content::BrowserPluginGuest* guest);
// WebContentsView methods.
@ -68,6 +69,8 @@ class CefWebContentsViewOSR : public content::WebContentsView,
void UpdateDragCursor(blink::WebDragOperation operation) override;
private:
const bool transparent_;
content::WebContents* web_contents_;
CefRenderWidgetHostViewOSR* view_;
@ -77,4 +80,4 @@ class CefWebContentsViewOSR : public content::WebContentsView,
DISALLOW_COPY_AND_ASSIGN(CefWebContentsViewOSR);
};
#endif // CEF_LIBCEF_BROWSER_WEB_CONTENTS_VIEW_OSR_H_
#endif // CEF_LIBCEF_BROWSER_OSR_WEB_CONTENTS_VIEW_OSR_H_

View File

@ -1,25 +0,0 @@
// Copyright (c) 2014 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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 "libcef/browser/render_widget_host_view_osr.h"
#include <X11/Xlib.h>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/window_x11.h"
#include "ui/gfx/x/x11_types.h"
void CefRenderWidgetHostViewOSR::PlatformCreateCompositorWidget() {
// Create a hidden 1x1 window. It will delete itself on close.
window_ = new CefWindowX11(NULL, None, gfx::Rect(0, 0, 1, 1));
compositor_widget_ = window_->xwindow();
}
void CefRenderWidgetHostViewOSR::PlatformDestroyCompositorWidget() {
DCHECK(window_);
window_->Close();
compositor_widget_ = gfx::kNullAcceleratedWidget;
}

View File

@ -1,59 +0,0 @@
// Copyright (c) 2014 The Chromium Embedded Framework Authors.
// Portions copyright (c) 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 "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/browser/browser_host_impl.h"
namespace {
class CefCompositorHostWin : public gfx::WindowImpl {
public:
CefCompositorHostWin() {
// Create a hidden 1x1 borderless window.
set_window_style(WS_POPUP | WS_SYSMENU);
Init(NULL, gfx::Rect(0, 0, 1, 1));
}
~CefCompositorHostWin() override {
DestroyWindow(hwnd());
}
private:
CR_BEGIN_MSG_MAP_EX(CompositorHostWin)
CR_MSG_WM_PAINT(OnPaint)
CR_END_MSG_MAP()
void OnPaint(HDC dc) {
ValidateRect(hwnd(), NULL);
}
DISALLOW_COPY_AND_ASSIGN(CefCompositorHostWin);
};
} // namespace
void CefRenderWidgetHostViewOSR::SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) {
}
gfx::NativeViewId
CefRenderWidgetHostViewOSR::GetParentForWindowlessPlugin() const {
if (browser_impl_.get()) {
return reinterpret_cast<gfx::NativeViewId>(
browser_impl_->GetWindowHandle());
}
return NULL;
}
void CefRenderWidgetHostViewOSR::PlatformCreateCompositorWidget() {
DCHECK(!window_);
window_.reset(new CefCompositorHostWin());
compositor_widget_ = window_->hwnd();
}
void CefRenderWidgetHostViewOSR::PlatformDestroyCompositorWidget() {
window_.reset(NULL);
compositor_widget_ = gfx::kNullAcceleratedWidget;
}

View File

@ -30,6 +30,7 @@
#include "base/command_line.h"
#include "base/metrics/user_metrics_action.h"
#include "base/path_service.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/common/chrome_switches.h"
@ -58,6 +59,7 @@
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/render_view_visitor.h"
#include "content/renderer/render_frame_impl.h"
#include "content/renderer/render_widget.h"
#include "extensions/renderer/renderer_extension_registry.h"
#include "ipc/ipc_sync_channel.h"
#include "media/base/media.h"
@ -147,6 +149,20 @@ std::string GetPluginInstancePosterAttribute(
} // namespace
// Placeholder object for guest views.
class CefGuestView : public content::RenderViewObserver {
public:
explicit CefGuestView(content::RenderView* render_view)
: content::RenderViewObserver(render_view) {
}
private:
// RenderViewObserver methods.
void OnDestruct() override {
CefContentRendererClient::Get()->OnGuestViewDestroyed(this);
}
};
CefContentRendererClient::CefContentRendererClient()
: devtools_agent_count_(0),
uncaught_exception_stack_size_(0),
@ -162,6 +178,10 @@ CefContentRendererClient::CefContentRendererClient()
}
CefContentRendererClient::~CefContentRendererClient() {
if (!guest_views_.empty()) {
STLDeleteContainerPairSecondPointers(guest_views_.begin(),
guest_views_.end());
}
}
// static
@ -209,6 +229,28 @@ void CefContentRendererClient::OnBrowserDestroyed(CefBrowserImpl* browser) {
NOTREACHED();
}
bool CefContentRendererClient::HasGuestViewForView(
content::RenderView* view) {
CEF_REQUIRE_RT_RETURN(false);
GuestViewMap::const_iterator it = guest_views_.find(view);
return it != guest_views_.end();
}
void CefContentRendererClient::OnGuestViewDestroyed(CefGuestView* guest_view) {
GuestViewMap::iterator it = guest_views_.begin();
for (; it != guest_views_.end(); ++it) {
if (it->second == guest_view) {
delete it->second;
guest_views_.erase(it);
return;
}
}
// No guest view was found in the map.
NOTREACHED();
}
void CefContentRendererClient::WebKitInitialized() {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
@ -769,24 +811,42 @@ blink::WebPlugin* CefContentRendererClient::CreatePlugin(
void CefContentRendererClient::BrowserCreated(
content::RenderView* render_view,
content::RenderFrame* render_frame) {
// Swapped out RenderWidgets will be created in the parent/owner process for
// frames that are hosted in a separate process (e.g. guest views or OOP
// frames). Don't create any CEF objects for swapped out RenderWidgets.
content::RenderFrameImpl* render_frame_impl =
static_cast<content::RenderFrameImpl*>(render_frame);
if (render_frame_impl->GetRenderWidget()->is_swapped_out())
return;
// Don't create another browser or guest view object if one already exists for
// the view.
if (GetBrowserForView(render_view).get() || HasGuestViewForView(render_view))
return;
const int render_view_routing_id = render_view->GetRoutingID();
const int render_frame_routing_id = render_frame->GetRoutingID();
// Retrieve the browser information synchronously. This will also register
// the routing ids with the browser info object in the browser process.
CefProcessHostMsg_GetNewBrowserInfo_Params params;
content::RenderThread::Get()->Send(
new CefProcessHostMsg_GetNewBrowserInfo(
render_view->GetRoutingID(),
render_frame->GetRoutingID(),
render_view_routing_id,
render_frame_routing_id,
&params));
DCHECK_GT(params.browser_id, 0);
if (params.is_guest_view) {
// Don't create a CefBrowser for guest views.
if (params.browser_id == 0) {
// The request failed for some reason.
return;
}
// Don't create another browser object if one already exists for the view.
if (GetBrowserForView(render_view).get())
if (params.is_guest_view) {
// Don't create a CefBrowser for guest views.
guest_views_.insert(
std::make_pair(render_view, new CefGuestView(render_view)));
return;
}
#if defined(OS_MACOSX)
// FIXME: It would be better if this API would be a callback from the

View File

@ -34,6 +34,7 @@ namespace web_cache {
class WebCacheRenderProcessObserver;
}
class CefGuestView;
class CefRenderProcessObserver;
struct Cef_CrossOriginWhiteListEntry_Params;
struct CefViewHostMsg_GetPluginInfo_Output;
@ -58,6 +59,12 @@ class CefContentRendererClient : public content::ContentRendererClient,
// Called from CefBrowserImpl::OnDestruct().
void OnBrowserDestroyed(CefBrowserImpl* browser);
// Returns true if a guest view associated with the specified RenderView.
bool HasGuestViewForView(content::RenderView* view);
// Called from CefGuestView::OnDestruct().
void OnGuestViewDestroyed(CefGuestView* guest_view);
// Render thread task runner.
base::SequencedTaskRunner* render_task_runner() const {
return render_task_runner_.get();
@ -143,6 +150,10 @@ class CefContentRendererClient : public content::ContentRendererClient,
typedef std::map<content::RenderView*, CefRefPtr<CefBrowserImpl> > BrowserMap;
BrowserMap browsers_;
// Map of RenderView poiners to CefGuestView implementations.
typedef std::map<content::RenderView*, CefGuestView* > GuestViewMap;
GuestViewMap guest_views_;
// Cross-origin white list entries that need to be registered with WebKit.
typedef std::vector<Cef_CrossOriginWhiteListEntry_Params> CrossOriginList;
CrossOriginList cross_origin_whitelist_entries_;

View File

@ -220,11 +220,10 @@ bool ClientDialogHandlerGtk::OnFileDialog(
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog),
!(mode & FILE_DIALOG_HIDEREADONLY_FLAG));
if (!default_file_path.empty()) {
if (!default_file_path.empty() && mode_type == FILE_DIALOG_SAVE) {
const std::string& file_path = default_file_path;
bool exists = false;
if (mode_type == FILE_DIALOG_SAVE) {
struct stat sb;
if (stat(file_path.c_str(), &sb) == 0 && S_ISREG(sb.st_mode)) {
// Use the directory and name of the existing file.
@ -232,7 +231,6 @@ bool ClientDialogHandlerGtk::OnFileDialog(
file_path.data());
exists = true;
}
}
if (!exists) {
// Set the current file name but let the user choose the directory.

View File

@ -2152,6 +2152,275 @@ TEST(NavigationTest, PopupNavigateAfterCreation) {
}
namespace {
const char kSimultPopupMainUrl[] = "http://www.tests-sp.com/main.html";
const char kSimultPopupPopupUrl[] = "http://www.tests-sp.com/popup";
const size_t kSimultPopupCount = 5U;
// Test multiple popups simultaniously.
class PopupSimultaneousTestHandler : public TestHandler {
public:
explicit PopupSimultaneousTestHandler(bool same_url)
: same_url_(same_url),
before_popup_ct_(0U),
after_created_ct_(0U),
before_close_ct_(0U) {}
void RunTest() override {
std::string main_html = "<html><script>\n";
for (size_t i = 0; i < kSimultPopupCount; ++i) {
if (same_url_) {
popup_url_[i] = std::string(kSimultPopupPopupUrl) + ".html";
} else {
std::stringstream ss;
ss << kSimultPopupPopupUrl << i << ".html";
popup_url_[i] = ss.str();
}
main_html += "window.open('" + popup_url_[i] + "');\n";
AddResource(popup_url_[i], "<html>Popup " + popup_url_[i] + "</html>",
"text/html");
}
main_html += "</script></html>";
AddResource(kSimultPopupMainUrl, main_html, "text/html");
// Create the browser.
CreateBrowser(kSimultPopupMainUrl);
// Time out the test after a reasonable period of time.
SetTestTimeout();
}
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
const CefString& target_frame_name,
cef_window_open_disposition_t target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings,
bool* no_javascript_access) override {
const std::string& url = target_url;
EXPECT_LT(before_popup_ct_, kSimultPopupCount);
EXPECT_STREQ(popup_url_[before_popup_ct_].c_str(), url.c_str()) <<
before_popup_ct_;
before_popup_ct_++;
return false;
}
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
TestHandler::OnAfterCreated(browser);
if (browser->IsPopup()) {
EXPECT_LT(after_created_ct_, kSimultPopupCount);
browser_id_[after_created_ct_] = browser->GetIdentifier();
after_created_ct_++;
}
}
void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
bool isLoading,
bool canGoBack,
bool canGoForward) override {
if (isLoading)
return;
if (browser->IsPopup()) {
const std::string& url = browser->GetMainFrame()->GetURL();
for (size_t i = 0; i < kSimultPopupCount; ++i) {
if (browser->GetIdentifier() == browser_id_[i]) {
EXPECT_STREQ(popup_url_[i].c_str(), url.c_str()) << i;
got_loading_state_change_[i].yes();
browser->GetHost()->CloseBrowser(true);
return;
}
}
EXPECT_FALSE(true); // Not reached.
}
}
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
TestHandler::OnBeforeClose(browser);
if (browser->IsPopup()) {
const std::string& url = browser->GetMainFrame()->GetURL();
for (size_t i = 0; i < kSimultPopupCount; ++i) {
if (browser->GetIdentifier() == browser_id_[i]) {
EXPECT_STREQ(popup_url_[i].c_str(), url.c_str()) << i;
got_before_close_[i].yes();
if (++before_close_ct_ == kSimultPopupCount)
DestroyTest();
return;
}
}
EXPECT_FALSE(true); // Not reached.
}
}
private:
void DestroyTest() override {
EXPECT_EQ(kSimultPopupCount, before_popup_ct_);
EXPECT_EQ(kSimultPopupCount, after_created_ct_);
EXPECT_EQ(kSimultPopupCount, before_close_ct_);
for (size_t i = 0; i < kSimultPopupCount; ++i) {
EXPECT_GT(browser_id_[i], 0) << i;
EXPECT_TRUE(got_loading_state_change_[i]) << i;
EXPECT_TRUE(got_before_close_[i]) << i;
}
TestHandler::DestroyTest();
}
const bool same_url_;
std::string popup_url_[kSimultPopupCount];
size_t before_popup_ct_;
int browser_id_[kSimultPopupCount];
size_t after_created_ct_;
TrackCallback got_loading_state_change_[kSimultPopupCount];
TrackCallback got_before_close_[kSimultPopupCount];
size_t before_close_ct_;
IMPLEMENT_REFCOUNTING(PopupSimultaneousTestHandler);
};
} // namespace
// Test simultaneous popups with different URLs.
TEST(NavigationTest, PopupSimultaneousDifferentUrl) {
CefRefPtr<PopupSimultaneousTestHandler> handler =
new PopupSimultaneousTestHandler(false);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Test simultaneous popups with the same URL.
TEST(NavigationTest, PopupSimultaneousSameUrl) {
CefRefPtr<PopupSimultaneousTestHandler> handler =
new PopupSimultaneousTestHandler(true);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
namespace {
const char kPopupJSOpenMainUrl[] = "http://www.tests-pjso.com/main.html";
const char kPopupJSOpenPopupUrl[] = "http://www.tests-pjso.com/popup.html";
// Test a popup where the URL is a JavaScript URI that opens another popup.
// See comments on CefBrowserInfoManager::FilterPendingPopupURL.
class PopupJSWindowOpenTestHandler : public TestHandler {
public:
PopupJSWindowOpenTestHandler()
: before_popup_ct_(0U),
after_created_ct_(0U),
load_end_ct_(0U),
before_close_ct_(0U) {}
void RunTest() override {
AddResource(kPopupJSOpenMainUrl, "<html>Main</html>", "text/html");
AddResource(kPopupJSOpenPopupUrl, "<html>Popup</html>", "text/html");
// Create the browser.
CreateBrowser(kPopupJSOpenMainUrl);
// Time out the test after a reasonable period of time.
SetTestTimeout();
}
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
const CefString& target_frame_name,
cef_window_open_disposition_t target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings,
bool* no_javascript_access) override {
before_popup_ct_++;
return false;
}
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
TestHandler::OnAfterCreated(browser);
if (browser->IsPopup())
after_created_ct_++;
}
void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
bool isLoading,
bool canGoBack,
bool canGoForward) override {
if (isLoading)
return;
if (browser->IsPopup()) {
const std::string& url = browser->GetMainFrame()->GetURL();
if (load_end_ct_ == 0)
EXPECT_TRUE(url.empty());
else
EXPECT_STREQ(kPopupJSOpenPopupUrl, url.c_str());
load_end_ct_++;
browser->GetHost()->CloseBrowser(true);
} else if (browser->GetMainFrame()->GetURL() == kPopupJSOpenMainUrl) {
// Load the problematic JS URI.
// This will result in 2 popups being created:
// - An empty popup
// - A popup that loads kPopupJSOpenPopupUrl
browser->GetMainFrame()->LoadURL(
"javascript:window.open(\"javascript:window.open('" +
std::string(kPopupJSOpenPopupUrl) + "')\")");
}
}
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
TestHandler::OnBeforeClose(browser);
before_close_ct_++;
if (before_close_ct_ == 2U)
DestroyTest();
}
private:
void DestroyTest() override {
EXPECT_EQ(2U, before_popup_ct_);
EXPECT_EQ(2U, after_created_ct_);
EXPECT_EQ(2U, load_end_ct_);
EXPECT_EQ(2U, before_close_ct_);
TestHandler::DestroyTest();
}
size_t before_popup_ct_;
size_t after_created_ct_;
size_t load_end_ct_;
size_t before_close_ct_;
IMPLEMENT_REFCOUNTING(PopupJSWindowOpenTestHandler);
};
} // namespace
// Test a popup where the URL is a JavaScript URI that opens another popup.
TEST(NavigationTest, PopupJSWindowOpen) {
CefRefPtr<PopupJSWindowOpenTestHandler> handler =
new PopupJSWindowOpenTestHandler();
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
namespace {
const char kBrowseNavPageUrl[] = "http://tests-browsenav/nav.html";

View File

@ -85,7 +85,7 @@ const int kVerticalScrollbarWidth = GetSystemMetrics(SM_CXVSCROLL);
const CefRect kEditBoxRect(442, 251, 46, 16);
const CefRect kNavigateButtonRect(375, 275, 130, 20);
const CefRect kSelectRect(461, 21, 87, 26);
const CefRect kExpandedSelectRect(466, 42, 76, 286);
const CefRect kExpandedSelectRect(466, 42, 78, 286);
const CefRect kDropDivRect(9, 330, 52, 52);
const CefRect kDragDivRect(60, 330, 52, 52);
const int kVerticalScrollbarWidth = 15;
@ -183,10 +183,15 @@ enum OSRTestType {
OSR_TEST_DRAG_DROP_UPDATE_CURSOR,
// dropping element inside drop region will move the element
OSR_TEST_DRAG_DROP_DROP,
// Define the range for popup tests.
OSR_TEST_POPUP_FIRST = OSR_TEST_POPUP_PAINT,
OSR_TEST_POPUP_LAST = OSR_TEST_POPUP_SCROLL_INSIDE,
};
// Used in the browser process.
class OSRTestHandler : public RoutingTestHandler,
public CefFocusHandler,
public CefRenderHandler,
public CefContextMenuHandler {
public:
@ -278,6 +283,10 @@ class OSRTestHandler : public RoutingTestHandler,
}
// CefClient methods, providing handlers
CefRefPtr<CefFocusHandler> GetFocusHandler() override {
return this;
}
CefRefPtr<CefRenderHandler> GetRenderHandler() override {
return this;
}
@ -762,6 +771,23 @@ class OSRTestHandler : public RoutingTestHandler,
}
}
bool OnSetFocus(CefRefPtr<CefBrowser> browser,
FocusSource source) override {
if (source == FOCUS_SOURCE_NAVIGATION) {
got_navigation_focus_event_.yes();
// Ignore focus from the original navigation when we're testing focus
// event delivery.
if (test_type_ == OSR_TEST_FOCUS)
return true;
return false;
}
EXPECT_EQ(source, FOCUS_SOURCE_SYSTEM);
got_system_focus_event_.yes();
return false;
}
void OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
CursorType type,
@ -937,6 +963,23 @@ class OSRTestHandler : public RoutingTestHandler,
CefPostTask(TID_UI, base::Bind(&OSRTestHandler::DestroyTest, this));
}
void DestroyTest() override {
// Always get the OnSetFocus call for the initial navigation.
EXPECT_TRUE(got_navigation_focus_event_);
if (test_type_ == OSR_TEST_FOCUS ||
(test_type_ >= OSR_TEST_POPUP_FIRST &&
test_type_ <= OSR_TEST_POPUP_LAST)) {
// SetFocus is called by the system when we explicitly set the focus and
// when popups are dismissed.
EXPECT_TRUE(got_system_focus_event_);
} else {
EXPECT_FALSE(got_system_focus_event_);
}
RoutingTestHandler::DestroyTest();
}
void ExpandDropDown() {
GetBrowser()->GetHost()->SendFocusEvent(true);
CefMouseEvent mouse_event;
@ -1013,6 +1056,8 @@ class OSRTestHandler : public RoutingTestHandler,
int event_total_;
bool started_;
TrackCallback got_update_cursor_;
TrackCallback got_navigation_focus_event_;
TrackCallback got_system_focus_event_;
IMPLEMENT_REFCOUNTING(OSRTestHandler);
};