- Add off-screen rendering support for Mac OS-X (issue #540).

- Add patch for ninja build support on Mac OS-X.

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@624 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2012-05-16 16:56:38 +00:00
parent 808e89e01e
commit fb2d3f9490
38 changed files with 2236 additions and 594 deletions

View File

@ -212,6 +212,7 @@
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
'$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
],
},
'sources': [
@ -490,6 +491,7 @@
],
'xcode_settings': {
'INSTALL_PATH': '@executable_path',
'DYLIB_INSTALL_NAME_BASE': '@executable_path',
# The libcef_static target contains ObjC categories. Passing the -ObjC flag
# is necessary to properly load them and avoid a "selector not recognized"
# runtime error. See http://developer.apple.com/library/mac/#qa/qa1490/_index.html

View File

@ -111,6 +111,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',
@ -135,6 +137,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': [
@ -146,6 +152,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': [

View File

@ -259,8 +259,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
@ -279,10 +279,11 @@ typedef struct _cef_browser_t {
///
// Send a mouse wheel event to the browser. The |x| and |y| coordinates are
// relative to the upper-left corner of the view.
// relative to the upper-left corner of the view. The |deltaX| and |deltaY|
// values represent the movement delta in the X and Y directions respectively.
///
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.

View File

@ -294,8 +294,8 @@ class CefBrowser : public virtual CefBase {
// 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
@ -314,10 +314,11 @@ class CefBrowser : public virtual CefBase {
///
// Send a mouse wheel event to the browser. The |x| and |y| coordinates are
// relative to the upper-left corner of the view.
// relative to the upper-left corner of the view. The |deltaX| and |deltaY|
// values represent the movement delta in the X and Y directions respectively.
///
/*--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.

View File

@ -37,7 +37,9 @@
#include "include/internal/cef_types_linux.h"
#include "include/internal/cef_types_wrappers.h"
///
// Atomic increment and decrement.
///
inline long CefAtomicIncrement(long volatile *pDest) { // NOLINT(runtime/int)
return __sync_add_and_fetch(pDest, 1);
}
@ -45,7 +47,9 @@ inline long CefAtomicDecrement(long volatile *pDest) { // NOLINT(runtime/int)
return __sync_sub_and_fetch(pDest, 1);
}
///
// Critical section wrapper.
///
class CefCriticalSection {
public:
CefCriticalSection() {
@ -68,10 +72,13 @@ class CefCriticalSection {
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;
@ -85,7 +92,9 @@ struct CefWindowInfoTraits {
}
};
///
// Class representing window information.
///
class CefWindowInfo : public CefStructBase<CefWindowInfoTraits> {
public:
typedef CefStructBase<CefWindowInfoTraits> parent;
@ -99,6 +108,7 @@ class CefWindowInfo : public CefStructBase<CefWindowInfoTraits> {
}
};
struct CefPrintInfoTraits {
typedef cef_print_info_t struct_type;
@ -111,9 +121,29 @@ struct CefPrintInfoTraits {
}
};
///
// Class representing print context information.
///
typedef CefStructBase<CefPrintInfoTraits> CefPrintInfo;
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<CefKeyInfoTraits> CefKeyInfo;
#endif // OS_LINUX
#endif // CEF_INCLUDE_INTERNAL_CEF_LINUX_H_

View File

@ -37,7 +37,9 @@
#include "include/internal/cef_types_mac.h"
#include "include/internal/cef_types_wrappers.h"
///
// Atomic increment and decrement.
///
inline long CefAtomicIncrement(long volatile *pDest) { // NOLINT(runtime/int)
return __sync_add_and_fetch(pDest, 1);
}
@ -45,11 +47,15 @@ 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() {
@ -72,6 +78,7 @@ class CefCriticalSection {
pthread_mutexattr_t attr_;
};
struct CefWindowInfoTraits {
typedef cef_window_info_t struct_type;
@ -92,10 +99,14 @@ 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<CefWindowInfoTraits> {
public:
typedef CefStructBase<CefWindowInfoTraits> parent;
@ -113,8 +124,18 @@ class CefWindowInfo : public CefStructBase<CefWindowInfoTraits> {
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;
@ -127,9 +148,31 @@ struct CefPrintInfoTraits {
}
};
///
// Class representing print context information.
///
typedef CefStructBase<CefPrintInfoTraits> CefPrintInfo;
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->keyCode = src->keyCode;
target->character = src->character;
target->characterNoModifiers = src->characterNoModifiers;
}
};
///
// Class representing key information.
///
typedef CefStructBase<CefKeyInfoTraits> CefKeyInfo;
#endif // OS_MACOSX
#endif // CEF_INCLUDE_INTERNAL_CEF_MAC_H_

View File

@ -856,10 +856,11 @@ 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
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
};
///

View File

@ -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

View File

@ -40,15 +40,18 @@
// Window handle.
#ifdef __cplusplus
#ifdef __OBJC__
@class NSCursor;
@class NSView;
#else
class NSCursor;
struct 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" {
@ -76,6 +79,14 @@ 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;
@ -87,6 +98,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 keyCode;
int character;
int characterNoModifiers;
} cef_key_info_t;
#ifdef __cplusplus
}
#endif

View File

@ -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

View File

@ -71,7 +71,6 @@ class CefCriticalSection {
#define CefWindowHandle cef_window_handle_t
#define CefCursorHandle cef_cursor_handle_t
struct CefWindowInfoTraits {
typedef cef_window_info_t struct_type;
@ -162,6 +161,26 @@ struct CefPrintInfoTraits {
///
typedef CefStructBase<CefPrintInfoTraits> CefPrintInfo;
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<CefKeyInfoTraits> CefKeyInfo;
#endif // OS_WIN
#endif // CEF_INCLUDE_INTERNAL_CEF_WIN_H_

View File

@ -440,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,
@ -466,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) {
@ -1051,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);
}
}
@ -1091,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);
}
}

View File

@ -106,12 +106,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;
@ -269,12 +270,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();

View File

@ -29,18 +29,19 @@ CefWindowHandle CefBrowserImpl::GetWindowHandle() {
}
bool CefBrowserImpl::IsWindowRenderingDisabled() {
// TODO(port): Add support for off-screen rendering.
return false;
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) {
@ -61,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;
@ -92,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());
@ -101,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();
@ -142,11 +155,24 @@ void CefBrowserImpl::UIT_SetFocus(WebWidgetHost* host, bool enable) {
}
}
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;
}

View File

@ -48,6 +48,7 @@ namespace {
void AddMenuItem(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefMenuHandler> handler,
NSMenu* menu,
id target,
cef_menu_id_t menuId,
const std::string& label,
bool enabled) {
@ -65,7 +66,8 @@ void AddMenuItem(CefRefPtr<CefBrowser> 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 <NSMenuDelegate> {
@private
CefRefPtr<CefBrowserImpl> 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<cef_menu_id_t>([sender tag]);
bool handled = false;
CefRefPtr<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefMenuHandler> 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<BrowserWebView*>(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<CefClient> 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<CefRenderHandler> 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).GetNativeCursor();
[ns_cursor set];
if (!browser_->IsWindowRenderingDisabled()) {
[ns_cursor set];
} else {
// Notify the handler of cursor change.
CefRefPtr<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefRenderHandler> 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<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefRenderHandler> 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 ----------------------------------------------------------

View File

@ -448,7 +448,7 @@ void BrowserWebViewDelegate::showContextMenu(
if (client.get() && browser_->IsWindowRenderingDisabled()) {
// Retrieve the screen coordinates.
CefRefPtr<CefRenderHandler> 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;

View File

@ -18,7 +18,7 @@ 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 <NSMenuDelegate> {
@interface BrowserWebView : NSView {
@private
CefBrowserImpl* browser_; // weak
NSTrackingArea* trackingArea_;
@ -46,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;

View File

@ -239,25 +239,6 @@
browser_->GetFocusedFrame()->SelectAll();
}
- (void)menuItemSelected:(id)sender {
cef_menu_id_t menuId = static_cast<cef_menu_id_t>([sender tag]);
bool handled = false;
CefRefPtr<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefMenuHandler> 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]);

View File

@ -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<CefClient> client = browser->GetClient();
if (client.get()) {
// Retrieve the view rect.
CefRect rect;
CefRefPtr<CefRenderHandler> 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];

View File

@ -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);

View File

@ -106,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
}

View File

@ -123,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();
@ -284,6 +284,11 @@ class WebWidgetHost {
WebKit::WebRect caret_bounds_;
#endif
#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.

View File

@ -440,8 +440,9 @@ 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();
}
@ -458,7 +459,7 @@ void WebWidgetHost::SendMouseMoveEvent(int x, int y, bool mouseLeave) {
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();
}

View File

@ -3,7 +3,18 @@
// found in the LICENSE file.
#import <Cocoa/Cocoa.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"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#import "third_party/WebKit/Source/WebKit/chromium/public/platform/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;
@ -46,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;
}
@ -66,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);
}
@ -74,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();
@ -106,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;
}
@ -144,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);
@ -202,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<CGContextRef>([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<CGContextRef>([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, &copy_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, &copy_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<CefRect> 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.
@ -233,7 +333,12 @@ 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) {
@ -241,17 +346,50 @@ void WebWidgetHost::SetTooltipText(const CefString& tooltip_text) {
}
void WebWidgetHost::InvalidateRect(const gfx::Rect& rect) {
// TODO(port): Implement this method as part of off-screen rendering support.
NOTIMPLEMENTED();
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) {
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<skia::PlatformCanvas> 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() {
@ -326,44 +464,213 @@ 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();
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();
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<float>(deltaX);
event.deltaY = static_cast<float>(deltaY);
event.wheelTicksX = static_cast<float>(deltaX/scrollbarPixelsPerCocoaTick);
event.wheelTicksY = static_cast<float>(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();
SetFocus(setFocus);
}
void WebWidgetHost::SendCaptureLostEvent() {
// TODO(port): Implement this method as part of off-screen rendering support.
NOTIMPLEMENTED();
}
void WebWidgetHost::EnsureTooltip() {

View File

@ -777,30 +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)
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)
if (keyInfo.sysChar)
message = WM_SYSCHAR;
else if (imeChar)
else if (keyInfo.imeChar)
message = WM_IME_CHAR;
else
message = WM_CHAR;
@ -903,8 +904,8 @@ 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)

View File

@ -606,21 +606,28 @@ 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);
}
void CEF_CALLBACK browser_send_mouse_click_event(struct _cef_browser_t* self,
@ -657,7 +664,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
DCHECK(self);
@ -668,7 +675,8 @@ void CEF_CALLBACK browser_send_mouse_wheel_event(struct _cef_browser_t* self,
CefBrowserCppToC::Get(self)->SendMouseWheelEvent(
x,
y,
delta);
deltaX,
deltaY);
}
void CEF_CALLBACK browser_send_focus_event(struct _cef_browser_t* self,

View File

@ -491,8 +491,8 @@ bool CefBrowserCToCpp::GetImage(PaintElementType type, int width, int height,
return _retval?true:false;
}
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;
@ -501,10 +501,8 @@ void CefBrowserCToCpp::SendKeyEvent(KeyType type, int key, int modifiers,
// Execute
struct_->send_key_event(struct_,
type,
key,
modifiers,
sysChar,
imeChar);
&keyInfo,
modifiers);
}
void CefBrowserCToCpp::SendMouseClickEvent(int x, int y, MouseButtonType type,
@ -536,7 +534,8 @@ void CefBrowserCToCpp::SendMouseMoveEvent(int x, int y, bool mouseLeave) {
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;
@ -546,7 +545,8 @@ void CefBrowserCToCpp::SendMouseWheelEvent(int x, int y, int delta) {
struct_->send_mouse_wheel_event(struct_,
x,
y,
delta);
deltaX,
deltaY);
}
void CefBrowserCToCpp::SendFocusEvent(bool setFocus) {

View File

@ -70,12 +70,13 @@ class CefBrowserCToCpp
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;
};

View File

@ -18,6 +18,7 @@ patches = [
},
{
# http://code.google.com/p/gyp/issues/detail?id=223
# http://codereview.chromium.org/10383117/
'name': 'tools_gyp',
'path': '../tools/gyp/',
},

View File

@ -1,6 +1,6 @@
Index: pylib/gyp/input.py
===================================================================
--- pylib/gyp/input.py (revision 1107)
--- pylib/gyp/input.py (revision 1323)
+++ pylib/gyp/input.py (working copy)
@@ -666,7 +666,8 @@
# that don't load quickly, this can be faster than
@ -12,3 +12,25 @@ Index: pylib/gyp/input.py
parsed_contents = shlex.split(contents)
py_module = __import__(parsed_contents[0])
Index: pylib/gyp/mac_tool.py
===================================================================
--- pylib/gyp/mac_tool.py (revision 1323)
+++ pylib/gyp/mac_tool.py (working copy)
@@ -54,16 +54,8 @@
return self._CopyXIBFile(source, dest)
elif extension == '.strings':
self._CopyStringsFile(source, dest)
- # TODO: Given that files with arbitrary extensions can be copied to the
- # bundle, we will want to get rid of this whitelist eventually.
- elif extension in [
- '.icns', '.manifest', '.pak', '.pdf', '.png', '.sb', '.sh',
- '.ttf', '.sdef']:
- shutil.copyfile(source, dest)
else:
- raise NotImplementedError(
- "Don't know how to copy bundle resources of type %s while copying "
- "%s to %s)" % (extension, source, dest))
+ shutil.copyfile(source, dest)
def _CopyXIBFile(self, source, dest):
"""Compiles a XIB file with ibtool into a binary plist in the bundle."""

View File

@ -14,6 +14,7 @@
#include "cefclient/binding_test.h"
#include "cefclient/client_handler.h"
#include "cefclient/extension_test.h"
#include "cefclient/osrtest_mac.h"
#include "cefclient/resource_util.h"
#include "cefclient/scheme_test.h"
#include "cefclient/string_util.h"
@ -212,6 +213,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
@ -305,6 +308,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];
@ -531,6 +540,14 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
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 {

View File

@ -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 "cefclient/osrenderer.h"
#include "cefclient/util.h"
#if defined(OS_WIN)
#include <gl/gl.h>
#include <gl/glu.h>
#elif defined(OS_MACOSX)
#include <OpenGL/gl.h>
#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<CefBrowser> 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<CefBrowser> 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<CefBrowser> 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_);
}
}

View File

@ -0,0 +1,64 @@
// 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_browser.h"
#include "include/cef_render_handler.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<CefBrowser> browser,
bool show);
void OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect);
void OnPaint(CefRefPtr<CefBrowser> 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_

View File

@ -4,6 +4,7 @@
// found in the LICENSE file.
#include "cefclient/osrplugin.h"
#include "cefclient/osrenderer.h"
#if defined(OS_WIN)
@ -28,27 +29,22 @@ 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<CefBrowser> 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;
ClientPlugin(bool transparent)
: renderer(transparent),
hWnd(NULL),
hDC(NULL),
hRC(NULL) {
}
ClientOSRenderer renderer;
HWND hWnd;
HDC hDC;
HGLRC hRC;
@ -63,17 +59,9 @@ class ClientOSRHandler : public CefClient,
public CefRenderHandler {
public:
explicit ClientOSRHandler(ClientPlugin* plugin)
: plugin_(plugin),
view_buffer_(NULL),
view_buffer_size_(0),
popup_buffer_(NULL),
popup_buffer_size_(0) {
: plugin_(plugin) {
}
~ClientOSRHandler() {
if (view_buffer_)
delete [] view_buffer_;
if (popup_buffer_)
delete [] popup_buffer_;
}
// CefClient methods
@ -111,10 +99,12 @@ class ClientOSRHandler : public CefClient,
virtual void OnAfterCreated(CefRefPtr<CefBrowser> 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<CefBrowser> browser) OVERRIDE {
@ -214,9 +204,12 @@ class ClientOSRHandler : public CefClient,
// 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;
}
@ -243,29 +236,13 @@ class ClientOSRHandler : public CefClient,
virtual void OnPopupShow(CefRefPtr<CefBrowser> browser,
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<CefBrowser> browser,
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<CefBrowser> browser,
@ -275,65 +252,7 @@ class ClientOSRHandler : public CefClient,
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<CefBrowser> browser,
@ -357,112 +276,7 @@ class ClientOSRHandler : public CefClient,
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);
@ -473,12 +287,12 @@ 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));
@ -489,83 +303,30 @@ 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;
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);
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;
plugin->renderer.SetSize(width, height);
if (g_offscreenBrowser.get())
g_offscreenBrowser->SetSize(PET_VIEW, width, height);
@ -575,58 +336,7 @@ void SizeGL(ClientPlugin* plugin, int width, int height) {
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);
}
@ -637,7 +347,7 @@ 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<void*>(plugin);
return NPERR_NO_ERROR;
@ -649,7 +359,7 @@ NPError NPP_DestroyImpl(NPP instance, NPSavedData** save) {
if (plugin) {
if (plugin->hWnd) {
DestroyWindow(plugin->hWnd);
DisableGL(plugin->hWnd, plugin->hDC, plugin->hRC);
DisableGL(plugin);
}
delete plugin;
}
@ -693,7 +403,7 @@ NPError NPP_SetWindowImpl(NPP instance, NPWindow* window_info) {
reinterpret_cast<LONG_PTR>(plugin));
// Enable GL drawing for the window.
EnableGL(plugin->hWnd, &(plugin->hDC), &(plugin->hRC));
EnableGL(plugin);
// Create the off-screen rendering window.
CefWindowInfo windowInfo;
@ -771,8 +481,7 @@ 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),
@ -786,8 +495,8 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam,
// 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 {
@ -825,7 +534,7 @@ 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;
@ -860,7 +569,8 @@ 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;
@ -869,12 +579,12 @@ LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT message, WPARAM wParam,
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;

View File

@ -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_

View File

@ -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 <Cocoa/Cocoa.h>
#include <OpenGL/gl.h>
#include "cefclient/osrtest_mac.h"
#include "include/cef_browser.h"
#include "cefclient/osrenderer.h"
#include "cefclient/client_popup_handler.h"
#include "cefclient/resource_util.h"
#include "cefclient/util.h"
// The client OpenGL view.
@interface ClientOpenGLView : NSOpenGLView {
@public
NSTrackingArea* tracking_area_;
CefRefPtr<CefBrowser> 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<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefRequestHandler> GetRequestHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefRenderHandler> GetRenderHandler() OVERRIDE {
return this;
}
// CefLifeSpanHandler methods
virtual bool OnBeforePopup(CefRefPtr<CefBrowser> parentBrowser,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
const CefString& url,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) OVERRIDE {
REQUIRE_UI_THREAD();
windowInfo.m_bWindowRenderingDisabled = TRUE;
client = new ClientPopupHandler(view_->browser_);
return false;
}
virtual void OnAfterCreated(CefRefPtr<CefBrowser> 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<CefBrowser> browser) OVERRIDE {
if (view_)
view_->browser_ = NULL;
}
// CefLoadHandler methods
virtual void OnLoadStart(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame) OVERRIDE {
REQUIRE_UI_THREAD();
if (!browser->IsPopup() && frame->IsMain()) {
// We've just started loading a page
SetLoading(true);
}
}
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> 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<CefBrowser> browser,
CefRefPtr<CefRequest> request,
CefString& redirectUrl,
CefRefPtr<CefStreamReader>& resourceStream,
CefRefPtr<CefResponse> 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<CefBrowser> browser,
bool canGoBack,
bool canGoForward) OVERRIDE {
REQUIRE_UI_THREAD();
}
virtual void OnAddressChange(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& url) OVERRIDE {
REQUIRE_UI_THREAD();
}
virtual void OnTitleChange(CefRefPtr<CefBrowser> 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<CefBrowser> 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<CefBrowser> browser,
CefRect& rect) OVERRIDE {
return GetViewRect(browser, rect);
}
virtual bool GetScreenPoint(CefRefPtr<CefBrowser> 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<CefBrowser> browser,
bool show) OVERRIDE {
REQUIRE_UI_THREAD();
if (!view_)
return;
view_->renderer_->OnPopupShow(browser, show);
}
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) OVERRIDE {
REQUIRE_UI_THREAD();
if (!view_)
return;
view_->renderer_->OnPopupSize(browser, rect);
}
virtual void OnPaint(CefRefPtr<CefBrowser> 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<CefBrowser> 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<ClientOSRHandler*>(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

View File

@ -0,0 +1,40 @@
<html>
<head>
<title>Off-Screen Rendering Test</title>
</head>
<body bottommargin="2" rightmargin="0" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0" style="font-family: Verdana, Arial;" bgcolor="white">
<div align="center">
<table border="0" cellpadding="2" cellspacing="0">
<tr>
<td colspan="2" style="font-size: 18pt;">Off-Screen Rendering App Example</td>
</tr>
<tr>
<td colspan="2" style="font-size: 8pt;"><i>An OpenGL view that renders content from an off-screen browser window.</i></td>
</tr>
<tr>
<td colspan="2" height="10"></td>
</tr>
<tr>
<td width="100" valign="top"><img src="logoball.png" width="100" height="101"></td>
<td style="font-size: 10pt;"><span style="font-size: 12pt;">You can rotate the view!</span>
<ul>
<li>Click and drag the view with the left mouse button while holding the shift key.</li>
<li>Enter a URL and click the "Go!" button to browse to a new Website.</li>
<li><a href="http://tests/transparency">Click here</a> to test transparency.</li>
<li><a href="http://www.adobe.com/software/flash/about/">Click here</a> to test a windowless plugin.</li>
</ul>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<form>
<input type="text" id="url" size="100" value="http://www.google.com"/>
<input type="button" value="Go!" onClick="document.location=document.getElementById('url').value;"/>
</form>
</td>
</tr>
</table>
</div>
</body>
</html>

View File

@ -96,6 +96,7 @@
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
'$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
'$(CONFIGURATION)/libcef.dylib'
],
},