From e193688d10172b90fa065e56a37e426e54ecc4c9 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Wed, 16 May 2012 17:03:23 +0000 Subject: [PATCH] Merge revision 569 and 624 changes: - Add off-screen rendering support for Mac OS-X (issue #540). - Avoid calling OnSetFocus multiple times (issue #563). git-svn-id: https://chromiumembedded.googlecode.com/svn/branches/963@627 5089003a-bbd8-11dd-ad1f-f1f9622dbc98 --- cef.gyp | 1 + cef_paths.gypi | 9 + include/cef.h | 6 +- include/cef_capi.h | 6 +- include/internal/cef_linux.h | 88 +-- include/internal/cef_mac.h | 104 ++-- include/internal/cef_types.h | 196 +++---- include/internal/cef_types_linux.h | 7 + include/internal/cef_types_mac.h | 46 +- include/internal/cef_types_win.h | 9 + include/internal/cef_win.h | 85 +-- libcef/browser_impl.cc | 50 +- libcef/browser_impl.h | 18 +- libcef/browser_impl_mac.mm | 137 +++-- libcef/browser_webview_delegate_mac.mm | 189 +++++-- libcef/browser_webview_delegate_win.cc | 84 ++- libcef/browser_webview_mac.h | 19 +- libcef/browser_webview_mac.mm | 34 +- libcef/external_popup_menu_mac.mm | 32 +- libcef/webview_host_mac.mm | 13 +- libcef/webwidget_host.cc | 35 +- libcef/webwidget_host.h | 43 +- libcef/webwidget_host_gtk.cc | 43 +- libcef/webwidget_host_mac.mm | 508 +++++++++++++---- libcef/webwidget_host_win.cc | 157 +++--- libcef_dll/cpptoc/browser_cpptoc.cc | 24 +- libcef_dll/ctocpp/browser_ctocpp.cc | 15 +- libcef_dll/ctocpp/browser_ctocpp.h | 7 +- tests/cefclient/cefclient_mac.mm | 81 +-- tests/cefclient/osrenderer.cpp | 410 ++++++++++++++ tests/cefclient/osrenderer.h | 63 +++ tests/cefclient/osrplugin.cpp | 603 +++++--------------- tests/cefclient/osrtest_mac.h | 15 + tests/cefclient/osrtest_mac.mm | 752 +++++++++++++++++++++++++ tests/cefclient/res/osrtest.html | 40 ++ tools/distrib/cefclient.gyp | 1 + 36 files changed, 2722 insertions(+), 1208 deletions(-) create mode 100644 tests/cefclient/osrenderer.cpp create mode 100644 tests/cefclient/osrenderer.h create mode 100644 tests/cefclient/osrtest_mac.h create mode 100644 tests/cefclient/osrtest_mac.mm create mode 100644 tests/cefclient/res/osrtest.html diff --git a/cef.gyp b/cef.gyp index 6c7952933..00f49dba3 100644 --- a/cef.gyp +++ b/cef.gyp @@ -209,6 +209,7 @@ 'link_settings': { 'libraries': [ '$(SDKROOT)/System/Library/Frameworks/AppKit.framework', + '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework', ], }, 'sources': [ diff --git a/cef_paths.gypi b/cef_paths.gypi index 56a71b2f9..a951f589a 100644 --- a/cef_paths.gypi +++ b/cef_paths.gypi @@ -73,6 +73,8 @@ 'tests/cefclient/client_handler_win.cpp', 'tests/cefclient/clientplugin.cpp', 'tests/cefclient/clientplugin.h', + 'tests/cefclient/osrenderer.cpp', + 'tests/cefclient/osrenderer.h', 'tests/cefclient/osrplugin.cpp', 'tests/cefclient/osrplugin.h', 'tests/cefclient/osrplugin_test.cpp', @@ -97,6 +99,10 @@ 'cefclient_sources_mac': [ 'tests/cefclient/cefclient_mac.mm', 'tests/cefclient/client_handler_mac.mm', + 'tests/cefclient/osrenderer.cpp', + 'tests/cefclient/osrenderer.h', + 'tests/cefclient/osrtest_mac.h', + 'tests/cefclient/osrtest_mac.mm', 'tests/cefclient/resource_util_mac.mm', ], 'cefclient_bundle_resources_mac': [ @@ -109,6 +115,9 @@ 'tests/cefclient/res/extensionperf.html', 'tests/cefclient/res/localstorage.html', 'tests/cefclient/res/logo.png', + 'tests/cefclient/res/logoball.png', + 'tests/cefclient/res/osrtest.html', + 'tests/cefclient/res/transparency.html', 'tests/cefclient/res/xmlhttprequest.html', ], 'cefclient_sources_linux': [ diff --git a/include/cef.h b/include/cef.h index 163247c8a..27b141393 100644 --- a/include/cef.h +++ b/include/cef.h @@ -933,8 +933,8 @@ public: // Send a key event to the browser. /// /*--cef()--*/ - virtual void SendKeyEvent(KeyType type, int key, int modifiers, bool sysChar, - bool imeChar) =0; + virtual void SendKeyEvent(KeyType type, const CefKeyInfo& keyInfo, + int modifiers) =0; /// // Send a mouse click event to the browser. The |x| and |y| coordinates are @@ -956,7 +956,7 @@ public: // relative to the upper-left corner of the view. /// /*--cef()--*/ - virtual void SendMouseWheelEvent(int x, int y, int delta) =0; + virtual void SendMouseWheelEvent(int x, int y, int deltaX, int deltaY) =0; /// // Send a focus event to the browser. diff --git a/include/cef_capi.h b/include/cef_capi.h index 8de8a7028..e2cc21401 100644 --- a/include/cef_capi.h +++ b/include/cef_capi.h @@ -754,8 +754,8 @@ typedef struct _cef_browser_t // Send a key event to the browser. /// void (CEF_CALLBACK *send_key_event)(struct _cef_browser_t* self, - enum cef_key_type_t type, int key, int modifiers, int sysChar, - int imeChar); + enum cef_key_type_t type, const struct _cef_key_info_t* keyInfo, + int modifiers); /// // Send a mouse click event to the browser. The |x| and |y| coordinates are @@ -777,7 +777,7 @@ typedef struct _cef_browser_t // relative to the upper-left corner of the view. /// void (CEF_CALLBACK *send_mouse_wheel_event)(struct _cef_browser_t* self, - int x, int y, int delta); + int x, int y, int deltaX, int deltaY); /// // Send a focus event to the browser. diff --git a/include/internal/cef_linux.h b/include/internal/cef_linux.h index 1f59468f1..0c9003b06 100644 --- a/include/internal/cef_linux.h +++ b/include/internal/cef_linux.h @@ -28,45 +28,43 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef _CEF_LINUX_H -#define _CEF_LINUX_H +#ifndef CEF_INCLUDE_INTERNAL_CEF_LINUX_H_ +#define CEF_INCLUDE_INTERNAL_CEF_LINUX_H_ +#pragma once #if defined(OS_LINUX) #include -#include "cef_types_linux.h" -#include "cef_types_wrappers.h" +#include "include/internal/cef_types_linux.h" +#include "include/internal/cef_types_wrappers.h" +/// // Atomic increment and decrement. -inline long CefAtomicIncrement(long volatile *pDest) -{ +/// +inline long CefAtomicIncrement(long volatile *pDest) { // NOLINT(runtime/int) return __sync_add_and_fetch(pDest, 1); } -inline long CefAtomicDecrement(long volatile *pDest) -{ +inline long CefAtomicDecrement(long volatile *pDest) { // NOLINT(runtime/int) return __sync_sub_and_fetch(pDest, 1); } +/// // Critical section wrapper. -class CefCriticalSection -{ -public: - CefCriticalSection() - { +/// +class CefCriticalSection { + public: + CefCriticalSection() { pthread_mutexattr_init(&attr_); pthread_mutexattr_settype(&attr_, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&lock_, &attr_); } - virtual ~CefCriticalSection() - { + virtual ~CefCriticalSection() { pthread_mutex_destroy(&lock_); pthread_mutexattr_destroy(&attr_); } - void Lock() - { + void Lock() { pthread_mutex_lock(&lock_); } - void Unlock() - { + void Unlock() { pthread_mutex_unlock(&lock_); } @@ -74,54 +72,78 @@ public: pthread_mutexattr_t attr_; }; +/// // Handle types. +/// #define CefWindowHandle cef_window_handle_t #define CefCursorHandle cef_cursor_handle_t + struct CefWindowInfoTraits { typedef cef_window_info_t struct_type; static inline void init(struct_type* s) {} static inline void clear(struct_type* s) {} - static inline void set(const struct_type* src, struct_type* target, bool copy) - { + static inline void set(const struct_type* src, struct_type* target, + bool copy) { target->m_Widget = src->m_Widget; target->m_ParentWidget = src->m_ParentWidget; } }; +/// // Class representing window information. -class CefWindowInfo : public CefStructBase -{ -public: +/// +class CefWindowInfo : public CefStructBase { + public: typedef CefStructBase parent; CefWindowInfo() : parent() {} - CefWindowInfo(const cef_window_info_t& r) : parent(r) {} - CefWindowInfo(const CefWindowInfo& r) : parent(r) {} - - void SetAsChild(CefWindowHandle ParentWidget) - { + explicit CefWindowInfo(const cef_window_info_t& r) : parent(r) {} + explicit CefWindowInfo(const CefWindowInfo& r) : parent(r) {} + + void SetAsChild(CefWindowHandle ParentWidget) { m_ParentWidget = ParentWidget; } }; + struct CefPrintInfoTraits { typedef cef_print_info_t struct_type; static inline void init(struct_type* s) {} static inline void clear(struct_type* s) {} - static inline void set(const struct_type* src, struct_type* target, bool copy) - { + static inline void set(const struct_type* src, struct_type* target, + bool copy) { target->m_Scale = src->m_Scale; } }; +/// // Class representing print context information. +/// typedef CefStructBase CefPrintInfo; -#endif // OS_LINUX -#endif // _CEF_LINUX_H +struct CefKeyInfoTraits { + typedef cef_key_info_t struct_type; + + static inline void init(struct_type* s) {} + static inline void clear(struct_type* s) {} + + static inline void set(const struct_type* src, struct_type* target, + bool copy) { + target->key = src->key; + } +}; + +/// +// Class representing key information. +/// +typedef CefStructBase CefKeyInfo; + +#endif // OS_LINUX + +#endif // CEF_INCLUDE_INTERNAL_CEF_LINUX_H_ diff --git a/include/internal/cef_mac.h b/include/internal/cef_mac.h index b949343af..d979e80fe 100644 --- a/include/internal/cef_mac.h +++ b/include/internal/cef_mac.h @@ -28,49 +28,49 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef _CEF_MAC_H -#define _CEF_MAC_H +#ifndef CEF_INCLUDE_INTERNAL_CEF_MAC_H_ +#define CEF_INCLUDE_INTERNAL_CEF_MAC_H_ +#pragma once #if defined(OS_MACOSX) #include -#include "cef_types_mac.h" -#include "cef_types_wrappers.h" +#include "include/internal/cef_types_mac.h" +#include "include/internal/cef_types_wrappers.h" +/// // Atomic increment and decrement. -inline long CefAtomicIncrement(long volatile *pDest) -{ +/// +inline long CefAtomicIncrement(long volatile *pDest) { // NOLINT(runtime/int) return __sync_add_and_fetch(pDest, 1); } -inline long CefAtomicDecrement(long volatile *pDest) -{ +inline long CefAtomicDecrement(long volatile *pDest) { // NOLINT(runtime/int) return __sync_sub_and_fetch(pDest, 1); } +/// // Handle types. +/// #define CefWindowHandle cef_window_handle_t #define CefCursorHandle cef_cursor_handle_t +/// // Critical section wrapper. -class CefCriticalSection -{ -public: - CefCriticalSection() - { +/// +class CefCriticalSection { + public: + CefCriticalSection() { pthread_mutexattr_init(&attr_); pthread_mutexattr_settype(&attr_, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&lock_, &attr_); } - virtual ~CefCriticalSection() - { + virtual ~CefCriticalSection() { pthread_mutex_destroy(&lock_); pthread_mutexattr_destroy(&attr_); } - void Lock() - { + void Lock() { pthread_mutex_lock(&lock_); } - void Unlock() - { + void Unlock() { pthread_mutex_unlock(&lock_); } @@ -78,18 +78,18 @@ public: pthread_mutexattr_t attr_; }; + struct CefWindowInfoTraits { typedef cef_window_info_t struct_type; static inline void init(struct_type* s) {} - static inline void clear(struct_type* s) - { + static inline void clear(struct_type* s) { cef_string_clear(&s->m_windowName); } - static inline void set(const struct_type* src, struct_type* target, bool copy) - { + static inline void set(const struct_type* src, struct_type* target, + bool copy) { target->m_View = src->m_View; target->m_ParentView = src->m_ParentView; cef_string_set(src->m_windowName.str, src->m_windowName.length, @@ -99,22 +99,24 @@ struct CefWindowInfoTraits { target->m_nWidth = src->m_nWidth; target->m_nHeight = src->m_nHeight; target->m_bHidden = src->m_bHidden; + target->m_bWindowRenderingDisabled = src->m_bWindowRenderingDisabled; + target->m_bTransparentPainting = src->m_bTransparentPainting; } }; +/// // Class representing window information. -class CefWindowInfo : public CefStructBase -{ -public: +/// +class CefWindowInfo : public CefStructBase { + public: typedef CefStructBase parent; CefWindowInfo() : parent() {} - CefWindowInfo(const cef_window_info_t& r) : parent(r) {} - CefWindowInfo(const CefWindowInfo& r) : parent(r) {} - + explicit CefWindowInfo(const cef_window_info_t& r) : parent(r) {} + explicit CefWindowInfo(const CefWindowInfo& r) : parent(r) {} + void SetAsChild(CefWindowHandle ParentView, int x, int y, int width, - int height) - { + int height) { m_ParentView = ParentView; m_x = x; m_y = y; @@ -122,23 +124,55 @@ public: m_nHeight = height; m_bHidden = false; } + + void SetAsOffScreen(NSView* parent) { + m_bWindowRenderingDisabled = true; + m_ParentView = parent; + } + + void SetTransparentPainting(int transparentPainting) { + m_bTransparentPainting = transparentPainting; + } }; + struct CefPrintInfoTraits { typedef cef_print_info_t struct_type; static inline void init(struct_type* s) {} static inline void clear(struct_type* s) {} - static inline void set(const struct_type* src, struct_type* target, bool copy) - { + static inline void set(const struct_type* src, struct_type* target, + bool copy) { target->m_Scale = src->m_Scale; } }; +/// // Class representing print context information. +/// typedef CefStructBase CefPrintInfo; -#endif // OS_MACOSX +struct CefKeyInfoTraits { + typedef cef_key_info_t struct_type; -#endif // _CEF_MAC_H + static inline void init(struct_type* s) {} + static inline void clear(struct_type* s) {} + + static inline void set(const struct_type* src, struct_type* target, + bool copy) { + target->keyCode = src->keyCode; + target->character = src->character; + target->characterNoModifiers = src->characterNoModifiers; + } +}; + +/// +// Class representing key information. +/// +typedef CefStructBase CefKeyInfo; + + +#endif // OS_MACOSX + +#endif // CEF_INCLUDE_INTERNAL_CEF_MAC_H_ diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h index 933f462c4..1365173e0 100644 --- a/include/internal/cef_types.h +++ b/include/internal/cef_types.h @@ -28,31 +28,37 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef _CEF_TYPES_H -#define _CEF_TYPES_H +#ifndef CEF_INCLUDE_INTERNAL_CEF_TYPES_H_ +#define CEF_INCLUDE_INTERNAL_CEF_TYPES_H_ +#pragma once -#include "cef_build.h" -#include "cef_string.h" -#include "cef_string_list.h" -#include "cef_time.h" +#include "include/internal/cef_build.h" +#include "include/internal/cef_string.h" +#include "include/internal/cef_string_list.h" +#include "include/internal/cef_time.h" // Bring in platform-specific definitions. #if defined(OS_WIN) -#include "cef_types_win.h" +#include "include/internal/cef_types_win.h" #elif defined(OS_MACOSX) -#include "cef_types_mac.h" +#include "include/internal/cef_types_mac.h" #elif defined(OS_LINUX) -#include "cef_types_linux.h" +#include "include/internal/cef_types_linux.h" #endif -// The NSPR system headers define 64-bit as |long| when possible. In order to -// not have typedef mismatches, we do the same on LP64. -#if __LP64__ -typedef long int64; -typedef unsigned long uint64; +#include // For size_t + +// The NSPR system headers define 64-bit as |long| when possible, except on +// Mac OS X. In order to not have typedef mismatches, we do the same on LP64. +// +// On Mac OS X, |long long| is used for 64-bit types for compatibility with +// format macros even in the LP64 model. +#if defined(__LP64__) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) +typedef long int64; // NOLINT(runtime/int) +typedef unsigned long uint64; // NOLINT(runtime/int) #else -typedef long long int64; -typedef unsigned long long uint64; +typedef long long int64; // NOLINT(runtime/int) +typedef unsigned long long uint64; // NOLINT(runtime/int) #endif #ifdef __cplusplus @@ -62,8 +68,7 @@ extern "C" { /// // Log severity levels. /// -enum cef_log_severity_t -{ +enum cef_log_severity_t { LOGSEVERITY_VERBOSE = -1, LOGSEVERITY_INFO, LOGSEVERITY_WARNING, @@ -77,8 +82,7 @@ enum cef_log_severity_t // Initialization settings. Specify NULL or 0 to get the recommended default // values. /// -typedef struct _cef_settings_t -{ +typedef struct _cef_settings_t { /// // Size of this structure. /// @@ -90,14 +94,14 @@ typedef struct _cef_settings_t // your application message loop. /// bool multi_threaded_message_loop; - + /// // The location where cache data will be stored on disk. If empty an // in-memory cache will be used. HTML5 databases such as localStorage will // only persist across sessions if a cache path is specified. /// cef_string_t cache_path; - + /// // Value that will be returned as the User-Agent HTTP header. If empty the // default User-Agent string will be used. @@ -113,7 +117,9 @@ typedef struct _cef_settings_t /// // The locale string that will be passed to WebKit. If empty the default - // locale of "en-US" will be used. + // locale of "en-US" will be used. This value is ignored on Linux where locale + // is determined using environment variable parsing with the precedence order: + // LANGUAGE, LC_ALL, LC_MESSAGES and LANG. /// cef_string_t locale; @@ -160,7 +166,7 @@ typedef struct _cef_settings_t #if defined(OS_WIN) /// - // Set to true (1) to use the system proxy resolver on Windows when + // Set to true (1) to use the system proxy resolver on Windows when // "Automatically detect settings" is checked. This setting is disabled // by default for performance reasons. /// @@ -173,8 +179,7 @@ typedef struct _cef_settings_t // default values. The consequences of using custom values may not be well // tested. /// -typedef struct _cef_browser_settings_t -{ +typedef struct _cef_browser_settings_t { /// // Size of this structure. /// @@ -328,7 +333,7 @@ typedef struct _cef_browser_settings_t // Set to true (1) to enable the user style sheet for all pages. /// bool user_style_sheet_enabled; - + /// // Location of the user style sheet. This must be a data URL of the form // "data:text/css;charset=utf-8;base64,csscontent" where "csscontent" is the @@ -414,8 +419,7 @@ typedef struct _cef_browser_settings_t /// // URL component parts. /// -typedef struct _cef_urlparts_t -{ +typedef struct _cef_urlparts_t { /// // The complete URL specification. /// @@ -461,8 +465,7 @@ typedef struct _cef_urlparts_t /// // Cookie information. /// -typedef struct _cef_cookie_t -{ +typedef struct _cef_cookie_t { /// // The cookie name. /// @@ -501,7 +504,7 @@ typedef struct _cef_cookie_t // cookie creation. /// cef_time_t creation; - + /// // The cookie last access date. This is automatically populated by the system // on access. @@ -518,8 +521,7 @@ typedef struct _cef_cookie_t /// // Storage types. /// -enum cef_storage_type_t -{ +enum cef_storage_type_t { ST_LOCALSTORAGE = 0, ST_SESSIONSTORAGE, }; @@ -527,8 +529,7 @@ enum cef_storage_type_t /// // Mouse button types. /// -enum cef_mouse_button_type_t -{ +enum cef_mouse_button_type_t { MBT_LEFT = 0, MBT_MIDDLE, MBT_RIGHT, @@ -537,8 +538,7 @@ enum cef_mouse_button_type_t /// // Key types. /// -enum cef_key_type_t -{ +enum cef_key_type_t { KT_KEYUP = 0, KT_KEYDOWN, KT_CHAR, @@ -547,8 +547,7 @@ enum cef_key_type_t /// // Various browser navigation types supported by chrome. /// -enum cef_handler_navtype_t -{ +enum cef_handler_navtype_t { NAVTYPE_LINKCLICKED = 0, NAVTYPE_FORMSUBMITTED, NAVTYPE_BACKFORWARD, @@ -562,8 +561,7 @@ enum cef_handler_navtype_t // Supported error code values. See net\base\net_error_list.h for complete // descriptions of the error codes. /// -enum cef_handler_errorcode_t -{ +enum cef_handler_errorcode_t { ERR_FAILED = -2, ERR_ABORTED = -3, ERR_INVALID_ARGUMENT = -4, @@ -619,8 +617,7 @@ enum cef_handler_errorcode_t // destination. These constants match their equivalents in WebCore's // DragActions.h and should not be renumbered. /// -enum cef_drag_operations_mask_t -{ +enum cef_drag_operations_mask_t { DRAG_OPERATION_NONE = 0, DRAG_OPERATION_COPY = 1, DRAG_OPERATION_LINK = 2, @@ -634,8 +631,7 @@ enum cef_drag_operations_mask_t /// // V8 access control values. /// -enum cef_v8_accesscontrol_t -{ +enum cef_v8_accesscontrol_t { V8_ACCESS_CONTROL_DEFAULT = 0, V8_ACCESS_CONTROL_ALL_CAN_READ = 1, V8_ACCESS_CONTROL_ALL_CAN_WRITE = 1 << 1, @@ -645,9 +641,8 @@ enum cef_v8_accesscontrol_t /// // V8 property attribute values. /// -enum cef_v8_propertyattribute_t -{ - V8_PROPERTY_ATTRIBUTE_NONE = 0, // Writeable, Enumerable, +enum cef_v8_propertyattribute_t { + V8_PROPERTY_ATTRIBUTE_NONE = 0, // Writeable, Enumerable, // Configurable V8_PROPERTY_ATTRIBUTE_READONLY = 1 << 0, // Not writeable V8_PROPERTY_ATTRIBUTE_DONTENUM = 1 << 1, // Not enumerable @@ -657,8 +652,7 @@ enum cef_v8_propertyattribute_t /// // Structure representing menu information. /// -typedef struct _cef_menu_info_t -{ +typedef struct _cef_menu_info_t { /// // Values from the cef_handler_menutypebits_t enumeration. /// @@ -690,8 +684,7 @@ typedef struct _cef_menu_info_t // The cef_menu_info_t typeFlags value will be a combination of the // following values. /// -enum cef_menu_typebits_t -{ +enum cef_menu_typebits_t { /// // No node is selected /// @@ -738,8 +731,7 @@ enum cef_menu_typebits_t // The cef_menu_info_t editFlags value will be a combination of the // following values. /// -enum cef_menu_capabilitybits_t -{ +enum cef_menu_capabilitybits_t { // Values from WebContextMenuData::EditFlags in WebContextMenuData.h MENU_CAN_DO_NONE = 0x0, MENU_CAN_UNDO = 0x1, @@ -758,8 +750,7 @@ enum cef_menu_capabilitybits_t /// // Supported menu ID values. /// -enum cef_menu_id_t -{ +enum cef_menu_id_t { MENU_ID_NAV_BACK = 10, MENU_ID_NAV_FORWARD = 11, MENU_ID_NAV_RELOAD = 12, @@ -776,8 +767,7 @@ enum cef_menu_id_t MENU_ID_VIEWSOURCE = 31, }; -enum cef_paint_element_type_t -{ +enum cef_paint_element_type_t { PET_VIEW = 0, PET_POPUP, }; @@ -785,15 +775,13 @@ enum cef_paint_element_type_t /// // Post data elements may represent either bytes or files. /// -enum cef_postdataelement_type_t -{ +enum cef_postdataelement_type_t { PDE_TYPE_EMPTY = 0, PDE_TYPE_BYTES, PDE_TYPE_FILE, }; -enum cef_weburlrequest_flags_t -{ +enum cef_weburlrequest_flags_t { WUR_FLAG_NONE = 0, WUR_FLAG_SKIP_CACHE = 0x1, WUR_FLAG_ALLOW_CACHED_CREDENTIALS = 0x2, @@ -803,8 +791,7 @@ enum cef_weburlrequest_flags_t WUR_FLAG_REPORT_RAW_HEADERS = 0x20 }; -enum cef_weburlrequest_state_t -{ +enum cef_weburlrequest_state_t { WUR_STATE_UNSENT = 0, WUR_STATE_STARTED = 1, WUR_STATE_HEADERS_RECEIVED = 2, @@ -817,8 +804,7 @@ enum cef_weburlrequest_state_t /// // Focus sources. /// -enum cef_handler_focus_source_t -{ +enum cef_handler_focus_source_t { /// // The source is explicit navigation via the API (LoadURL(), etc). /// @@ -836,8 +822,7 @@ enum cef_handler_focus_source_t /// // Key event types. /// -enum cef_handler_keyevent_type_t -{ +enum cef_handler_keyevent_type_t { KEYEVENT_RAWKEYDOWN = 0, KEYEVENT_KEYDOWN, KEYEVENT_KEYUP, @@ -847,19 +832,18 @@ enum cef_handler_keyevent_type_t /// // Key event modifiers. /// -enum cef_handler_keyevent_modifiers_t -{ - KEY_SHIFT = 1 << 0, - KEY_CTRL = 1 << 1, - KEY_ALT = 1 << 2, - KEY_META = 1 << 3 +enum cef_handler_keyevent_modifiers_t { + KEY_SHIFT = 1 << 0, + KEY_CTRL = 1 << 1, + KEY_ALT = 1 << 2, + KEY_META = 1 << 3, + KEY_KEYPAD = 1 << 4, // Only used on Mac OS-X }; /// // Structure representing a rectangle. /// -typedef struct _cef_rect_t -{ +typedef struct _cef_rect_t { int x; int y; int width; @@ -869,8 +853,7 @@ typedef struct _cef_rect_t /// // Existing thread IDs. /// -enum cef_thread_id_t -{ +enum cef_thread_id_t { TID_UI = 0, TID_IO = 1, TID_FILE = 2, @@ -879,8 +862,7 @@ enum cef_thread_id_t /// // Paper type for printing. /// -enum cef_paper_type_t -{ +enum cef_paper_type_t { PT_LETTER = 0, PT_LEGAL, PT_EXECUTIVE, @@ -892,11 +874,10 @@ enum cef_paper_type_t /// // Paper metric information for printing. /// -struct cef_paper_metrics -{ +struct cef_paper_metrics { enum cef_paper_type_t paper_type; - //Length and width needed if paper_type is custom_size - //Units are in inches. + // Length and width needed if paper_type is custom_size + // Units are in inches. double length; double width; }; @@ -904,14 +885,13 @@ struct cef_paper_metrics /// // Paper print margins. /// -struct cef_print_margins -{ - //Margin size in inches for left/right/top/bottom (this is content margins). +struct cef_print_margins { + // Margin size in inches for left/right/top/bottom (this is content margins). double left; double right; double top; double bottom; - //Margin size (top/bottom) in inches for header/footer. + // Margin size (top/bottom) in inches for header/footer. double header; double footer; }; @@ -919,8 +899,7 @@ struct cef_print_margins /// // Page orientation for printing. /// -enum cef_page_orientation -{ +enum cef_page_orientation { PORTRAIT = 0, LANDSCAPE }; @@ -928,8 +907,7 @@ enum cef_page_orientation /// // Printing options. /// -typedef struct _cef_print_options_t -{ +typedef struct _cef_print_options_t { enum cef_page_orientation page_orientation; struct cef_paper_metrics paper_metrics; struct cef_print_margins paper_margins; @@ -941,8 +919,7 @@ typedef struct _cef_print_options_t // before being passed to the parser. If a BOM is detected and the correct // decoder is available then that decoder will be used automatically. /// -enum cef_xml_encoding_type_t -{ +enum cef_xml_encoding_type_t { XML_ENCODING_NONE = 0, XML_ENCODING_UTF8, XML_ENCODING_UTF16LE, @@ -953,8 +930,7 @@ enum cef_xml_encoding_type_t /// // XML node types. /// -enum cef_xml_node_type_t -{ +enum cef_xml_node_type_t { XML_NODE_UNSUPPORTED = 0, XML_NODE_PROCESSING_INSTRUCTION, XML_NODE_DOCUMENT_TYPE, @@ -971,8 +947,7 @@ enum cef_xml_node_type_t /// // Status message types. /// -enum cef_handler_statustype_t -{ +enum cef_handler_statustype_t { STATUSTYPE_TEXT = 0, STATUSTYPE_MOUSEOVER_URL, STATUSTYPE_KEYBOARD_FOCUS_URL, @@ -981,8 +956,7 @@ enum cef_handler_statustype_t /// // Popup window features. /// -typedef struct _cef_popup_features_t -{ +typedef struct _cef_popup_features_t { int x; bool xSet; int y; @@ -1007,8 +981,7 @@ typedef struct _cef_popup_features_t /// // DOM document types. /// -enum cef_dom_document_type_t -{ +enum cef_dom_document_type_t { DOM_DOCUMENT_TYPE_UNKNOWN = 0, DOM_DOCUMENT_TYPE_HTML, DOM_DOCUMENT_TYPE_XHTML, @@ -1018,8 +991,7 @@ enum cef_dom_document_type_t /// // DOM event category flags. /// -enum cef_dom_event_category_t -{ +enum cef_dom_event_category_t { DOM_EVENT_CATEGORY_UNKNOWN = 0x0, DOM_EVENT_CATEGORY_UI = 0x1, DOM_EVENT_CATEGORY_MOUSE = 0x2, @@ -1045,8 +1017,7 @@ enum cef_dom_event_category_t /// // DOM event processing phases. /// -enum cef_dom_event_phase_t -{ +enum cef_dom_event_phase_t { DOM_EVENT_PHASE_UNKNOWN = 0, DOM_EVENT_PHASE_CAPTURING, DOM_EVENT_PHASE_AT_TARGET, @@ -1056,8 +1027,7 @@ enum cef_dom_event_phase_t /// // DOM node types. /// -enum cef_dom_node_type_t -{ +enum cef_dom_node_type_t { DOM_NODE_TYPE_UNSUPPORTED = 0, DOM_NODE_TYPE_ELEMENT, DOM_NODE_TYPE_ATTRIBUTE, @@ -1077,8 +1047,7 @@ enum cef_dom_node_type_t /// // Proxy types. /// -enum cef_proxy_type_t -{ +enum cef_proxy_type_t { PROXY_TYPE_DIRECT = 0, PROXY_TYPE_NAMED, PROXY_TYPE_PAC_STRING, @@ -1087,8 +1056,7 @@ enum cef_proxy_type_t /// // Proxy information. /// -typedef struct _cef_proxy_info_t -{ +typedef struct _cef_proxy_info_t { enum cef_proxy_type_t proxyType; cef_string_t proxyList; } cef_proxy_info_t; @@ -1097,4 +1065,4 @@ typedef struct _cef_proxy_info_t } #endif -#endif // _CEF_TYPES_H +#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_H_ diff --git a/include/internal/cef_types_linux.h b/include/internal/cef_types_linux.h index 42da97ace..86b1d10ed 100644 --- a/include/internal/cef_types_linux.h +++ b/include/internal/cef_types_linux.h @@ -72,6 +72,13 @@ typedef struct _cef_print_info_t double m_Scale; } cef_print_info_t; +/// +// Class representing key information. +/// +typedef struct _cef_key_info_t { + int key; +} cef_key_info_t; + #ifdef __cplusplus } #endif diff --git a/include/internal/cef_types_mac.h b/include/internal/cef_types_mac.h index 0773a9772..9d73253cb 100644 --- a/include/internal/cef_types_mac.h +++ b/include/internal/cef_types_mac.h @@ -28,24 +28,30 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef _CEF_TYPES_MAC_H -#define _CEF_TYPES_MAC_H +#ifndef CEF_INCLUDE_INTERNAL_CEF_TYPES_MAC_H_ +#define CEF_INCLUDE_INTERNAL_CEF_TYPES_MAC_H_ +#pragma once + +#include "include/internal/cef_build.h" #if defined(OS_MACOSX) -#include "cef_string.h" +#include "include/internal/cef_string.h" // Window handle. #ifdef __cplusplus #ifdef __OBJC__ +@class NSCursor; @class NSView; #else +class NSCursor; class NSView; #endif #define cef_window_handle_t NSView* +#define cef_cursor_handle_t NSCursor* #else #define cef_window_handle_t void* -#endif #define cef_cursor_handle_t void* +#endif #ifdef __cplusplus extern "C" { @@ -54,8 +60,7 @@ extern "C" { /// // Supported graphics implementations. /// -enum cef_graphics_implementation_t -{ +enum cef_graphics_implementation_t { DESKTOP_IN_PROCESS = 0, DESKTOP_IN_PROCESS_COMMAND_BUFFER, }; @@ -63,8 +68,7 @@ enum cef_graphics_implementation_t /// // Class representing window information. /// -typedef struct _cef_window_info_t -{ +typedef struct _cef_window_info_t { cef_string_t m_windowName; int m_x; int m_y; @@ -74,7 +78,15 @@ typedef struct _cef_window_info_t // NSView pointer for the parent view. cef_window_handle_t m_ParentView; - + + // If window rendering is disabled no browser window will be created. Set + // |m_ParentView| to the window that will act as the parent for popup menus, + // dialog boxes, etc. + int m_bWindowRenderingDisabled; + + // Set to true to enable transparent painting. + int m_bTransparentPainting; + // NSView pointer for the new browser view. cef_window_handle_t m_View; } cef_window_info_t; @@ -82,15 +94,23 @@ typedef struct _cef_window_info_t /// // Class representing print context information. /// -typedef struct _cef_print_info_t -{ +typedef struct _cef_print_info_t { double m_Scale; } cef_print_info_t; +/// +// Class representing key information. +/// +typedef struct _cef_key_info_t { + int keyCode; + int character; + int characterNoModifiers; +} cef_key_info_t; + #ifdef __cplusplus } #endif -#endif // OS_MACOSX +#endif // OS_MACOSX -#endif // _CEF_TYPES_MAC_H +#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_MAC_H_ diff --git a/include/internal/cef_types_win.h b/include/internal/cef_types_win.h index 7ce143bd2..b8705104f 100644 --- a/include/internal/cef_types_win.h +++ b/include/internal/cef_types_win.h @@ -92,6 +92,15 @@ typedef struct _cef_print_info_t double m_Scale; } cef_print_info_t; +/// +// Class representing key information. +/// +typedef struct _cef_key_info_t { + int key; + BOOL sysChar; + BOOL imeChar; +} cef_key_info_t; + #ifdef __cplusplus } #endif diff --git a/include/internal/cef_win.h b/include/internal/cef_win.h index bbdf034ca..68d91dced 100644 --- a/include/internal/cef_win.h +++ b/include/internal/cef_win.h @@ -28,13 +28,14 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef _CEF_WIN_H -#define _CEF_WIN_H +#ifndef CEF_INCLUDE_INTERNAL_CEF_WIN_H_ +#define CEF_INCLUDE_INTERNAL_CEF_WIN_H_ +#pragma once #if defined(OS_WIN) #include -#include "cef_types_win.h" -#include "cef_types_wrappers.h" +#include "include/internal/cef_types_win.h" +#include "include/internal/cef_types_wrappers.h" /// // Atomic increment and decrement. @@ -45,24 +46,19 @@ /// // Critical section wrapper. /// -class CefCriticalSection -{ -public: - CefCriticalSection() - { +class CefCriticalSection { + public: + CefCriticalSection() { memset(&m_sec, 0, sizeof(CRITICAL_SECTION)); InitializeCriticalSection(&m_sec); } - virtual ~CefCriticalSection() - { + virtual ~CefCriticalSection() { DeleteCriticalSection(&m_sec); } - void Lock() - { + void Lock() { EnterCriticalSection(&m_sec); } - void Unlock() - { + void Unlock() { LeaveCriticalSection(&m_sec); } @@ -75,19 +71,17 @@ public: #define CefWindowHandle cef_window_handle_t #define CefCursorHandle cef_cursor_handle_t - struct CefWindowInfoTraits { typedef cef_window_info_t struct_type; static inline void init(struct_type* s) {} - static inline void clear(struct_type* s) - { + static inline void clear(struct_type* s) { cef_string_clear(&s->m_windowName); } - static inline void set(const struct_type* src, struct_type* target, bool copy) - { + static inline void set(const struct_type* src, struct_type* target, + bool copy) { target->m_dwExStyle = src->m_dwExStyle; cef_string_set(src->m_windowName.str, src->m_windowName.length, &target->m_windowName, copy); @@ -107,17 +101,15 @@ struct CefWindowInfoTraits { /// // Class representing window information. /// -class CefWindowInfo : public CefStructBase -{ -public: +class CefWindowInfo : public CefStructBase { + public: typedef CefStructBase parent; CefWindowInfo() : parent() {} - CefWindowInfo(const cef_window_info_t& r) : parent(r) {} - CefWindowInfo(const CefWindowInfo& r) : parent(r) {} - - void SetAsChild(HWND hWndParent, RECT windowRect) - { + explicit CefWindowInfo(const cef_window_info_t& r) : parent(r) {} + explicit CefWindowInfo(const CefWindowInfo& r) : parent(r) {} + + void SetAsChild(HWND hWndParent, RECT windowRect) { m_dwStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE; m_hWndParent = hWndParent; @@ -127,8 +119,7 @@ public: m_nHeight = windowRect.bottom - windowRect.top; } - void SetAsPopup(HWND hWndParent, const CefString& windowName) - { + void SetAsPopup(HWND hWndParent, const CefString& windowName) { m_dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE; m_hWndParent = hWndParent; @@ -140,14 +131,12 @@ public: cef_string_copy(windowName.c_str(), windowName.length(), &m_windowName); } - void SetAsOffScreen(HWND hWndParent) - { + void SetAsOffScreen(HWND hWndParent) { m_bWindowRenderingDisabled = TRUE; m_hWndParent = hWndParent; } - void SetTransparentPainting(BOOL transparentPainting) - { + void SetTransparentPainting(BOOL transparentPainting) { m_bTransparentPainting = transparentPainting; } }; @@ -159,8 +148,8 @@ struct CefPrintInfoTraits { static inline void init(struct_type* s) {} static inline void clear(struct_type* s) {} - static inline void set(const struct_type* src, struct_type* target, bool copy) - { + static inline void set(const struct_type* src, struct_type* target, + bool copy) { target->m_hDC = src->m_hDC; target->m_Rect = src->m_Rect; target->m_Scale = src->m_Scale; @@ -172,6 +161,26 @@ struct CefPrintInfoTraits { /// typedef CefStructBase CefPrintInfo; -#endif // OS_WIN -#endif // _CEF_WIN_H +struct CefKeyInfoTraits { + typedef cef_key_info_t struct_type; + + static inline void init(struct_type* s) {} + static inline void clear(struct_type* s) {} + + static inline void set(const struct_type* src, struct_type* target, + bool copy) { + target->key = src->key; + target->sysChar = src->sysChar; + target->imeChar = src->imeChar; + } +}; + +/// +// Class representing key information. +/// +typedef CefStructBase CefKeyInfo; + +#endif // OS_WIN + +#endif // CEF_INCLUDE_INTERNAL_CEF_WIN_H_ diff --git a/libcef/browser_impl.cc b/libcef/browser_impl.cc index f6b9b71bc..8e6799f26 100644 --- a/libcef/browser_impl.cc +++ b/libcef/browser_impl.cc @@ -169,6 +169,7 @@ CefBrowserImpl::CefBrowserImpl(const CefWindowInfo& windowInfo, can_go_forward_(false), has_document_(false), is_dropping_(false), + is_in_onsetfocus_(false), unique_id_(0) #if defined(OS_WIN) , opener_was_disabled_by_modal_loop_(false), @@ -229,6 +230,26 @@ void CefBrowserImpl::StopLoad() { void CefBrowserImpl::SetFocus(bool enable) { if (CefThread::CurrentlyOn(CefThread::UI)) { + // If SetFocus() is called from inside the OnSetFocus() callback do not re- + // enter the callback. + if (enable && !is_in_onsetfocus_) { + WebViewHost* host = UIT_GetWebViewHost(); + if (host) { + CefRefPtr client = GetClient(); + if (client.get()) { + CefRefPtr handler = client->GetFocusHandler(); + if (handler.get()) { + is_in_onsetfocus_ = true; + bool handled = handler->OnSetFocus(this, FOCUS_SOURCE_SYSTEM); + is_in_onsetfocus_ = false; + + if (handled) + return; + } + } + } + } + UIT_SetFocus(UIT_GetWebViewHost(), enable); } else { CefThread::PostTask(CefThread::UI, FROM_HERE, @@ -419,13 +440,13 @@ bool CefBrowserImpl::GetImage(PaintElementType type, int width, int height, return false; } -void CefBrowserImpl::SendKeyEvent(KeyType type, int key, int modifiers, - bool sysChar, bool imeChar) { +void CefBrowserImpl::SendKeyEvent(KeyType type, const CefKeyInfo& keyInfo, + int modifiers) { // Intentially post event tasks in all cases so that painting tasks can be // handled at sane times. CefThread::PostTask(CefThread::UI, FROM_HERE, - base::Bind(&CefBrowserImpl::UIT_SendKeyEvent, this, type, key, modifiers, - sysChar, imeChar)); + base::Bind(&CefBrowserImpl::UIT_SendKeyEvent, this, type, keyInfo, + modifiers)); } void CefBrowserImpl::SendMouseClickEvent(int x, int y, MouseButtonType type, @@ -445,11 +466,12 @@ void CefBrowserImpl::SendMouseMoveEvent(int x, int y, bool mouseLeave) { mouseLeave)); } -void CefBrowserImpl::SendMouseWheelEvent(int x, int y, int delta) { +void CefBrowserImpl::SendMouseWheelEvent(int x, int y, int deltaX, int deltaY) { // Intentially post event tasks in all cases so that painting tasks can be // handled at sane times. CefThread::PostTask(CefThread::UI, FROM_HERE, - base::Bind(&CefBrowserImpl::UIT_SendMouseWheelEvent, this, x, y, delta)); + base::Bind(&CefBrowserImpl::UIT_SendMouseWheelEvent, this, x, y, deltaX, + deltaY)); } void CefBrowserImpl::SendFocusEvent(bool setFocus) { @@ -1003,7 +1025,6 @@ bool CefBrowserImpl::UIT_Navigate(const BrowserNavigationEntry& entry, return true; } - void CefBrowserImpl::UIT_SetSize(PaintElementType type, int width, int height) { if (type == PET_VIEW) { WebViewHost* host = UIT_GetWebViewHost(); @@ -1031,16 +1052,16 @@ void CefBrowserImpl::UIT_Invalidate(const CefRect& dirtyRect) { } } -void CefBrowserImpl::UIT_SendKeyEvent(KeyType type, int key, int modifiers, - bool sysChar, bool imeChar) { +void CefBrowserImpl::UIT_SendKeyEvent(KeyType type, const CefKeyInfo& keyInfo, + int modifiers) { REQUIRE_UIT(); if (popuphost_) { // Send the event to the popup. - popuphost_->SendKeyEvent(type, key, modifiers, sysChar, imeChar); + popuphost_->SendKeyEvent(type, keyInfo, modifiers); } else { WebViewHost* host = UIT_GetWebViewHost(); if (host) - host->SendKeyEvent(type, key, modifiers, sysChar, imeChar); + host->SendKeyEvent(type, keyInfo, modifiers); } } @@ -1071,16 +1092,17 @@ void CefBrowserImpl::UIT_SendMouseMoveEvent(int x, int y, bool mouseLeave) { } } -void CefBrowserImpl::UIT_SendMouseWheelEvent(int x, int y, int delta) { +void CefBrowserImpl::UIT_SendMouseWheelEvent(int x, int y, int deltaX, + int deltaY) { REQUIRE_UIT(); if (popuphost_ && popup_rect_.Contains(x, y)) { // Send the event to the popup. popuphost_->SendMouseWheelEvent(x - popup_rect_.x(), y - popup_rect_.y(), - delta); + deltaX, deltaY); } else { WebViewHost* host = UIT_GetWebViewHost(); if (host) - host->SendMouseWheelEvent(x, y, delta); + host->SendMouseWheelEvent(x, y, deltaX, deltaY); } } diff --git a/libcef/browser_impl.h b/libcef/browser_impl.h index 0eb923f30..350e89b6f 100644 --- a/libcef/browser_impl.h +++ b/libcef/browser_impl.h @@ -104,12 +104,13 @@ class CefBrowserImpl : public CefBrowser { virtual void Invalidate(const CefRect& dirtyRect) OVERRIDE; virtual bool GetImage(PaintElementType type, int width, int height, void* buffer) OVERRIDE; - virtual void SendKeyEvent(KeyType type, int key, int modifiers, bool sysChar, - bool imeChar) OVERRIDE; + virtual void SendKeyEvent(KeyType type, const CefKeyInfo& keyInfo, + int modifiers) OVERRIDE; virtual void SendMouseClickEvent(int x, int y, MouseButtonType type, bool mouseUp, int clickCount) OVERRIDE; virtual void SendMouseMoveEvent(int x, int y, bool mouseLeave) OVERRIDE; - virtual void SendMouseWheelEvent(int x, int y, int delta) OVERRIDE; + virtual void SendMouseWheelEvent(int x, int y, int deltaX, int deltaY) + OVERRIDE; virtual void SendFocusEvent(bool setFocus) OVERRIDE; virtual void SendCaptureLostEvent() OVERRIDE; @@ -267,12 +268,11 @@ class CefBrowserImpl : public CefBrowser { void UIT_SetFocus(WebWidgetHost* host, bool enable); void UIT_SetSize(PaintElementType type, int width, int height); void UIT_Invalidate(const CefRect& dirtyRect); - void UIT_SendKeyEvent(KeyType type, int key, int modifiers, bool sysChar, - bool imeChar); + void UIT_SendKeyEvent(KeyType type, const CefKeyInfo& keyInfo, int modifiers); void UIT_SendMouseClickEvent(int x, int y, MouseButtonType type, bool mouseUp, int clickCount); void UIT_SendMouseMoveEvent(int x, int y, bool mouseLeave); - void UIT_SendMouseWheelEvent(int x, int y, int delta); + void UIT_SendMouseWheelEvent(int x, int y, int deltaX, int deltaY); void UIT_SendFocusEvent(bool setFocus); void UIT_SendCaptureLostEvent(); @@ -318,7 +318,7 @@ class CefBrowserImpl : public CefBrowser { // Frame objects will be deleted immediately before the frame is closed. void UIT_AddFrameObject(WebKit::WebFrame* frame, - CefTrackObject* tracked_object); + CefTrackObject* tracked_object); void UIT_BeforeFrameClosed(WebKit::WebFrame* frame); // These variables are read-only. @@ -397,6 +397,10 @@ class CefBrowserImpl : public CefBrowser { // True if a drop action is occuring. bool is_dropping_; + // True if currently in the OnSetFocus callback. Only accessed on the UI + // thread. + bool is_in_onsetfocus_; + #if defined(OS_WIN) // Context object used to manage printing. printing::PrintingContext print_context_; diff --git a/libcef/browser_impl_mac.mm b/libcef/browser_impl_mac.mm index c07d7cba2..ddf72ffa5 100644 --- a/libcef/browser_impl_mac.mm +++ b/libcef/browser_impl_mac.mm @@ -3,13 +3,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "cef_context.h" -#include "browser_impl.h" -#include "browser_settings.h" -#include "browser_webview_mac.h" - #import +#include "libcef/cef_context.h" +#include "libcef/browser_impl.h" +#include "libcef/browser_settings.h" +#include "libcef/browser_webview_mac.h" + #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" @@ -19,35 +19,32 @@ using WebKit::WebRect; using WebKit::WebSize; -void CefBrowserImpl::ParentWindowWillClose() -{ +void CefBrowserImpl::ParentWindowWillClose() { // TODO(port): Implement this method if necessary. } -CefWindowHandle CefBrowserImpl::GetWindowHandle() -{ +CefWindowHandle CefBrowserImpl::GetWindowHandle() { AutoLock lock_scope(this); return window_info_.m_View; } -bool CefBrowserImpl::IsWindowRenderingDisabled() -{ - // TODO(port): Add support for off-screen rendering. - return false; +bool CefBrowserImpl::IsWindowRenderingDisabled() { + return (window_info_.m_bWindowRenderingDisabled ? true : false); } gfx::NativeView CefBrowserImpl::UIT_GetMainWndHandle() { REQUIRE_UIT(); - return window_info_.m_View; + return window_info_.m_bWindowRenderingDisabled ? + window_info_.m_ParentView : window_info_.m_View; } void CefBrowserImpl::UIT_ClearMainWndHandle() { REQUIRE_UIT(); - window_info_.m_View = NULL; + if (!window_info_.m_bWindowRenderingDisabled) + window_info_.m_View = NULL; } -bool CefBrowserImpl::UIT_CreateBrowser(const CefString& url) -{ +bool CefBrowserImpl::UIT_CreateBrowser(const CefString& url) { REQUIRE_UIT(); Lock(); @@ -65,29 +62,35 @@ bool CefBrowserImpl::UIT_CreateBrowser(const CefString& url) NSView* parentView = window_info_.m_ParentView; gfx::Rect contentRect(window_info_.m_x, window_info_.m_y, window_info_.m_nWidth, window_info_.m_nHeight); - if (parentView == nil) { - // Create a new window. - NSRect screen_rect = [[NSScreen mainScreen] visibleFrame]; - NSRect window_rect = {{window_info_.m_x, - screen_rect.size.height - window_info_.m_y}, - {window_info_.m_nWidth, window_info_.m_nHeight}}; - if (window_rect.size.width == 0) - window_rect.size.width = 750; - if (window_rect.size.height == 0) - window_rect.size.height = 750; - contentRect.SetRect(0, 0, window_rect.size.width, window_rect.size.height); + if (!window_info_.m_bWindowRenderingDisabled) { + if (parentView == nil) { + // Create a new window. + NSRect screen_rect = [[NSScreen mainScreen] visibleFrame]; + NSRect window_rect = {{window_info_.m_x, + screen_rect.size.height - window_info_.m_y}, + {window_info_.m_nWidth, window_info_.m_nHeight}}; + if (window_rect.size.width == 0) + window_rect.size.width = 750; + if (window_rect.size.height == 0) + window_rect.size.height = 750; + contentRect.SetRect(0, 0, window_rect.size.width, + window_rect.size.height); - newWnd = [[NSWindow alloc] - initWithContentRect:window_rect - styleMask:(NSTitledWindowMask | - NSClosableWindowMask | - NSMiniaturizableWindowMask | - NSResizableWindowMask | - NSUnifiedTitleAndToolbarWindowMask ) - backing:NSBackingStoreBuffered - defer:NO]; - parentView = [newWnd contentView]; - window_info_.m_ParentView = parentView; + newWnd = [[NSWindow alloc] + initWithContentRect:window_rect + styleMask:(NSTitledWindowMask | + NSClosableWindowMask | + NSMiniaturizableWindowMask | + NSResizableWindowMask | + NSUnifiedTitleAndToolbarWindowMask ) + backing:NSBackingStoreBuffered + defer:NO]; + parentView = [newWnd contentView]; + window_info_.m_ParentView = parentView; + } + } else { + // Create a new paint delegate. + paint_delegate_.reset(new PaintDelegate(this)); } WebPreferences prefs; @@ -96,7 +99,11 @@ bool CefBrowserImpl::UIT_CreateBrowser(const CefString& url) // Create the webview host object webviewhost_.reset( WebViewHost::Create(parentView, contentRect, delegate_.get(), - NULL, dev_tools_agent_.get(), prefs)); + paint_delegate_.get(), dev_tools_agent_.get(), + prefs)); + + if (window_info_.m_bTransparentPainting) + webviewhost_->webview()->setIsTransparent(true); if (!settings_.developer_tools_disabled) dev_tools_agent_->SetWebView(webviewhost_->webview()); @@ -105,8 +112,10 @@ bool CefBrowserImpl::UIT_CreateBrowser(const CefString& url) browserView.browser = this; window_info_.m_View = browserView; - if (!settings_.drag_drop_disabled) - [browserView registerDragDrop]; + if (!window_info_.m_bWindowRenderingDisabled) { + if (!settings_.drag_drop_disabled) + [browserView registerDragDrop]; + } Unlock(); @@ -129,26 +138,41 @@ bool CefBrowserImpl::UIT_CreateBrowser(const CefString& url) return true; } -void CefBrowserImpl::UIT_SetFocus(WebWidgetHost* host, bool enable) -{ +void CefBrowserImpl::UIT_SetFocus(WebWidgetHost* host, bool enable) { REQUIRE_UIT(); if (!host) return; - NSView* view = host->view_handle(); - if (!view) + BrowserWebView* browserView = (BrowserWebView*)host->view_handle(); + if (!browserView) return; - if (enable) - [[view window] makeFirstResponder:view]; + if (enable) { + // Guard against calling OnSetFocus twice. + browserView.in_setfocus = true; + [[browserView window] makeFirstResponder:browserView]; + browserView.in_setfocus = false; + } } -bool CefBrowserImpl::UIT_ViewDocumentString(WebKit::WebFrame *frame) -{ +bool CefBrowserImpl::UIT_ViewDocumentString(WebKit::WebFrame* frame) { REQUIRE_UIT(); - // TODO(port): Add implementation. - NOTIMPLEMENTED(); + char sztmp[L_tmpnam+4]; + if (tmpnam(sztmp)) { + strcat(sztmp, ".txt"); + + FILE* fp = fopen(sztmp, "wb"); + if (fp) { + std::string markup = frame->contentAsMarkup().utf8(); + fwrite(markup.c_str(), 1, markup.size(), fp); + fclose(fp); + + char szopen[L_tmpnam + 14]; + snprintf(szopen, sizeof(szopen), "open -t \"%s\"", sztmp); + return (system(szopen) >= 0); + } + } return false; } @@ -168,8 +192,7 @@ void CefBrowserImpl::UIT_PrintPages(WebKit::WebFrame* frame) { NOTIMPLEMENTED(); } -int CefBrowserImpl::UIT_GetPagesCount(WebKit::WebFrame* frame) -{ +int CefBrowserImpl::UIT_GetPagesCount(WebKit::WebFrame* frame) { REQUIRE_UIT(); // TODO(port): Add implementation. @@ -178,15 +201,13 @@ int CefBrowserImpl::UIT_GetPagesCount(WebKit::WebFrame* frame) } // static -void CefBrowserImpl::UIT_CloseView(gfx::NativeView view) -{ +void CefBrowserImpl::UIT_CloseView(gfx::NativeView view) { [[view window] performSelector:@selector(performClose:) withObject:nil afterDelay:0]; } // static -bool CefBrowserImpl::UIT_IsViewVisible(gfx::NativeView view) -{ +bool CefBrowserImpl::UIT_IsViewVisible(gfx::NativeView view) { return [[view window] isVisible]; } diff --git a/libcef/browser_webview_delegate_mac.mm b/libcef/browser_webview_delegate_mac.mm index 04476246a..f11a66773 100644 --- a/libcef/browser_webview_delegate_mac.mm +++ b/libcef/browser_webview_delegate_mac.mm @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "browser_webview_delegate.h" -#import "browser_webview_mac.h" -#include "browser_impl.h" -#include "drag_data_impl.h" +#include "libcef/browser_webview_delegate.h" +#import "libcef/browser_webview_mac.h" +#include "libcef/browser_impl.h" +#include "libcef/drag_data_impl.h" #import "include/cef_application_mac.h" #import @@ -48,6 +48,7 @@ namespace { void AddMenuItem(CefRefPtr browser, CefRefPtr handler, NSMenu* menu, + id target, cef_menu_id_t menuId, const std::string& label, bool enabled) { @@ -65,7 +66,8 @@ void AddMenuItem(CefRefPtr browser, NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:str action:enabled?@selector(menuItemSelected:):nil - keyEquivalent:@""] autorelease]; + keyEquivalent:@""] autorelease]; + [item setTarget:target]; [item setTag:menuId]; [menu addItem:item]; } @@ -77,6 +79,46 @@ void AddMenuSeparator(NSMenu* menu) { } // namespace +@interface BrowserMenuDelegate : NSObject { + @private + CefRefPtr browser_; +} + +- (id)initWithBrowser:(CefBrowserImpl*)browser; +- (void)menuItemSelected:(id)sender; +@end + +@implementation BrowserMenuDelegate + +- (id)initWithBrowser:(CefBrowserImpl*)browser { + self = [super init]; + if (self) + browser_ = browser; + return self; + +} + +// Called when a context menu item is selected by the user. +- (void)menuItemSelected:(id)sender { + cef_menu_id_t menuId = static_cast([sender tag]); + bool handled = false; + + CefRefPtr client = browser_->GetClient(); + if (client.get()) { + CefRefPtr handler = client->GetMenuHandler(); + if (handler.get()) { + // Ask the handler if it wants to handle the action. + handled = handler->OnMenuAction(browser_.get(), menuId); + } + } + + if(!handled) { + // Execute the action. + browser_->UIT_HandleAction(menuId, browser_->GetFocusedFrame()); + } +} + +@end // WebViewClient -------------------------------------------------------------- @@ -102,12 +144,21 @@ void BrowserWebViewDelegate::showContextMenu( if (!host) return; - BrowserWebView *view = static_cast(host->view_handle()); + NSView *view = browser_->UIT_GetMainWndHandle(); if (!view) return; NSWindow* window = [view window]; - NSPoint position = [window mouseLocationOutsideOfEventStream]; + + int screenX = -1; + int screenY = -1; + NSPoint mouse_pt = {data.mousePosition.x, data.mousePosition.y}; + if (!browser_->IsWindowRenderingDisabled()) { + mouse_pt = [window mouseLocationOutsideOfEventStream]; + NSPoint screen_pt = [window convertBaseToScreen:mouse_pt]; + screenX = screen_pt.x; + screenY = screen_pt.y; + } int edit_flags = 0; int type_flags = 0; @@ -117,7 +168,7 @@ void BrowserWebViewDelegate::showContextMenu( MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); // Give the client a chance to handle the menu. - if (OnBeforeMenu(data, position.x, position.y, edit_flags, type_flags)) + if (OnBeforeMenu(data, mouse_pt.x, mouse_pt.y, edit_flags, type_flags)) return; CefRefPtr client = browser_->GetClient(); @@ -125,43 +176,57 @@ void BrowserWebViewDelegate::showContextMenu( if (client.get()) handler = client->GetMenuHandler(); + if (client.get() && browser_->IsWindowRenderingDisabled()) { + // Retrieve the screen coordinates. + CefRefPtr render_handler = client->GetRenderHandler(); + if (!render_handler.get() || + !render_handler->GetScreenPoint(browser_, mouse_pt.x, mouse_pt.y, + screenX, screenY)) { + return; + } + } + + BrowserMenuDelegate* delegate = + [[[BrowserMenuDelegate alloc] initWithBrowser:browser_] autorelease]; + // Build the correct default context menu if (type_flags & MENUTYPE_EDITABLE) { menu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; - AddMenuItem(browser_, handler, menu, MENU_ID_UNDO, "Undo", + AddMenuItem(browser_, handler, menu, delegate, MENU_ID_UNDO, "Undo", !!(edit_flags & MENU_CAN_UNDO)); - AddMenuItem(browser_, handler, menu, MENU_ID_REDO, "Redo", + AddMenuItem(browser_, handler, menu, delegate, MENU_ID_REDO, "Redo", !!(edit_flags & MENU_CAN_REDO)); AddMenuSeparator(menu); - AddMenuItem(browser_, handler, menu, MENU_ID_CUT, "Cut", + AddMenuItem(browser_, handler, menu, delegate, MENU_ID_CUT, "Cut", !!(edit_flags & MENU_CAN_CUT)); - AddMenuItem(browser_, handler, menu, MENU_ID_COPY, "Copy", + AddMenuItem(browser_, handler, menu, delegate, MENU_ID_COPY, "Copy", !!(edit_flags & MENU_CAN_COPY)); - AddMenuItem(browser_, handler, menu, MENU_ID_PASTE, "Paste", + AddMenuItem(browser_, handler, menu, delegate, MENU_ID_PASTE, "Paste", !!(edit_flags & MENU_CAN_PASTE)); - AddMenuItem(browser_, handler, menu, MENU_ID_DELETE, "Delete", + AddMenuItem(browser_, handler, menu, delegate, MENU_ID_DELETE, "Delete", !!(edit_flags & MENU_CAN_DELETE)); AddMenuSeparator(menu); - AddMenuItem(browser_, handler, menu, MENU_ID_SELECTALL, "Select All", - !!(edit_flags & MENU_CAN_SELECT_ALL)); + AddMenuItem(browser_, handler, menu, delegate, MENU_ID_SELECTALL, + "Select All", !!(edit_flags & MENU_CAN_SELECT_ALL)); } else if(type_flags & MENUTYPE_SELECTION) { menu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; - AddMenuItem(browser_, handler, menu, MENU_ID_COPY, "Copy", + AddMenuItem(browser_, handler, menu, delegate, MENU_ID_COPY, "Copy", !!(edit_flags & MENU_CAN_COPY)); } else if(type_flags & (MENUTYPE_PAGE | MENUTYPE_FRAME)) { menu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; - AddMenuItem(browser_, handler, menu, MENU_ID_NAV_BACK, "Back", + AddMenuItem(browser_, handler, menu, delegate, MENU_ID_NAV_BACK, "Back", !!(edit_flags & MENU_CAN_GO_BACK)); - AddMenuItem(browser_, handler, menu, MENU_ID_NAV_FORWARD, "Forward", - !!(edit_flags & MENU_CAN_GO_FORWARD)); + AddMenuItem(browser_, handler, menu, delegate, MENU_ID_NAV_FORWARD, + "Forward", !!(edit_flags & MENU_CAN_GO_FORWARD)); // TODO(port): Enable the below menu items when supported. //AddMenuSeparator(menu); - //AddMenuItem(browser_, handler, menu, MENU_ID_PRINT, "Print", true); - //AddMenuItem(browser_, handler, menu, MENU_ID_VIEWSOURCE, "View Source", - // true); + //AddMenuItem(browser_, handler, menu, delegate, MENU_ID_PRINT, "Print", + // true); + //AddMenuItem(browser_, handler, menu, delegate, MENU_ID_VIEWSOURCE, + // "View Source", true); } if (!menu) @@ -169,21 +234,24 @@ void BrowserWebViewDelegate::showContextMenu( // Synthesize an event for the click, as there is no certainty that // [NSApp currentEvent] will return a valid event. + NSPoint screen_pt = {screenX, screenY}; + NSPoint window_pt = [window convertScreenToBase:screen_pt]; + NSEvent* currentEvent = [NSApp currentEvent]; 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]; + location:window_pt + modifierFlags:NSRightMouseDownMask + timestamp:eventTime + windowNumber:[window windowNumber] + context:nil + eventNumber:0 + clickCount:1 + pressure:1.0]; - // Menu selection events go to the BrowserWebView. - [menu setDelegate:view]; + // Menu selection events go to the BrowserMenuDelegate. + [menu setDelegate:delegate]; // Show the menu. [NSMenu popUpContextMenu:menu @@ -194,18 +262,43 @@ void BrowserWebViewDelegate::showContextMenu( // WebWidgetClient ------------------------------------------------------------ void BrowserWebViewDelegate::show(WebNavigationPolicy policy) { + DCHECK(this != browser_->UIT_GetPopupDelegate()); } void BrowserWebViewDelegate::didChangeCursor(const WebCursorInfo& cursor_info) { NSCursor* ns_cursor = WebCursor(cursor_info).GetCursor(); - [ns_cursor set]; + + if (!browser_->IsWindowRenderingDisabled()) { + [ns_cursor set]; + } else { + // Notify the handler of cursor change. + CefRefPtr client = browser_->GetClient(); + if (client.get()) { + CefRefPtr handler = client->GetRenderHandler(); + if (handler.get()) + handler->OnCursorChange(browser_, ns_cursor); + } + } } WebRect BrowserWebViewDelegate::windowRect() { if (WebWidgetHost* host = GetWidgetHost()) { - NSView *view = host->view_handle(); - NSRect rect = [view frame]; - return gfx::Rect(NSRectToCGRect(rect)); + if (!browser_->IsWindowRenderingDisabled()) { + NSView *view = host->view_handle(); + NSRect rect = [view frame]; + return gfx::Rect(NSRectToCGRect(rect)); + } else { + // Retrieve the view rectangle from the handler. + CefRefPtr client = browser_->GetClient(); + if (client.get()) { + CefRefPtr handler = client->GetRenderHandler(); + if (handler.get()) { + CefRect rect(0, 0, 0, 0); + if (handler->GetViewRect(browser_, rect)) + return WebRect(rect.x, rect.y, rect.width, rect.height); + } + } + } } return WebRect(); } @@ -213,6 +306,8 @@ WebRect BrowserWebViewDelegate::windowRect() { void BrowserWebViewDelegate::setWindowRect(const WebRect& rect) { if (this == browser_->UIT_GetWebViewDelegate()) { // TODO(port): Set the window rectangle. + } else if (this == browser_->UIT_GetPopupDelegate()) { + NOTREACHED(); } } @@ -257,7 +352,8 @@ void BrowserWebViewDelegate::startDragging(const WebDragData& data, WebDragOperationsMask mask, const WebImage& image, const WebPoint& image_offset) { - if (browser_->settings().drag_drop_disabled) { + if (browser_->settings().drag_drop_disabled || + browser_->IsWindowRenderingDisabled()) { browser_->UIT_GetWebView()->dragSourceSystemDragEnded(); return; } @@ -332,15 +428,30 @@ webkit::npapi::WebPluginDelegate* BrowserWebViewDelegate::CreatePluginDelegate( void BrowserWebViewDelegate::CreatedPluginWindow( gfx::PluginWindowHandle handle) { + if (browser_->IsWindowRenderingDisabled()) { + WebViewHost* host = browser_->UIT_GetWebViewHost(); + if (host) + host->AddWindowedPlugin(handle); + } } void BrowserWebViewDelegate::WillDestroyPluginWindow( gfx::PluginWindowHandle handle) { + if (browser_->IsWindowRenderingDisabled()) { + WebViewHost* host = browser_->UIT_GetWebViewHost(); + if (host) + host->RemoveWindowedPlugin(handle); + } } void BrowserWebViewDelegate::DidMovePlugin( const webkit::npapi::WebPluginGeometry& move) { - // TODO(port): add me once plugins work. + if (browser_->IsWindowRenderingDisabled()) { + WebViewHost* host = browser_->UIT_GetWebViewHost(); + if (host) { + host->MoveWindowedPlugin(move); + } + } } // Protected methods ---------------------------------------------------------- diff --git a/libcef/browser_webview_delegate_win.cc b/libcef/browser_webview_delegate_win.cc index 3e6110f9d..0da680f74 100644 --- a/libcef/browser_webview_delegate_win.cc +++ b/libcef/browser_webview_delegate_win.cc @@ -7,18 +7,19 @@ // as the WebViewDelegate for the BrowserWebHost. The host is expected to // have initialized a MessageLoop before these methods are called. -#include "browser_drag_delegate_win.h" -#include "browser_navigation_controller.h" -#include "browser_impl.h" -#include "browser_webview_delegate.h" -#include "cef_context.h" -#include "drag_data_impl.h" -#include "web_drop_target_win.h" +#include "libcef/browser_webview_delegate.h" #include #include #include +#include "libcef/browser_drag_delegate_win.h" +#include "libcef/browser_navigation_controller.h" +#include "libcef/browser_impl.h" +#include "libcef/cef_context.h" +#include "libcef/drag_data_impl.h" +#include "libcef/web_drop_target_win.h" + #include "base/message_loop.h" #include "base/string_util.h" #include "net/base/net_errors.h" @@ -66,8 +67,7 @@ void AddMenuItem(CefRefPtr browser, cef_menu_id_t menuId, const wchar_t* label, bool enabled, - std::list& label_list) -{ + std::list& label_list) { CefString actual_label(label); if (handler.get()) { // Let the handler change the label if desired, @@ -91,8 +91,7 @@ void AddMenuItem(CefRefPtr browser, InsertMenuItem(menu, -1, TRUE, &mii); } -void AddMenuSeparator(HMENU menu) -{ +void AddMenuSeparator(HMENU menu) { MENUITEMINFO mii; mii.cbSize = sizeof(mii); mii.fMask = MIIM_FTYPE; @@ -101,7 +100,7 @@ void AddMenuSeparator(HMENU menu) InsertMenuItem(menu, -1, TRUE, &mii); } -} // namespace +} // namespace // WebViewClient -------------------------------------------------------------- @@ -120,7 +119,7 @@ void BrowserWebViewDelegate::show(WebNavigationPolicy) { // Restore the window and bring it to the top if the window is currently // visible. HWND root = GetAncestor(browser_->UIT_GetMainWndHandle(), GA_ROOT); - if(IsWindowVisible(root)) { + if (IsWindowVisible(root)) { ShowWindow(root, SW_SHOWNORMAL); SetWindowPos(root, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); } @@ -145,7 +144,7 @@ void BrowserWebViewDelegate::didChangeCursor(const WebCursorInfo& cursor_info) { if (WebWidgetHost* host = GetWidgetHost()) { current_cursor_.InitFromCursorInfo(cursor_info); HMODULE hModule = ::GetModuleHandle(L"libcef.dll"); - if(!hModule) + if (!hModule) hModule = ::GetModuleHandle(NULL); HCURSOR hCursor = current_cursor_.GetCursor(hModule); @@ -195,7 +194,7 @@ void BrowserWebViewDelegate::setWindowRect(const WebRect& rect) { } else { browser_->set_popup_rect(rect); browser_->UIT_GetPopupHost()->SetSize(rect.width, rect.height); - + // Notify the handler of popup size change. CefRefPtr client = browser_->GetClient(); if (client.get()) { @@ -268,9 +267,9 @@ void BrowserWebViewDelegate::runModal() { CefRefPtr client = browser_->GetClient(); CefRefPtr handler; - if( client.get()) + if (client.get()) handler = client->GetLifeSpanHandler(); - + bool handled(false); if (handler.get()) { @@ -293,7 +292,7 @@ void BrowserWebViewDelegate::runModal() { } DWORD dwStyle = ::GetWindowLong(child, GWL_STYLE); DWORD dwNewStyle = dwStyle | WS_POPUP; - if(dwStyle != dwNewStyle) + if (dwStyle != dwNewStyle) ::SetWindowLong(child, GWL_STYLE, dwNewStyle); } @@ -313,8 +312,7 @@ void BrowserWebViewDelegate::runModal() { webkit::npapi::WebPluginDelegate* BrowserWebViewDelegate::CreatePluginDelegate( const FilePath& file_path, - const std::string& mime_type) -{ + const std::string& mime_type) { WebViewHost* host = browser_->UIT_GetWebViewHost(); if (!host) return NULL; @@ -379,7 +377,7 @@ void BrowserWebViewDelegate::WillDestroyPluginWindow( void BrowserWebViewDelegate::DidMovePlugin( const webkit::npapi::WebPluginGeometry& move) { - unsigned long flags = 0; + UINT flags = 0; if (move.rects_valid) { HRGN hrgn = ::CreateRectRgn(move.clip_rect.x(), @@ -417,10 +415,9 @@ void BrowserWebViewDelegate::DidMovePlugin( } void BrowserWebViewDelegate::showContextMenu( - WebFrame* frame, const WebContextMenuData& data) -{ + WebFrame* frame, const WebContextMenuData& data) { int screenX = -1, screenY = -1; - + POINT mouse_pt = {data.mousePosition.x, data.mousePosition.y}; if (!browser_->IsWindowRenderingDisabled()) { // Perform the conversion to screen coordinates only if window rendering is @@ -451,7 +448,7 @@ void BrowserWebViewDelegate::showContextMenu( if (client.get() && browser_->IsWindowRenderingDisabled()) { // Retrieve the screen coordinates. CefRefPtr render_handler = client->GetRenderHandler(); - if (render_handler.get() && + if (!render_handler.get() || !render_handler->GetScreenPoint(browser_, mouse_pt.x, mouse_pt.y, screenX, screenY)) { return; @@ -477,11 +474,11 @@ void BrowserWebViewDelegate::showContextMenu( AddMenuSeparator(menu); AddMenuItem(browser_, handler, menu, MENU_ID_SELECTALL, L"Select All", !!(edit_flags & MENU_CAN_SELECT_ALL), label_list); - } else if(type_flags & MENUTYPE_SELECTION) { + } else if (type_flags & MENUTYPE_SELECTION) { menu = CreatePopupMenu(); AddMenuItem(browser_, handler, menu, MENU_ID_COPY, L"Copy", !!(edit_flags & MENU_CAN_COPY), label_list); - } else if(type_flags & (MENUTYPE_PAGE | MENUTYPE_FRAME)) { + } else if (type_flags & (MENUTYPE_PAGE | MENUTYPE_FRAME)) { menu = CreatePopupMenu(); AddMenuItem(browser_, handler, menu, MENU_ID_NAV_BACK, L"Back", !!(edit_flags & MENU_CAN_GO_BACK), label_list); @@ -511,7 +508,7 @@ void BrowserWebViewDelegate::showContextMenu( handled = handler->OnMenuAction(browser_, menuId); } - if(!handled) { + if (!handled) { // Execute the action browser_->UIT_HandleAction(menuId, browser_->GetFocusedFrame()); } @@ -539,8 +536,7 @@ void BrowserWebViewDelegate::EndDragging() { } void BrowserWebViewDelegate::ShowJavaScriptAlert(WebFrame* webframe, - const CefString& message) -{ + const CefString& message) { // TODO(cef): Think about what we should be showing as the prompt caption std::wstring messageStr = message; std::wstring titleStr = browser_->UIT_GetTitle(); @@ -549,8 +545,7 @@ void BrowserWebViewDelegate::ShowJavaScriptAlert(WebFrame* webframe, } bool BrowserWebViewDelegate::ShowJavaScriptConfirm(WebFrame* webframe, - const CefString& message) -{ + const CefString& message) { // TODO(cef): Think about what we should be showing as the prompt caption std::wstring messageStr = message; std::wstring titleStr = browser_->UIT_GetTitle(); @@ -562,19 +557,16 @@ bool BrowserWebViewDelegate::ShowJavaScriptConfirm(WebFrame* webframe, bool BrowserWebViewDelegate::ShowJavaScriptPrompt(WebFrame* webframe, const CefString& message, const CefString& default_value, - CefString* result) -{ + CefString* result) { // TODO(cef): Implement a default prompt dialog return false; } -namespace -{ +namespace { // from chrome/browser/views/shell_dialogs_win.cc -bool RunOpenFileDialog(const std::wstring& filter, HWND owner, FilePath* path) -{ +bool RunOpenFileDialog(const std::wstring& filter, HWND owner, FilePath* path) { OPENFILENAME ofn; // We must do this otherwise the ofn's FlagsEx may be initialized to random @@ -603,8 +595,7 @@ bool RunOpenFileDialog(const std::wstring& filter, HWND owner, FilePath* path) } bool RunOpenMultiFileDialog(const std::wstring& filter, HWND owner, - std::vector* paths) -{ + std::vector* paths) { OPENFILENAME ofn; // We must do this otherwise the ofn's FlagsEx may be initialized to random @@ -655,15 +646,14 @@ bool RunOpenMultiFileDialog(const std::wstring& filter, HWND owner, return success; } -} +} // namespace -bool BrowserWebViewDelegate::ShowFileChooser(std::vector& file_names, - const bool multi_select, - const WebKit::WebString& title, - const FilePath& default_file) -{ +bool BrowserWebViewDelegate::ShowFileChooser(std::vector& file_names, + const bool multi_select, + const WebKit::WebString& title, + const FilePath& default_file) { bool result = false; - + if (multi_select) { result = RunOpenMultiFileDialog(L"", browser_->UIT_GetMainWndHandle(), &file_names); diff --git a/libcef/browser_webview_mac.h b/libcef/browser_webview_mac.h index 2abdf05ce..790fc1ac9 100644 --- a/libcef/browser_webview_mac.h +++ b/libcef/browser_webview_mac.h @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifndef CEF_LIBCEF_BROWSER_WEBVIEW_MAC_H_ +#define CEF_LIBCEF_BROWSER_WEBVIEW_MAC_H_ +#pragma once + #import #import "base/mac/cocoa_protocols.h" #include "base/memory/scoped_nsobject.h" @@ -14,10 +18,11 @@ struct WebDropData; // A view to wrap the WebCore view and help it live in a Cocoa world. The // (rough) equivalent of Apple's WebView. -@interface BrowserWebView : NSView { +@interface BrowserWebView : NSView { @private - CefBrowserImpl *browser_; // weak - NSTrackingArea *trackingArea_; + CefBrowserImpl* browser_; // weak + NSTrackingArea* trackingArea_; + bool is_in_setfocus_; scoped_nsobject dragSource_; scoped_nsobject dropTarget_; @@ -41,9 +46,6 @@ struct WebDropData; - (BOOL)isOpaque; - (void)setFrame:(NSRect)frameRect; -// Called when a context menu item is selected by the user. -- (void)menuItemSelected:(id)sender; - // Register this WebView as a drag/drop target. - (void)registerDragDrop; @@ -53,6 +55,9 @@ struct WebDropData; image:(NSImage*)image offset:(NSPoint)offset; -@property (nonatomic, assign) CefBrowserImpl *browser; +@property (nonatomic, assign) CefBrowserImpl* browser; +@property (nonatomic, assign) bool in_setfocus; @end + +#endif // CEF_LIBCEF_BROWSER_WEBVIEW_MAC_H_ diff --git a/libcef/browser_webview_mac.mm b/libcef/browser_webview_mac.mm index 3031894a7..e743875aa 100644 --- a/libcef/browser_webview_mac.mm +++ b/libcef/browser_webview_mac.mm @@ -21,6 +21,7 @@ @implementation BrowserWebView @synthesize browser = browser_; +@synthesize in_setfocus = is_in_setfocus_; - (id)initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; @@ -168,12 +169,14 @@ - (BOOL)becomeFirstResponder { if (browser_ && browser_->UIT_GetWebView()) { - CefRefPtr client = browser_->GetClient(); - if (client.get()) { - CefRefPtr handler = client->GetFocusHandler(); - if (handler.get() && - handler->OnSetFocus(browser_, FOCUS_SOURCE_SYSTEM)) { - return NO; + if (!is_in_setfocus_) { + CefRefPtr client = browser_->GetClient(); + if (client.get()) { + CefRefPtr handler = client->GetFocusHandler(); + if (handler.get() && + handler->OnSetFocus(browser_, FOCUS_SOURCE_SYSTEM)) { + return NO; + } } } @@ -236,25 +239,6 @@ browser_->GetFocusedFrame()->SelectAll(); } -- (void)menuItemSelected:(id)sender { - cef_menu_id_t menuId = static_cast([sender tag]); - bool handled = false; - - CefRefPtr client = browser_->GetClient(); - if (client.get()) { - CefRefPtr handler = client->GetMenuHandler(); - if (handler.get()) { - // Ask the handler if it wants to handle the action. - handled = handler->OnMenuAction(browser_, menuId); - } - } - - if(!handled) { - // Execute the action. - browser_->UIT_HandleAction(menuId, browser_->GetFocusedFrame()); - } -} - - (void)registerDragDrop { dropTarget_.reset([[WebDropTarget alloc] initWithWebView:self]); diff --git a/libcef/external_popup_menu_mac.mm b/libcef/external_popup_menu_mac.mm index 8f62e0502..889334dd5 100644 --- a/libcef/external_popup_menu_mac.mm +++ b/libcef/external_popup_menu_mac.mm @@ -33,9 +33,35 @@ void ExternalPopupMenu::show(const WebKit::WebRect& bounds) { CefBrowserImpl* browser = delegate_->GetBrowser(); + NSView* view = nil; + NSRect view_rect; + + if (!browser->IsWindowRenderingDisabled()) { + view = browser->UIT_GetWebViewWndHandle(); + view_rect = [view bounds]; + } else { + view = browser->UIT_GetMainWndHandle(); + if (view != nil) { + CefRefPtr client = browser->GetClient(); + if (client.get()) { + // Retrieve the view rect. + CefRect rect; + CefRefPtr render_handler = client->GetRenderHandler(); + if (render_handler.get() && + render_handler->GetViewRect(browser, rect)) { + view_rect = NSMakeRect(rect.x, rect.y, rect.width, rect.height); + } + } + } + } + + if (view == nil || view_rect.size.width == 0 || view_rect.size.height == 0) { + popup_menu_client_->didCancel(); + delegate_->ClosePopupMenu(); + return; + } + // Set up the menu position. - NSView* web_view = browser->UIT_GetWebViewWndHandle(); - NSRect view_rect = [web_view bounds]; int y_offset = bounds.y + bounds.height; NSRect position = NSMakeRect(bounds.x, view_rect.size.height - y_offset, bounds.width, bounds.height); @@ -46,7 +72,7 @@ void ExternalPopupMenu::show(const WebKit::WebRect& bounds) { fontSize:font_size rightAligned:right_aligned]); - [menu_runner runMenuInView:browser->UIT_GetWebViewWndHandle() + [menu_runner runMenuInView:view withBounds:position initialIndex:selected_index]; diff --git a/libcef/webview_host_mac.mm b/libcef/webview_host_mac.mm index de990cc5c..f8e0f8902 100644 --- a/libcef/webview_host_mac.mm +++ b/libcef/webview_host_mac.mm @@ -35,10 +35,15 @@ WebViewHost* WebViewHost::Create(NSView* parent_view, WebViewHost* host = new WebViewHost(delegate); NSRect content_rect = {{rect.x(), rect.y()}, {rect.width(), rect.height()}}; - host->view_ = [[BrowserWebView alloc] initWithFrame:content_rect]; - [host->view_ setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; - [parent_view addSubview:host->view_]; - [host->view_ release]; + if (!paint_delegate) { + host->view_ = [[BrowserWebView alloc] initWithFrame:content_rect]; + [host->view_ setAutoresizingMask:(NSViewWidthSizable | + NSViewHeightSizable)]; + [parent_view addSubview:host->view_]; + [host->view_ release]; + } else { + host->paint_delegate_ = paint_delegate; + } #if defined(WEBKIT_HAS_WEB_AUTO_FILL_CLIENT) host->webwidget_ = WebView::create(delegate, NULL); diff --git a/libcef/webwidget_host.cc b/libcef/webwidget_host.cc index 33f345b65..c1ae0be65 100644 --- a/libcef/webwidget_host.cc +++ b/libcef/webwidget_host.cc @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "webwidget_host.h" -#include "cef_thread.h" +#include "libcef/webwidget_host.h" +#include "libcef/cef_thread.h" #include "base/bind.h" #include "base/message_loop.h" @@ -46,7 +46,7 @@ void WebWidgetHost::UpdatePaintRect(const gfx::Rect& rect) { paint_rgn_.op(rect.x(), rect.y(), rect.right(), rect.bottom(), SkRegion::kUnion_Op); #else - // TODO: Update all ports to use regions instead of rectangles. + // TODO(cef): Update all ports to use regions instead of rectangles. paint_rect_ = paint_rect_.Union(rect); #endif } @@ -68,21 +68,18 @@ void WebWidgetHost::GetSize(int& width, int& height) { height = size.height; } -void WebWidgetHost::AddWindowedPlugin(gfx::PluginWindowHandle handle) -{ +void WebWidgetHost::AddWindowedPlugin(gfx::PluginWindowHandle handle) { WebPluginGeometry geometry; plugin_map_.insert(std::make_pair(handle, geometry)); } -void WebWidgetHost::RemoveWindowedPlugin(gfx::PluginWindowHandle handle) -{ +void WebWidgetHost::RemoveWindowedPlugin(gfx::PluginWindowHandle handle) { PluginMap::iterator it = plugin_map_.find(handle); DCHECK(it != plugin_map_.end()); plugin_map_.erase(it); } -void WebWidgetHost::MoveWindowedPlugin(const WebPluginGeometry& move) -{ +void WebWidgetHost::MoveWindowedPlugin(const WebPluginGeometry& move) { PluginMap::iterator it = plugin_map_.find(move.window); DCHECK(it != plugin_map_.end()); @@ -96,11 +93,10 @@ void WebWidgetHost::MoveWindowedPlugin(const WebPluginGeometry& move) it->second.visible = move.visible; } -gfx::PluginWindowHandle WebWidgetHost::GetWindowedPluginAt(int x, int y) -{ +gfx::PluginWindowHandle WebWidgetHost::GetWindowedPluginAt(int x, int y) { if (!plugin_map_.empty()) { PluginMap::const_iterator it = plugin_map_.begin(); - for(; it != plugin_map_.end(); ++it) { + for (; it != plugin_map_.end(); ++it) { if (it->second.visible && it->second.window_rect.Contains(x, y)) return it->second.window; } @@ -110,21 +106,18 @@ gfx::PluginWindowHandle WebWidgetHost::GetWindowedPluginAt(int x, int y) } void WebWidgetHost::DoPaint() { - // TODO(cef): The below code is cross-platform but the IsIdle() method - // currently requires patches to Chromium. Since this code is only executed - // on Windows it's been stuck behind an #ifdef for now to avoid having to - // patch Chromium code on other platforms. -#if defined(OS_WIN) - if (MessageLoop::current()->IsIdle()) { + if (MessageLoop::current()->IsIdle()) { has_update_task_ = false; // Paint to the delegate. +#if defined(OS_MACOSX) + SkRegion region; + Paint(region); +#else Paint(); +#endif } else { // Try again later. CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&WebWidgetHost::DoPaint, weak_factory_.GetWeakPtr())); } -#else - NOTIMPLEMENTED(); -#endif } diff --git a/libcef/webwidget_host.h b/libcef/webwidget_host.h index 4b350a3b0..b5dfec428 100644 --- a/libcef/webwidget_host.h +++ b/libcef/webwidget_host.h @@ -2,16 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef _WEBWIDGET_HOST_H -#define _WEBWIDGET_HOST_H +#ifndef CEF_LIBCEF_WEBWIDGET_HOST_H_ +#define CEF_LIBCEF_WEBWIDGET_HOST_H_ +#pragma once + +#include +#include #include "include/internal/cef_string.h" #include "include/internal/cef_types.h" #include "include/internal/cef_types_wrappers.h" + #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" -#include "base/task.h" #include "base/time.h" #include "skia/ext/platform_canvas.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" @@ -21,14 +25,13 @@ #include "ui/gfx/native_widget_types.h" #include "ui/gfx/rect.h" #include "webkit/plugins/npapi/webplugin.h" -#include #if defined(OS_WIN) #include "ui/base/win/ime_input.h" #endif -#if defined(TOOLKIT_USES_GTK) -#include +#if defined(TOOLKIT_GTK) +#include // NOLINT(build/include_order) #endif namespace gfx { @@ -56,6 +59,7 @@ class WebWidgetHost { public: class PaintDelegate { public: + virtual ~PaintDelegate() {} virtual void Paint(bool popup, const std::vector& dirtyRects, const void* buffer) =0; }; @@ -119,12 +123,12 @@ class WebWidgetHost { void SetTooltipText(const CefString& tooltip_text); - void SendKeyEvent(cef_key_type_t type, int key, int modifiers, bool sysChar, - bool imeChar); + void SendKeyEvent(cef_key_type_t type, const cef_key_info_t& keyInfo, + int modifiers); void SendMouseClickEvent(int x, int y, cef_mouse_button_type_t type, bool mouseUp, int clickCount); void SendMouseMoveEvent(int x, int y, bool mouseLeave); - void SendMouseWheelEvent(int x, int y, int delta); + void SendMouseWheelEvent(int x, int y, int deltaX, int deltaY); void SendFocusEvent(bool setFocus); void SendCaptureLostEvent(); @@ -176,12 +180,14 @@ class WebWidgetHost { // These need to be called from a non-subclass, so they need to be public. public: void Resize(const gfx::Rect& rect); - virtual void MouseEvent(NSEvent *); - void WheelEvent(NSEvent *); - virtual void KeyEvent(NSEvent *); + virtual void MouseEvent(NSEvent* event); + void WheelEvent(NSEvent* event); + virtual void KeyEvent(NSEvent* event); virtual void SetFocus(bool enable); + protected: -#elif defined(TOOLKIT_USES_GTK) +#elif defined(TOOLKIT_GTK) + public: // --------------------------------------------------------------------------- // This is needed on Linux because the GtkWidget creation is the same between @@ -250,7 +256,7 @@ class WebWidgetHost { // The map of windowed plugins that need to be drawn when window rendering is // disabled. - typedef std::map + typedef std::map PluginMap; PluginMap plugin_map_; @@ -278,7 +284,12 @@ class WebWidgetHost { WebKit::WebRect caret_bounds_; #endif -#if defined(TOOLKIT_USES_GTK) +#if defined(OS_MACOSX) + int mouse_modifiers_; + WebKit::WebMouseEvent::Button mouse_button_down_; +#endif + +#if defined(TOOLKIT_GTK) // Since GtkWindow resize is asynchronous, we have to stash the dimensions, // so that the backing store doesn't have to wait for sizing to take place. gfx::Size logical_size_; @@ -293,4 +304,4 @@ class WebWidgetHost { base::WeakPtrFactory weak_factory_; }; -#endif // _WEBWIDGET_HOST_H +#endif // CEF_LIBCEF_WEBWIDGET_HOST_H_ diff --git a/libcef/webwidget_host_gtk.cc b/libcef/webwidget_host_gtk.cc index 1d13b7c07..38b1658b9 100644 --- a/libcef/webwidget_host_gtk.cc +++ b/libcef/webwidget_host_gtk.cc @@ -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 "webwidget_host.h" +#include "libcef/webwidget_host.h" #include #include @@ -379,7 +379,7 @@ void WebWidgetHost::Paint() { total_paint = total_paint.Union(rect); } } - //DCHECK(paint_rect_.IsEmpty()); + // DCHECK(paint_rect_.IsEmpty()); // Invalidate the paint region on the widget's underlying gdk window. Note // that gdk_window_invalidate_* will generate extra expose events, which @@ -410,19 +410,16 @@ void WebWidgetHost::Paint() { has_invalidate_task_ = false; } -void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) -{ +void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) { // TODO(port): Implement this method as part of tooltip support. } -void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) -{ +void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) { // TODO(port): Implement this method as part of off-screen rendering support. NOTIMPLEMENTED(); } -bool WebWidgetHost::GetImage(int width, int height, void* rgba_buffer) -{ +bool WebWidgetHost::GetImage(int width, int height, void* rgba_buffer) { if (!canvas_.get()) return false; @@ -443,57 +440,49 @@ void WebWidgetHost::PaintRect(const gfx::Rect& rect) { set_painting(false); } -void WebWidgetHost::SendKeyEvent(cef_key_type_t type, int key, int modifiers, - bool sysChar, bool imeChar) -{ +void WebWidgetHost::SendKeyEvent(cef_key_type_t type, + const cef_key_info_t& keyInfo, + int modifiers) { // TODO(port): Implement this method as part of off-screen rendering support. NOTIMPLEMENTED(); } void WebWidgetHost::SendMouseClickEvent(int x, int y, cef_mouse_button_type_t type, - bool mouseUp, int clickCount) -{ + bool mouseUp, int clickCount) { // TODO(port): Implement this method as part of off-screen rendering support. NOTIMPLEMENTED(); } -void WebWidgetHost::SendMouseMoveEvent(int x, int y, bool mouseLeave) -{ +void WebWidgetHost::SendMouseMoveEvent(int x, int y, bool mouseLeave) { // TODO(port): Implement this method as part of off-screen rendering support. NOTIMPLEMENTED(); } -void WebWidgetHost::SendMouseWheelEvent(int x, int y, int delta) -{ +void WebWidgetHost::SendMouseWheelEvent(int x, int y, int deltaX, int deltaY) { // TODO(port): Implement this method as part of off-screen rendering support. NOTIMPLEMENTED(); } -void WebWidgetHost::SendFocusEvent(bool setFocus) -{ +void WebWidgetHost::SendFocusEvent(bool setFocus) { // TODO(port): Implement this method as part of off-screen rendering support. NOTIMPLEMENTED(); } -void WebWidgetHost::SendCaptureLostEvent() -{ +void WebWidgetHost::SendCaptureLostEvent() { // TODO(port): Implement this method as part of off-screen rendering support. NOTIMPLEMENTED(); } -void WebWidgetHost::EnsureTooltip() -{ +void WebWidgetHost::EnsureTooltip() { // TODO(port): Implement this method as part of tooltip support. } -void WebWidgetHost::ResetTooltip() -{ +void WebWidgetHost::ResetTooltip() { // TODO(port): Implement this method as part of tooltip support. } -void WebWidgetHost::KeyEvent(GdkEventKey* event) -{ +void WebWidgetHost::KeyEvent(GdkEventKey* event) { WebKeyboardEvent keyboard_event(WebInputEventFactory::keyboardEvent(event)); last_key_event_ = keyboard_event; webwidget()->handleInputEvent(keyboard_event); diff --git a/libcef/webwidget_host_mac.mm b/libcef/webwidget_host_mac.mm index 6f94c7ab0..4dc62565c 100644 --- a/libcef/webwidget_host_mac.mm +++ b/libcef/webwidget_host_mac.mm @@ -3,7 +3,18 @@ // found in the LICENSE file. #import -#import "webwidget_host.h" + +#include "base/compiler_specific.h" +#include "third_party/WebKit/Source/WebCore/config.h" +MSVC_PUSH_WARNING_LEVEL(0); +#include "KeyEventCocoa.h" // NOLINT(build/include) +MSVC_POP_WARNING(); + +#undef LOG +#import "libcef/webwidget_host.h" +#include "libcef/cef_thread.h" + +#include "base/bind.h" #import "base/logging.h" #import "skia/ext/platform_canvas.h" #import "third_party/WebKit/Source/WebKit/chromium/public/mac/WebInputEventFactory.h" @@ -11,12 +22,14 @@ #import "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" #import "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h" #import "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" +#import "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #import "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" #import "third_party/skia/include/core/SkRegion.h" #import "ui/gfx/rect.h" #import "ui/gfx/size.h" #import "webkit/glue/webkit_glue.h" +using webkit::npapi::WebPluginGeometry; using WebKit::WebInputEvent; using WebKit::WebInputEventFactory; using WebKit::WebKeyboardEvent; @@ -30,17 +43,15 @@ using WebKit::WebWidgetClient; namespace { -inline SkIRect convertToSkiaRect(const gfx::Rect& r) -{ +inline SkIRect convertToSkiaRect(const gfx::Rect& r) { return SkIRect::MakeLTRB(r.x(), r.y(), r.right(), r.bottom()); } -inline gfx::Rect convertFromSkiaRect(const SkIRect& r) -{ +inline gfx::Rect convertFromSkiaRect(const SkIRect& r) { return gfx::Rect(r.x(), r.y(), r.width(), r.height()); } -} // namespace +} // namespace /*static*/ WebWidgetHost* WebWidgetHost::Create(NSView* parent_view, @@ -48,14 +59,19 @@ WebWidgetHost* WebWidgetHost::Create(NSView* parent_view, PaintDelegate* paint_delegate) { WebWidgetHost* host = new WebWidgetHost(); - const NSRect bounds = [parent_view bounds]; - host->view_ = [[NSView alloc] initWithFrame:bounds]; - [parent_view addSubview:host->view_]; + if (!paint_delegate) { + const NSRect bounds = [parent_view bounds]; + host->view_ = [[NSView alloc] initWithFrame:bounds]; + [parent_view addSubview:host->view_]; + + host->webwidget_ = WebPopupMenu::create(client); + host->webwidget_->resize(WebSize(NSWidth(bounds), NSHeight(bounds))); + } else { + host->paint_delegate_ = paint_delegate; + host->view_ = nil; + host->webwidget_ = WebPopupMenu::create(client); + } - host->painting_ = false; - host->layouting_ = false; - host->webwidget_ = WebPopupMenu::create(client); - host->webwidget_->resize(WebSize(NSWidth(bounds), NSHeight(bounds))); return host; } @@ -68,6 +84,9 @@ WebWidgetHost::WebWidgetHost() popup_(false), has_update_task_(false), has_invalidate_task_(false), + mouse_modifiers_(0), + painting_(false), + layouting_(false), ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { set_painting(false); } @@ -76,21 +95,38 @@ WebWidgetHost::~WebWidgetHost() { } void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) { - const gfx::Rect client_rect(NSRectToCGRect([view_ bounds])); + int width, height; + GetSize(width, height); + const gfx::Rect client_rect(width, height); + const gfx::Rect damaged_rect_in_client = client_rect.Intersect(damaged_rect); if (!damaged_rect_in_client.IsEmpty()) { UpdatePaintRect(damaged_rect_in_client); - NSRect cocoa_rect = NSRectFromCGRect(damaged_rect_in_client.ToCGRect()); - cocoa_rect.origin.y = client_rect.height() - NSMaxY(cocoa_rect); - [view_ setNeedsDisplayInRect:cocoa_rect]; + + if (view_) { + NSRect cocoa_rect = NSRectFromCGRect(damaged_rect_in_client.ToCGRect()); + cocoa_rect.origin.y = client_rect.height() - NSMaxY(cocoa_rect); + [view_ setNeedsDisplayInRect:cocoa_rect]; + } else { + // Don't post a paint task if this invalidation occurred during layout or + // if a paint task is already pending. Paint() will be called by + // DoPaint(). + if (!layouting_ && !has_update_task_) { + has_update_task_ = true; + CefThread::PostTask(CefThread::UI, FROM_HERE, + base::Bind(&WebWidgetHost::DoPaint, weak_factory_.GetWeakPtr())); + } + } } } void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { DCHECK(dx || dy); - const gfx::Rect client_rect(NSRectToCGRect([view_ bounds])); + int width, height; + GetSize(width, height); + const gfx::Rect client_rect(width, height); gfx::Rect rect = clip_rect.Intersect(client_rect); const int x = rect.x(); @@ -108,7 +144,8 @@ void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { // needs to be laid out; calling scrollRect:by: in this situation leads to // unwanted behavior. Finally, scrolling the rectangle by more than the size // of the view means we can just invalidate the entire scroll rect. - if (![view_ canDraw] || painting_ || layouting_ || Dx >= w || Dy >= h) { + if (!view_ || [view_ canDraw] || painting_ || layouting_ || Dx >= w || + Dy >= h) { DidInvalidateRect(clip_rect); return; } @@ -146,36 +183,56 @@ void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { } void WebWidgetHost::Paint(SkRegion& update_rgn) { - gfx::Rect client_rect(NSRectToCGRect([view_ bounds])); + int width, height; + GetSize(width, height); + gfx::Rect client_rect(width, height); - // Union the rectangle that WebKit think needs repainting with the rectangle - // of the view that must be painted now. In most situations this will not - // affect the painted rectangle. In some situations we could end up re- - // painting areas that are already in the canvas and only dirty in the view - // itself. However, if we don't do this we can get artifacts when scrolling - // because contents of the canvas are no longer correct after scrolling only - // in the view. - paint_rgn_.op(update_rgn, SkRegion::kUnion_Op); + SkRegion damaged_rgn; + if (!view_ && !redraw_rect_.IsEmpty()) { + // At a minimum we need to send the delegate the rectangle that was + // requested by calling CefBrowser::InvalidateRect(). + damaged_rgn.setRect(convertToSkiaRect(redraw_rect_)); + redraw_rect_ = gfx::Rect(); + } - // When we are not using accelerated compositing the canvas area is allowed - // to differ in size from the client by a certain number of pixels (128 in - // this case). When accelerated compositing is in effect the size must match - // exactly. - const int extra_w = (webwidget_->isAcceleratedCompositingActive()? 0: 128); - const int extra_h = (webwidget_->isAcceleratedCompositingActive()? 0: 128); - const int min_w = client_rect.width(); - const int min_h = client_rect.height(); - const int max_w = client_rect.width() + extra_w * 2; - const int max_h = client_rect.height() + extra_h * 2; + if (view_) { + // Union the rectangle that WebKit think needs repainting with the rectangle + // of the view that must be painted now. In most situations this will not + // affect the painted rectangle. In some situations we could end up re- + // painting areas that are already in the canvas and only dirty in the view + // itself. However, if we don't do this we can get artifacts when scrolling + // because contents of the canvas are no longer correct after scrolling only + // in the view. + paint_rgn_.op(update_rgn, SkRegion::kUnion_Op); - const bool too_small = (canvas_w_ < min_w || canvas_h_ < min_h); - const bool too_large = (canvas_w_ > max_w || canvas_h_ > max_h); + // When we are not using accelerated compositing the canvas area is allowed + // to differ in size from the client by a certain number of pixels (128 in + // this case). When accelerated compositing is in effect the size must match + // exactly. + const int extra_w = (webwidget_->isAcceleratedCompositingActive()? 0: 128); + const int extra_h = (webwidget_->isAcceleratedCompositingActive()? 0: 128); + const int min_w = client_rect.width(); + const int min_h = client_rect.height(); + const int max_w = client_rect.width() + extra_w * 2; + const int max_h = client_rect.height() + extra_h * 2; - if (!canvas_.get() || too_small || too_large) { - canvas_w_ = client_rect.width() + extra_w; - canvas_h_ = client_rect.height() + extra_h; - canvas_.reset(new skia::PlatformCanvas(canvas_w_, canvas_h_, true)); + const bool too_small = (canvas_w_ < min_w || canvas_h_ < min_h); + const bool too_large = (canvas_w_ > max_w || canvas_h_ > max_h); + + if (!canvas_.get() || too_small || too_large) { + canvas_w_ = client_rect.width() + extra_w; + canvas_h_ = client_rect.height() + extra_h; + canvas_.reset(new skia::PlatformCanvas(canvas_w_, canvas_h_, true)); + paint_rgn_.setRect(convertToSkiaRect(client_rect)); + } + } else if (!canvas_.get() || canvas_w_ != client_rect.width() || + canvas_h_ != client_rect.height()) { paint_rgn_.setRect(convertToSkiaRect(client_rect)); + + // The canvas must be the exact size of the client area. + canvas_w_ = client_rect.width(); + canvas_h_ = client_rect.height(); + canvas_.reset(new skia::PlatformCanvas(canvas_w_, canvas_h_, true)); } webwidget_->animate(0.0); @@ -204,28 +261,69 @@ void WebWidgetHost::Paint(SkRegion& update_rgn) { draw_rgn.swap(paint_rgn_); SkRegion::Cliperator iterator(draw_rgn, convertToSkiaRect(client_rect)); - for (; !iterator.done(); iterator.next()) - PaintRect(convertFromSkiaRect(iterator.rect())); + for (; !iterator.done(); iterator.next()) { + const SkIRect& r = iterator.rect(); + PaintRect(convertFromSkiaRect(r)); - // If any more rectangles were made dirty during the paint operation, make - // sure they are copied to the window buffer, by including the paint region. - // If nothing needs additional painting, this is a no-op. - update_rgn.op(paint_rgn_, SkRegion::kUnion_Op); + if (!view_) + damaged_rgn.op(r, SkRegion::kUnion_Op); + } + + if (view_) { + // If any more rectangles were made dirty during the paint operation, make + // sure they are copied to the window buffer, by including the paint + // region. If nothing needs additional painting, this is a no-op. + update_rgn.op(paint_rgn_, SkRegion::kUnion_Op); + } + } + + if (!view_ && plugin_map_.size() > 0) { + // Flash seems to stop calling NPN_InvalidateRect, which means we stop + // painting. If we've got a plugin make sure we paint its rect each time. + + PluginMap::const_iterator it = plugin_map_.begin(); + for (; it != plugin_map_.end(); ++it) { + if (it->second.visible && + client_rect.Intersects(it->second.window_rect)) { + const WebPluginGeometry* geom = &it->second; + damaged_rgn.op(convertToSkiaRect(geom->window_rect), + SkRegion::kUnion_Op); + } + } } - // Set the context back to our view and copy the bitmap that we just painted - // into to the view. Only the regions that were updated are copied. - [NSGraphicsContext restoreGraphicsState]; - NSGraphicsContext* view_context = [NSGraphicsContext currentContext]; - CGContextRef context = static_cast([view_context graphicsPort]); + if (view_) { + // Set the context back to our view and copy the bitmap that we just painted + // into to the view. Only the regions that were updated are copied. + [NSGraphicsContext restoreGraphicsState]; + NSGraphicsContext* view_context = [NSGraphicsContext currentContext]; + CGContextRef context = + static_cast([view_context graphicsPort]); - SkRegion::Cliperator iterator(update_rgn, convertToSkiaRect(client_rect)); - for (; !iterator.done(); iterator.next()) { - const SkIRect& r = iterator.rect(); - CGRect copy_rect = { { r.x(), r.y() }, { r.width(), r.height() } }; - const float x = r.x(); - const float y = client_rect.height() - r.bottom(); - skia::DrawToNativeContext(canvas_.get(), context, x, y, ©_rect); + SkRegion::Cliperator iterator(update_rgn, convertToSkiaRect(client_rect)); + for (; !iterator.done(); iterator.next()) { + const SkIRect& r = iterator.rect(); + CGRect copy_rect = { { r.x(), r.y() }, { r.width(), r.height() } }; + const float x = r.x(); + const float y = client_rect.height() - r.bottom(); + skia::DrawToNativeContext(canvas_.get(), context, x, y, ©_rect); + } + } else { + // Paint to the delegate. + DCHECK(paint_delegate_); + const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false); + DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config); + const void* pixels = bitmap.getPixels(); + + std::vector damaged_rects; + SkRegion::Cliperator iterator(damaged_rgn, convertToSkiaRect(client_rect)); + for (; !iterator.done(); iterator.next()) { + const SkIRect& r = iterator.rect(); + damaged_rects.push_back( + CefRect(r.left(), r.top(), r.width(), r.height())); + } + + paint_delegate_->Paint(popup_, damaged_rects, pixels); } // Used with scheduled invalidation to maintain a consistent frame rate. @@ -235,28 +333,63 @@ void WebWidgetHost::Paint(SkRegion& update_rgn) { } void WebWidgetHost::Invalidate() { - [view_ setNeedsDisplay:YES]; + if (view_) { + [view_ setNeedsDisplay:YES]; + } else if (webwidget_) { + WebSize size = webwidget_->size(); + InvalidateRect(gfx::Rect(0, 0, size.width, size.height)); + } } -void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) -{ +void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) { // TODO(port): Implement this method as part of tooltip support. } -void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) -{ - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); +void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) { + if (rect.IsEmpty()) + return; + + if (!view_) { + // Don't post a paint task if this invalidation occurred during layout or if + // a paint task is already pending. Paint() will be called by DoPaint(). + if (!layouting_ && !has_update_task_) { + has_update_task_ = true; + CefThread::PostTask(CefThread::UI, FROM_HERE, + base::Bind(&WebWidgetHost::DoPaint, weak_factory_.GetWeakPtr())); + } + } else { + NOTIMPLEMENTED(); + } } -bool WebWidgetHost::GetImage(int width, int height, void* rgba_buffer) -{ +bool WebWidgetHost::GetImage(int width, int height, void* rgba_buffer) { if (!canvas_.get()) return false; - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); - return false; + const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false); + DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config); + + if (width == canvas_->getDevice()->width() && + height == canvas_->getDevice()->height()) { + // The specified width and height values are the same as the canvas size. + // Return the existing canvas contents. + const void* pixels = bitmap.getPixels(); + memcpy(rgba_buffer, pixels, width * height * 4); + return true; + } + + // Create a new canvas of the requested size. + scoped_ptr new_canvas( + new skia::PlatformCanvas(width, height, true)); + + new_canvas->writePixels(bitmap, 0, 0); + const SkBitmap& new_bitmap = new_canvas->getDevice()->accessBitmap(false); + DCHECK(new_bitmap.config() == SkBitmap::kARGB_8888_Config); + + // Return the new canvas contents. + const void* pixels = new_bitmap.getPixels(); + memcpy(rgba_buffer, pixels, width * height * 4); + return true; } WebScreenInfo WebWidgetHost::GetScreenInfo() { @@ -331,58 +464,219 @@ void WebWidgetHost::PaintRect(const gfx::Rect& rect) { #endif DCHECK(canvas_.get()); - if (!rect.IsEmpty()) { - set_painting(true); - webwidget_->paint(webkit_glue::ToWebCanvas(canvas_.get()), rect); - set_painting(false); + if (rect.IsEmpty()) + return; + + if (!popup() && ((WebKit::WebView*)webwidget_)->isTransparent()) { + // When using transparency mode clear the rectangle before painting. + SkPaint clearpaint; + clearpaint.setARGB(0, 0, 0, 0); + clearpaint.setXfermodeMode(SkXfermode::kClear_Mode); + + SkRect skrc; + skrc.set(rect.x(), rect.y(), rect.right(), rect.bottom()); + canvas_->drawRect(skrc, clearpaint); } + + set_painting(true); + webwidget_->paint(webkit_glue::ToWebCanvas(canvas_.get()), rect); + set_painting(false); } -void WebWidgetHost::SendKeyEvent(cef_key_type_t type, int key, int modifiers, - bool sysChar, bool imeChar) -{ - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); +void WebWidgetHost::SendKeyEvent(cef_key_type_t type, + const cef_key_info_t& keyInfo, + int modifiers) { + WebKeyboardEvent event; + + switch (type) { + case KT_KEYUP: + default: + event.type = WebInputEvent::KeyUp; + break; + case KT_KEYDOWN: + event.type = WebInputEvent::RawKeyDown; + break; + case KT_CHAR: + event.type = WebInputEvent::Char; + break; + } + event.timeStampSeconds = TickCount(); + + if (modifiers & KEY_SHIFT) + event.modifiers |= WebInputEvent::ShiftKey; + if (modifiers & KEY_ALT) + event.modifiers |= WebInputEvent::AltKey; + if (modifiers & KEY_CTRL) + event.modifiers |= WebInputEvent::ControlKey; + if (modifiers & KEY_META) + event.modifiers |= WebInputEvent::MetaKey; + if (modifiers & KEY_KEYPAD) + event.modifiers |= WebInputEvent::IsKeyPad; + + // There are several kinds of characters for which we produce key code from + // char code: + // 1. Roman letters. Windows keyboard layouts affect both virtual key codes + // and character codes for these, so e.g. 'A' gets the same keyCode on + // QWERTY, AZERTY or Dvorak layouts. + // 2. Keys for which there is no known Mac virtual key codes, like + // PrintScreen. + // 3. Certain punctuation keys. On Windows, these are also remapped depending + // on current keyboard layout, but see comment in + // windowsKeyCodeForCharCode(). + + if (type == KT_KEYUP || type == KT_KEYDOWN) { + if (keyInfo.character != 0) { + // Cmd switches Roman letters for Dvorak-QWERTY layout, so try modified + // characters first. + event.windowsKeyCode = + WebCore::windowsKeyCodeForCharCode(keyInfo.character); + } + if (event.windowsKeyCode == 0 && keyInfo.characterNoModifiers != 0) { + // Ctrl+A on an AZERTY keyboard would get VK_Q keyCode if we relied on + // keyInfo.keyCode below. + event.windowsKeyCode = + WebCore::windowsKeyCodeForCharCode(keyInfo.characterNoModifiers); + } + } + + if (event.windowsKeyCode == 0) { + // Map Mac virtual key code directly to Windows one for any keys not handled + // above. E.g. the key next to Caps Lock has the same Event.keyCode on U.S. + // keyboard ('A') and on Russian keyboard (CYRILLIC LETTER EF). + event.windowsKeyCode = WebCore::windowsKeyCodeForKeyCode(keyInfo.keyCode); + } + + event.nativeKeyCode = keyInfo.keyCode; + + int textChar = keyInfo.character; + int unmodifiedChar = keyInfo.characterNoModifiers; + + // Always use 13 for Enter/Return -- we don't want to use AppKit's + // different character for Enter. + if (event.windowsKeyCode == '\r') { + textChar = '\r'; + unmodifiedChar = '\r'; + } + + // The adjustments below are only needed in backward compatibility mode, + // but we cannot tell what mode we are in from here. + + // Turn 0x7F into 8, because backspace needs to always be 8. + if (textChar == '\x7F') + textChar = '\x8'; + if (unmodifiedChar == '\x7F') + unmodifiedChar = '\x8'; + // Always use 9 for tab -- we don't want to use AppKit's different character + // for shift-tab. + if (event.windowsKeyCode == 9) { + textChar = '\x9'; + unmodifiedChar = '\x9'; + } + + event.text[0] = textChar; + event.unmodifiedText[0] = unmodifiedChar; + + event.setKeyIdentifierFromWindowsKeyCode(); + + event.isSystemKey = !!(modifiers & KEY_META); + + last_key_event_ = event; + + webwidget_->handleInputEvent(event); } void WebWidgetHost::SendMouseClickEvent(int x, int y, cef_mouse_button_type_t type, - bool mouseUp, int clickCount) -{ - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); + bool mouseUp, int clickCount) { + WebMouseEvent event; + + switch(type) { + case MBT_LEFT: + event.button = WebMouseEvent::ButtonLeft; + event.modifiers |= WebInputEvent::LeftButtonDown; + break; + case MBT_MIDDLE: + event.button = WebMouseEvent::ButtonMiddle; + event.modifiers |= WebInputEvent::MiddleButtonDown; + break; + case MBT_RIGHT: + event.button = WebMouseEvent::ButtonRight; + event.modifiers |= WebInputEvent::RightButtonDown; + break; + } + + if (mouseUp) + event.type = WebInputEvent::MouseUp; + else + event.type = WebInputEvent::MouseDown; + + event.clickCount = clickCount; + event.timeStampSeconds = TickCount(); + event.x = x; + event.y = y; + event.windowX = event.x; + event.windowY = event.y; + + if (mouseUp) { + mouse_button_down_ = WebMouseEvent::ButtonNone; + mouse_modifiers_ &= ~event.modifiers; + } else { + mouse_modifiers_ |= event.modifiers; + mouse_button_down_ = event.button; + } + event.modifiers = mouse_modifiers_; + + webwidget_->handleInputEvent(event); } -void WebWidgetHost::SendMouseMoveEvent(int x, int y, bool mouseLeave) -{ - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); +void WebWidgetHost::SendMouseMoveEvent(int x, int y, bool mouseLeave) { + WebMouseEvent event; + + event.type = WebInputEvent::MouseMove; + event.timeStampSeconds = TickCount(); + event.button = mouse_button_down_; + event.x = x; + event.y = y; + event.windowX = event.x; + event.windowY = event.y; + event.modifiers = mouse_modifiers_; + + webwidget_->handleInputEvent(event); } -void WebWidgetHost::SendMouseWheelEvent(int x, int y, int delta) -{ - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); +void WebWidgetHost::SendMouseWheelEvent(int x, int y, int deltaX, int deltaY) { + WebMouseWheelEvent event; + + // Conversion between wheel delta amounts and number of pixels to scroll. + static const double scrollbarPixelsPerCocoaTick = 40.0; + + event.type = WebInputEvent::MouseWheel; + event.timeStampSeconds = TickCount(); + event.button = WebMouseEvent::ButtonNone; + event.deltaX = static_cast(deltaX); + event.deltaY = static_cast(deltaY); + event.wheelTicksX = static_cast(deltaX/scrollbarPixelsPerCocoaTick); + event.wheelTicksY = static_cast(deltaY/scrollbarPixelsPerCocoaTick); + event.hasPreciseScrollingDeltas = true; + event.x = x; + event.y = y; + event.windowX = event.x; + event.windowY = event.y; + + webwidget_->handleInputEvent(event); } -void WebWidgetHost::SendFocusEvent(bool setFocus) -{ - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); +void WebWidgetHost::SendFocusEvent(bool setFocus) { + SetFocus(setFocus); } -void WebWidgetHost::SendCaptureLostEvent() -{ - // TODO(port): Implement this method as part of off-screen rendering support. - NOTIMPLEMENTED(); +void WebWidgetHost::SendCaptureLostEvent() { } -void WebWidgetHost::EnsureTooltip() -{ +void WebWidgetHost::EnsureTooltip() { // TODO(port): Implement this method as part of tooltip support. } -void WebWidgetHost::ResetTooltip() -{ +void WebWidgetHost::ResetTooltip() { // TODO(port): Implement this method as part of tooltip support. } diff --git a/libcef/webwidget_host_win.cc b/libcef/webwidget_host_win.cc index 185a8f27e..37658f5d0 100644 --- a/libcef/webwidget_host_win.cc +++ b/libcef/webwidget_host_win.cc @@ -3,8 +3,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "webwidget_host.h" -#include "cef_thread.h" +#include +#include + +#include "libcef/webwidget_host.h" +#include "libcef/browser_impl.h" +#include "libcef/cef_thread.h" #include "base/bind.h" #include "base/logging.h" @@ -26,8 +30,6 @@ #include "ui/gfx/gdi_util.h" #include "ui/gfx/rect.h" -#include - using webkit::npapi::WebPluginGeometry; using WebKit::WebInputEvent; using WebKit::WebInputEventFactory; @@ -51,8 +53,7 @@ struct MessageInfo { LPARAM lParam; }; -BOOL CALLBACK SendMessageFunc(HWND hwnd, LPARAM lParam) -{ +BOOL CALLBACK SendMessageFunc(HWND hwnd, LPARAM lParam) { MessageInfo* info = reinterpret_cast(lParam); SendMessage(hwnd, info->message, info->wParam, info->lParam); return TRUE; @@ -61,18 +62,16 @@ BOOL CALLBACK SendMessageFunc(HWND hwnd, LPARAM lParam) // Plugins are hosted in a Chromium-created parent window so it's necessary to // send messages directly to the child window. void SendMessageToPlugin(HWND hwnd, UINT message, WPARAM wParam, - LPARAM lParam) -{ + LPARAM lParam) { MessageInfo info = {message, wParam, lParam}; EnumChildWindows(hwnd, SendMessageFunc, reinterpret_cast(&info)); } -inline SkIRect convertToSkiaRect(const gfx::Rect& r) -{ +inline SkIRect convertToSkiaRect(const gfx::Rect& r) { return SkIRect::MakeLTRB(r.x(), r.y(), r.right(), r.bottom()); } -} // namespace +} // namespace /*static*/ WebWidgetHost* WebWidgetHost::Create(HWND parent_view, @@ -254,7 +253,7 @@ LRESULT CALLBACK WebWidgetHost::WndProc(HWND hwnd, UINT message, WPARAM wparam, break; case WM_NOTIFY: - host->OnNotify(0, (NMHDR*)lparam); + host->OnNotify(0, reinterpret_cast(lparam)); break; case WM_GETDLGCODE: @@ -262,7 +261,7 @@ LRESULT CALLBACK WebWidgetHost::WndProc(HWND hwnd, UINT message, WPARAM wparam, } } - return DefWindowProc(hwnd, message, wparam, lparam);; + return DefWindowProc(hwnd, message, wparam, lparam); } void WebWidgetHost::DidInvalidateRect(const gfx::Rect& damaged_rect) { @@ -304,7 +303,7 @@ void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) { { skia::ScopedPlatformPaint scoped_platform_paint(canvas_.get()); HDC hdc = scoped_platform_paint.GetPlatformSurface(); - RECT clip_rect_win32 = clip_rect.ToRECT(), uncovered_rect = {0,0,0,0}; + RECT clip_rect_win32 = clip_rect.ToRECT(), uncovered_rect = {0, 0, 0, 0}; ScrollDC(hdc, dx, dy, NULL, &clip_rect_win32, NULL, &uncovered_rect); UpdatePaintRect(gfx::Rect(uncovered_rect)); @@ -402,8 +401,8 @@ void WebWidgetHost::Paint() { canvas_h_ = client_rect.height() + kCanvasGrowSize; canvas_.reset(new skia::PlatformCanvas(canvas_w_, canvas_h_, true)); } - } else if(!canvas_.get() || canvas_w_ != client_rect.width() || - canvas_h_ != client_rect.height()) { + } else if (!canvas_.get() || canvas_w_ != client_rect.width() || + canvas_h_ != client_rect.height()) { paint_rgn_.setRect(convertToSkiaRect(client_rect)); // The canvas must be the exact size of the client area. @@ -447,10 +446,10 @@ void WebWidgetHost::Paint() { if (!view_ && plugin_map_.size() > 0) { typedef std::list PluginList; PluginList visible_plugins; - + // Identify the visible plugins. PluginMap::const_iterator it = plugin_map_.begin(); - for(; it != plugin_map_.end(); ++it) { + for (; it != plugin_map_.end(); ++it) { if (it->second.visible && client_rect.Intersects(it->second.window_rect)) visible_plugins.push_back(&it->second); } @@ -463,10 +462,10 @@ void WebWidgetHost::Paint() { // Paint the plugin windows. PluginList::const_iterator it = visible_plugins.begin(); - for(; it != visible_plugins.end(); ++it) { + for (; it != visible_plugins.end(); ++it) { const WebPluginGeometry* geom = *(it); - - oldRGN = CreateRectRgn(0,0,1,1); + + oldRGN = CreateRectRgn(0, 0, 1, 1); GetClipRgn(drawDC, oldRGN); // Only paint inside the clip region. @@ -485,7 +484,7 @@ void WebWidgetHost::Paint() { SendMessageToPlugin(geom->window, WM_PRINT, reinterpret_cast(drawDC), PRF_OWNED | PRF_ERASEBKGND | PRF_CLIENT | PRF_NONCLIENT); - + SetViewportOrgEx(drawDC, oldViewport.x, oldViewport.y, NULL); SelectClipRgn(drawDC, oldRGN); @@ -534,11 +533,10 @@ void WebWidgetHost::Paint() { has_invalidate_task_ = false; } -void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) -{ +void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) { if (rect.IsEmpty()) return; - + if (view_) { // Let the window handle painting. RECT r = rect.ToRECT(); @@ -554,8 +552,7 @@ void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) } } -bool WebWidgetHost::GetImage(int width, int height, void* buffer) -{ +bool WebWidgetHost::GetImage(int width, int height, void* buffer) { const SkBitmap& bitmap = canvas_->getDevice()->accessBitmap(false); DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config); @@ -603,11 +600,24 @@ void WebWidgetHost::MouseEvent(UINT message, WPARAM wparam, LPARAM lparam) { case WebInputEvent::MouseDown: if (!popup()) { SetCapture(view_); - // This mimics a temporary workaround in RenderWidgetHostViewWin - // for bug 765011 to get focus when the mouse is clicked. This - // happens after the mouse down event is sent to the renderer - // because normally Windows does a WM_SETFOCUS after WM_LBUTTONDOWN. - ::SetFocus(view_); + + if (::GetFocus() != view_) { + // Set focus to this window. + HWND parent_hwnd = ::GetParent(view_); + if (parent_hwnd) { + CefRefPtr browser = + static_cast( + ui::GetWindowUserData(parent_hwnd)); + if (browser.get()) { + // This mimics a temporary workaround in RenderWidgetHostViewWin + // for bug 765011 to get focus when the mouse is clicked. This + // happens after the mouse down event is sent to the renderer + // because normally Windows does a WM_SETFOCUS after + // WM_LBUTTONDOWN. + browser->SetFocus(true); + } + } + } } break; case WebInputEvent::MouseUp: @@ -646,7 +656,7 @@ void WebWidgetHost::OnNotify(WPARAM wparam, NMHDR* header) { return; switch (header->code) { - case TTN_GETDISPINFO: + case TTN_GETDISPINFO: { NMTTDISPINFOW* tooltip_info = reinterpret_cast(header); tooltip_info->szText[0] = L'\0'; @@ -680,8 +690,7 @@ void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) { ::SendMessage(tooltip_view_, TTM_POP, 0, 0); ::SendMessage(tooltip_view_, TTM_POPUP, 0, 0); } - } - else { + } else { // Make sure the tooltip gets closed after TTN_POP gets sent. For some // reason this doesn't happen automatically, so moving the mouse around // within the same link/image/etc doesn't cause the tooltip to re-appear. @@ -755,7 +764,7 @@ void WebWidgetHost::PaintRect(const gfx::Rect& rect) { if (!popup() && ((WebKit::WebView*)webwidget_)->isTransparent()) { // When using transparency mode clear the rectangle before painting. SkPaint clearpaint; - clearpaint.setARGB(0,0,0,0); + clearpaint.setARGB(0, 0, 0, 0); clearpaint.setXfermodeMode(SkXfermode::kClear_Mode); SkRect skrc; @@ -768,31 +777,31 @@ void WebWidgetHost::PaintRect(const gfx::Rect& rect) { set_painting(false); } -void WebWidgetHost::SendKeyEvent(cef_key_type_t type, int key, int modifiers, - bool sysChar, bool imeChar) -{ +void WebWidgetHost::SendKeyEvent(cef_key_type_t type, + const cef_key_info_t& keyInfo, + int modifiers) { UINT message = 0; - WPARAM wparam = key; + WPARAM wparam = keyInfo.key; LPARAM lparam = modifiers; if (type == KT_KEYUP) { - if (sysChar) + if (keyInfo.sysChar) message = WM_SYSKEYUP; - else if(imeChar) + else if (keyInfo.imeChar) message = WM_IME_KEYUP; else message = WM_KEYUP; - } else if(type == KT_KEYDOWN) { - if (sysChar) + } else if (type == KT_KEYDOWN) { + if (keyInfo.sysChar) message = WM_SYSKEYDOWN; - else if(imeChar) + else if (keyInfo.imeChar) message = WM_IME_KEYDOWN; else message = WM_KEYDOWN; - } else if(type == KT_CHAR) { - if (sysChar) + } else if (type == KT_CHAR) { + if (keyInfo.sysChar) message = WM_SYSCHAR; - else if(imeChar) + else if (keyInfo.imeChar) message = WM_IME_CHAR; else message = WM_CHAR; @@ -812,27 +821,26 @@ void WebWidgetHost::SendKeyEvent(cef_key_type_t type, int key, int modifiers, void WebWidgetHost::SendMouseClickEvent(int x, int y, cef_mouse_button_type_t type, - bool mouseUp, int clickCount) -{ + bool mouseUp, int clickCount) { DCHECK(clickCount >=1 && clickCount <= 2); - + UINT message = 0; WPARAM wparam = 0; LPARAM lparam = MAKELPARAM(x, y); if (type == MBT_LEFT) { if (mouseUp) - message = (clickCount==1?WM_LBUTTONUP:WM_LBUTTONDBLCLK); + message = (clickCount == 1?WM_LBUTTONUP:WM_LBUTTONDBLCLK); else message = WM_LBUTTONDOWN; } else if (type == MBT_MIDDLE) { if (mouseUp) - message = (clickCount==1?WM_MBUTTONUP:WM_MBUTTONDBLCLK); + message = (clickCount == 1?WM_MBUTTONUP:WM_MBUTTONDBLCLK); else message = WM_MBUTTONDOWN; } else if (type == MBT_RIGHT) { if (mouseUp) - message = (clickCount==1?WM_RBUTTONUP:WM_RBUTTONDBLCLK); + message = (clickCount == 1?WM_RBUTTONUP:WM_RBUTTONDBLCLK); else message = WM_RBUTTONDOWN; } @@ -841,7 +849,7 @@ void WebWidgetHost::SendMouseClickEvent(int x, int y, NOTREACHED(); return; } - + if (GetKeyState(VK_CONTROL) & 0x8000) wparam |= MK_CONTROL; if (GetKeyState(VK_SHIFT) & 0x8000) @@ -863,12 +871,11 @@ void WebWidgetHost::SendMouseClickEvent(int x, int y, } } -void WebWidgetHost::SendMouseMoveEvent(int x, int y, bool mouseLeave) -{ +void WebWidgetHost::SendMouseMoveEvent(int x, int y, bool mouseLeave) { UINT message; WPARAM wparam = 0; LPARAM lparam = 0; - + if (mouseLeave) { message = WM_MOUSELEAVE; } else { @@ -897,11 +904,10 @@ void WebWidgetHost::SendMouseMoveEvent(int x, int y, bool mouseLeave) } } -void WebWidgetHost::SendMouseWheelEvent(int x, int y, int delta) -{ - WPARAM wparam = MAKEWPARAM(0, delta); +void WebWidgetHost::SendMouseWheelEvent(int x, int y, int deltaX, int deltaY) { + WPARAM wparam = MAKEWPARAM(0, deltaY); LPARAM lparam = MAKELPARAM(x, y); - + if (GetKeyState(VK_CONTROL) & 0x8000) wparam |= MK_CONTROL; if (GetKeyState(VK_SHIFT) & 0x8000) @@ -923,19 +929,16 @@ void WebWidgetHost::SendMouseWheelEvent(int x, int y, int delta) } } -void WebWidgetHost::SendFocusEvent(bool setFocus) -{ +void WebWidgetHost::SendFocusEvent(bool setFocus) { SetFocus(setFocus); } -void WebWidgetHost::SendCaptureLostEvent() -{ +void WebWidgetHost::SendCaptureLostEvent() { CaptureLostEvent(); } LRESULT WebWidgetHost::OnImeSetContext(UINT message, WPARAM wparam, - LPARAM lparam, BOOL& handled) -{ + LPARAM lparam, BOOL& handled) { if (!webwidget_) return 0; @@ -963,8 +966,7 @@ LRESULT WebWidgetHost::OnImeSetContext(UINT message, WPARAM wparam, } LRESULT WebWidgetHost::OnImeStartComposition(UINT message, WPARAM wparam, - LPARAM lparam, BOOL& handled) -{ + LPARAM lparam, BOOL& handled) { if (!webwidget_) return 0; @@ -979,8 +981,7 @@ LRESULT WebWidgetHost::OnImeStartComposition(UINT message, WPARAM wparam, } LRESULT WebWidgetHost::OnImeComposition(UINT message, WPARAM wparam, - LPARAM lparam, BOOL& handled) -{ + LPARAM lparam, BOOL& handled) { if (!webwidget_) return 0; @@ -1030,8 +1031,7 @@ LRESULT WebWidgetHost::OnImeComposition(UINT message, WPARAM wparam, } LRESULT WebWidgetHost::OnImeEndComposition(UINT message, WPARAM wparam, - LPARAM lparam, BOOL& handled) -{ + LPARAM lparam, BOOL& handled) { if (!webwidget_) return 0; @@ -1050,8 +1050,7 @@ LRESULT WebWidgetHost::OnImeEndComposition(UINT message, WPARAM wparam, } void WebWidgetHost::OnInputLangChange(DWORD character_set, - HKL input_language_id) -{ + HKL input_language_id) { // Send the given Locale ID to the ImeInput object and retrieves whether // or not the current input context has IMEs. // If the current input context has IMEs, a browser process has to send a @@ -1089,8 +1088,7 @@ void WebWidgetHost::OnInputLangChange(DWORD character_set, } void WebWidgetHost::ImeUpdateTextInputState(WebKit::WebTextInputType type, - const gfx::Rect& caret_rect) -{ + const gfx::Rect& caret_rect) { if (text_input_type_ != type) { text_input_type_ = type; if (type == WebKit::WebTextInputTypeText) @@ -1104,8 +1102,7 @@ void WebWidgetHost::ImeUpdateTextInputState(WebKit::WebTextInputType type, ime_input_.UpdateCaretRect(view_, caret_rect); } -void WebWidgetHost::UpdateInputMethod() -{ +void WebWidgetHost::UpdateInputMethod() { REQUIRE_UIT(); has_update_input_method_task_ = false; diff --git a/libcef_dll/cpptoc/browser_cpptoc.cc b/libcef_dll/cpptoc/browser_cpptoc.cc index 018eb698c..03d397edc 100644 --- a/libcef_dll/cpptoc/browser_cpptoc.cc +++ b/libcef_dll/cpptoc/browser_cpptoc.cc @@ -674,22 +674,29 @@ int CEF_CALLBACK browser_get_image(struct _cef_browser_t* self, void CEF_CALLBACK browser_send_key_event(struct _cef_browser_t* self, - enum cef_key_type_t type, int key, int modifiers, int sysChar, - int imeChar) + enum cef_key_type_t type, const struct _cef_key_info_t* keyInfo, + int modifiers) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING DCHECK(self); if (!self) return; + // Verify param: keyInfo; type: struct_byref_const + DCHECK(keyInfo); + if (!keyInfo) + return; + + // Translate param: keyInfo; type: struct_byref_const + CefKeyInfo keyInfoObj; + if (keyInfo) + keyInfoObj.Set(*keyInfo, false); // Execute CefBrowserCppToC::Get(self)->SendKeyEvent( type, - key, - modifiers, - sysChar?true:false, - imeChar?true:false); + keyInfoObj, + modifiers); } @@ -731,7 +738,7 @@ void CEF_CALLBACK browser_send_mouse_move_event(struct _cef_browser_t* self, void CEF_CALLBACK browser_send_mouse_wheel_event(struct _cef_browser_t* self, - int x, int y, int delta) + int x, int y, int deltaX, int deltaY) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING @@ -743,7 +750,8 @@ void CEF_CALLBACK browser_send_mouse_wheel_event(struct _cef_browser_t* self, CefBrowserCppToC::Get(self)->SendMouseWheelEvent( x, y, - delta); + deltaX, + deltaY); } diff --git a/libcef_dll/ctocpp/browser_ctocpp.cc b/libcef_dll/ctocpp/browser_ctocpp.cc index 3de7375e9..2815e851f 100644 --- a/libcef_dll/ctocpp/browser_ctocpp.cc +++ b/libcef_dll/ctocpp/browser_ctocpp.cc @@ -561,8 +561,8 @@ bool CefBrowserCToCpp::GetImage(PaintElementType type, int width, int height, } -void CefBrowserCToCpp::SendKeyEvent(KeyType type, int key, int modifiers, - bool sysChar, bool imeChar) +void CefBrowserCToCpp::SendKeyEvent(KeyType type, const CefKeyInfo& keyInfo, + int modifiers) { if (CEF_MEMBER_MISSING(struct_, send_key_event)) return; @@ -572,10 +572,8 @@ void CefBrowserCToCpp::SendKeyEvent(KeyType type, int key, int modifiers, // Execute struct_->send_key_event(struct_, type, - key, - modifiers, - sysChar, - imeChar); + &keyInfo, + modifiers); } @@ -612,7 +610,7 @@ void CefBrowserCToCpp::SendMouseMoveEvent(int x, int y, bool mouseLeave) } -void CefBrowserCToCpp::SendMouseWheelEvent(int x, int y, int delta) +void CefBrowserCToCpp::SendMouseWheelEvent(int x, int y, int deltaX, int deltaY) { if (CEF_MEMBER_MISSING(struct_, send_mouse_wheel_event)) return; @@ -623,7 +621,8 @@ void CefBrowserCToCpp::SendMouseWheelEvent(int x, int y, int delta) struct_->send_mouse_wheel_event(struct_, x, y, - delta); + deltaX, + deltaY); } diff --git a/libcef_dll/ctocpp/browser_ctocpp.h b/libcef_dll/ctocpp/browser_ctocpp.h index ddfc053df..029fac639 100644 --- a/libcef_dll/ctocpp/browser_ctocpp.h +++ b/libcef_dll/ctocpp/browser_ctocpp.h @@ -67,12 +67,13 @@ public: virtual void Invalidate(const CefRect& dirtyRect) OVERRIDE; virtual bool GetImage(PaintElementType type, int width, int height, void* buffer) OVERRIDE; - virtual void SendKeyEvent(KeyType type, int key, int modifiers, bool sysChar, - bool imeChar) OVERRIDE; + virtual void SendKeyEvent(KeyType type, const CefKeyInfo& keyInfo, + int modifiers) OVERRIDE; virtual void SendMouseClickEvent(int x, int y, MouseButtonType type, bool mouseUp, int clickCount) OVERRIDE; virtual void SendMouseMoveEvent(int x, int y, bool mouseLeave) OVERRIDE; - virtual void SendMouseWheelEvent(int x, int y, int delta) OVERRIDE; + virtual void SendMouseWheelEvent(int x, int y, int deltaX, + int deltaY) OVERRIDE; virtual void SendFocusEvent(bool setFocus) OVERRIDE; virtual void SendCaptureLostEvent() OVERRIDE; }; diff --git a/tests/cefclient/cefclient_mac.mm b/tests/cefclient/cefclient_mac.mm index c404de0c3..424ef8966 100644 --- a/tests/cefclient/cefclient_mac.mm +++ b/tests/cefclient/cefclient_mac.mm @@ -3,17 +3,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import +#include +#include "cefclient.h" #include "include/cef.h" #import "include/cef_application_mac.h" -#include "cefclient.h" #include "binding_test.h" #include "client_handler.h" #include "extension_test.h" +#include "osrtest_mac.h" #include "resource_util.h" #include "scheme_test.h" #include "string_util.h" -#import -#include // The global ClientHandler reference. extern CefRefPtr g_handler; @@ -141,7 +142,7 @@ static NSAutoreleasePool* g_autopool = nil; } - (void)windowDidBecomeKey:(NSNotification*)notification { - if(g_handler.get() && g_handler->GetBrowserHwnd()) { + if (g_handler.get() && g_handler->GetBrowserHwnd()) { // Give focus to the browser window. g_handler->GetBrowser()->SetFocus(true); } @@ -209,6 +210,8 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { - (IBAction)testDevToolsShow:(id)sender; - (IBAction)testDevToolsClose:(id)sender; - (IBAction)testPluginInfo:(id)sender; +- (IBAction)testOffscreenRendering:(id)sender; +- (IBAction)testTransparentOffscreenRendering:(id)sender; @end @implementation ClientAppDelegate @@ -302,6 +305,12 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { [testMenu addItemWithTitle:@"Plugin Info" action:@selector(testPluginInfo:) keyEquivalent:@""]; + [testMenu addItemWithTitle:@"Offscreen Rendering" + action:@selector(testOffscreenRendering:) + keyEquivalent:@""]; + [testMenu addItemWithTitle:@"Transparent Offscreen Rendering" + action:@selector(testTransparentOffscreenRendering:) + keyEquivalent:@""]; [testItem setSubmenu:testMenu]; [menubar addItem:testItem]; @@ -394,140 +403,148 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { } - (IBAction)testGetSource:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunGetSourceTest(g_handler->GetBrowser()); } - (IBAction)testGetText:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunGetTextTest(g_handler->GetBrowser()); } - (IBAction)testJSBinding:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunBindingTest(g_handler->GetBrowser()); } - (IBAction)testJSExtension:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunExtensionTest(g_handler->GetBrowser()); } - (IBAction)testJSExtensionPerf:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunExtensionPerfTest(g_handler->GetBrowser()); } - (IBAction)testJSExecute:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunJavaScriptExecuteTest(g_handler->GetBrowser()); } - (IBAction)testJSInvoke:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunJavaScriptInvokeTest(g_handler->GetBrowser()); } - (IBAction)testRequest:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunRequestTest(g_handler->GetBrowser()); } - (IBAction)testLocalStorage:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunLocalStorageTest(g_handler->GetBrowser()); } - (IBAction)testXMLHttpRequest:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunXMLHTTPRequestTest(g_handler->GetBrowser()); } - (IBAction)testWebURLRequest:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunWebURLRequestTest(g_handler->GetBrowser()); } - (IBAction)testDOMAccess:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunDOMAccessTest(g_handler->GetBrowser()); } - (IBAction)testSchemeHandler:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunSchemeTest(g_handler->GetBrowser()); } - (IBAction)testPopupWindow:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunPopupTest(g_handler->GetBrowser()); } - (IBAction)testAccelerated2DCanvas:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunAccelerated2DCanvasTest(g_handler->GetBrowser()); } - (IBAction)testAcceleratedLayers:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunAcceleratedLayersTest(g_handler->GetBrowser()); } - (IBAction)testWebGL:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunWebGLTest(g_handler->GetBrowser()); } - (IBAction)testHTML5Video:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunHTML5VideoTest(g_handler->GetBrowser()); } - (IBAction)testDragDrop:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunDragDropTest(g_handler->GetBrowser()); } - (IBAction)testZoomIn:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) { + if (g_handler.get() && g_handler->GetBrowserHwnd()) { CefRefPtr browser = g_handler->GetBrowser(); browser->SetZoomLevel(browser->GetZoomLevel() + 0.5); } } - (IBAction)testZoomOut:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) { + if (g_handler.get() && g_handler->GetBrowserHwnd()) { CefRefPtr browser = g_handler->GetBrowser(); browser->SetZoomLevel(browser->GetZoomLevel() - 0.5); } } - (IBAction)testZoomReset:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) { + if (g_handler.get() && g_handler->GetBrowserHwnd()) { CefRefPtr browser = g_handler->GetBrowser(); browser->SetZoomLevel(0.0); } } - (IBAction)testDevToolsShow:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) { + if (g_handler.get() && g_handler->GetBrowserHwnd()) { CefRefPtr browser = g_handler->GetBrowser(); browser->ShowDevTools(); } } - (IBAction)testDevToolsClose:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) { + if (g_handler.get() && g_handler->GetBrowserHwnd()) { CefRefPtr browser = g_handler->GetBrowser(); browser->CloseDevTools(); } } - (IBAction)testPluginInfo:(id)sender { - if(g_handler.get() && g_handler->GetBrowserHwnd()) + if (g_handler.get() && g_handler->GetBrowserHwnd()) RunPluginInfoTest(g_handler->GetBrowser()); } +- (IBAction)testOffscreenRendering:(id)sender { + osrtest::RunTest(false); +} + +- (IBAction)testTransparentOffscreenRendering:(id)sender { + osrtest::RunTest(true); +} + // Sent by the default notification center immediately before the application // terminates. - (void)applicationWillTerminate:(NSNotification *)aNotification { @@ -544,8 +561,7 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { @end -int main(int argc, char* argv[]) -{ +int main(int argc, char* argv[]) { // Retrieve the current working directory. getcwd(szWorkingDir, sizeof(szWorkingDir)); @@ -586,7 +602,6 @@ int main(int argc, char* argv[]) // Global functions -std::string AppGetWorkingDirectory() -{ +std::string AppGetWorkingDirectory() { return szWorkingDir; } diff --git a/tests/cefclient/osrenderer.cpp b/tests/cefclient/osrenderer.cpp new file mode 100644 index 000000000..87fc29609 --- /dev/null +++ b/tests/cefclient/osrenderer.cpp @@ -0,0 +1,410 @@ +// 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 "osrenderer.h" +#include "util.h" + +#if defined(OS_WIN) +#include +#include +#elif defined(OS_MACOSX) +#include +#else +#error Platform is not supported. +#endif + +namespace { + +// Convert from BGRA to RGBA format and from upper-left to lower-left origin. +void ConvertToRGBA(const unsigned char* src, unsigned char* dst, + int width, int height) { + int sp = 0, dp = (height-1) * width * 4; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++, dp += 4, sp += 4) { + dst[dp] = src[sp+2]; // R + dst[dp+1] = src[sp+1]; // G + dst[dp+2] = src[sp]; // B + dst[dp+3] = src[sp+3]; // A + } + dp -= width * 8; + } +} + +void ConvertToRGBARect(const CefRect& clipRect, + const unsigned char* src, unsigned char* dst, + int width, int height) { + int sp = 0, dp = (height-1) * width * 4; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++, dp += 4, sp += 4) { + if ((clipRect.x <= j) && (clipRect.x + clipRect.width > j) && + (clipRect.y <= i) && (clipRect.y + clipRect.height > i)) { + dst[dp] = src[sp+2]; // R + dst[dp+1] = src[sp+1]; // G + dst[dp+2] = src[sp]; // B + dst[dp+3] = src[sp+3]; // A + } + } + dp -= width * 8; + } +} + +// Convert from BGRA to RGB format and from upper-left to lower-left origin. +void ConvertToRGB(const unsigned char* src, unsigned char* dst, + int width, int height) { + int sp = 0, dp = (height-1) * width * 3; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++, dp += 3, sp += 4) { + dst[dp] = src[sp+2]; // R + dst[dp+1] = src[sp+1]; // G + dst[dp+2] = src[sp]; // B + } + dp -= width * 6; + } +} + +void ConvertToRGBRect(const CefRect& clipRect, + const unsigned char* src, unsigned char* dst, + int width, int height) { + int sp = 0, dp = (height-1) * width * 3; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++, dp += 3, sp += 4) { + if ((clipRect.x <= j) && (clipRect.x + clipRect.width > j) && + (clipRect.y <= i) && (clipRect.y + clipRect.height > i)) { + dst[dp] = src[sp+2]; // R + dst[dp+1] = src[sp+1]; // G + dst[dp+2] = src[sp]; // B + } + } + dp -= width * 6; + } +} + +} // namespace + +ClientOSRenderer::ClientOSRenderer(bool transparent) + : transparent_(transparent), + initialized_(false), + texture_id_(0), + view_buffer_(NULL), + view_buffer_size_(0), + popup_buffer_(NULL), + popup_buffer_size_(0), + view_width_(0), + view_height_(0), + spin_x_(0), + spin_y_(0) { +} + +ClientOSRenderer::~ClientOSRenderer() { + Cleanup(); +} + +void ClientOSRenderer::Initialize() { + if (initialized_) + return; + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + + // Necessary for non-power-of-2 textures to render correctly. + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + if (transparent_) { + // Alpha blending style. + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + initialized_ = true; +} + +void ClientOSRenderer::Cleanup() { + if (view_buffer_) { + delete [] view_buffer_; + view_buffer_ = NULL; + view_buffer_size_ = 0; + } + if (popup_buffer_) { + delete [] popup_buffer_; + popup_buffer_ = NULL; + popup_buffer_size_ = 0; + } + + if (texture_id_ != 0) + glDeleteTextures(1, &texture_id_); +} + +void ClientOSRenderer::SetSize(int width, int height) { + if (!initialized_) + Initialize(); + + // Match GL units to screen coordinates. + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, 0, width, height, 0.1, 100.0); + + if (transparent_) { + // Enable alpha blending. + glEnable(GL_BLEND); + } + + // Enable 2D textures. + glEnable(GL_TEXTURE_2D); + + GLuint new_texture_id = 0; + + // Create a new texture. + glGenTextures(1, &new_texture_id); + ASSERT(new_texture_id != 0); + glBindTexture(GL_TEXTURE_2D, new_texture_id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // Start with all white contents. + { + int size = width * height * (transparent_?4:3); + unsigned char* buffer = new unsigned char[size]; + memset(buffer, 255, size); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, + transparent_?GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, buffer); + + delete [] buffer; + } + + if (texture_id_ != 0) { + // Draw the existing view buffer to the new texture. + DrawViewBuffer(width, height); + + // Delete the old texture. + glDeleteTextures(1, &texture_id_); + } + + texture_id_ = new_texture_id; + + // Disable 2D textures. + glDisable(GL_TEXTURE_2D); + + if (transparent_) { + // Disable alpha blending. + glDisable(GL_BLEND); + } +} + +void ClientOSRenderer::Render() { + ASSERT(initialized_); + + struct { + float tu, tv; + float x, y, z; + } static vertices[] = { + {0.0f, 0.0f, -1.0f, -1.0f, 0.0f}, + {1.0f, 0.0f, 1.0f, -1.0f, 0.0f}, + {1.0f, 1.0f, 1.0f, 1.0f, 0.0f}, + {0.0f, 1.0f, -1.0f, 1.0f, 0.0f} + }; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + // Draw the background gradient. + glPushAttrib(GL_ALL_ATTRIB_BITS); + glBegin(GL_QUADS); + glColor4f(1.0, 0.0, 0.0, 1.0); // red + glVertex2f(-1.0, -1.0); + glVertex2f(1.0, -1.0); + glColor4f(0.0, 0.0, 1.0, 1.0); // blue + glVertex2f(1.0, 1.0); + glVertex2f(-1.0, 1.0); + glEnd(); + glPopAttrib(); + + // Rotate the view based on the mouse spin. + glRotatef(-spin_x_, 1.0f, 0.0f, 0.0f); + glRotatef(-spin_y_, 0.0f, 1.0f, 0.0f); + + if (transparent_) { + // Enable alpha blending. + glEnable(GL_BLEND); + } + + // Enable 2D textures. + glEnable(GL_TEXTURE_2D); + + // Draw the facets with the texture. + ASSERT(texture_id_ != 0); + glBindTexture(GL_TEXTURE_2D, texture_id_); + glInterleavedArrays(GL_T2F_V3F, 0, vertices); + glDrawArrays(GL_QUADS, 0, 4); + + // Disable 2D textures. + glDisable(GL_TEXTURE_2D); + + if (transparent_) { + // Disable alpha blending. + glDisable(GL_BLEND); + } + + glFlush(); +} + +void ClientOSRenderer::OnPopupShow(CefRefPtr browser, + bool show) { + if (!show) { + // Clear the popup buffer. + popup_rect_.Set(0, 0, 0, 0); + if (popup_buffer_) { + delete [] popup_buffer_; + popup_buffer_ = NULL; + popup_buffer_size_ = 0; + } + } +} + +void ClientOSRenderer::OnPopupSize(CefRefPtr browser, + const CefRect& rect) { + if (rect.width > 0) { + // Update the popup rectange. It should always be inside the view. + ASSERT(rect.x + rect.width < view_width_ && + rect.y + rect.height < view_height_); + popup_rect_ = rect; + } +} + +void ClientOSRenderer::OnPaint(CefRefPtr browser, + CefRenderHandler::PaintElementType type, + const CefRenderHandler::RectList& dirtyRects, + const void* buffer) { + ASSERT(initialized_); + + // Retrieve the current size of the browser view. + browser->GetSize(type, view_width_, view_height_); + + if (transparent_) { + // Enable alpha blending. + glEnable(GL_BLEND); + } + + // Enable 2D textures. + glEnable(GL_TEXTURE_2D); + + ASSERT(texture_id_ != 0); + glBindTexture(GL_TEXTURE_2D, texture_id_); + + if (type == PET_VIEW) { + SetBufferSize(view_width_, view_height_, true); + + // Paint the view. + if (transparent_) { + CefRenderHandler::RectList::const_iterator i = dirtyRects.begin(); + for (; i != dirtyRects.end(); ++i) { + ConvertToRGBARect(*i, (unsigned char*)buffer, view_buffer_, + view_width_, view_height_); + } + } else { + CefRenderHandler::RectList::const_iterator i = dirtyRects.begin(); + for (; i != dirtyRects.end(); ++i) { + ConvertToRGBRect(*i, (unsigned char*)buffer, view_buffer_, + view_width_, view_height_); + } + } + + // Update the whole texture. This is done for simplicity instead of + // updating just the dirty region. + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, view_width_, view_height_, + transparent_?GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, view_buffer_); + } + + if (popup_rect_.width > 0) { + if (type == PET_POPUP) { + // Paint the popup. + if (transparent_) + SetRGBA(buffer, popup_rect_.width, popup_rect_.height, false); + else + SetRGB(buffer, popup_rect_.width, popup_rect_.height, false); + } + + if (popup_buffer_) { + // Update the popup region. + glTexSubImage2D(GL_TEXTURE_2D, 0, popup_rect_.x, + view_height_ - popup_rect_.y - popup_rect_.height, + popup_rect_.width, popup_rect_.height, + transparent_?GL_RGBA:GL_RGB, + GL_UNSIGNED_BYTE, popup_buffer_); + } + } + + // Disable 2D textures. + glDisable(GL_TEXTURE_2D); + + if (transparent_) { + // Disable alpha blending. + glDisable(GL_BLEND); + } +} + +void ClientOSRenderer::SetSpin(float spinX, float spinY) { + spin_x_ = spinX; + spin_y_ = spinY; +} + +void ClientOSRenderer::IncrementSpin(float spinDX, float spinDY) { + spin_x_ -= spinDX; + spin_y_ -= spinDY; +} + +void ClientOSRenderer::SetBufferSize(int width, int height, bool view) { + int dst_size = width * height * (transparent_?4:3); + + // Allocate a new buffer if necesary. + if (view) { + if (dst_size > view_buffer_size_) { + if (view_buffer_) + delete [] view_buffer_; + view_buffer_ = new unsigned char[dst_size]; + view_buffer_size_ = dst_size; + } + } else { + if (dst_size > popup_buffer_size_) { + if (popup_buffer_) + delete [] popup_buffer_; + popup_buffer_ = new unsigned char[dst_size]; + popup_buffer_size_ = dst_size; + } + } +} + +// Set the contents of the RGBA buffer. +void ClientOSRenderer::SetRGBA(const void* src, int width, int height, + bool view) { + SetBufferSize(width, height, view); + ConvertToRGBA((unsigned char*)src, view?view_buffer_:popup_buffer_, width, + height); +} + +// Set the contents of the RGB buffer. +void ClientOSRenderer::SetRGB(const void* src, int width, int height, + bool view) { + SetBufferSize(width, height, view); + ConvertToRGB((unsigned char*)src, view?view_buffer_:popup_buffer_, width, + height); +} + +void ClientOSRenderer::DrawViewBuffer(int max_width, int max_height) { + if (max_width < view_width_ || max_height < view_height_) { + // The requested max size is smaller than the current view buffer. + int width = std::min(max_width, view_width_); + int height = std::min(max_height, view_height_); + + glPixelStorei(GL_UNPACK_ROW_LENGTH, view_width_); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, + transparent_?GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, + view_buffer_); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, view_width_, view_height_, + transparent_?GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, view_buffer_); + } +} diff --git a/tests/cefclient/osrenderer.h b/tests/cefclient/osrenderer.h new file mode 100644 index 000000000..35c2bd76c --- /dev/null +++ b/tests/cefclient/osrenderer.h @@ -0,0 +1,63 @@ +// 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_TESTS_CEFCLIENT_OSRENDERER_H_ +#define CEF_TESTS_CEFCLIENT_OSRENDERER_H_ + +#include "include/cef.h" + +class ClientOSRenderer { + public: + // The context must outlive this object. + explicit ClientOSRenderer(bool transparent); + virtual ~ClientOSRenderer(); + + // Initialize the OpenGL environment. + void Initialize(); + + // Clean up the OpenGL environment. + void Cleanup(); + + // Set the size of the viewport. + void SetSize(int width, int height); + + // Render to the screen. + void Render(); + + // Forwarded from CefRenderHandler callbacks. + void OnPopupShow(CefRefPtr browser, + bool show); + void OnPopupSize(CefRefPtr browser, + const CefRect& rect); + void OnPaint(CefRefPtr browser, + CefRenderHandler::PaintElementType type, + const CefRenderHandler::RectList& dirtyRects, + const void* buffer); + + // Apply spin. + void SetSpin(float spinX, float spinY); + void IncrementSpin(float spinDX, float spinDY); + + private: + void SetBufferSize(int width, int height, bool view); + void SetRGBA(const void* src, int width, int height, bool view); + void SetRGB(const void* src, int width, int height, bool view); + void DrawViewBuffer(int max_width, int max_height); + + bool transparent_; + bool initialized_; + unsigned int texture_id_; + unsigned char* view_buffer_; + int view_buffer_size_; + unsigned char* popup_buffer_; + int popup_buffer_size_; + CefRect popup_rect_; + int view_width_; + int view_height_; + float spin_x_; + float spin_y_; +}; + +#endif // CEF_TESTS_CEFCLIENT_OSR_RENDERER_H_ + diff --git a/tests/cefclient/osrplugin.cpp b/tests/cefclient/osrplugin.cpp index 42535d9ee..97c94441b 100644 --- a/tests/cefclient/osrplugin.cpp +++ b/tests/cefclient/osrplugin.cpp @@ -3,50 +3,47 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "osrplugin.h" +#include "osrenderer.h" + +#if defined(OS_WIN) + +#include +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include #include "include/cef.h" #include "cefclient.h" #include "client_popup_handler.h" -#include "osrplugin.h" #include "resource.h" #include "resource_util.h" #include "string_util.h" #include "util.h" -#include -#include -#define _USE_MATH_DEFINES -#include -#include - -#if defined(OS_WIN) // Initialized in NP_Initialize. NPNetscapeFuncs* g_osrbrowser = NULL; namespace { -GLuint g_textureID = -1; -float g_spinX = 0.0f; -float g_spinY = 0.0f; -int g_width = -1, g_height = -1; CefRefPtr g_offscreenBrowser; // If set to true alpha transparency will be used. bool g_offscreenTransparent = false; -#define GL_IMAGE_FORMAT (g_offscreenTransparent?GL_RGBA:GL_RGB) -#define GL_BYTE_COUNT (g_offscreenTransparent?4:3) - // Class holding pointers for the client plugin window. -class ClientPlugin -{ -public: - ClientPlugin() - { - hWnd = NULL; - hDC = NULL; - hRC = NULL; +class ClientPlugin { + public: + ClientPlugin(bool transparent) + : renderer(transparent), + hWnd(NULL), + hDC(NULL), + hRC(NULL) { } + ClientOSRenderer renderer; HWND hWnd; HDC hDC; HGLRC hRC; @@ -58,36 +55,30 @@ class ClientOSRHandler : public CefClient, public CefLoadHandler, public CefRequestHandler, public CefDisplayHandler, - public CefRenderHandler -{ -public: - ClientOSRHandler(ClientPlugin* plugin) - : plugin_(plugin), - view_buffer_(NULL), - view_buffer_size_(0), - popup_buffer_(NULL), - popup_buffer_size_(0) - { + public CefRenderHandler { + public: + explicit ClientOSRHandler(ClientPlugin* plugin) + : plugin_(plugin) { } - ~ClientOSRHandler() - { - if (view_buffer_) - delete [] view_buffer_; - if (popup_buffer_) - delete [] popup_buffer_; + ~ClientOSRHandler() { } // CefClient methods - virtual CefRefPtr GetLifeSpanHandler() OVERRIDE - { return this; } - virtual CefRefPtr GetLoadHandler() OVERRIDE - { return this; } - virtual CefRefPtr GetRequestHandler() OVERRIDE - { return this; } - virtual CefRefPtr GetDisplayHandler() OVERRIDE - { return this; } - virtual CefRefPtr GetRenderHandler() OVERRIDE - { return this; } + virtual CefRefPtr GetLifeSpanHandler() OVERRIDE { + return this; + } + virtual CefRefPtr GetLoadHandler() OVERRIDE { + return this; + } + virtual CefRefPtr GetRequestHandler() OVERRIDE { + return this; + } + virtual CefRefPtr GetDisplayHandler() OVERRIDE { + return this; + } + virtual CefRefPtr GetRenderHandler() OVERRIDE { + return this; + } // CefLifeSpanHandler methods @@ -96,8 +87,7 @@ public: CefWindowInfo& windowInfo, const CefString& url, CefRefPtr& client, - CefBrowserSettings& settings) OVERRIDE - { + CefBrowserSettings& settings) OVERRIDE { REQUIRE_UI_THREAD(); windowInfo.m_bWindowRenderingDisabled = TRUE; @@ -105,29 +95,28 @@ public: return false; } - virtual void OnAfterCreated(CefRefPtr browser) OVERRIDE - { + virtual void OnAfterCreated(CefRefPtr browser) OVERRIDE { REQUIRE_UI_THREAD(); - // Set the view size to match the plugin window size. - browser->SetSize(PET_VIEW, g_width, g_height); - g_offscreenBrowser = browser; + + // Set the off-screen browser size to match the plugin window size. + RECT clientRect; + ::GetClientRect(plugin_->hWnd, &clientRect); + g_offscreenBrowser->SetSize(PET_VIEW, clientRect.right, clientRect.bottom); } - virtual void OnBeforeClose(CefRefPtr browser) OVERRIDE - { + virtual void OnBeforeClose(CefRefPtr browser) OVERRIDE { g_offscreenBrowser = NULL; } // CefLoadHandler methods virtual void OnLoadStart(CefRefPtr browser, - CefRefPtr frame) OVERRIDE - { + CefRefPtr frame) OVERRIDE { REQUIRE_UI_THREAD(); - if(!browser->IsPopup() && frame->IsMain()) { + if (!browser->IsPopup() && frame->IsMain()) { // We've just started loading a page SetLoading(true); } @@ -135,11 +124,10 @@ public: virtual void OnLoadEnd(CefRefPtr browser, CefRefPtr frame, - int httpStatusCode) OVERRIDE - { + int httpStatusCode) OVERRIDE { REQUIRE_UI_THREAD(); - if(!browser->IsPopup() && frame->IsMain()) { + if (!browser->IsPopup() && frame->IsMain()) { // We've just finished loading a page SetLoading(false); } @@ -152,12 +140,11 @@ public: CefString& redirectUrl, CefRefPtr& resourceStream, CefRefPtr response, - int loadFlags) OVERRIDE - { + int loadFlags) OVERRIDE { REQUIRE_IO_THREAD(); std::string url = request->GetURL(); - if(url == "http://tests/transparency") { + if (url == "http://tests/transparency") { resourceStream = GetBinaryResourceReader(IDS_TRANSPARENCY); response->SetMimeType("text/html"); response->SetStatus(200); @@ -170,8 +157,7 @@ public: virtual void OnNavStateChange(CefRefPtr browser, bool canGoBack, - bool canGoForward) OVERRIDE - { + bool canGoForward) OVERRIDE { REQUIRE_UI_THREAD(); // Set the "back" and "forward" button state in the HTML. @@ -185,8 +171,7 @@ public: virtual void OnAddressChange(CefRefPtr browser, CefRefPtr frame, - const CefString& url) OVERRIDE - { + const CefString& url) OVERRIDE { REQUIRE_UI_THREAD(); // Set the "url" value in the HTML. @@ -198,8 +183,7 @@ public: } virtual void OnTitleChange(CefRefPtr browser, - const CefString& title) OVERRIDE - { + const CefString& title) OVERRIDE { REQUIRE_UI_THREAD(); // Set the "title" value in the HTML. @@ -214,21 +198,22 @@ public: // CefRenderHandler methods virtual bool GetViewRect(CefRefPtr browser, - CefRect& rect) OVERRIDE - { + CefRect& rect) OVERRIDE { REQUIRE_UI_THREAD(); // The simulated screen and view rectangle are the same. This is necessary // for popup menus to be located and sized inside the view. + RECT clientRect; + ::GetClientRect(plugin_->hWnd, &clientRect); + rect.x = rect.y = 0; - rect.width = g_width; - rect.height = g_height; + rect.width = clientRect.right; + rect.height = clientRect.bottom; return true; } virtual bool GetScreenRect(CefRefPtr browser, - CefRect& rect) OVERRIDE - { + CefRect& rect) OVERRIDE { return GetViewRect(browser, rect); } @@ -236,8 +221,7 @@ public: int viewX, int viewY, int& screenX, - int& screenY) OVERRIDE - { + int& screenY) OVERRIDE { REQUIRE_UI_THREAD(); // Convert the point from view coordinates to actual screen coordinates. @@ -249,107 +233,29 @@ public: } virtual void OnPopupShow(CefRefPtr browser, - bool show) OVERRIDE - { + bool show) OVERRIDE { REQUIRE_UI_THREAD(); - - if(!show) { - // Clear the popup buffer. - popup_rect_.Set(0,0,0,0); - if (popup_buffer_) { - delete [] popup_buffer_; - popup_buffer_ = NULL; - popup_buffer_size_ = 0; - } - } + plugin_->renderer.OnPopupShow(browser, show); } virtual void OnPopupSize(CefRefPtr browser, - const CefRect& rect) OVERRIDE - { + const CefRect& rect) OVERRIDE { REQUIRE_UI_THREAD(); - - if (rect.width > 0) { - // Update the popup rectange. It will always be inside the view due to - // HandleGetRect(). - ASSERT(rect.x + rect.width < g_width && - rect.y + rect.height < g_height); - popup_rect_ = rect; - } + plugin_->renderer.OnPopupSize(browser, rect); } virtual void OnPaint(CefRefPtr browser, PaintElementType type, const RectList& dirtyRects, - const void* buffer) OVERRIDE - { + const void* buffer) OVERRIDE { REQUIRE_UI_THREAD(); wglMakeCurrent(plugin_->hDC, plugin_->hRC); - - if (g_offscreenTransparent) { - // Enable alpha blending. - glEnable(GL_BLEND); - } - - // Enable 2D textures. - glEnable(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, g_textureID); - - if (type == PET_VIEW) { - SetBufferSize(g_width, g_height, true); - // Paint the view. - if (g_offscreenTransparent) { - RectList::const_iterator i = dirtyRects.begin(); - for (; i != dirtyRects.end(); ++i) { - ConvertToRGBARect(*i, (unsigned char*)buffer, view_buffer_, g_width, - g_height); - } - } else { - RectList::const_iterator i = dirtyRects.begin(); - for (i; i != dirtyRects.end(); ++i) { - ConvertToRGBRect(*i, (unsigned char*)buffer, view_buffer_, g_width, - g_height); - } - } - - // Update the whole texture. This is done for simplicity instead of - // updating just the dirty region. - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_width, g_height, - GL_IMAGE_FORMAT, GL_UNSIGNED_BYTE, view_buffer_); - } - - if(popup_rect_.width > 0) { - if (type == PET_POPUP) { - // Paint the popup. - if (g_offscreenTransparent) - SetRGBA(buffer, popup_rect_.width, popup_rect_.height, false); - else - SetRGB(buffer, popup_rect_.width, popup_rect_.height, false); - } - - if (popup_buffer_) { - // Update the popup region. - glTexSubImage2D(GL_TEXTURE_2D, 0, popup_rect_.x, - g_height-popup_rect_.y-popup_rect_.height, popup_rect_.width, - popup_rect_.height, GL_IMAGE_FORMAT, GL_UNSIGNED_BYTE, - popup_buffer_); - } - } - - // Disable 2D textures. - glDisable(GL_TEXTURE_2D); - - if (g_offscreenTransparent) { - // Disable alpha blending. - glDisable(GL_BLEND); - } + plugin_->renderer.OnPaint(browser, type, dirtyRects, buffer); } virtual void OnCursorChange(CefRefPtr browser, - CefCursorHandle cursor) OVERRIDE - { + CefCursorHandle cursor) OVERRIDE { REQUIRE_UI_THREAD(); // Change the plugin window's cursor. @@ -358,9 +264,8 @@ public: SetCursor(cursor); } -private: - void SetLoading(bool isLoading) - { + private: + void SetLoading(bool isLoading) { // Set the "stop" and "reload" button state in the HTML. std::stringstream ss; ss << "document.getElementById('stop').disabled = " @@ -370,119 +275,7 @@ private: AppGetBrowser()->GetMainFrame()->ExecuteJavaScript(ss.str(), "", 0); } - // Size the RGB buffer. - void SetBufferSize(int width, int height, bool view) - { - int dst_size = width * height * GL_BYTE_COUNT; - - // Allocate a new buffer if necesary. - if (view) { - if (dst_size > view_buffer_size_) { - if (view_buffer_) - delete [] view_buffer_; - view_buffer_ = new unsigned char[dst_size]; - view_buffer_size_ = dst_size; - } - } else { - if (dst_size > popup_buffer_size_) { - if (popup_buffer_) - delete [] popup_buffer_; - popup_buffer_ = new unsigned char[dst_size]; - popup_buffer_size_ = dst_size; - } - } - } - - // Set the contents of the RGBA buffer. - void SetRGBA(const void* src, int width, int height, bool view) - { - SetBufferSize(width, height, view); - ConvertToRGBA((unsigned char*)src, view?view_buffer_:popup_buffer_, width, - height); - } - - // Convert from BGRA to RGBA format and from upper-left to lower-left origin. - static void ConvertToRGBA(const unsigned char* src, unsigned char* dst, - int width, int height) - { - int sp = 0, dp = (height-1) * width * 4; - for(int i = 0; i < height; i++) { - for(int j = 0; j < width; j++, dp += 4, sp += 4) { - dst[dp] = src[sp+2]; // R - dst[dp+1] = src[sp+1]; // G - dst[dp+2] = src[sp]; // B - dst[dp+3] = src[sp+3]; // A - } - dp -= width * 8; - } - } - - static void ConvertToRGBARect(const CefRect& clipRect, - const unsigned char* src, unsigned char* dst, - int width, int height) - { - int sp = 0, dp = (height-1) * width * 4; - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++, dp += 4, sp += 4) { - if ((clipRect.x <= j) && (clipRect.x + clipRect.width > j) && - (clipRect.y <= i) && (clipRect.y + clipRect.height > i)) { - dst[dp] = src[sp+2]; // R - dst[dp+1] = src[sp+1]; // G - dst[dp+2] = src[sp]; // B - dst[dp+3] = src[sp+3]; // A - } - } - dp -= width * 8; - } - } - - // Set the contents of the RGB buffer. - void SetRGB(const void* src, int width, int height, bool view) - { - SetBufferSize(width, height, view); - ConvertToRGB((unsigned char*)src, view?view_buffer_:popup_buffer_, width, - height); - } - - // Convert from BGRA to RGB format and from upper-left to lower-left origin. - static void ConvertToRGB(const unsigned char* src, unsigned char* dst, - int width, int height) - { - int sp = 0, dp = (height-1) * width * 3; - for(int i = 0; i < height; i++) { - for(int j = 0; j < width; j++, dp += 3, sp += 4) { - dst[dp] = src[sp+2]; // R - dst[dp+1] = src[sp+1]; // G - dst[dp+2] = src[sp]; // B - } - dp -= width * 6; - } - } - - static void ConvertToRGBRect(const CefRect& clipRect, - const unsigned char* src, unsigned char* dst, - int width, int height) - { - int sp = 0, dp = (height-1) * width * 3; - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++, dp += 3, sp += 4) { - if ((clipRect.x <= j) && (clipRect.x + clipRect.width > j) && - (clipRect.y <= i) && (clipRect.y + clipRect.height > i)) { - dst[dp] = src[sp+2]; // R - dst[dp+1] = src[sp+1]; // G - dst[dp+2] = src[sp]; // B - } - } - dp -= width * 6; - } - } - ClientPlugin* plugin_; - unsigned char* view_buffer_; - int view_buffer_size_; - unsigned char* popup_buffer_; - int popup_buffer_size_; - CefRect popup_rect_; // Include the default reference counting implementation. IMPLEMENT_REFCOUNTING(ClientOSRPlugin); @@ -493,14 +286,13 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); // Enable GL. -void EnableGL(HWND hWnd, HDC * hDC, HGLRC * hRC) -{ +void EnableGL(ClientPlugin* plugin) { PIXELFORMATDESCRIPTOR pfd; int format; - + // Get the device context. - *hDC = GetDC(hWnd); - + plugin->hDC = GetDC(plugin->hWnd); + // Set the pixel format for the DC. ZeroMemory(&pfd, sizeof(pfd)); pfd.nSize = sizeof(pfd); @@ -510,147 +302,40 @@ void EnableGL(HWND hWnd, HDC * hDC, HGLRC * hRC) pfd.cColorBits = 24; pfd.cDepthBits = 16; pfd.iLayerType = PFD_MAIN_PLANE; - format = ChoosePixelFormat(*hDC, &pfd); - SetPixelFormat(*hDC, format, &pfd); - + format = ChoosePixelFormat(plugin->hDC, &pfd); + SetPixelFormat(plugin->hDC, format, &pfd); + // Create and enable the render context. - *hRC = wglCreateContext(*hDC); - wglMakeCurrent(*hDC, *hRC); + plugin->hRC = wglCreateContext(plugin->hDC); + wglMakeCurrent(plugin->hDC, plugin->hRC); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - - // Necessary for non-power-of-2 textures to render correctly. - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - if (g_offscreenTransparent) { - // Alpha blending style. - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } + plugin->renderer.Initialize(); } // Disable GL. -void DisableGL(HWND hWnd, HDC hDC, HGLRC hRC) -{ - // Delete the texture. - if(g_textureID != -1) - glDeleteTextures(1, &g_textureID); - +void DisableGL(ClientPlugin* plugin) { + plugin->renderer.Cleanup(); + wglMakeCurrent(NULL, NULL); - wglDeleteContext(hRC); - ReleaseDC(hWnd, hDC); + wglDeleteContext(plugin->hRC); + ReleaseDC(plugin->hWnd, plugin->hDC); } // Size the GL view. -void SizeGL(ClientPlugin* plugin, int width, int height) -{ - g_width = width; - g_height = height; - +void SizeGL(ClientPlugin* plugin, int width, int height) { wglMakeCurrent(plugin->hDC, plugin->hRC); - // Match GL units to screen coordinates. - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, 0, width, height, 0.1, 100.0); + plugin->renderer.SetSize(width, height); - if (g_offscreenTransparent) { - // Enable alpha blending. - glEnable(GL_BLEND); - } - - // Enable 2D textures. - glEnable(GL_TEXTURE_2D); - - // Delete the existing exture. - if(g_textureID != -1) - glDeleteTextures(1, &g_textureID); - - // Create a new texture. - glGenTextures(1, &g_textureID); - glBindTexture(GL_TEXTURE_2D, g_textureID); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - // Start with all white contents. - int size = width * height * GL_BYTE_COUNT; - unsigned char* buffer = new unsigned char[size]; - memset(buffer, 255, size); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, - GL_IMAGE_FORMAT, GL_UNSIGNED_BYTE, buffer); - - // Disable 2D textures. - glDisable(GL_TEXTURE_2D); - - if (g_offscreenTransparent) { - // Disable alpha blending. - glDisable(GL_BLEND); - } - - delete [] buffer; - - if(g_offscreenBrowser.get()) + if (g_offscreenBrowser.get()) g_offscreenBrowser->SetSize(PET_VIEW, width, height); } // Render the view contents. -void RenderGL(ClientPlugin* plugin) -{ +void RenderGL(ClientPlugin* plugin) { wglMakeCurrent(plugin->hDC, plugin->hRC); - - struct { - float tu, tv; - float x, y, z; - } static vertices[] = { - {0.0f, 0.0f, -1.0f, -1.0f, 0.0f}, - {1.0f, 0.0f, 1.0f, -1.0f, 0.0f}, - {1.0f, 1.0f, 1.0f, 1.0f, 0.0f}, - {0.0f, 1.0f, -1.0f, 1.0f, 0.0f} - }; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - //glTranslatef(0.0f, 0.0f, -3.0f); - - // Draw the background gradient. - glPushAttrib(GL_ALL_ATTRIB_BITS); - glBegin(GL_QUADS); - glColor4f(1.0,0.0,0.0,1.0); // red - glVertex2f(-1.0,-1.0); - glVertex2f(1.0,-1.0); - glColor4f(0.0,0.0,1.0,1.0); // blue - glVertex2f(1.0, 1.0); - glVertex2f(-1.0, 1.0); - glEnd(); - glPopAttrib(); - - // Rotate the view based on the mouse spin. - glRotatef(-g_spinX, 1.0f, 0.0f, 0.0f); - glRotatef(-g_spinY, 0.0f, 1.0f, 0.0f); - - if (g_offscreenTransparent) { - // Enable alpha blending. - glEnable(GL_BLEND); - } - - // Enable 2D textures. - glEnable(GL_TEXTURE_2D); - - // Draw the facets with the texture. - glBindTexture(GL_TEXTURE_2D, g_textureID); - glInterleavedArrays(GL_T2F_V3F, 0, vertices); - glDrawArrays(GL_QUADS, 0, 4); - - // Disable 2D textures. - glDisable(GL_TEXTURE_2D); - - if (g_offscreenTransparent) { - // Disable alpha blending. - glDisable(GL_BLEND); - } + plugin->renderer.Render(); SwapBuffers(plugin->hDC); } @@ -661,19 +346,19 @@ NPError NPP_NewImpl(NPMIMEType plugin_type, NPP instance, uint16 mode, if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; - ClientPlugin *plugin = new ClientPlugin; + ClientPlugin* plugin = new ClientPlugin(g_offscreenTransparent); instance->pdata = reinterpret_cast(plugin); return NPERR_NO_ERROR; } NPError NPP_DestroyImpl(NPP instance, NPSavedData** save) { - ClientPlugin *plugin = reinterpret_cast(instance->pdata); - + ClientPlugin* plugin = reinterpret_cast(instance->pdata); + if (plugin) { - if(plugin->hWnd) { + if (plugin->hWnd) { DestroyWindow(plugin->hWnd); - DisableGL(plugin->hWnd, plugin->hDC, plugin->hRC); + DisableGL(plugin); } delete plugin; } @@ -688,14 +373,13 @@ NPError NPP_SetWindowImpl(NPP instance, NPWindow* window_info) { if (window_info == NULL) return NPERR_GENERIC_ERROR; - ClientPlugin *plugin = reinterpret_cast(instance->pdata); + ClientPlugin* plugin = reinterpret_cast(instance->pdata); HWND parent_hwnd = reinterpret_cast(window_info->window); - - if (plugin->hWnd == NULL) - { + + if (plugin->hWnd == NULL) { WNDCLASS wc; HINSTANCE hInstance = GetModuleHandle(NULL); - + // Register the window class. wc.style = CS_OWNDC; wc.lpfnWndProc = PluginWndProc; @@ -708,7 +392,7 @@ NPError NPP_SetWindowImpl(NPP instance, NPWindow* window_info) { wc.lpszMenuName = NULL; wc.lpszClassName = L"ClientOSRPlugin"; RegisterClass(&wc); - + // Create the main window. plugin->hWnd = CreateWindow(L"ClientOSRPlugin", L"Client OSR Plugin", WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 0, 0, 0, 0, parent_hwnd, NULL, @@ -716,9 +400,9 @@ NPError NPP_SetWindowImpl(NPP instance, NPWindow* window_info) { SetWindowLongPtr(plugin->hWnd, GWLP_USERDATA, reinterpret_cast(plugin)); - + // Enable GL drawing for the window. - EnableGL(plugin->hWnd, &(plugin->hDC), &(plugin->hRC)); + EnableGL(plugin); // Create the off-screen rendering window. CefWindowInfo windowInfo; @@ -745,22 +429,20 @@ NPError NPP_SetWindowImpl(NPP instance, NPWindow* window_info) { // Plugin window procedure. LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, - LPARAM lParam) -{ + LPARAM lParam) { static POINT lastMousePos, curMousePos; static bool mouseRotation = false; static bool mouseTracking = false; ClientPlugin* plugin = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); - - switch(message) - { + + switch (message) { case WM_CREATE: // Start the timer that's used for redrawing. SetTimer(hWnd, 1, 20, NULL); return 0; - + case WM_DESTROY: // Stop the timer that's used for redrawing. KillTimer(hWnd, 1); @@ -770,10 +452,10 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, g_offscreenBrowser = NULL; return 0; - case WM_TIMER: + case WM_TIMER: RenderGL(plugin); break; - + case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: SetCapture(hWnd); @@ -786,7 +468,7 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, } else { if (g_offscreenBrowser.get()) { g_offscreenBrowser->SendMouseClickEvent(LOWORD(lParam), HIWORD(lParam), - (message==WM_LBUTTONDOWN?MBT_LEFT:MBT_RIGHT), false, 1); + (message == WM_LBUTTONDOWN?MBT_LEFT:MBT_RIGHT), false, 1); } } break; @@ -798,23 +480,22 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, if (mouseRotation) { // End rotation effect. mouseRotation = false; - g_spinX = 0; - g_spinY = 0; + plugin->renderer.SetSpin(0, 0); } else { if (g_offscreenBrowser.get()) { g_offscreenBrowser->SendMouseClickEvent(LOWORD(lParam), HIWORD(lParam), - (message==WM_LBUTTONUP?MBT_LEFT:MBT_RIGHT), true, 1); + (message == WM_LBUTTONUP?MBT_LEFT:MBT_RIGHT), true, 1); } } break; case WM_MOUSEMOVE: - if(mouseRotation) { + if (mouseRotation) { // Apply rotation effect. curMousePos.x = LOWORD(lParam); curMousePos.y = HIWORD(lParam); - g_spinX -= (curMousePos.x - lastMousePos.x); - g_spinY -= (curMousePos.y - lastMousePos.y); + plugin->renderer.IncrementSpin((curMousePos.x - lastMousePos.x), + (curMousePos.y - lastMousePos.y)); lastMousePos.x = curMousePos.x; lastMousePos.y = curMousePos.y; } else { @@ -852,26 +533,27 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, case WM_MOUSEWHEEL: if (g_offscreenBrowser.get()) { g_offscreenBrowser->SendMouseWheelEvent(LOWORD(lParam), HIWORD(lParam), - GET_WHEEL_DELTA_WPARAM(wParam)); + 0, GET_WHEEL_DELTA_WPARAM(wParam)); } break; - + case WM_SIZE: { - int width = LOWORD(lParam); + int width = LOWORD(lParam); int height = HIWORD(lParam); - if(width > 0 && height > 0) + if (width > 0 && height > 0) SizeGL(plugin, width, height); - } break; + break; + } case WM_SETFOCUS: case WM_KILLFOCUS: if (g_offscreenBrowser.get()) - g_offscreenBrowser->SendFocusEvent(message==WM_SETFOCUS); + g_offscreenBrowser->SendFocusEvent(message == WM_SETFOCUS); break; case WM_CAPTURECHANGED: case WM_CANCELMODE: - if(!mouseRotation) { + if (!mouseRotation) { if (g_offscreenBrowser.get()) g_offscreenBrowser->SendCaptureLostEvent(); } @@ -886,21 +568,22 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, case WM_IME_CHAR: if (g_offscreenBrowser.get()) { CefBrowser::KeyType type = KT_CHAR; - bool sysChar = false, imeChar = false; + CefKeyInfo keyInfo; + keyInfo.key = wParam; if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) type = KT_KEYDOWN; else if (message == WM_KEYUP || message == WM_SYSKEYUP) type = KT_KEYUP; - + if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP || message == WM_SYSCHAR) - sysChar = true; + keyInfo.sysChar = true; if (message == WM_IME_CHAR) - imeChar = true; + keyInfo.imeChar = true; - g_offscreenBrowser->SendKeyEvent(type, wParam, lParam, sysChar, imeChar); + g_offscreenBrowser->SendKeyEvent(type, keyInfo, lParam); } break; @@ -908,7 +591,8 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, PAINTSTRUCT ps; BeginPaint(hWnd, &ps); EndPaint(hWnd, &ps); - } return 0; + return 0; + } case WM_ERASEBKGND: return 0; @@ -917,36 +601,31 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam, return DefWindowProc(hWnd, message, wParam, lParam); } -} // namespace +} // namespace -NPError API_CALL NP_OSRGetEntryPoints(NPPluginFuncs* pFuncs) -{ +NPError API_CALL NP_OSRGetEntryPoints(NPPluginFuncs* pFuncs) { pFuncs->newp = NPP_NewImpl; pFuncs->destroy = NPP_DestroyImpl; pFuncs->setwindow = NPP_SetWindowImpl; return NPERR_NO_ERROR; } -NPError API_CALL NP_OSRInitialize(NPNetscapeFuncs* pFuncs) -{ +NPError API_CALL NP_OSRInitialize(NPNetscapeFuncs* pFuncs) { g_osrbrowser = pFuncs; return NPERR_NO_ERROR; } -NPError API_CALL NP_OSRShutdown(void) -{ +NPError API_CALL NP_OSRShutdown(void) { g_osrbrowser = NULL; return NPERR_NO_ERROR; } -CefRefPtr GetOffScreenBrowser() -{ +CefRefPtr GetOffScreenBrowser() { return g_offscreenBrowser; } -void SetOffScreenTransparent(bool transparent) -{ +void SetOffScreenTransparent(bool transparent) { g_offscreenTransparent = transparent; } -#endif // OS_WIN +#endif // OS_WIN diff --git a/tests/cefclient/osrtest_mac.h b/tests/cefclient/osrtest_mac.h new file mode 100644 index 000000000..a6e1ee297 --- /dev/null +++ b/tests/cefclient/osrtest_mac.h @@ -0,0 +1,15 @@ +// 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_TESTS_CEFCLIENT_OSRTEST_MAC_H_ +#define CEF_TESTS_CEFCLIENT_OSRTEST_MAC_H_ + +namespace osrtest { + +void RunTest(bool transparent); + +} // namespace osrtest + +#endif // CEF_TESTS_CEFCLIENT_OSRTEST_MAC_H_ + diff --git a/tests/cefclient/osrtest_mac.mm b/tests/cefclient/osrtest_mac.mm new file mode 100644 index 000000000..48f45bb54 --- /dev/null +++ b/tests/cefclient/osrtest_mac.mm @@ -0,0 +1,752 @@ + // 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. + +#import +#include + +#include "osrtest_mac.h" +#include "include/cef.h" +#include "osrenderer.h" +#include "client_popup_handler.h" +#include "resource_util.h" +#include "util.h" + +// The client OpenGL view. +@interface ClientOpenGLView : NSOpenGLView { + @public + NSTrackingArea* tracking_area_; + CefRefPtr browser_; + ClientOSRenderer* renderer_; + NSPoint last_mouse_pos_; + NSPoint cur_mouse_pos_; + bool rotating_; +} + +- (id)initWithFrame:(NSRect)frame andTransparency:(bool)transparency; +- (NSPoint)getClickPointForEvent:(NSEvent*)event; +- (void)getKeyInfo:(CefKeyInfo&)info forEvent:(NSEvent*)event; +- (int)getModifiersForEvent:(NSEvent*)event; +- (BOOL)isKeyUpEvent:(NSEvent*)event; +- (BOOL)isKeyPadEvent:(NSEvent*)event; +@end + + +namespace { + +// Handler for off-screen rendering windows. +class ClientOSRHandler : public CefClient, + public CefLifeSpanHandler, + public CefLoadHandler, + public CefRequestHandler, + public CefDisplayHandler, + public CefRenderHandler { + public: + explicit ClientOSRHandler(ClientOpenGLView* view) + : view_(view) { + } + ~ClientOSRHandler() { + } + + void Disconnect() { + view_ = nil; + } + + // CefClient methods + virtual CefRefPtr GetLifeSpanHandler() OVERRIDE { + return this; + } + virtual CefRefPtr GetLoadHandler() OVERRIDE { + return this; + } + virtual CefRefPtr GetRequestHandler() OVERRIDE { + return this; + } + virtual CefRefPtr GetDisplayHandler() OVERRIDE { + return this; + } + virtual CefRefPtr GetRenderHandler() OVERRIDE { + return this; + } + + // CefLifeSpanHandler methods + + virtual bool OnBeforePopup(CefRefPtr parentBrowser, + const CefPopupFeatures& popupFeatures, + CefWindowInfo& windowInfo, + const CefString& url, + CefRefPtr& client, + CefBrowserSettings& settings) OVERRIDE { + REQUIRE_UI_THREAD(); + + windowInfo.m_bWindowRenderingDisabled = TRUE; + client = new ClientPopupHandler(view_->browser_); + return false; + } + + virtual void OnAfterCreated(CefRefPtr browser) OVERRIDE { + REQUIRE_UI_THREAD(); + + // Set the view size to match the window size. + const NSRect bounds = [view_ bounds]; + browser->SetSize(PET_VIEW, bounds.size.width, bounds.size.height); + + view_->browser_ = browser; + } + + virtual void OnBeforeClose(CefRefPtr browser) OVERRIDE { + if (view_) + view_->browser_ = NULL; + } + + // CefLoadHandler methods + + virtual void OnLoadStart(CefRefPtr browser, + CefRefPtr frame) OVERRIDE { + REQUIRE_UI_THREAD(); + + if (!browser->IsPopup() && frame->IsMain()) { + // We've just started loading a page + SetLoading(true); + } + } + + virtual void OnLoadEnd(CefRefPtr browser, + CefRefPtr frame, + int httpStatusCode) OVERRIDE { + REQUIRE_UI_THREAD(); + + if (!browser->IsPopup() && frame->IsMain()) { + // We've just finished loading a page + SetLoading(false); + } + } + + // CefRequestHandler methods + + virtual bool OnBeforeResourceLoad(CefRefPtr browser, + CefRefPtr request, + CefString& redirectUrl, + CefRefPtr& resourceStream, + CefRefPtr response, + int loadFlags) OVERRIDE { + REQUIRE_IO_THREAD(); + + std::string url = request->GetURL(); + if (url == "http://tests/osrtest") { + // Show the osrtest HTML contents + resourceStream = GetBinaryResourceReader("osrtest.html"); + response->SetMimeType("text/html"); + response->SetStatus(200); + } else if (url == "http://tests/transparency") { + // Show the osrtest HTML contents + resourceStream = GetBinaryResourceReader("transparency.html"); + response->SetMimeType("text/html"); + response->SetStatus(200); + } else if (strstr(url.c_str(), "/logoball.png") != NULL) { + // Load the "logoball.png" image resource. + resourceStream = GetBinaryResourceReader("logoball.png"); + response->SetMimeType("image/png"); + response->SetStatus(200); + } + + return false; + } + + // CefDisplayHandler methods + + virtual void OnNavStateChange(CefRefPtr browser, + bool canGoBack, + bool canGoForward) OVERRIDE { + REQUIRE_UI_THREAD(); + } + + virtual void OnAddressChange(CefRefPtr browser, + CefRefPtr frame, + const CefString& url) OVERRIDE { + REQUIRE_UI_THREAD(); + } + + virtual void OnTitleChange(CefRefPtr browser, + const CefString& title) OVERRIDE { + REQUIRE_UI_THREAD(); + + if (!view_) + return; + + // Set the frame window title bar + NSWindow* window = [view_ window]; + std::string titleStr(title); + NSString* str = [NSString stringWithUTF8String:titleStr.c_str()]; + [window setTitle:str]; + } + + // CefRenderHandler methods + + virtual bool GetViewRect(CefRefPtr browser, + CefRect& rect) OVERRIDE { + REQUIRE_UI_THREAD(); + + if (!view_) + return false; + + // The simulated screen and view rectangle are the same. This is necessary + // for popup menus to be located and sized inside the view. + const NSRect bounds = [view_ bounds]; + rect.x = rect.y = 0; + rect.width = bounds.size.width; + rect.height = bounds.size.height; + return true; + } + + virtual bool GetScreenRect(CefRefPtr browser, + CefRect& rect) OVERRIDE { + return GetViewRect(browser, rect); + } + + virtual bool GetScreenPoint(CefRefPtr browser, + int viewX, + int viewY, + int& screenX, + int& screenY) OVERRIDE { + REQUIRE_UI_THREAD(); + + if (!view_) + return false; + + // Convert the point from view coordinates to actual screen coordinates. + NSRect bounds = [view_ bounds]; + NSPoint view_pt = {viewX, bounds.size.height - viewY}; + NSPoint window_pt = [view_ convertPoint:view_pt toView:nil]; + NSPoint screen_pt = [[view_ window] convertBaseToScreen:window_pt]; + screenX = screen_pt.x; + screenY = screen_pt.y; + return true; + } + + virtual void OnPopupShow(CefRefPtr browser, + bool show) OVERRIDE { + REQUIRE_UI_THREAD(); + + if (!view_) + return; + + view_->renderer_->OnPopupShow(browser, show); + } + + virtual void OnPopupSize(CefRefPtr browser, + const CefRect& rect) OVERRIDE { + REQUIRE_UI_THREAD(); + + if (!view_) + return; + + view_->renderer_->OnPopupSize(browser, rect); + } + + virtual void OnPaint(CefRefPtr browser, + PaintElementType type, + const RectList& dirtyRects, + const void* buffer) OVERRIDE { + REQUIRE_UI_THREAD(); + + if (!view_) + return; + + [[view_ openGLContext] makeCurrentContext]; + + view_->renderer_->OnPaint(browser, type, dirtyRects, buffer); + + // Notify the view to redraw the invalidated regions. + { + RectList::const_iterator i = dirtyRects.begin(); + for (; i != dirtyRects.end(); ++i) { + NSRect rect = {{i->x, i->y}, {i->width, i->height}}; + [view_ setNeedsDisplayInRect:rect]; + } + } + } + + virtual void OnCursorChange(CefRefPtr browser, + CefCursorHandle cursor) OVERRIDE { + REQUIRE_UI_THREAD(); + [cursor set]; + } + + private: + void SetLoading(bool isLoading) { + } + + ClientOpenGLView* view_; + + // Include the default reference counting implementation. + IMPLEMENT_REFCOUNTING(ClientOSRPlugin); +}; + +} // namespace + + +@implementation ClientOpenGLView + +- (id)initWithFrame:(NSRect)frame andTransparency:(bool)transparency { + NSOpenGLPixelFormat * pixelFormat = + [[NSOpenGLPixelFormat alloc] + initWithAttributes:(NSOpenGLPixelFormatAttribute[]) { + NSOpenGLPFAWindow, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFADepthSize, + 32, + 0}]; + [pixelFormat autorelease]; + + self = [super initWithFrame:frame pixelFormat:pixelFormat]; + if (self) { + renderer_ = new ClientOSRenderer(transparency); + rotating_ = false; + + tracking_area_ = + [[NSTrackingArea alloc] initWithRect:frame + options:NSTrackingMouseMoved | + NSTrackingActiveInActiveApp | + NSTrackingInVisibleRect + owner:self + userInfo:nil]; + [self addTrackingArea:tracking_area_]; + } + return self; +} + +- (void)dealloc { + if (browser_) { + static_cast(browser_->GetClient().get())->Disconnect(); + browser_->CloseBrowser(); + browser_ = NULL; + } + if (renderer_) + delete renderer_; + + [super dealloc]; +} + +- (void)drawRect: (NSRect)bounds { + NSOpenGLContext* context = [self openGLContext]; + [context makeCurrentContext]; + + renderer_->Render(); + + [context flushBuffer]; +} + +- (void)setFrame:(NSRect)frameRect { + [super setFrame:frameRect]; + + int width = frameRect.size.width; + int height = frameRect.size.height; + + [[self openGLContext] makeCurrentContext]; + + renderer_->SetSize(width, height); + + if (browser_) + browser_->SetSize(PET_VIEW, width, height); +} + +- (void)mouseDown:(NSEvent *)event { + if (!browser_) + return; + + NSPoint point = [self getClickPointForEvent:event]; + int clickCount = [event clickCount]; + + browser_->SendMouseClickEvent(point.x, point.y, MBT_LEFT, false, clickCount); +} + +- (void)rightMouseDown:(NSEvent *)event { + if (!browser_) + return; + + NSPoint point = [self getClickPointForEvent:event]; + + if ([event modifierFlags] & NSShiftKeyMask) { + // Start rotation effect. + last_mouse_pos_ = cur_mouse_pos_ = point; + rotating_ = true; + return; + } + + int clickCount = [event clickCount]; + + browser_->SendMouseClickEvent(point.x, point.y, MBT_RIGHT, false, clickCount); +} + +- (void)otherMouseDown:(NSEvent *)event { + if (!browser_) + return; + + NSPoint point = [self getClickPointForEvent:event]; + int clickCount = [event clickCount]; + + browser_->SendMouseClickEvent(point.x, point.y, MBT_MIDDLE, false, + clickCount); +} + +- (void)mouseUp:(NSEvent *)event { + if (!browser_) + return; + + NSPoint point = [self getClickPointForEvent:event]; + int clickCount = [event clickCount]; + + browser_->SendMouseClickEvent(point.x, point.y, MBT_LEFT, true, clickCount); +} + +- (void)rightMouseUp:(NSEvent *)event { + if (!browser_) + return; + + if (rotating_) { + // End rotation effect. + renderer_->SetSpin(0, 0); + rotating_ = false; + [self setNeedsDisplay:YES]; + return; + } + + NSPoint point = [self getClickPointForEvent:event]; + int clickCount = [event clickCount]; + + browser_->SendMouseClickEvent(point.x, point.y, MBT_RIGHT, true, clickCount); +} + +- (void)otherMouseUp:(NSEvent *)event { + if (!browser_) + return; + + NSPoint point = [self getClickPointForEvent:event]; + int clickCount = [event clickCount]; + + browser_->SendMouseClickEvent(point.x, point.y, MBT_MIDDLE, true, clickCount); +} + +- (void)mouseMoved:(NSEvent *)event { + if (!browser_) + return; + + NSPoint point = [self getClickPointForEvent:event]; + + if (rotating_) { + // Apply rotation effect. + cur_mouse_pos_ = point; + renderer_->IncrementSpin((cur_mouse_pos_.x - last_mouse_pos_.x), + (cur_mouse_pos_.y - last_mouse_pos_.y)); + last_mouse_pos_ = cur_mouse_pos_; + [self setNeedsDisplay:YES]; + return; + } + + browser_->SendMouseMoveEvent(point.x, point.y, false); +} + +- (void)mouseDragged:(NSEvent *)event { + [self mouseMoved:event]; +} + +- (void)rightMouseDragged:(NSEvent *)event { + [self mouseMoved:event]; +} + +- (void)otherMouseDragged:(NSEvent *)event { + [self mouseMoved:event]; +} + +- (void)mouseEntered:(NSEvent *)event { + [self mouseMoved:event]; +} + +- (void)mouseExited:(NSEvent *)event { + if (!browser_) + return; + + NSPoint point = [self getClickPointForEvent:event]; + + browser_->SendMouseMoveEvent(point.x, point.y, true); +} + +- (void)keyDown:(NSEvent *)event { + if (!browser_) + return; + + CefKeyInfo keyInfo; + [self getKeyInfo:keyInfo forEvent:event]; + int modifiers = [self getModifiersForEvent:event]; + + browser_->SendKeyEvent(KT_KEYDOWN, keyInfo, modifiers); + + if ([event modifierFlags] & (NSNumericPadKeyMask | NSFunctionKeyMask)) { + // Don't send a Char event for non-char keys like arrows, function keys and + // clear. + switch (keyInfo.keyCode) { + case 81: // = + case 75: // / + case 67: // * + case 78: // - + case 69: // + + case 76: // Enter + case 65: // . + case 82: // 0 + case 83: // 1 + case 84: // 2 + case 85: // 3 + case 86: // 4 + case 87: // 5 + case 88: // 6 + case 89: // 7 + case 91: // 8 + case 92: // 9 + break; + default: + return; + } + } + + browser_->SendKeyEvent(KT_CHAR, keyInfo, modifiers); +} + +- (void)keyUp:(NSEvent *)event { + if (!browser_) + return; + + CefKeyInfo keyInfo; + [self getKeyInfo:keyInfo forEvent:event]; + int modifiers = [self getModifiersForEvent:event]; + + browser_->SendKeyEvent(KT_KEYUP, keyInfo, modifiers); +} + +- (void)flagsChanged:(NSEvent *)event { + if ([self isKeyUpEvent:event]) + [self keyUp:event]; + else + [self keyDown:event]; +} + +- (void)scrollWheel:(NSEvent *)event { + if (!browser_) + return; + + CGEventRef cgEvent = [event CGEvent]; + ASSERT(cgEvent); + + NSPoint point = [self getClickPointForEvent:event]; + int deltaX = + CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis2); + int deltaY = + CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1); + + browser_->SendMouseWheelEvent(point.x, point.y, deltaX, deltaY); +} + +- (BOOL)canBecomeKeyView { + return (browser_ != NULL); +} + +- (BOOL)acceptsFirstResponder { + return (browser_ != NULL); +} + +- (BOOL)becomeFirstResponder { + if (browser_) { + browser_->SendFocusEvent(true); + return [super becomeFirstResponder]; + } + + return NO; +} + +- (BOOL)resignFirstResponder { + if (browser_) { + browser_->SendFocusEvent(false); + return [super resignFirstResponder]; + } + + return NO; +} + +- (void)undo:(id)sender { + if (browser_) + browser_->GetFocusedFrame()->Undo(); +} + +- (void)redo:(id)sender { + if (browser_) + browser_->GetFocusedFrame()->Redo(); +} + +- (void)cut:(id)sender { + if (browser_) + browser_->GetFocusedFrame()->Cut(); +} + +- (void)copy:(id)sender { + if (browser_) + browser_->GetFocusedFrame()->Copy(); +} + +- (void)paste:(id)sender { + if (browser_) + browser_->GetFocusedFrame()->Paste(); +} + +- (void)delete:(id)sender { + if (browser_) + browser_->GetFocusedFrame()->Delete(); +} + +- (void)selectAll:(id)sender { + if (browser_) + browser_->GetFocusedFrame()->SelectAll(); +} + +- (NSPoint)getClickPointForEvent:(NSEvent*)event { + NSPoint windowLocal = [event locationInWindow]; + NSPoint contentLocal = [self convertPoint:windowLocal fromView:nil]; + int x = contentLocal.x; + int y = [self frame].size.height - contentLocal.y; // Flip y. + + return {x,y}; +} + +- (void)getKeyInfo:(CefKeyInfo&)info forEvent:(NSEvent*)event { + if ([event type] == NSKeyDown || [event type] == NSKeyUp) { + NSString* s = [event characters]; + if ([s length] > 0) + info.character = [s characterAtIndex:0]; + + s = [event charactersIgnoringModifiers]; + if ([s length] > 0) + info.characterNoModifiers = [s characterAtIndex:0]; + } + + info.keyCode = [event keyCode]; +} + +- (int)getModifiersForEvent:(NSEvent*)event { + int modifiers = 0; + + if ([event modifierFlags] & NSControlKeyMask) + modifiers |= KEY_CTRL; + if ([event modifierFlags] & NSShiftKeyMask) + modifiers |= KEY_SHIFT; + if ([event modifierFlags] & NSAlternateKeyMask) + modifiers |= KEY_ALT; + if ([event modifierFlags] & NSCommandKeyMask) + modifiers |= KEY_META; + if ([self isKeyPadEvent:event]) + modifiers |= KEY_KEYPAD; + + return modifiers; +} + +- (BOOL)isKeyUpEvent:(NSEvent*)event { + if ([event type] != NSFlagsChanged) + return [event type] == NSKeyUp; + + // FIXME: This logic fails if the user presses both Shift keys at once, for + // example: we treat releasing one of them as keyDown. + switch ([event keyCode]) { + case 54: // Right Command + case 55: // Left Command + return ([event modifierFlags] & NSCommandKeyMask) == 0; + + case 57: // Capslock + return ([event modifierFlags] & NSAlphaShiftKeyMask) == 0; + + case 56: // Left Shift + case 60: // Right Shift + return ([event modifierFlags] & NSShiftKeyMask) == 0; + + case 58: // Left Alt + case 61: // Right Alt + return ([event modifierFlags] & NSAlternateKeyMask) == 0; + + case 59: // Left Ctrl + case 62: // Right Ctrl + return ([event modifierFlags] & NSControlKeyMask) == 0; + + case 63: // Function + return ([event modifierFlags] & NSFunctionKeyMask) == 0; + } + return false; +} + +- (BOOL)isKeyPadEvent:(NSEvent*)event { + if ([event modifierFlags] & NSNumericPadKeyMask) + return true; + + switch ([event keyCode]) { + case 71: // Clear + case 81: // = + case 75: // / + case 67: // * + case 78: // - + case 69: // + + case 76: // Enter + case 65: // . + case 82: // 0 + case 83: // 1 + case 84: // 2 + case 85: // 3 + case 86: // 4 + case 87: // 5 + case 88: // 6 + case 89: // 7 + case 91: // 8 + case 92: // 9 + return true; + } + + return false; +} + +@end + + +namespace osrtest { + +void RunTest(bool transparent) { + NSRect screen_rect = [[NSScreen mainScreen] visibleFrame]; + NSRect window_rect = {{0, screen_rect.size.height}, {700, 700}}; + NSWindow* newWnd = [[NSWindow alloc] + initWithContentRect:window_rect + styleMask:(NSTitledWindowMask | + NSClosableWindowMask | + NSMiniaturizableWindowMask | + NSResizableWindowMask | + NSUnifiedTitleAndToolbarWindowMask) + backing:NSBackingStoreBuffered + defer:NO]; + ASSERT(newWnd); + + ClientOpenGLView* view = [[ClientOpenGLView alloc] initWithFrame:window_rect + andTransparency:transparent]; + [view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; + + [newWnd setContentView:view]; + [view release]; + + CefWindowInfo info; + CefBrowserSettings settings; + + // Initialize the window info as off-screen. + info.SetAsOffScreen(view); + info.SetTransparentPainting(transparent); + + // Creat the browser window. + CefBrowser::CreateBrowser(info, new ClientOSRHandler(view), + "http://tests/osrtest", settings); + + [newWnd makeKeyAndOrderFront: nil]; +} + +} // namespace osrtest + diff --git a/tests/cefclient/res/osrtest.html b/tests/cefclient/res/osrtest.html new file mode 100644 index 000000000..c3fdc2eee --- /dev/null +++ b/tests/cefclient/res/osrtest.html @@ -0,0 +1,40 @@ + + +Off-Screen Rendering Test + + +
+ + + + + + + + + + + + + + + + + +
Off-Screen Rendering App Example
An OpenGL view that renders content from an off-screen browser window.
You can rotate the view! +
    +
  • Click and drag the view with the left mouse button while holding the shift key.
  • +
  • Enter a URL and click the "Go!" button to browse to a new Website.
  • +
  • Click here to test transparency.
  • +
  • Click here to test a windowless plugin.
  • +
+
+
+ + +
+
+
+ + + diff --git a/tools/distrib/cefclient.gyp b/tools/distrib/cefclient.gyp index 769cf9614..394691c45 100644 --- a/tools/distrib/cefclient.gyp +++ b/tools/distrib/cefclient.gyp @@ -96,6 +96,7 @@ 'link_settings': { 'libraries': [ '$(SDKROOT)/System/Library/Frameworks/AppKit.framework', + '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework', '$(CONFIGURATION)/libcef.dylib' ], },