Mac: Add off-screen rendering support (issue #518).

- Build with the 10.7 SDK (set GYP_DEFINES='mac_sdk=10.7') to include Retina support in the cefclient OSR example.

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1226 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2013-04-16 19:23:00 +00:00
parent 0f8af86b79
commit c41127f236
49 changed files with 2447 additions and 204 deletions

25
cef.gyp
View File

@ -86,7 +86,7 @@
'-lshlwapi.lib',
'-lrpcrt4.lib',
'-lopengl32.lib',
'-lglu32.lib',
'-lglu32.lib',
],
},
'sources': [
@ -199,6 +199,7 @@
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
'$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
],
},
'sources': [
@ -237,6 +238,7 @@
'<(DEPTH)/testing/gtest.gyp:gtest',
'<(DEPTH)/third_party/icu/icu.gyp:icui18n',
'<(DEPTH)/third_party/icu/icu.gyp:icuuc',
'<(DEPTH)/ui/ui.gyp:ui',
'cef_pak',
'libcef',
'libcef_dll_wrapper',
@ -258,6 +260,7 @@
'tests/unittests/navigation_unittest.cc',
'tests/unittests/process_message_unittest.cc',
'tests/unittests/request_unittest.cc',
'tests/cefclient/resource_util.h',
'tests/unittests/run_all_unittests.cc',
'tests/unittests/scheme_handler_unittest.cc',
'tests/unittests/stream_unittest.cc',
@ -280,6 +283,7 @@
'tests/unittests/zip_reader_unittest.cc',
],
'mac_bundle_resources': [
'tests/cefclient/res/osr_test.html',
'tests/unittests/mac/unittests.icns',
'tests/unittests/mac/English.lproj/InfoPlist.strings',
'tests/unittests/mac/English.lproj/MainMenu.xib',
@ -299,10 +303,16 @@
},
'include_dirs': [
'.',
# Necessary to allow resouce_util_* implementation files in cefclient to
# include 'cefclient/*' files, without the tests/ fragment
'./tests'
],
'conditions': [
[ 'OS=="win"', {
'sources': [
'tests/cefclient/cefclient.rc',
'tests/cefclient/res/osr_test.html',
'tests/cefclient/resource_util_win.cpp',
'tests/unittests/os_rendering_unittest.cc',
],
}],
@ -410,6 +420,11 @@
],
},
'sources': [
'tests/cefclient/resource_util_mac.mm',
'tests/cefclient/resource_util_posix.cpp',
'tests/unittests/os_rendering_unittest.cc',
'tests/unittests/os_rendering_unittest_mac.h',
'tests/unittests/os_rendering_unittest_mac.mm',
'tests/unittests/run_all_unittests_mac.mm',
],
}],
@ -995,8 +1010,8 @@
'libcef/browser/javascript_dialog_win.cc',
'libcef/browser/menu_creator_runner_win.cc',
'libcef/browser/menu_creator_runner_win.h',
'libcef/browser/render_widget_host_view_osr.h',
'libcef/browser/render_widget_host_view_osr.cc',
'libcef/browser/render_widget_host_view_osr.h',
'libcef/browser/web_contents_view_osr.cc',
'libcef/browser/web_contents_view_osr.h',
# Include sources for context menu implementation.
@ -1016,11 +1031,17 @@
'<@(includes_mac)',
'libcef/browser/application_mac.h',
'libcef/browser/application_mac.mm',
'libcef/browser/backing_store_osr.cc',
'libcef/browser/backing_store_osr.h',
'libcef/browser/browser_host_impl_mac.mm',
'libcef/browser/browser_main_mac.mm',
'libcef/browser/javascript_dialog_mac.mm',
'libcef/browser/menu_creator_runner_mac.h',
'libcef/browser/menu_creator_runner_mac.mm',
'libcef/browser/render_widget_host_view_osr.cc',
'libcef/browser/render_widget_host_view_osr.h',
'libcef/browser/web_contents_view_osr.cc',
'libcef/browser/web_contents_view_osr.h',
# Include sources for context menu implementation.
'<(DEPTH)/chrome/browser/ui/cocoa/event_utils.mm',
'<(DEPTH)/chrome/browser/ui/cocoa/event_utils.h',

View File

@ -134,13 +134,18 @@
'tests/cefclient/osrenderer.cpp',
'tests/cefclient/resource.h',
'tests/cefclient/res/cefclient.ico',
'tests/cefclient/res/osr_test.html',
'tests/cefclient/res/small.ico',
'tests/cefclient/resource_util_win.cpp',
'tests/cefclient/window_test_win.cpp',
],
'cefclient_sources_mac': [
'tests/cefclient/cefclient_mac.mm',
'tests/cefclient/cefclient_osr_widget_mac.h',
'tests/cefclient/cefclient_osr_widget_mac.mm',
'tests/cefclient/client_handler_mac.mm',
'tests/cefclient/osrenderer.h',
'tests/cefclient/osrenderer.cpp',
'tests/cefclient/resource_util_mac.mm',
'tests/cefclient/resource_util_posix.cpp',
'tests/cefclient/window_test_mac.mm',
@ -184,6 +189,7 @@
'tests/cefclient/mac/English.lproj/InfoPlist.strings',
'tests/cefclient/mac/English.lproj/MainMenu.xib',
'tests/cefclient/mac/Info.plist',
'tests/cefclient/res/osr_test.html',
'<@(cefclient_bundle_resources_common)',
],
'cefclient_sources_linux': [

View File

@ -346,6 +346,17 @@ typedef struct _cef_browser_host_t {
///
void (CEF_CALLBACK *was_hidden)(struct _cef_browser_host_t* self, int hidden);
///
// Send a notification to the browser that the screen info has changed. The
// browser will then call cef_render_handler_t::GetScreenInfo to update the
// screen information with the new values. This simulates moving the webview
// window from one display to another, or changing the properties of the
// current display. This function is only used when window rendering is
// disabled.
///
void (CEF_CALLBACK *notify_screen_info_changed)(
struct _cef_browser_host_t* self);
///
// Invalidate the |dirtyRect| region of the view. The browser will call
// cef_render_handler_t::OnPaint asynchronously with the updated regions. This

View File

@ -77,6 +77,18 @@ typedef struct _cef_render_handler_t {
struct _cef_browser_t* browser, int viewX, int viewY, int* screenX,
int* screenY);
///
// Called to allow the client to fill in the CefScreenInfo object with
// appropriate values. Return true (1) if the |screen_info| structure has been
// modified.
//
// If the screen info rectangle is left NULL the rectangle from GetViewRect
// will be used. If the rectangle is still NULL or invalid popups may not be
// drawn correctly.
///
int (CEF_CALLBACK *get_screen_info)(struct _cef_render_handler_t* self,
struct _cef_browser_t* browser, struct _cef_screen_info_t* screen_info);
///
// Called when the browser wants to show or hide the popup widget. The popup
// should be shown if |show| is true (1) and hidden if |show| is false (0).

View File

@ -388,6 +388,17 @@ class CefBrowserHost : public virtual CefBase {
/*--cef()--*/
virtual void WasHidden(bool hidden) =0;
///
// Send a notification to the browser that the screen info has changed. The
// browser will then call CefRenderHandler::GetScreenInfo to update the
// screen information with the new values. This simulates moving the webview
// window from one display to another, or changing the properties of the
// current display. This method is only used when window rendering is
// disabled.
///
/*--cef()--*/
virtual void NotifyScreenInfoChanged() =0;
///
// Invalidate the |dirtyRect| region of the view. The browser will call
// CefRenderHandler::OnPaint asynchronously with the updated regions. This

View File

@ -78,6 +78,19 @@ class CefRenderHandler : public virtual CefBase {
int& screenX,
int& screenY) { return false; }
///
// Called to allow the client to fill in the CefScreenInfo object with
// appropriate values. Return true if the |screen_info| structure has been
// modified.
//
// If the screen info rectangle is left empty the rectangle from GetViewRect
// will be used. If the rectangle is still empty or invalid popups may not be
// drawn correctly.
///
/*--cef()--*/
virtual bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) { return false; }
///
// Called when the browser wants to show or hide the popup widget. The popup
// should be shown if |show| is true and hidden if |show| is false.

View File

@ -120,6 +120,8 @@ struct CefWindowInfoTraits {
target->width = src->width;
target->height = src->height;
target->hidden = src->hidden;
target->transparent_painting = src->transparent_painting;
target->window_rendering_disabled = src->window_rendering_disabled;
}
};
@ -141,6 +143,15 @@ class CefWindowInfo : public CefStructBase<CefWindowInfoTraits> {
this->height = height;
hidden = false;
}
void SetTransparentPainting(bool transparentPainting) {
transparent_painting = transparentPainting;
}
void SetAsOffScreen(NSView* view) {
window_rendering_disabled = true;
parent_view = view;
}
};
#endif // OS_MACOSX

View File

@ -966,6 +966,62 @@ enum cef_jsdialog_type_t {
JSDIALOGTYPE_PROMPT,
};
///
// Screen information used when window rendering is disabled. This structure is
// passed as a parameter to CefRenderHandler::GetScreenInfo and should be filled
// in by the client.
///
typedef struct _cef_screen_info_t {
///
// Device scale factor. Specifies the ratio between physical and logical
// pixels.
///
float device_scale_factor;
///
// The screen depth in bits per pixel.
///
int depth;
///
// The bits per color component. This assumes that the colors are balanced
// equally.
///
int depth_per_component;
///
// This can be true for black and white printers.
///
bool is_monochrome;
///
// This is set from the rcMonitor member of MONITORINFOEX, to whit:
// "A RECT structure that specifies the display monitor rectangle,
// expressed in virtual-screen coordinates. Note that if the monitor
// is not the primary display monitor, some of the rectangle's
// coordinates may be negative values."
//
// The |rect| and |available_rect| properties are used to determine the
// available surface for rendering popup views.
///
cef_rect_t rect;
///
// This is set from the rcWork member of MONITORINFOEX, to whit:
// "A RECT structure that specifies the work area rectangle of the
// display monitor that can be used by applications, expressed in
// virtual-screen coordinates. Windows uses this rectangle to
// maximize an application on the monitor. The rest of the area in
// rcMonitor contains system windows such as the task bar and side
// bars. Note that if the monitor is not the primary display monitor,
// some of the rectangle's coordinates may be negative values".
//
// The |rect| and |available_rect| properties are used to determine the
// available surface for rendering popup views.
///
cef_rect_t available_rect;
} cef_screen_info_t;
///
// Supported menu IDs. Non-English translations can be provided for the
// IDS_MENU_* strings in CefResourceBundleHandler::GetLocalizedString().

View File

@ -83,6 +83,14 @@ typedef struct _cef_window_info_t {
// NSView pointer for the parent view.
cef_window_handle_t parent_view;
// If window rendering is disabled no browser window will be created. Set
// |parent_view| to the window that will act as the parent for popup menus,
// dialog boxes, etc.
bool window_rendering_disabled;
// Set to true to enable transparent painting.
bool transparent_painting;
// NSView pointer for the new browser view.
cef_window_handle_t view;
} cef_window_info_t;

View File

@ -174,6 +174,60 @@ inline bool operator!=(const CefRect& a, const CefRect& b) {
return !(a == b);
}
struct CefScreenInfoTraits {
typedef cef_screen_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->device_scale_factor = src->device_scale_factor;
target->depth = src->depth;
target->depth_per_component = src->depth_per_component;
target->is_monochrome = src->is_monochrome;
target->rect = src->rect;
target->available_rect = src->available_rect;
}
};
///
// Class representing the virtual screen information for use when window rendering
// is disabled.
///
class CefScreenInfo : public CefStructBase<CefScreenInfoTraits> {
public:
typedef CefStructBase<CefScreenInfoTraits> parent;
CefScreenInfo() : parent() {}
CefScreenInfo(const cef_screen_info_t& r) : parent(r) {} // NOLINT(runtime/explicit)
CefScreenInfo(const CefScreenInfo& r) : parent(r) {} // NOLINT(runtime/explicit)
CefScreenInfo(float device_scale_factor,
int depth,
int depth_per_component,
bool is_monochrome,
const CefRect& rect,
const CefRect& available_rect) : parent() {
Set(device_scale_factor, depth, depth_per_component,
is_monochrome, rect, available_rect);
}
void Set(float device_scale_factor,
int depth,
int depth_per_component,
bool is_monochrome,
const CefRect& rect,
const CefRect& available_rect) {
this->device_scale_factor = device_scale_factor;
this->depth = depth;
this->depth_per_component = depth_per_component;
this->is_monochrome = is_monochrome;
this->rect = rect;
this->available_rect = available_rect;
}
};
struct CefKeyEventTraits {
typedef cef_key_event_t struct_type;

View File

@ -4,16 +4,76 @@
#include "libcef/browser/backing_store_osr.h"
#include <algorithm>
#include "content/browser/renderer_host/dip_util.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/size_conversions.h"
#include "ui/gfx/vector2d_conversions.h"
#include "ui/surface/transport_dib.h"
// Assume that somewhere along the line, someone will do width * height * 4
// with signed numbers. If the maximum value is 2**31, then 2**31 / 4 =
// 2**29 and floor(sqrt(2**29)) = 23170.
// Max height and width for layers
static const int kMaxVideoLayerSize = 23170;
BackingStoreOSR::BackingStoreOSR(content::RenderWidgetHost* widget,
const gfx::Size& size)
const gfx::Size& size,
float scale_factor)
: content::BackingStore(widget, size),
device_(SkBitmap::kARGB_8888_Config, size.width(), size.height(), true),
canvas_(&device_) {
canvas_.drawColor(SK_ColorWHITE);
device_scale_factor_(scale_factor) {
gfx::Size pixel_size = gfx::ToFlooredSize(
gfx::ScaleSize(size, device_scale_factor_));
device_.reset(new SkDevice(SkBitmap::kARGB_8888_Config,
pixel_size.width(),
pixel_size.height(),
true));
canvas_.reset(new SkCanvas(device_.get()));
canvas_->drawColor(SK_ColorWHITE);
}
void BackingStoreOSR::ScaleFactorChanged(float scale_factor) {
if (scale_factor == device_scale_factor_)
return;
gfx::Size old_pixel_size = gfx::ToFlooredSize(
gfx::ScaleSize(size(), device_scale_factor_));
device_scale_factor_ = scale_factor;
gfx::Size pixel_size = gfx::ToFlooredSize(
gfx::ScaleSize(size(), device_scale_factor_));
scoped_ptr<SkDevice> new_device(new SkDevice(SkBitmap::kARGB_8888_Config,
pixel_size.width(),
pixel_size.height(),
true));
scoped_ptr<SkCanvas> new_canvas(new SkCanvas(new_device.get()));
// Copy old contents; a low-res flash is better than a black flash.
SkPaint copy_paint;
copy_paint.setXfermodeMode(SkXfermode::kSrc_Mode);
SkIRect src_rect = SkIRect::MakeWH(old_pixel_size.width(),
old_pixel_size.height());
SkRect dst_rect = SkRect::MakeWH(pixel_size.width(), pixel_size.height());
new_canvas.get()->drawBitmapRect(device_->accessBitmap(false), &src_rect,
dst_rect, &copy_paint);
canvas_.swap(new_canvas);
device_.swap(new_device);
}
size_t BackingStoreOSR::MemorySize() {
// NOTE: The computation may be different when the canvas is a subrectangle of
// a larger bitmap.
return gfx::ToFlooredSize(
gfx::ScaleSize(size(), device_scale_factor_)).GetArea() * 4;
}
void BackingStoreOSR::PaintToBackingStore(
@ -25,36 +85,58 @@ void BackingStoreOSR::PaintToBackingStore(
const base::Closure& completion_callback,
bool* scheduled_completion_callback) {
*scheduled_completion_callback = false;
if (bitmap_rect.IsEmpty())
return;
gfx::Rect pixel_bitmap_rect = gfx::ToEnclosedRect(
gfx::ScaleRect(bitmap_rect, scale_factor));
const int width = pixel_bitmap_rect.width();
const int height = pixel_bitmap_rect.height();
if (width <= 0 || width > kMaxVideoLayerSize ||
height <= 0 || height > kMaxVideoLayerSize) {
return;
}
TransportDIB* dib = process->GetTransportDIB(bitmap);
if (!dib)
return;
SkBitmap src_bitmap;
src_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
bitmap_rect.width(),
bitmap_rect.height());
src_bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
src_bitmap.setPixels(dib->memory());
SkPaint copy_paint;
copy_paint.setXfermodeMode(SkXfermode::kSrc_Mode);
for (size_t i = 0; i < copy_rects.size(); i++) {
SkIRect src_rect = SkIRect::MakeXYWH(copy_rects[i].x() - bitmap_rect.x(),
copy_rects[i].y() - bitmap_rect.y(),
copy_rects[i].width(),
copy_rects[i].height());
SkRect paint_rect = SkRect::MakeXYWH(copy_rects[i].x(),
copy_rects[i].y(),
copy_rects[i].width(),
copy_rects[i].height());
canvas_.drawBitmapRect(src_bitmap, &src_rect, paint_rect, &copy_paint);
const gfx::Rect pixel_copy_rect = gfx::ToEnclosingRect(
gfx::ScaleRect(copy_rects[i], scale_factor));
SkIRect src_rect =
SkIRect::MakeXYWH(pixel_copy_rect.x() - pixel_bitmap_rect.x(),
pixel_copy_rect.y() - pixel_bitmap_rect.y(),
pixel_copy_rect.width(),
pixel_copy_rect.height());
const gfx::Rect pixel_copy_dst_rect = gfx::ToEnclosingRect(
gfx::ScaleRect(copy_rects[i], device_scale_factor_));
SkRect paint_rect = SkRect::MakeXYWH(pixel_copy_dst_rect.x(),
pixel_copy_dst_rect.y(),
pixel_copy_dst_rect.width(),
pixel_copy_dst_rect.height());
canvas_->drawBitmapRect(src_bitmap, &src_rect, paint_rect, &copy_paint);
}
src_bitmap.setPixels(0);
}
bool BackingStoreOSR::CopyFromBackingStore(const gfx::Rect& rect,
skia::PlatformBitmap* output) {
if (!output->Allocate(rect.width(), rect.height(), true))
const int width =
std::min(size().width(), rect.width()) * device_scale_factor_;
const int height =
std::min(size().height(), rect.height()) * device_scale_factor_;
if (!output->Allocate(width, height, true))
return false;
SkPaint copy_paint;
@ -62,21 +144,30 @@ bool BackingStoreOSR::CopyFromBackingStore(const gfx::Rect& rect,
SkCanvas canvas(output->GetBitmap());
canvas.drawColor(SK_ColorWHITE);
canvas.drawBitmap(device_.accessBitmap(false), 0, 0, &copy_paint);
canvas.drawBitmap(device_->accessBitmap(false), 0, 0, &copy_paint);
return true;
}
void BackingStoreOSR::ScrollBackingStore(const gfx::Vector2d& delta,
const gfx::Rect& clip_rect,
const gfx::Size& view_size) {
SkIRect subset_rect = SkIRect::MakeXYWH(clip_rect.x(),
clip_rect.y(),
clip_rect.width(),
clip_rect.height());
device_.accessBitmap(true).scrollRect(&subset_rect, delta.x(), delta.y());
gfx::Rect pixel_rect = gfx::ToEnclosingRect(
gfx::ScaleRect(clip_rect, device_scale_factor_));
gfx::Vector2d pixel_delta = gfx::ToFlooredVector2d(
gfx::ScaleVector2d(delta, device_scale_factor_));
int x = std::min(pixel_rect.x(), pixel_rect.x() - pixel_delta.x());
int y = std::min(pixel_rect.y(), pixel_rect.y() - pixel_delta.y());
int w = pixel_rect.width() + abs(pixel_delta.x());
int h = pixel_rect.height() + abs(pixel_delta.y());
SkIRect rect = SkIRect::MakeXYWH(x, y, w, h);
device_->accessBitmap(true).scrollRect(&rect,
pixel_delta.x(),
pixel_delta.y());
}
const void* BackingStoreOSR::getPixels() const {
return const_cast<BackingStoreOSR*>(this)->device_.
return const_cast<BackingStoreOSR*>(this)->device_->
accessBitmap(false).getPixels();
}

View File

@ -19,6 +19,7 @@ class BackingStoreOSR : public content::BackingStore {
}
// BackingStore implementation.
virtual size_t MemorySize() OVERRIDE;
virtual void PaintToBackingStore(
content::RenderProcessHost* process,
TransportDIB::Id bitmap,
@ -33,17 +34,22 @@ class BackingStoreOSR : public content::BackingStore {
const gfx::Rect& clip_rect,
const gfx::Size& view_size) OVERRIDE;
void ScaleFactorChanged(float scale_factor);
const void* getPixels() const;
private:
// Can be instantiated only within CefRenderWidgetHostViewOSR.
friend class CefRenderWidgetHostViewOSR;
explicit BackingStoreOSR(content::RenderWidgetHost* widget,
const gfx::Size& size);
const gfx::Size& size, float scale_factor);
virtual ~BackingStoreOSR() {}
SkDevice device_;
SkCanvas canvas_;
scoped_ptr<SkDevice> device_;
scoped_ptr<SkCanvas> canvas_;
float device_scale_factor_;
DISALLOW_COPY_AND_ASSIGN(BackingStoreOSR);
};

View File

@ -47,7 +47,7 @@
#include "content/public/common/file_chooser_params.h"
#include "ui/shell_dialogs/selected_file_info.h"
#if defined(OS_WIN)
#if defined(OS_WIN) || defined(OS_MACOSX)
#include "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/browser/web_contents_view_osr.h"
#endif
@ -300,6 +300,9 @@ CefRefPtr<CefBrowser> CefBrowserHost::CreateBrowserSync(
scoped_refptr<CefBrowserInfo> info =
CefContentBrowserClient::Get()->CreateBrowserInfo();
info->set_window_rendering_disabled(
CefBrowserHostImpl::IsWindowRenderingDisabled(windowInfo));
DCHECK(!info->is_popup());
CefRefPtr<CefBrowserHostImpl> browser =
CefBrowserHostImpl::Create(windowInfo, new_settings, client, NULL, info,
@ -346,7 +349,7 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::Create(
// TODO(port): Implement this method to work on other platforms as part of
// off-screen rendering support.
#if defined(OS_WIN)
#if defined(OS_WIN) || defined(OS_MACOSX)
if (browser->IsWindowRenderingDisabled()) {
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(
@ -354,7 +357,7 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::Create(
if (view)
view->set_browser_impl(browser);
}
#endif // OS_WIN
#endif // defined(OS_WIN) || defined(OS_MACOSX)
if (client.get()) {
CefRefPtr<CefLifeSpanHandler> handler = client->GetLifeSpanHandler();
@ -667,6 +670,38 @@ void CefBrowserHostImpl::WasHidden(bool hidden) {
widget->WasShown();
}
void CefBrowserHostImpl::NotifyScreenInfoChanged() {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::NotifyScreenInfoChanged, this));
return;
}
if (!IsWindowRenderingDisabled()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
if (!web_contents())
return;
content::RenderWidgetHostView* view =
web_contents()->GetRenderViewHost()->GetView();
if (!view)
return;
#if defined(OS_WIN) || defined(OS_MACOSX)
CefRenderWidgetHostViewOSR* orview =
static_cast<CefRenderWidgetHostViewOSR*>(view);
orview->OnScreenInfoChanged();
#else
// TODO(port): Implement this method to work on other platforms as part of
// off-screen rendering support.
NOTREACHED();
#endif
}
void CefBrowserHostImpl::Invalidate(const CefRect& dirtyRect,
PaintElementType type) {
if (!IsWindowRenderingDisabled()) {
@ -683,7 +718,7 @@ void CefBrowserHostImpl::Invalidate(const CefRect& dirtyRect,
if (!web_contents())
return;
#if defined(OS_WIN)
#if defined(OS_WIN) || defined(OS_MACOSX)
content::RenderWidgetHostView* view =
web_contents()->GetRenderViewHost()->GetView();
CefRenderWidgetHostViewOSR* orview =
@ -716,7 +751,7 @@ void CefBrowserHostImpl::SendKeyEvent(const CefKeyEvent& event) {
if (widget)
widget->ForwardKeyboardEvent(web_event);
} else {
#if defined(OS_WIN)
#if defined(OS_WIN) || defined(OS_MACOSX)
if (!web_contents())
return;
content::RenderWidgetHostView* view =
@ -780,7 +815,7 @@ void CefBrowserHostImpl::SendMouseWheelEvent(const CefMouseEvent& event,
if (widget)
widget->ForwardWheelEvent(web_event);
} else {
#if defined(OS_WIN)
#if defined(OS_WIN) || defined(OS_MACOSX)
if (!web_contents())
return;
content::RenderWidgetHostView* view =
@ -834,7 +869,7 @@ void CefBrowserHostImpl::SendMouseEvent(const WebKit::WebMouseEvent& event) {
if (widget)
widget->ForwardMouseEvent(event);
} else {
#if defined(OS_WIN)
#if defined(OS_WIN) || defined(OS_MACOSX)
if (!web_contents())
return;
content::RenderWidgetHostView* view =

View File

@ -130,6 +130,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
virtual bool IsWindowRenderingDisabled() OVERRIDE;
virtual void WasResized() OVERRIDE;
virtual void WasHidden(bool hidden) OVERRIDE;
virtual void NotifyScreenInfoChanged() OVERRIDE;
virtual void Invalidate(const CefRect& dirtyRect,
PaintElementType type) OVERRIDE;
virtual void SendKeyEvent(const CefKeyEvent& event) OVERRIDE;
@ -430,6 +431,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
int deltaX, int deltaY);
void PlatformTranslateMouseEvent(WebKit::WebMouseEvent& web_event,
const CefMouseEvent& mouse_event);
int TranslateModifiers(uint32 cefKeyStates);
void SendMouseEvent(const WebKit::WebMouseEvent& web_event);

View File

@ -19,11 +19,13 @@
#include "content/public/common/file_chooser_params.h"
#include "grit/ui_strings.h"
#include "net/base/mime_util.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/mac/WebInputEventFactory.h"
#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
#include "ui/base/keycodes/keyboard_codes_posix.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/rect.h"
// Wrapper NSView for the native view. Necessary to destroy the browser when
// the view is deleted.
@interface CefBrowserHostView : NSView {
@ -142,7 +144,7 @@ void RunOpenFileDialog(const content::FileChooserParams& params,
NSView* view,
std::vector<base::FilePath>* files) {
NSOpenPanel* openPanel = [NSOpenPanel openPanel];
string16 title;
if (!params.title.empty()) {
title = params.title;
@ -201,7 +203,7 @@ bool RunSaveFileDialog(const content::FileChooserParams& params,
NSView* view,
base::FilePath* file) {
NSSavePanel* savePanel = [NSSavePanel savePanel];
string16 title;
if (!params.title.empty())
title = params.title;
@ -338,7 +340,9 @@ void CefBrowserHostImpl::PlatformSizeTo(int width, int height) {
}
CefWindowHandle CefBrowserHostImpl::PlatformGetWindowHandle() {
return window_info_.view;
return IsWindowRenderingDisabled() ?
window_info_.parent_view :
window_info_.view;
}
void CefBrowserHostImpl::PlatformHandleKeyboardEvent(
@ -372,49 +376,214 @@ void CefBrowserHostImpl::PlatformHandleExternalProtocol(const GURL& url) {
// static
bool CefBrowserHostImpl::IsWindowRenderingDisabled(const CefWindowInfo& info) {
// TODO(port): Implement this method as part of off-screen rendering support.
return false;
return info.window_rendering_disabled ? true : false;
}
static NSTimeInterval currentEventTimestamp() {
NSEvent* currentEvent = [NSApp currentEvent];
if (currentEvent)
return [currentEvent timestamp];
else {
// FIXME(API): In case there is no current event, the timestamp could be
// obtained by getting the time since the application started. This involves
// taking some more static functions from Chromium code.
// Another option is to have the timestamp as a field in CefEvent structures
// and let the client provide it.
return 0;
}
}
bool CefBrowserHostImpl::IsTransparent() {
return false;
return window_info_.transparent_painting != 0;
}
static NSUInteger NativeModifiers(int cef_modifiers) {
NSUInteger native_modifiers = 0;
if (cef_modifiers & EVENTFLAG_SHIFT_DOWN)
native_modifiers |= NSShiftKeyMask;
if (cef_modifiers & EVENTFLAG_CONTROL_DOWN)
native_modifiers |= NSControlKeyMask;
if (cef_modifiers & EVENTFLAG_ALT_DOWN)
native_modifiers |= NSAlternateKeyMask;
if (cef_modifiers & EVENTFLAG_COMMAND_DOWN)
native_modifiers |= NSCommandKeyMask;
if (cef_modifiers & EVENTFLAG_CAPS_LOCK_ON)
native_modifiers |= NSAlphaShiftKeyMask;
if (cef_modifiers & EVENTFLAG_NUM_LOCK_ON)
native_modifiers |= NSNumericPadKeyMask;
return native_modifiers;
}
void CefBrowserHostImpl::PlatformTranslateKeyEvent(
content::NativeWebKeyboardEvent& native_event,
const CefKeyEvent& event) {
// TODO(port): Implement this method as part of off-screen rendering support.
NOTIMPLEMENTED();
const CefKeyEvent& key_event) {
// Use a synthetic NSEvent in order to obtain the windowsKeyCode member from
// the NativeWebKeyboardEvent constructor. This is the only member which can
// not be easily translated (without hardcoding keyCodes)
// Determining whether a modifier key is left or right seems to be done
// through the key code as well.
NSEventType event_type;
if (key_event.character == 0 && key_event.unmodified_character == 0) {
// Check if both character and unmodified_characther are empty to determine
// if this was a NSFlagsChanged event.
// A dead key will have an empty character, but a non-empty unmodified
// character
event_type = NSFlagsChanged;
} else {
switch (key_event.type) {
case KEYEVENT_RAWKEYDOWN:
case KEYEVENT_KEYDOWN:
case KEYEVENT_CHAR:
event_type = NSKeyDown;
break;
case KEYEVENT_KEYUP:
event_type = NSKeyUp;
break;
}
}
NSString* charactersIgnoringModifiers = [[[NSString alloc]
initWithCharacters:&key_event.unmodified_character length:1]
autorelease];
NSString* characters = [[[NSString alloc]
initWithCharacters:&key_event.character length:1] autorelease];
NSEvent* synthetic_event =
[NSEvent keyEventWithType:event_type
location:NSMakePoint(0, 0)
modifierFlags:NativeModifiers(key_event.modifiers)
timestamp:currentEventTimestamp()
windowNumber:0
context:nil
characters:characters
charactersIgnoringModifiers:charactersIgnoringModifiers
isARepeat:NO
keyCode:key_event.native_key_code];
native_event = content::NativeWebKeyboardEvent(synthetic_event);
if (key_event.type == KEYEVENT_CHAR)
native_event.type = WebKit::WebInputEvent::Char;
native_event.isSystemKey = key_event.is_system_key;
}
void CefBrowserHostImpl::PlatformTranslateClickEvent(
WebKit::WebMouseEvent& ev,
WebKit::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
MouseButtonType type,
bool mouseUp, int clickCount) {
// TODO(port): Implement this method as part of off-screen rendering support.
NOTIMPLEMENTED();
PlatformTranslateMouseEvent(result, mouse_event);
switch (type) {
case MBT_LEFT:
result.type = mouseUp ? WebKit::WebInputEvent::MouseUp :
WebKit::WebInputEvent::MouseDown;
result.button = WebKit::WebMouseEvent::ButtonLeft;
break;
case MBT_MIDDLE:
result.type = mouseUp ? WebKit::WebInputEvent::MouseUp :
WebKit::WebInputEvent::MouseDown;
result.button = WebKit::WebMouseEvent::ButtonMiddle;
break;
case MBT_RIGHT:
result.type = mouseUp ? WebKit::WebInputEvent::MouseUp :
WebKit::WebInputEvent::MouseDown;
result.button = WebKit::WebMouseEvent::ButtonRight;
break;
default:
NOTREACHED();
}
result.clickCount = clickCount;
}
void CefBrowserHostImpl::PlatformTranslateMoveEvent(
WebKit::WebMouseEvent& ev,
WebKit::WebMouseEvent& result,
const CefMouseEvent& mouse_event,
bool mouseLeave) {
// TODO(port): Implement this method as part of off-screen rendering support.
NOTIMPLEMENTED();
PlatformTranslateMouseEvent(result, mouse_event);
if (!mouseLeave) {
result.type = WebKit::WebInputEvent::MouseMove;
if (mouse_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON)
result.button = WebKit::WebMouseEvent::ButtonLeft;
else if (mouse_event.modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON)
result.button = WebKit::WebMouseEvent::ButtonMiddle;
else if (mouse_event.modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON)
result.button = WebKit::WebMouseEvent::ButtonRight;
else
result.button = WebKit::WebMouseEvent::ButtonNone;
} else {
result.type = WebKit::WebInputEvent::MouseLeave;
result.button = WebKit::WebMouseEvent::ButtonNone;
}
result.clickCount = 0;
}
void CefBrowserHostImpl::PlatformTranslateWheelEvent(
WebKit::WebMouseWheelEvent& ev,
WebKit::WebMouseWheelEvent& result,
const CefMouseEvent& mouse_event,
int deltaX, int deltaY) {
// TODO(port): Implement this method as part of off-screen rendering support.
NOTIMPLEMENTED();
result = WebKit::WebMouseWheelEvent();
PlatformTranslateMouseEvent(result, mouse_event);
result.type = WebKit::WebInputEvent::MouseWheel;
static const double scrollbarPixelsPerCocoaTick = 40.0;
result.deltaX = deltaX;
result.deltaY = deltaY;
result.wheelTicksX = result.deltaX / scrollbarPixelsPerCocoaTick;
result.wheelTicksY = result.deltaY / scrollbarPixelsPerCocoaTick;
result.hasPreciseScrollingDeltas = true;
// Unless the phase and momentumPhase are passed in as parameters to this
// function, there is no way to know them
result.phase = WebKit::WebMouseWheelEvent::PhaseNone;
result.momentumPhase = WebKit::WebMouseWheelEvent::PhaseNone;
if (mouse_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON)
result.button = WebKit::WebMouseEvent::ButtonLeft;
else if (mouse_event.modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON)
result.button = WebKit::WebMouseEvent::ButtonMiddle;
else if (mouse_event.modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON)
result.button = WebKit::WebMouseEvent::ButtonRight;
else
result.button = WebKit::WebMouseEvent::ButtonNone;
}
void CefBrowserHostImpl::PlatformTranslateMouseEvent(
WebKit::WebMouseEvent& ev,
WebKit::WebMouseEvent& result,
const CefMouseEvent& mouse_event) {
// TODO(port): Implement this method as part of off-screen rendering support.
NOTIMPLEMENTED();
// position
result.x = mouse_event.x;
result.y = mouse_event.y;
result.windowX = result.x;
result.windowY = result.y;
result.globalX = result.x;
result.globalY = result.y;
if (IsWindowRenderingDisabled()) {
GetClient()->GetRenderHandler()->GetScreenPoint(GetBrowser(),
result.x, result.y,
result.globalX, result.globalY);
} else {
NSView* view = window_info_.parent_view;
if (view) {
NSRect bounds = [view bounds];
NSPoint view_pt = {result.x, bounds.size.height - result.y};
NSPoint window_pt = [view convertPoint:view_pt toView:nil];
NSPoint screen_pt = [[view window] convertBaseToScreen:window_pt];
result.globalX = screen_pt.x;
result.globalY = screen_pt.y;
}
}
// modifiers
result.modifiers |= TranslateModifiers(mouse_event.modifiers);
// timestamp - Mac OSX specific
result.timeStampSeconds = currentEventTimestamp();
}

View File

@ -8,6 +8,7 @@
CefBrowserInfo::CefBrowserInfo(int browser_id, bool is_popup)
: browser_id_(browser_id),
is_popup_(is_popup),
is_window_rendering_disabled_(false),
render_process_id_(MSG_ROUTING_NONE),
render_view_id_(MSG_ROUTING_NONE) {
DCHECK_GT(browser_id, 0);
@ -16,6 +17,10 @@ CefBrowserInfo::CefBrowserInfo(int browser_id, bool is_popup)
CefBrowserInfo::~CefBrowserInfo() {
}
void CefBrowserInfo::set_window_rendering_disabled(bool disabled) {
is_window_rendering_disabled_ = disabled;
}
void CefBrowserInfo::set_render_ids(
int render_process_id, int render_view_id) {
base::AutoLock lock_scope(lock_);

View File

@ -22,6 +22,11 @@ class CefBrowserInfo : public base::RefCountedThreadSafe<CefBrowserInfo> {
int browser_id() const { return browser_id_; };
bool is_popup() const { return is_popup_; }
bool is_window_rendering_disabled() const {
return is_window_rendering_disabled_;
}
void set_window_rendering_disabled(bool disabled);
void set_render_ids(int render_process_id, int render_view_id);
@ -36,6 +41,7 @@ class CefBrowserInfo : public base::RefCountedThreadSafe<CefBrowserInfo> {
private:
int browser_id_;
bool is_popup_;
bool is_window_rendering_disabled_;
base::Lock lock_;

View File

@ -82,6 +82,7 @@ void CefBrowserMessageFilter::OnGetNewBrowserInfo(
routing_id);
params->browser_id = info->browser_id();
params->is_popup = info->is_popup();
params->is_window_rendering_disabled = info->is_window_rendering_disabled();
}
void CefBrowserMessageFilter::OnCreateWindow(

View File

@ -38,7 +38,7 @@
#include "googleurl/src/gurl.h"
#include "ui/base/ui_base_switches.h"
#if defined(OS_WIN)
#if defined(OS_WIN) || defined(OS_MACOSX)
#include "libcef/browser/web_contents_view_osr.h"
#endif
@ -376,7 +376,7 @@ CefContentBrowserClient::OverrideCreateWebContentsView(
*render_view_host_delegate_view = NULL;
// TODO(port): Implement this method to work on other platforms as part of
// off-screen rendering support.
#if defined(OS_WIN)
#if defined(OS_WIN) || defined(OS_MACOSX)
CefBrowserContext* browserContext =
static_cast<CefBrowserContext*>(web_contents->GetBrowserContext());
@ -386,7 +386,7 @@ CefContentBrowserClient::OverrideCreateWebContentsView(
*render_view_host_delegate_view = view_or;
view = view_or;
}
#endif // OS_WIN
#endif // defined(OS_WIN) || defined(OS_MACOSX)
return view;
}

View File

@ -35,7 +35,9 @@ bool CefMenuCreatorRunnerMac::RunContextMenu(CefMenuCreator* manager) {
// [NSApp currentEvent] will return a valid event.
NSEvent* currentEvent = [NSApp currentEvent];
NSWindow* window = [parent_view window];
NSPoint position = [window mouseLocationOutsideOfEventStream];
NSTimeInterval eventTime = [currentEvent timestamp];
NSEvent* clickEvent = [NSEvent mouseEventWithType:NSRightMouseDown
location:position
@ -59,9 +61,33 @@ bool CefMenuCreatorRunnerMac::RunContextMenu(CefMenuCreator* manager) {
base::mac::ScopedSendingEvent sendingEventScoper;
// Show the menu. Blocks until the menu is dismissed.
[NSMenu popUpContextMenu:[menu_controller_ menu]
withEvent:clickEvent
forView:parent_view];
if (manager->browser()->IsWindowRenderingDisabled()) {
// Showing the menu in OSR is pretty much self contained, only using
// the initialized menu_controller_ in this function, and the scoped
// variables in this block.
int screenX = 0, screenY = 0;
CefRefPtr<CefRenderHandler> handler =
manager->browser()->GetClient()->GetRenderHandler();
if (!handler->GetScreenPoint(manager->browser(),
manager->params().x, manager->params().y,
screenX, screenY)) {
return false;
}
// Don't show the menu unless there is a parent native window to tie it to
if (!manager->browser()->GetWindowHandle())
return false;
NSPoint screen_position =
NSPointFromCGPoint(gfx::Point(screenX, screenY).ToCGPoint());
[[menu_controller_ menu] popUpMenuPositioningItem:nil
atLocation:screen_position
inView:nil];
} else {
[NSMenu popUpContextMenu:[menu_controller_ menu]
withEvent:clickEvent
forView:parent_view];
}
}
return true;

View File

@ -19,17 +19,40 @@
#endif
#include "webkit/glue/webcursor.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h"
namespace {
const float kDefaultScaleFactor = 1.0;
static WebKit::WebScreenInfo webScreenInfoFrom(const CefScreenInfo& src) {
WebKit::WebScreenInfo webScreenInfo;
webScreenInfo.deviceScaleFactor = src.device_scale_factor;
webScreenInfo.depth = src.depth;
webScreenInfo.depthPerComponent = src.depth_per_component;
webScreenInfo.isMonochrome = src.is_monochrome;
webScreenInfo.rect = WebKit::WebRect(src.rect.x, src.rect.y,
src.rect.width, src.rect.height);
webScreenInfo.availableRect = WebKit::WebRect(src.available_rect.x,
src.available_rect.y,
src.available_rect.width,
src.available_rect.height);
return webScreenInfo;
}
} // namespace
///////////////////////////////////////////////////////////////////////////////
// CefRenderWidgetHostViewOSR, public:
CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR(
content::RenderWidgetHost* widget)
: render_widget_host_(content::RenderWidgetHostImpl::From(widget)),
about_to_validate_and_paint_(false),
: weak_factory_(this),
render_widget_host_(content::RenderWidgetHostImpl::From(widget)),
parent_host_view_(NULL),
popup_host_view_(NULL),
weak_factory_(this) {
about_to_validate_and_paint_(false) {
DCHECK(render_widget_host_);
render_widget_host_->SetView(this);
@ -60,7 +83,7 @@ void CefRenderWidgetHostViewOSR::SetBounds(const gfx::Rect& rect) {
}
gfx::NativeView CefRenderWidgetHostViewOSR::GetNativeView() const {
return browser_impl_.get() ? browser_impl_->GetWindowHandle() : NULL;
return NULL;
}
gfx::NativeViewId CefRenderWidgetHostViewOSR::GetNativeViewId() const {
@ -165,6 +188,12 @@ void CefRenderWidgetHostViewOSR::UpdateCursor(const WebCursor& cursor) {
HCURSOR hCursor = web_cursor.GetCursor((HINSTANCE)hModule);
browser_impl_->GetClient()->GetRenderHandler()->OnCursorChange(
browser_impl_->GetBrowser(), hCursor);
#elif defined(OS_MACOSX)
// cursor is const, and GetNativeCursor is not
WebCursor web_cursor = cursor;
NSCursor* native_cursor = web_cursor.GetNativeCursor();
browser_impl_->GetClient()->GetRenderHandler()->OnCursorChange(
browser_impl_->GetBrowser(), native_cursor);
#else
// TODO(port): Implement this method to work on other platforms as part of
// off-screen rendering support.
@ -215,11 +244,37 @@ void CefRenderWidgetHostViewOSR::WillWmDestroy() {
}
#endif
void CefRenderWidgetHostViewOSR::GetScreenInfo(
WebKit::WebScreenInfo* results) {
#if defined(OS_WIN)
*results = WebKit::WebScreenInfoFactory::screenInfo(GetNativeView());
#endif
void CefRenderWidgetHostViewOSR::GetScreenInfo(WebKit::WebScreenInfo* results) {
if (!browser_impl_.get())
return;
CefScreenInfo screen_info(
kDefaultScaleFactor, 0, 0, false, CefRect(), CefRect());
CefRefPtr<CefRenderHandler> handler =
browser_impl_->client()->GetRenderHandler();
if (!handler->GetScreenInfo(browser_impl_.get(), screen_info) ||
screen_info.rect.width == 0 ||
screen_info.rect.height == 0 ||
screen_info.available_rect.width == 0 ||
screen_info.available_rect.height == 0) {
// If a screen rectangle was not provided, try using the view rectangle
// instead. Otherwise, popup views may be drawn incorrectly, or not at all.
CefRect screenRect;
if (!handler->GetViewRect(browser_impl_.get(), screenRect)) {
NOTREACHED();
screenRect = CefRect();
}
if (screen_info.rect.width == 0 && screen_info.rect.height == 0)
screen_info.rect = screenRect;
if (screen_info.available_rect.width == 0 &&
screen_info.available_rect.height == 0)
screen_info.available_rect = screenRect;
}
*results = webScreenInfoFrom(screen_info);
}
gfx::Rect CefRenderWidgetHostViewOSR::GetBoundsInRootWindow() {
@ -270,7 +325,7 @@ void CefRenderWidgetHostViewOSR::ScrollOffsetChanged() {
content::BackingStore* CefRenderWidgetHostViewOSR::AllocBackingStore(
const gfx::Size& size) {
return render_widget_host_ ?
new BackingStoreOSR(render_widget_host_, size) :
new BackingStoreOSR(render_widget_host_, size, GetDeviceScaleFactor()) :
NULL;
}
@ -550,3 +605,79 @@ void CefRenderWidgetHostViewOSR::SendMouseWheelEvent(
return;
render_widget_host_->ForwardWheelEvent(event);
}
void CefRenderWidgetHostViewOSR::OnScreenInfoChanged() {
if (!render_widget_host_)
return;
BackingStoreOSR* backing_store =
BackingStoreOSR::From(render_widget_host_->GetBackingStore(true));
if (backing_store)
backing_store->ScaleFactorChanged(GetDeviceScaleFactor());
// What could be taken from UpdateScreenInfo(window_) - updates the renderer
// cached rectangles
//render_widget_host_->SendScreenRects();
render_widget_host_->NotifyScreenInfoChanged();
// We might want to change the cursor scale factor here as well - see the
// cache for the current_cursor_, as passed by UpdateCursor from the renderer
// in the rwhv_aura (current_cursor_.SetScaleFactor)
}
float CefRenderWidgetHostViewOSR::GetDeviceScaleFactor() {
if (!browser_impl_.get())
return kDefaultScaleFactor;
CefScreenInfo screen_info(
kDefaultScaleFactor, 0, 0, false, CefRect(), CefRect());
if (!browser_impl_->GetClient()->GetRenderHandler()->GetScreenInfo(
browser_impl_->GetBrowser(), screen_info)) {
// Use the default
return kDefaultScaleFactor;
}
return screen_info.device_scale_factor;
}
#if defined(OS_MACOSX)
void CefRenderWidgetHostViewOSR::AboutToWaitForBackingStoreMsg() {
}
bool CefRenderWidgetHostViewOSR::PostProcessEventForPluginIme(
const content::NativeWebKeyboardEvent& event) {
return false;
}
#endif
#if defined(OS_MACOSX)
void CefRenderWidgetHostViewOSR::SetActive(bool active) {
}
void CefRenderWidgetHostViewOSR::SetTakesFocusOnlyOnMouseDown(bool flag) {
}
void CefRenderWidgetHostViewOSR::SetWindowVisibility(bool visible) {
}
void CefRenderWidgetHostViewOSR::WindowFrameChanged() {
}
void CefRenderWidgetHostViewOSR::ShowDefinitionForSelection() {
}
bool CefRenderWidgetHostViewOSR::SupportsSpeech() const {
return false;
}
void CefRenderWidgetHostViewOSR::SpeakSelection() {
}
bool CefRenderWidgetHostViewOSR::IsSpeaking() const {
return false;
}
void CefRenderWidgetHostViewOSR::StopSpeaking() {
}
#endif // defined(OS_MACOSX)

View File

@ -57,6 +57,19 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase {
virtual void Hide() OVERRIDE;
virtual bool IsShowing() OVERRIDE;
virtual gfx::Rect GetViewBounds() const OVERRIDE;
#if defined(OS_MACOSX)
virtual void SetActive(bool active) OVERRIDE;
virtual void SetTakesFocusOnlyOnMouseDown(bool flag) OVERRIDE;
virtual void SetWindowVisibility(bool visible) OVERRIDE;
virtual void WindowFrameChanged() OVERRIDE;
virtual void ShowDefinitionForSelection() OVERRIDE;
virtual bool SupportsSpeech() const OVERRIDE;
virtual void SpeakSelection() OVERRIDE;
virtual bool IsSpeaking() const OVERRIDE;
virtual void StopSpeaking() OVERRIDE;
#endif // defined(OS_MACOSX)
// RenderWidgetHostViewPort methods.
virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
@ -130,6 +143,13 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase {
virtual void SetClickthroughRegion(SkRegion* region) OVERRIDE;
#endif
#if defined(OS_MACOSX)
virtual void AboutToWaitForBackingStoreMsg() OVERRIDE;
virtual bool PostProcessEventForPluginIme(
const content::NativeWebKeyboardEvent& event) OVERRIDE;
#endif
// RenderWidgetHostViewBase methods.
virtual void SetBackground(const SkBitmap& background) OVERRIDE;
@ -142,6 +162,9 @@ class CefRenderWidgetHostViewOSR : public content::RenderWidgetHostViewBase {
void Paint(const std::vector<gfx::Rect>& copy_rects);
bool InstallTransparency();
void OnScreenInfoChanged();
float GetDeviceScaleFactor();
void CancelWidget();
void NotifyShowWidget();
void NotifyHideWidget();

View File

@ -150,6 +150,7 @@ IPC_SYNC_MESSAGE_CONTROL0_1(
IPC_STRUCT_BEGIN(CefProcessHostMsg_GetNewBrowserInfo_Params)
IPC_STRUCT_MEMBER(int, browser_id)
IPC_STRUCT_MEMBER(bool, is_popup)
IPC_STRUCT_MEMBER(bool, is_window_rendering_disabled)
IPC_STRUCT_END()
// Retrieve information about a newly created browser window.

View File

@ -431,6 +431,15 @@ void CefContentRendererClient::RenderViewCreated(
&params));
DCHECK_GT(params.browser_id, 0);
#if defined(OS_MACOSX)
// FIXME: It would be better if this API would be a callback from the
// WebKit layer, or if it would be exposed as an WebView instance method; the
// current implementation uses a static variable, and WebKit needs to be
// patched in order to make it work for each WebView instance
render_view->GetWebView()->setUseExternalPopupMenusThisInstance(
!params.is_window_rendering_disabled);
#endif
CefRefPtr<CefBrowserImpl> browser =
new CefBrowserImpl(render_view, params.browser_id, params.is_popup);
browsers_.insert(std::make_pair(render_view, browser));

View File

@ -348,6 +348,18 @@ void CEF_CALLBACK browser_host_was_hidden(struct _cef_browser_host_t* self,
hidden?true:false);
}
void CEF_CALLBACK browser_host_notify_screen_info_changed(
struct _cef_browser_host_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Execute
CefBrowserHostCppToC::Get(self)->NotifyScreenInfoChanged();
}
void CEF_CALLBACK browser_host_invalidate(struct _cef_browser_host_t* self,
const cef_rect_t* dirtyRect, enum cef_paint_element_type_t type) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -518,6 +530,8 @@ CefBrowserHostCppToC::CefBrowserHostCppToC(CefBrowserHost* cls)
browser_host_is_window_rendering_disabled;
struct_.struct_.was_resized = browser_host_was_resized;
struct_.struct_.was_hidden = browser_host_was_hidden;
struct_.struct_.notify_screen_info_changed =
browser_host_notify_screen_info_changed;
struct_.struct_.invalidate = browser_host_invalidate;
struct_.struct_.send_key_event = browser_host_send_key_event;
struct_.struct_.send_mouse_click_event = browser_host_send_mouse_click_event;

View File

@ -127,6 +127,41 @@ int CEF_CALLBACK render_handler_get_screen_point(
return _retval;
}
int CEF_CALLBACK render_handler_get_screen_info(
struct _cef_render_handler_t* self, cef_browser_t* browser,
struct _cef_screen_info_t* screen_info) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Verify param: browser; type: refptr_diff
DCHECK(browser);
if (!browser)
return 0;
// Verify param: screen_info; type: struct_byref
DCHECK(screen_info);
if (!screen_info)
return 0;
// Translate param: screen_info; type: struct_byref
CefScreenInfo screen_infoObj;
if (screen_info)
screen_infoObj.AttachTo(*screen_info);
// Execute
bool _retval = CefRenderHandlerCppToC::Get(self)->GetScreenInfo(
CefBrowserCToCpp::Wrap(browser),
screen_infoObj);
// Restore param: screen_info; type: struct_byref
if (screen_info)
screen_infoObj.DetachTo(*screen_info);
// Return type: bool
return _retval;
}
void CEF_CALLBACK render_handler_on_popup_show(
struct _cef_render_handler_t* self, cef_browser_t* browser, int show) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -239,6 +274,7 @@ CefRenderHandlerCppToC::CefRenderHandlerCppToC(CefRenderHandler* cls)
struct_.struct_.get_root_screen_rect = render_handler_get_root_screen_rect;
struct_.struct_.get_view_rect = render_handler_get_view_rect;
struct_.struct_.get_screen_point = render_handler_get_screen_point;
struct_.struct_.get_screen_info = render_handler_get_screen_info;
struct_.struct_.on_popup_show = render_handler_on_popup_show;
struct_.struct_.on_popup_size = render_handler_on_popup_size;
struct_.struct_.on_paint = render_handler_on_paint;

View File

@ -290,6 +290,16 @@ void CefBrowserHostCToCpp::WasHidden(bool hidden) {
hidden);
}
void CefBrowserHostCToCpp::NotifyScreenInfoChanged() {
if (CEF_MEMBER_MISSING(struct_, notify_screen_info_changed))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
struct_->notify_screen_info_changed(struct_);
}
void CefBrowserHostCToCpp::Invalidate(const CefRect& dirtyRect,
PaintElementType type) {
if (CEF_MEMBER_MISSING(struct_, invalidate))

View File

@ -57,6 +57,7 @@ class CefBrowserHostCToCpp
virtual bool IsWindowRenderingDisabled() OVERRIDE;
virtual void WasResized() OVERRIDE;
virtual void WasHidden(bool hidden) OVERRIDE;
virtual void NotifyScreenInfoChanged() OVERRIDE;
virtual void Invalidate(const CefRect& dirtyRect,
PaintElementType type) OVERRIDE;
virtual void SendKeyEvent(const CefKeyEvent& event) OVERRIDE;

View File

@ -82,6 +82,27 @@ bool CefRenderHandlerCToCpp::GetScreenPoint(CefRefPtr<CefBrowser> browser,
return _retval?true:false;
}
bool CefRenderHandlerCToCpp::GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) {
if (CEF_MEMBER_MISSING(struct_, get_screen_info))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: browser; type: refptr_diff
DCHECK(browser.get());
if (!browser.get())
return false;
// Execute
int _retval = struct_->get_screen_info(struct_,
CefBrowserCppToC::Wrap(browser),
&screen_info);
// Return type: bool
return _retval?true:false;
}
void CefRenderHandlerCToCpp::OnPopupShow(CefRefPtr<CefBrowser> browser,
bool show) {
if (CEF_MEMBER_MISSING(struct_, on_popup_show))

View File

@ -40,6 +40,8 @@ class CefRenderHandlerCToCpp
CefRect& rect) OVERRIDE;
virtual bool GetScreenPoint(CefRefPtr<CefBrowser> browser, int viewX,
int viewY, int& screenX, int& screenY) OVERRIDE;
virtual bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) OVERRIDE;
virtual void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) OVERRIDE;
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) OVERRIDE;

View File

@ -41,6 +41,11 @@ patches = [
'name': 'gyp_331',
'path': '../tools/gyp/pylib/',
},
{
# Enable popups in offscreen rendering on Mac
'name': 'webkit_popups',
'path': '../third_party/WebKit/Source/WebKit/chromium/',
},
{
# http://code.google.com/p/chromiumembedded/issues/detail?id=364
'name': 'spi_webcore_364',

View File

@ -0,0 +1,76 @@
Index: src/WebViewImpl.cpp
===================================================================
--- src/WebViewImpl.cpp (revision 148366)
+++ src/WebViewImpl.cpp (working copy)
@@ -403,6 +403,7 @@
, m_fakeDoubleTapPageScaleFactor(0)
, m_fakeDoubleTapUseAnchor(false)
, m_contextMenuAllowed(false)
+ , m_shouldUseExternalPopupMenus(shouldUseExternalPopupMenus)
, m_doingDragAndDrop(false)
, m_ignoreInputEvents(false)
, m_suppressNextKeypressEvent(false)
@@ -3688,9 +3689,14 @@
updateLayerTreeViewport();
}
+void WebViewImpl::setUseExternalPopupMenusThisInstance(bool useExternalPopupMenus)
+{
+ m_shouldUseExternalPopupMenus = useExternalPopupMenus;
+}
+
bool WebViewImpl::useExternalPopupMenus()
{
- return shouldUseExternalPopupMenus;
+ return m_shouldUseExternalPopupMenus;
}
void WebViewImpl::setEmulatedTextZoomFactor(float textZoomFactor)
Index: src/WebViewImpl.h
===================================================================
--- src/WebViewImpl.h (revision 148366)
+++ src/WebViewImpl.h (working copy)
@@ -423,7 +423,8 @@
// Returns true if popup menus should be rendered by the browser, false if
// they should be rendered by WebKit (which is the default).
- static bool useExternalPopupMenus();
+ void setUseExternalPopupMenusThisInstance(bool);
+ bool useExternalPopupMenus();
bool contextMenuAllowed() const
{
@@ -752,6 +753,8 @@
bool m_contextMenuAllowed;
+ bool m_shouldUseExternalPopupMenus;
+
bool m_doingDragAndDrop;
bool m_ignoreInputEvents;
Index: src/ChromeClientImpl.cpp
===================================================================
--- src/ChromeClientImpl.cpp (revision 148366)
+++ src/ChromeClientImpl.cpp (working copy)
@@ -1024,7 +1024,7 @@
PassRefPtr<PopupMenu> ChromeClientImpl::createPopupMenu(PopupMenuClient* client) const
{
- if (WebViewImpl::useExternalPopupMenus())
+ if (m_webView->useExternalPopupMenus())
return adoptRef(new ExternalPopupMenu(client, m_webView->client()));
return adoptRef(new PopupMenuChromium(client));
Index: public/WebView.h
===================================================================
--- public/WebView.h (revision 148366)
+++ public/WebView.h (working copy)
@@ -413,6 +413,7 @@
// Sets whether select popup menus should be rendered by the browser.
WEBKIT_EXPORT static void setUseExternalPopupMenus(bool);
+ virtual void setUseExternalPopupMenusThisInstance(bool) = 0;
// Visited link state --------------------------------------------------

View File

@ -33,6 +33,7 @@ IDS_DIALOGS BINARY "res\\dialogs.html"
IDS_DOMACCESS BINARY "res\\domaccess.html"
IDS_LOCALSTORAGE BINARY "res\\localstorage.html"
IDS_LOGO BINARY "res\\logo.png"
IDS_OSRTEST BINARY "res\\osr_test.html"
IDS_OTHER_TESTS BINARY "res\\other_tests.html"
IDS_PERFORMANCE BINARY "res\\performance.html"
IDS_TRANSPARENCY BINARY "res\\transparency.html"
@ -54,7 +55,7 @@ IDI_SMALL ICON "res\small.ico"
// Menu
//
IDC_CEFCLIENT MENU
IDC_CEFCLIENT MENU
BEGIN
POPUP "&File"
BEGIN
@ -86,7 +87,7 @@ END
// Accelerator
//
IDC_CEFCLIENT ACCELERATORS
IDC_CEFCLIENT ACCELERATORS
BEGIN
"?", IDM_ABOUT, ASCII, ALT
"/", IDM_ABOUT, ASCII, ALT
@ -116,12 +117,12 @@ END
// TEXTINCLUDE
//
1 TEXTINCLUDE
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
2 TEXTINCLUDE
BEGIN
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""windows.h""\r\n"
@ -129,7 +130,7 @@ BEGIN
"\0"
END
3 TEXTINCLUDE
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
@ -143,7 +144,7 @@ END
// String Table
//
STRINGTABLE
STRINGTABLE
BEGIN
IDS_APP_TITLE "cefclient"
IDC_CEFCLIENT "CEFCLIENT"

View File

@ -11,7 +11,9 @@
#include "include/cef_browser.h"
#include "include/cef_frame.h"
#include "include/cef_runnable.h"
#include "cefclient/cefclient_osr_widget_mac.h"
#include "cefclient/client_handler.h"
#include "cefclient/client_switches.h"
#include "cefclient/resource_util.h"
#include "cefclient/scheme_test.h"
#include "cefclient/string_util.h"
@ -19,6 +21,15 @@
// The global ClientHandler reference.
extern CefRefPtr<ClientHandler> g_handler;
class MainBrowserProvider : public OSRBrowserProvider {
virtual CefRefPtr<CefBrowser> GetBrowser() {
if (g_handler.get())
return g_handler->GetBrowser();
return NULL;
}
} g_main_browser_provider;
char szWorkingDir[512]; // The current working directory
// Sizes for URL bar layout
@ -93,15 +104,15 @@ const int kWindowHeight = 600;
- (IBAction)takeURLStringValueFrom:(NSTextField *)sender {
if (!g_handler.get() || !g_handler->GetBrowserId())
return;
NSString *url = [sender stringValue];
// if it doesn't already have a prefix, add http. If we can't parse it,
// just don't bother rather than making things worse.
NSURL* tempUrl = [NSURL URLWithString:url];
if (tempUrl && ![tempUrl scheme])
url = [@"http://" stringByAppendingString:url];
std::string urlStr = [url UTF8String];
g_handler->GetBrowser()->GetMainFrame()->LoadURL(urlStr);
}
@ -176,7 +187,7 @@ const int kWindowHeight = 600;
}
// Deletes itself.
- (void)cleanup:(id)window {
- (void)cleanup:(id)window {
[self release];
}
@ -215,10 +226,10 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
- (void)createApp:(id)object {
[NSApplication sharedApplication];
[NSBundle loadNibNamed:@"MainMenu" owner:NSApp];
// Set the delegate for application events.
[NSApp setDelegate:self];
// Add the Tests menu.
NSMenu* menubar = [NSApp mainMenu];
NSMenuItem *testItem = [[[NSMenuItem alloc] initWithTitle:@"Tests"
@ -260,10 +271,10 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
keyEquivalent:@""];
[testItem setSubmenu:testMenu];
[menubar addItem:testItem];
// Create the delegate for control and browser window events.
ClientWindowDelegate* delegate = [[ClientWindowDelegate alloc] init];
// Create the main application window.
NSRect screen_rect = [[NSScreen mainScreen] visibleFrame];
NSRect window_rect = { {0, screen_rect.size.height - kWindowHeight},
@ -332,7 +343,22 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
CefWindowInfo window_info;
CefBrowserSettings settings;
window_info.SetAsChild(contentView, 0, 0, kWindowWidth, kWindowHeight);
if (AppIsOffScreenRenderingEnabled()) {
CefRefPtr<CefCommandLine> cmd_line = AppGetCommandLine();
bool transparent =
cmd_line->HasSwitch(cefclient::kTransparentPaintingEnabled);
CefRefPtr<OSRWindow> osr_window =
OSRWindow::Create(&g_main_browser_provider, transparent, contentView,
CefRect(0, 0, kWindowWidth, kWindowHeight));
window_info.SetAsOffScreen(osr_window->GetWindowHandle());
window_info.SetTransparentPainting(transparent);
g_handler->SetOSRHandler(osr_window->GetRenderHandler().get());
} else {
// Initialize window info to the defaults for a child window.
window_info.SetAsChild(contentView, 0, 0, kWindowWidth, kWindowHeight);
}
CefBrowserHost::CreateBrowser(window_info, g_handler.get(),
g_handler->GetStartupURL(), settings);
@ -407,7 +433,7 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
RunOtherTests(g_handler->GetBrowser());
}
// Called when the applications Quit menu item is selected.
// Called when the application's Quit menu item is selected.
- (NSApplicationTerminateReply)applicationShouldTerminate:
(NSApplication *)sender {
// Request that all browser windows close.
@ -445,7 +471,7 @@ int main(int argc, char* argv[]) {
// Initialize the ClientApplication instance.
[ClientApplication sharedApplication];
// Parse command line arguments.
AppInitCommandLine(argc, argv);

View File

@ -0,0 +1,125 @@
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
#ifndef CEF_TESTS_CEFCLIENT_CEFCLIENT_OSR_WIDGET_MAC_H_
#define CEF_TESTS_CEFCLIENT_CEFCLIENT_OSR_WIDGET_MAC_H_
#include "include/cef_client.h"
#include "cefclient/client_handler.h"
class ClientOSRenderer;
class OSRBrowserProvider {
public:
virtual CefRefPtr<CefBrowser> GetBrowser() =0;
protected:
virtual ~OSRBrowserProvider() {}
};
// The client OpenGL view.
@interface ClientOpenGLView : NSOpenGLView {
@public
NSTrackingArea* tracking_area_;
OSRBrowserProvider* browser_provider_;
ClientOSRenderer* renderer_;
NSPoint last_mouse_pos_;
NSPoint cur_mouse_pos_;
bool rotating_;
bool was_last_mouse_down_on_view_;
}
- (id)initWithFrame:(NSRect)frame andTransparency:(bool)transparency;
- (NSPoint)getClickPointForEvent:(NSEvent*)event;
- (void)getKeyEvent:(CefKeyEvent&)keyEvent forEvent:(NSEvent*)event;
- (void)getMouseEvent:(CefMouseEvent&)mouseEvent forEvent:(NSEvent*)event;
- (int)getModifiersForEvent:(NSEvent*)event;
- (BOOL)isKeyUpEvent:(NSEvent*)event;
- (BOOL)isKeyPadEvent:(NSEvent*)event;
- (CefRefPtr<CefBrowser>)getBrowser;
@end
// Handler for off-screen rendering windows.
class ClientOSRHandler : public ClientHandler::RenderHandler {
public:
explicit ClientOSRHandler(ClientOpenGLView* view,
OSRBrowserProvider* browser_provider);
virtual ~ClientOSRHandler();
void Disconnect();
// ClientHandler::RenderHandler
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
// CefRenderHandler methods
virtual bool GetViewRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) OVERRIDE;
virtual bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
int viewX,
int viewY,
int& screenX,
int& screenY) OVERRIDE;
virtual bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) OVERRIDE;
virtual void OnPopupShow(CefRefPtr<CefBrowser> browser,
bool show) OVERRIDE;
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) OVERRIDE;
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
PaintElementType type,
const RectList& dirtyRects,
const void* buffer,
int width, int height) OVERRIDE;
virtual void OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor) OVERRIDE;
CefWindowHandle view() { return view_; }
private:
void SetLoading(bool isLoading);
ClientOpenGLView* view_;
bool painting_popup_;
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(ClientOSRHandler);
};
class OSRWindow {
public:
static CefRefPtr<OSRWindow> Create(OSRBrowserProvider* browser_provider,
bool transparent,
CefWindowHandle parentView,
const CefRect& frame);
CefRefPtr<ClientHandler::RenderHandler> GetRenderHandler() {
return render_client.get();
}
CefWindowHandle GetWindowHandle() { return view_; }
private:
OSRWindow(OSRBrowserProvider* browser_provider,
bool transparent,
CefWindowHandle parentView,
const CefRect& frame);
~OSRWindow();
CefRefPtr<ClientOSRHandler> render_client;
CefWindowHandle view_;
IMPLEMENT_REFCOUNTING(OSRWindow);
};
#endif // CEF_TESTS_CEFCLIENT_CEFCLIENT_OSR_WIDGET_MAC_H_

View File

@ -0,0 +1,905 @@
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
#import <Cocoa/Cocoa.h>
#include <OpenGL/gl.h>
#include "cefclient/cefclient_osr_widget_mac.h"
#include "include/cef_browser.h"
#include "include/cef_client.h"
#include "cefclient/cefclient.h"
#include "cefclient/osrenderer.h"
#include "cefclient/resource_util.h"
#include "cefclient/util.h"
@interface ClientOpenGLView ()
- (float)getDeviceScaleFactor;
- (void)windowDidChangeBackingProperties:(NSNotification*)notification;
- (bool) isOverPopupWidgetX: (int) x andY: (int) y;
- (void) applyPopupOffsetToX: (int&) x andY: (int&) y;
- (int) getPopupXOffset;
- (int) getPopupYOffset;
- (void) sendMouseClick: (NSEvent *)event
button: (CefBrowserHost::MouseButtonType)type
isUp: (bool)isUp;
- (void) convertRects: (const CefRenderHandler::RectList&) rects
toBackingRects: (CefRenderHandler::RectList*) scaled_rects
andSize: (const NSSize) size
toBackingSize: (NSSize*) scaled_size;
- (CefRect) convertRectToBackingInternal: (const CefRect&) rect;
- (CefRect) convertRectFromBackingInternal: (const CefRect&) rect;
@property (readwrite, atomic) bool was_last_mouse_down_on_view;
@end
namespace {
static CefRect convertRect(const NSRect& target, const NSRect& frame) {
NSRect rect = target;
rect.origin.y = NSMaxY(frame) - NSMaxY(target);
return CefRect(rect.origin.x,
rect.origin.y,
rect.size.width,
rect.size.height);
}
} // namespace
ClientOSRHandler::ClientOSRHandler(ClientOpenGLView* view,
OSRBrowserProvider* browser_provider)
: view_(view),
painting_popup_(false) {
[view_ retain];
view_->browser_provider_ = browser_provider;
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
__MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
// Do not override the delegate; the mac client already does that
if ([view_ respondsToSelector:@selector(backingScaleFactor:)]) {
[[NSNotificationCenter defaultCenter]
addObserver:view_
selector:@selector(windowDidChangeBackingProperties:)
name:NSWindowDidChangeBackingPropertiesNotification
object:[view_ window]];
}
#endif
}
ClientOSRHandler:: ~ClientOSRHandler() {
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
__MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if ([view_ respondsToSelector:@selector(backingScaleFactor:)]) {
[[NSNotificationCenter defaultCenter]
removeObserver:view_
name:NSWindowDidChangeBackingPropertiesNotification
object:[view_ window]];
}
#endif
}
void ClientOSRHandler::Disconnect() {
[view_ release];
view_ = nil;
}
// CefRenderHandler methods
void ClientOSRHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
if (view_)
view_->browser_provider_ = NULL;
}
bool ClientOSRHandler::GetViewRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) {
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;
}
bool ClientOSRHandler::GetScreenPoint(CefRefPtr<CefBrowser> browser,
int viewX,
int viewY,
int& screenX,
int& screenY) {
REQUIRE_UI_THREAD();
if (!view_)
return false;
// Convert the point from view coordinates to actual screen coordinates.
NSRect bounds = [view_ bounds];
NSPoint view_pt = NSMakePoint(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;
}
bool ClientOSRHandler::GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) {
REQUIRE_UI_THREAD();
if (!view_)
return false;
NSWindow* window = [view_ window];
if (!window)
return false;
screen_info.device_scale_factor = [view_ getDeviceScaleFactor];
NSScreen* screen = [window screen];
if (!screen)
screen = [NSScreen deepestScreen];
screen_info.depth = NSBitsPerPixelFromDepth([screen depth]);
screen_info.depth_per_component = NSBitsPerSampleFromDepth([screen depth]);
screen_info.is_monochrome =
[[screen colorSpace] colorSpaceModel] == NSGrayColorSpaceModel;
// screen_info.is_monochrome = true;
screen_info.rect = convertRect([screen frame], [screen frame]);
screen_info.available_rect =
convertRect([screen visibleFrame], [screen frame]);
return true;
}
void ClientOSRHandler::OnPopupShow(CefRefPtr<CefBrowser> browser,
bool show) {
REQUIRE_UI_THREAD();
if (!view_)
return;
if (!show) {
CefRect client_popup_rect = view_->renderer_->popup_rect();
// Clear the popup rectangles, so that the paint triggered by Invalidate
// will not repaint the popup content over the OpenGL view.
view_->renderer_->ClearPopupRects();
CefRect scaled_rect =
[view_ convertRectFromBackingInternal:client_popup_rect];
browser->GetHost()->Invalidate(scaled_rect, PET_VIEW);
}
view_->renderer_->OnPopupShow(browser, show);
}
void ClientOSRHandler::OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) {
REQUIRE_UI_THREAD();
if (!view_)
return;
CefRect scaled_rect = [view_ convertRectToBackingInternal:rect];
view_->renderer_->OnPopupSize(browser, scaled_rect);
}
void ClientOSRHandler::OnPaint(CefRefPtr<CefBrowser> browser,
PaintElementType type,
const RectList& dirtyRects,
const void* buffer,
int width, int height) {
REQUIRE_UI_THREAD();
if (!view_)
return;
if (painting_popup_) {
RectList scaled_dirty_rects;
NSSize scaled_size = NSMakeSize(0, 0);
[view_ convertRects:dirtyRects
toBackingRects:&scaled_dirty_rects
andSize:NSMakeSize(width, height)
toBackingSize:&scaled_size];
view_->renderer_->OnPaint(browser, type, scaled_dirty_rects, buffer,
scaled_size.width, scaled_size.height);
return;
}
NSOpenGLContext* context = [view_ openGLContext];
[context makeCurrentContext];
RectList scaled_dirty_rects;
NSSize scaled_size = NSMakeSize(0, 0);
[view_ convertRects:dirtyRects
toBackingRects:&scaled_dirty_rects
andSize:NSMakeSize(width, height)
toBackingSize:&scaled_size];
view_->renderer_->OnPaint(browser, type, scaled_dirty_rects, buffer,
scaled_size.width, scaled_size.height);
if (type == PET_VIEW && !view_->renderer_->popup_rect().IsEmpty()) {
painting_popup_ = true;
CefRect client_popup_rect(0, 0,
view_->renderer_->popup_rect().width,
view_->renderer_->popup_rect().height);
CefRect scaled_popup_rect =
[view_ convertRectFromBackingInternal:client_popup_rect];
browser->GetHost()->Invalidate(scaled_popup_rect, PET_POPUP);
painting_popup_ = false;
}
view_->renderer_->Render();
[context flushBuffer];
}
void ClientOSRHandler::OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor) {
REQUIRE_UI_THREAD();
[cursor set];
}
void ClientOSRHandler::SetLoading(bool isLoading) {
}
@implementation ClientOpenGLView
@synthesize was_last_mouse_down_on_view = was_last_mouse_down_on_view_;
- (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_];
}
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
__MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if ([self respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
// enable HiDPI buffer
[self setWantsBestResolutionOpenGLSurface:YES];
}
#endif
return self;
}
- (void)dealloc {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (browser) {
static_cast<ClientOSRHandler*>(
browser->GetHost()->GetClient()->GetRenderHandler().get())->Disconnect();
browser->GetHost()->CloseBrowser(true);
browser = NULL;
}
if (renderer_)
delete renderer_;
[super dealloc];
}
- (CefRefPtr<CefBrowser>)getBrowser {
return browser_provider_->GetBrowser();
}
- (void)setFrame:(NSRect)frameRect {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (!browser)
return;
[super setFrame:frameRect];
browser->GetHost()->WasResized();
}
- (void) sendMouseClick:(NSEvent *)event
button: (CefBrowserHost::MouseButtonType)type
isUp: (bool)isUp {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (!browser)
return;
CefMouseEvent mouseEvent;
[self getMouseEvent: mouseEvent forEvent: event];
NSPoint point = [self getClickPointForEvent:event];
if (!isUp)
self.was_last_mouse_down_on_view = ![self isOverPopupWidgetX: point.x
andY: point.y];
else if (self.was_last_mouse_down_on_view &&
[self isOverPopupWidgetX:point.x andY: point.y] &&
([self getPopupXOffset] || [self getPopupYOffset])) {
return;
}
browser->GetHost()->SendMouseClickEvent(mouseEvent,
type,
isUp,
[event clickCount]);
}
- (void)mouseDown:(NSEvent *)event {
[self sendMouseClick: event button:MBT_LEFT isUp:false];
}
- (void)rightMouseDown:(NSEvent *)event {
if ([event modifierFlags] & NSShiftKeyMask) {
// Start rotation effect.
last_mouse_pos_ = cur_mouse_pos_ = [self getClickPointForEvent:event];
rotating_ = true;
return;
}
[self sendMouseClick: event button:MBT_RIGHT isUp:false];
}
- (void)otherMouseDown:(NSEvent *)event {
[self sendMouseClick: event button:MBT_MIDDLE isUp:false];
}
- (void)mouseUp:(NSEvent *)event {
[self sendMouseClick: event button: MBT_LEFT isUp: true];
}
- (void)rightMouseUp:(NSEvent *)event {
if (rotating_) {
// End rotation effect.
renderer_->SetSpin(0, 0);
rotating_ = false;
[self setNeedsDisplay:YES];
return;
}
[self sendMouseClick: event button: MBT_RIGHT isUp: true];
}
- (void)otherMouseUp:(NSEvent *)event {
[self sendMouseClick: event button: MBT_MIDDLE isUp: true];
}
- (void)mouseMoved:(NSEvent *)event {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (!browser)
return;
if (rotating_) {
// Apply rotation effect.
cur_mouse_pos_ = [self getClickPointForEvent:event];;
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;
}
CefMouseEvent mouseEvent;
[self getMouseEvent: mouseEvent forEvent: event];
browser->GetHost()->SendMouseMoveEvent(mouseEvent, 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 {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (!browser)
return;
CefMouseEvent mouseEvent;
[self getMouseEvent: mouseEvent forEvent: event];
browser->GetHost()->SendMouseMoveEvent(mouseEvent, true);
}
- (void)keyDown:(NSEvent *)event {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (!browser)
return;
CefKeyEvent keyEvent;
[self getKeyEvent:keyEvent forEvent:event];
keyEvent.type = KEYEVENT_KEYDOWN;
browser->GetHost()->SendKeyEvent(keyEvent);
if ([event modifierFlags] & (NSNumericPadKeyMask | NSFunctionKeyMask)) {
// Don't send a Char event for non-char keys like arrows, function keys and
// clear.
switch (keyEvent.native_key_code) {
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;
}
}
keyEvent.type = KEYEVENT_CHAR;
browser->GetHost()->SendKeyEvent(keyEvent);
}
- (void)keyUp:(NSEvent *)event {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (!browser)
return;
CefKeyEvent keyEvent;
[self getKeyEvent:keyEvent forEvent:event];
keyEvent.type = KEYEVENT_KEYUP;
browser->GetHost()->SendKeyEvent(keyEvent);
}
- (void)flagsChanged:(NSEvent *)event {
if ([self isKeyUpEvent:event])
[self keyUp:event];
else
[self keyDown:event];
}
- (void)scrollWheel:(NSEvent *)event {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (!browser)
return;
CGEventRef cgEvent = [event CGEvent];
ASSERT(cgEvent);
int deltaX =
CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis2);
int deltaY =
CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1);
CefMouseEvent mouseEvent;
[self getMouseEvent: mouseEvent forEvent: event];
browser->GetHost()->SendMouseWheelEvent(mouseEvent, deltaX, deltaY);
}
- (BOOL)canBecomeKeyView {
CefRefPtr<CefBrowser> browser = [self getBrowser];
return (browser != NULL);
}
- (BOOL)acceptsFirstResponder {
CefRefPtr<CefBrowser> browser = [self getBrowser];
return (browser != NULL);
}
- (BOOL)becomeFirstResponder {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (browser) {
browser->GetHost()->SendFocusEvent(true);
return [super becomeFirstResponder];
}
return NO;
}
- (BOOL)resignFirstResponder {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (browser) {
browser->GetHost()->SendFocusEvent(false);
return [super resignFirstResponder];
}
return NO;
}
- (void)undo:(id)sender {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (browser)
browser->GetFocusedFrame()->Undo();
}
- (void)redo:(id)sender {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (browser)
browser->GetFocusedFrame()->Redo();
}
- (void)cut:(id)sender {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (browser)
browser->GetFocusedFrame()->Cut();
}
- (void)copy:(id)sender {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (browser)
browser->GetFocusedFrame()->Copy();
}
- (void)paste:(id)sender {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (browser)
browser->GetFocusedFrame()->Paste();
}
- (void)delete:(id)sender {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (browser)
browser->GetFocusedFrame()->Delete();
}
- (void)selectAll:(id)sender {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (browser)
browser->GetFocusedFrame()->SelectAll();
}
- (NSPoint)getClickPointForEvent:(NSEvent*)event {
NSPoint windowLocal = [event locationInWindow];
NSPoint contentLocal = [self convertPoint:windowLocal fromView:nil];
NSPoint point;
point.x = contentLocal.x;
point.y = [self frame].size.height - contentLocal.y; // Flip y.
return point;
}
- (void)getKeyEvent:(CefKeyEvent &)keyEvent forEvent:(NSEvent *)event {
if ([event type] == NSKeyDown || [event type] == NSKeyUp) {
NSString* s = [event characters];
if ([s length] > 0)
keyEvent.character = [s characterAtIndex:0];
s = [event charactersIgnoringModifiers];
if ([s length] > 0)
keyEvent.unmodified_character = [s characterAtIndex:0];
}
if ([event type] == NSFlagsChanged) {
keyEvent.character = 0;
keyEvent.unmodified_character = 0;
}
keyEvent.native_key_code = [event keyCode];
keyEvent.modifiers = [self getModifiersForEvent:event];
}
- (void)getMouseEvent:(CefMouseEvent&)mouseEvent forEvent:(NSEvent*)event {
NSPoint point = [self getClickPointForEvent:event];
mouseEvent.x = point.x;
mouseEvent.y = point.y;
if ([self isOverPopupWidgetX:mouseEvent.x andY: mouseEvent.y]) {
[self applyPopupOffsetToX:mouseEvent.x andY: mouseEvent.y];
}
mouseEvent.modifiers = [self getModifiersForEvent:event];
}
- (int)getModifiersForEvent:(NSEvent*)event {
int modifiers = 0;
if ([event modifierFlags] & NSControlKeyMask)
modifiers |= EVENTFLAG_CONTROL_DOWN;
if ([event modifierFlags] & NSShiftKeyMask)
modifiers |= EVENTFLAG_SHIFT_DOWN;
if ([event modifierFlags] & NSAlternateKeyMask)
modifiers |= EVENTFLAG_ALT_DOWN;
if ([event modifierFlags] & NSCommandKeyMask)
modifiers |= EVENTFLAG_COMMAND_DOWN;
if ([event modifierFlags] & NSAlphaShiftKeyMask)
modifiers |= EVENTFLAG_CAPS_LOCK_ON;
if ([event type] == NSKeyUp ||
[event type] == NSKeyDown ||
[event type] == NSFlagsChanged) {
// Only perform this check for key events
if ([self isKeyPadEvent:event])
modifiers |= EVENTFLAG_IS_KEY_PAD;
}
// OS X does not have a modifier for NumLock, so I'm not entirely sure how to
// set EVENTFLAG_NUM_LOCK_ON;
//
// There is no EVENTFLAG for the function key either.
// Mouse buttons
switch ([event type]) {
case NSLeftMouseDragged:
case NSLeftMouseDown:
case NSLeftMouseUp:
modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
break;
case NSRightMouseDragged:
case NSRightMouseDown:
case NSRightMouseUp:
modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
break;
case NSOtherMouseDragged:
case NSOtherMouseDown:
case NSOtherMouseUp:
modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
break;
}
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;
}
- (void)windowDidChangeBackingProperties:(NSNotification*)notification {
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
__MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
// This delegate method is only called on 10.7 and later, so don't worry about
// other backing changes calling it on 10.6 or earlier
CGFloat newBackingScaleFactor = [self getDeviceScaleFactor];
NSNumber* oldBackingScaleFactor =
[[notification userInfo] objectForKey:NSBackingPropertyOldScaleFactorKey];
if (newBackingScaleFactor != [oldBackingScaleFactor doubleValue]) {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (!browser)
return;
browser->GetHost()->NotifyScreenInfoChanged();
}
#endif
}
- (void)drawRect: (NSRect) dirtyRect {
// The Invalidate below fixes flicker when resizing
if ([self inLiveResize]) {
CefRefPtr<CefBrowser> browser = [self getBrowser];
if (!browser)
return;
NSRect b = [self bounds];
CefRect boundsRect = CefRect((int)b.origin.x,
(int)b.origin.y,
(int)b.size.width,
(int)b.size.height);
browser->GetHost()->Invalidate(boundsRect, PET_VIEW);
}
}
// Utility - private
- (float)getDeviceScaleFactor {
float deviceScaleFactor = 1;
NSWindow* window = [self window];
if (!window)
return deviceScaleFactor;
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
__MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if ([window respondsToSelector:@selector(backingScaleFactor)])
deviceScaleFactor = [window backingScaleFactor];
else
#endif
deviceScaleFactor = [window userSpaceScaleFactor];
return deviceScaleFactor;
}
- (bool) isOverPopupWidgetX: (int) x andY: (int) y {
CefRect rc = [self convertRectFromBackingInternal:renderer_->popup_rect()];
int popup_right = rc.x + rc.width;
int popup_bottom = rc.y + rc.height;
return (x >= rc.x) && (x < popup_right) &&
(y >= rc.y) && (y < popup_bottom);
}
- (int) getPopupXOffset {
int original_x =
[self convertRectFromBackingInternal:renderer_->original_popup_rect()].x;
int popup_x =
[self convertRectFromBackingInternal:renderer_->popup_rect()].x;
return original_x - popup_x;
}
- (int) getPopupYOffset {
int original_y =
[self convertRectFromBackingInternal:renderer_->original_popup_rect()].y;
int popup_y =
[self convertRectFromBackingInternal:renderer_->popup_rect()].y;
return original_y - popup_y;
}
- (void) applyPopupOffsetToX: (int&) x andY: (int&) y {
if ([self isOverPopupWidgetX:x andY:y]) {
x += [self getPopupXOffset];
y += [self getPopupYOffset];
}
}
- (void) convertRects: (const CefRenderHandler::RectList&) rects
toBackingRects: (CefRenderHandler::RectList*) scaled_rects
andSize: (const NSSize) size
toBackingSize: (NSSize*) scaled_size {
*scaled_rects = rects;
*scaled_size = size;
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
__MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if ([self getDeviceScaleFactor] != 1 &&
[self respondsToSelector:@selector(convertSizeToBacking:)] &&
[self respondsToSelector:@selector(convertRectToBacking:)]) {
CefRenderHandler::RectList scaled_dirty_rects;
for (size_t i = 0; i < rects.size(); ++i) {
scaled_dirty_rects.push_back([self convertRectToBackingInternal:rects[i]]);
}
*scaled_rects = scaled_dirty_rects;
*scaled_size = [self convertSizeToBacking:size];
}
#endif
}
- (CefRect) convertRectToBackingInternal: (const CefRect&) rect {
if ([self getDeviceScaleFactor] == 1)
return rect;
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
__MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if ([self respondsToSelector:@selector(convertRectToBacking:)]) {
NSRect old_rect = NSMakeRect(rect.x, rect.y, rect.width, rect.height);
NSRect scaled_rect = [self convertRectToBacking:old_rect];
return CefRect((int)scaled_rect.origin.x,
(int)scaled_rect.origin.y,
(int)scaled_rect.size.width,
(int)scaled_rect.size.height);
}
#endif
return rect;
}
- (CefRect) convertRectFromBackingInternal: (const CefRect&) rect {
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
__MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if ([self respondsToSelector:@selector(convertRectFromBacking:)]) {
NSRect old_rect = NSMakeRect(rect.x, rect.y, rect.width, rect.height);
NSRect scaled_rect = [self convertRectFromBacking:old_rect];
return CefRect((int)scaled_rect.origin.x,
(int)scaled_rect.origin.y,
(int)scaled_rect.size.width,
(int)scaled_rect.size.height);
}
#endif
return rect;
}
@end
CefRefPtr<OSRWindow> OSRWindow::Create(OSRBrowserProvider* browser_provider,
bool transparent,
CefWindowHandle parentView,
const CefRect& frame) {
return new OSRWindow(browser_provider, transparent, parentView, frame);
}
OSRWindow::OSRWindow(OSRBrowserProvider* browser_provider,
bool transparent,
CefWindowHandle parentView,
const CefRect& frame) {
NSRect window_rect = NSMakeRect(frame.x, frame.y, frame.width, frame.height);
ClientOpenGLView* view = [[ClientOpenGLView alloc] initWithFrame:window_rect
andTransparency:transparent];
this->view_ = view;
[parentView addSubview:view];
[view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[view setAutoresizesSubviews: true];
this->render_client = new ClientOSRHandler(view, browser_provider);
}
OSRWindow::~OSRWindow() {
}

View File

@ -99,6 +99,11 @@ bool OSRWindow::GetScreenPoint(CefRefPtr<CefBrowser> browser,
void OSRWindow::OnPopupShow(CefRefPtr<CefBrowser> browser,
bool show) {
if (!show) {
CefRect dirty_rect = renderer_.popup_rect();
renderer_.ClearPopupRects();
browser->GetHost()->Invalidate(dirty_rect, PET_VIEW);
}
renderer_.OnPopupShow(browser, show);
}

View File

@ -3,10 +3,13 @@
// can be found in the LICENSE file.
#include "cefclient/client_handler.h"
#include <algorithm>
#include <stdio.h>
#include <algorithm>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include "include/cef_browser.h"
#include "include/cef_frame.h"
#include "include/cef_path_util.h"
@ -517,6 +520,13 @@ bool ClientHandler::GetScreenPoint(CefRefPtr<CefBrowser> browser,
return m_OSRHandler->GetScreenPoint(browser, viewX, viewY, screenX, screenY);
}
bool ClientHandler::GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) {
if (!m_OSRHandler.get())
return false;
return m_OSRHandler->GetScreenInfo(browser, screen_info);
}
void ClientHandler::OnPopupShow(CefRefPtr<CefBrowser> browser,
bool show) {
if (!m_OSRHandler.get())

View File

@ -194,6 +194,8 @@ class ClientHandler : public CefClient,
int viewY,
int& screenX,
int& screenY) OVERRIDE;
virtual bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) OVERRIDE;
virtual void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) OVERRIDE;
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) OVERRIDE;

View File

@ -143,11 +143,7 @@ void ClientOSRenderer::OnPopupShow(CefRefPtr<CefBrowser> browser,
bool show) {
if (!show) {
// Clear the popup rectangle.
CefRect popup_rect = popup_rect_;
popup_rect_.Set(0, 0, 0, 0);
original_popup_rect_.Set(0, 0, 0, 0);
// Invalidate the previous popup rectangle so that it will be repainted.
browser->GetHost()->Invalidate(popup_rect, PET_VIEW);
ClearPopupRects();
}
}
@ -179,6 +175,11 @@ CefRect ClientOSRenderer::GetPopupRectInWebView(const CefRect& original_rect) {
return rc;
}
void ClientOSRenderer::ClearPopupRects() {
popup_rect_.Set(0, 0, 0, 0);
original_popup_rect_.Set(0, 0, 0, 0);
}
void ClientOSRenderer::OnPaint(CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList& dirtyRects,

View File

@ -47,6 +47,7 @@ class ClientOSRenderer {
const CefRect& original_popup_rect() const { return original_popup_rect_; }
CefRect GetPopupRectInWebView(const CefRect& original_rect);
void ClearPopupRects();
private:
bool transparent_;

View File

@ -0,0 +1,69 @@
<html>
<head><title>OSR Test</title></head>
<style>
.red_hover:hover {color:red;}
#li { width: 530px; }
body {background:rgba(255, 0, 0, 0.5); }
input {-webkit-appearance: none; }
#LI11select {width: 75px;}
</style>
<script>
function sendBrowserMessage(paramString) {
app.sendMessage("osrtest", [paramString]);
}
function getElement(id) { return document.getElementById(id); }
function makeH1Red() { getElement('LI00').style.color='red'; }
function makeH1Black() { getElement('LI00').style.color='black'; }
function navigate() { location.href='?k='+getElement('editbox').value; }
function load() { var select = document.getElementById('LI11select');
for (var i = 1; i < 21; i++)
select.options.add(new Option('Option ' + i, i));
}
function onEventTest(event) {
var param = event.type;
if (event.type == "click")
param += event.button;
sendBrowserMessage(param);
}
</script>
<body onfocus='onEventTest(event)' onblur='onEventTest(event)' onload='load();'>
<h1 id='LI00' onclick="onEventTest(event)">
OSR Testing h1 - Focus and blur
<select id='LI11select'>
<option value='0'>Default</option>
</select>
this page and will get this red black
</h1>
<ol>
<li id='LI01'>OnPaint should be called each time a page loads</li>
<li id='LI02' style='cursor:pointer;'><span>Move mouse
to require an OnCursorChange call</span></li>
<li id='LI03' onmousemove="onEventTest(event)"><span>Hover will color this with
red. Will trigger OnPaint once on enter and once on leave</span></li>
<li id='LI04'>Right clicking will show contextual menu and will request
GetScreenPoint</li>
<li id='LI05'>IsWindowRenderingDisabled should be true</li>
<li id='LI06'>WasResized should trigger full repaint if size changes.
</li>
<li id='LI07'>Invalidate should trigger OnPaint once</li>
<li id='LI08'>Click and write here with SendKeyEvent to trigger repaints:
<input id='editbox' type='text' value=''></li>
<li id='LI09'>Click here with SendMouseClickEvent to navigate:
<input id='btnnavigate' type='button' onclick='navigate()'
value='Click here to navigate' id='editbox' /></li>
<li id='LI10' title='EXPECTED_TOOLTIP'>Mouse over this element will
trigger show a tooltip</li>
</ol>
<br />
<br />
<br />
<br />
<br />
<br />
</body>
</html>

View File

@ -44,11 +44,12 @@
#define IDS_LOCALSTORAGE 1003
#define IDS_LOGO 1004
#define IDS_LOGOBALL 1005
#define IDS_OTHER_TESTS 1006
#define IDS_PERFORMANCE 1007
#define IDS_TRANSPARENCY 1008
#define IDS_WINDOW 1009
#define IDS_XMLHTTPREQUEST 1010
#define IDS_OSRTEST 1006
#define IDS_OTHER_TESTS 1007
#define IDS_PERFORMANCE 1008
#define IDS_TRANSPARENCY 1009
#define IDS_WINDOW 1010
#define IDS_XMLHTTPREQUEST 1011
// Avoid files associated with MacOS
#define _X86_

View File

@ -29,7 +29,7 @@ bool AmIBundled() {
ASSERT(false);
return false;
}
return (info.nodeFlags & kFSNodeIsDirectoryMask);
}
@ -41,7 +41,7 @@ bool GetResourceDir(std::string& dir) {
// Retrieve the executable directory.
uint32_t pathSize = 0;
_NSGetExecutablePath(NULL, &pathSize);
if (pathSize > 0) {
if (pathSize > 0) {
dir.resize(pathSize);
_NSGetExecutablePath(const_cast<char*>(dir.c_str()), &pathSize);
}

View File

@ -38,6 +38,7 @@ int GetResourceId(const char* resource_name) {
{"domaccess.html", IDS_DOMACCESS},
{"localstorage.html", IDS_LOCALSTORAGE},
{"logo.png", IDS_LOGO},
{"osr_test.html", IDS_OSRTEST},
{"other_tests.html", IDS_OTHER_TESTS},
{"performance.html", IDS_PERFORMANCE},
{"transparency.html", IDS_TRANSPARENCY},

View File

@ -3,63 +3,31 @@
// can be found in the LICENSE file.
#include "include/cef_runnable.h"
#include "include/cef_v8.h"
#include "include/wrapper/cef_stream_resource_handler.h"
#include "tests/cefclient/client_app.h"
#include "tests/cefclient/resource_util.h"
#include "tests/unittests/test_handler.h"
#include "base/logging.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "ui/base/keycodes/keyboard_code_conversion.h"
#if defined(OS_MACOSX)
#include "tests/unittests/os_rendering_unittest_mac.h"
#elif defined(OS_WIN)
// Required for resource_util_win, which uses this as an extern
HINSTANCE hInst = ::GetModuleHandle(NULL);
#endif
namespace {
const char kTestUrl[] = "http://tests/OSRTest";
const char kTestUrl[] = "http://tests/osrtest";
// this html should render on a 600 x 400 window with a little vertical
// offset with scrollbar.
const char kOsrHtml[] =
"<html> "
" <head><title>OSR Test</title></head> "
" <style> "
" .red_hover:hover {color:red;} "
" body {background:rgba(255, 0, 0, 0.5);} "
" #LI11select {width: 75px;} "
" </style> "
" <script> "
" function getElement(id) { return document.getElementById(id); } "
" function makeH1Red() { getElement('LI00').style.color='red'; } "
" function makeH1Black() { getElement('LI00').style.color='black'; } "
" function navigate() { location.href='?k='+getElement('editbox').value; } "
" function load() { var select = document.getElementById('LI11select'); "
" for (var i = 1; i < 21; i++) "
" select.options.add(new Option('Option ' + i, i));} "
" </script> "
" <body onfocus='makeH1Red()' onblur='makeH1Black()' onload='load();'> "
" <h1 id='LI00'>OSR Testing h1 - Focus and blur "
" <select id='LI11select'><option value='0'>Default</option></select> "
" this page and will get this red black</h1> "
" <ol> "
" <li id='LI01'>OnPaint should be called each time a page loads</li> "
" <li id='LI02' style='cursor:pointer;'><span>Move mouse "
" to require an OnCursorChange call</span></li> "
" <li id='LI03' class='red_hover'><span>Hover will color this with "
" red. Will trigger OnPaint once on enter and once on leave</span></li> "
" <li id='LI04'>Right clicking will show contextual menu and will request "
" GetScreenPoint</li> "
" <li id='LI05'>IsWindowRenderingDisabled should be true</li> "
" <li id='LI06'>WasResized should trigger full repaint if size changes. "
" </li> "
" <li id='LI07'>Invalidate should trigger OnPaint once</li> "
" <li id='LI08'>Click and write here with SendKeyEvent to trigger repaints: "
" <input id='editbox' type='text' value=''></li> "
" <li id='LI09'>Click here with SendMouseClickEvent to navigate: "
" <input id='btnnavigate' type='button' onclick='navigate()' "
" value='Click here to navigate' id='editbox' /></li> "
" <li id='LI10' title='EXPECTED_TOOLTIP'>Mouse over this element will "
" trigger show a tooltip</li> "
" </ol> "
" <br /> "
" <br /> "
" <br /> "
" <br /> "
" </body> "
"</html> ";
// #define DEBUGGER_ATTACHED
// default osr widget size
@ -67,6 +35,7 @@ const int kOsrWidth = 600;
const int kOsrHeight = 400;
// precomputed bounding client rects for html elements (h1 and li).
#if defined(OS_WIN)
const CefRect kExpectedRectLI[] = {
CefRect(8, 8, 567, 74), // LI00
CefRect(27, 103, 548, 20), // LI01
@ -80,17 +49,44 @@ const CefRect kExpectedRectLI[] = {
CefRect(27, 269, 548, 26), // LI09
CefRect(27, 295, 548, 20), // LI10
};
#elif defined(OS_MACOSX)
const CefRect kExpectedRectLI[] = {
CefRect(8, 8, 584, 74), // LI00
CefRect(28, 103, 564, 18), // LI01
CefRect(28, 121, 564, 18), // LI02
CefRect(28, 139, 564, 18), // LI03
CefRect(28, 157, 564, 18), // LI04
CefRect(28, 175, 564, 18), // LI05
CefRect(28, 193, 564, 18), // LI06
CefRect(28, 211, 564, 18), // LI07
CefRect(28, 229, 564, 23), // LI08
CefRect(28, 252, 564, 26), // LI09
CefRect(20, 278, 572, 18), // LI10
};
#else
#error "Unsupported platform"
#endif // defined(OS_WIN)
// bounding client rects for edit box and navigate button
#if defined(OS_WIN)
const CefRect kEditBoxRect(412, 245, 153, 22);
const CefRect kNavigateButtonRect(360, 271, 140, 22);
const CefRect kSelectRect(467, 22, 75, 20);
const CefRect kExpandedSelectRect(467, 42, 81, 322);
const int kVerticalScrollbarWidth = GetSystemMetrics(SM_CXVSCROLL);
const int kHorizontalScrollbarWidth = GetSystemMetrics(SM_CXHSCROLL);
#elif defined(OS_MACOSX)
const CefRect kEditBoxRect(429, 228, 129, 25);
const CefRect kNavigateButtonRect(375, 251, 138, 28);
const CefRect kSelectRect(461, 21, 87, 26);
const CefRect kExpandedSelectRect(467, 42, 80, 262);
#else
#error "Unsupported platform"
#endif // defined(OS_WIN)
// adjusted expected rect regarding system vertical scrollbar width
CefRect ExpectedRect(int index) {
#if defined(OS_WIN)
// this is the scrollbar width for all the kExpectedRectLI
const int kDefaultVerticalScrollbarWidth = 17;
if (kDefaultVerticalScrollbarWidth == kVerticalScrollbarWidth)
@ -100,11 +96,23 @@ CefRect ExpectedRect(int index) {
adjustedRect.width += kDefaultVerticalScrollbarWidth -
kVerticalScrollbarWidth;
return adjustedRect;
#elif defined(OS_MACOSX)
return kExpectedRectLI[index];
#else
#error "Unsupported platform"
#endif
}
// word to be written into edit box
const char kKeyTestWord[] = "done";
const ui::KeyboardCode kKeyTestCodes[] = {
ui::VKEY_D,
ui::VKEY_O,
ui::VKEY_N,
ui::VKEY_E
};
// width for the icon that appear on the screen when pressing
// middle mouse button
const int kMiddleButtonIconWidth = 16;
@ -141,6 +149,9 @@ enum OSRTestType {
OSR_TEST_TOOLTIP,
// mouse wheel will trigger a scroll event
OSR_TEST_SCROLLING,
// Right click will trigger a context menu, and on destroying the test, it
// should not crash
OSR_TEST_CONTEXT_MENU,
// clicking on dropdown box, PET_POPUP OnPaint is triggered
OSR_TEST_POPUP_PAINT,
// clicking on dropdown box, a popup will show up
@ -174,7 +185,6 @@ class OSRTestHandler : public TestHandler,
// TestHandler methods
virtual void RunTest() OVERRIDE {
AddResource(kTestUrl, kOsrHtml, "text/html");
CreateOSRBrowser(kTestUrl);
#if !defined(DEBUGGER_ATTACHED)
// Each test has a 5 second timeout. After this timeout it will be destroyed
@ -196,13 +206,61 @@ class OSRTestHandler : public TestHandler,
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) OVERRIDE {
if (test_type_ == OSR_TEST_KEY_EVENTS && started()) {
std::string expectedUrl = std::string(kTestUrl) + "?k=" + kKeyTestWord;
EXPECT_EQ(frame->GetURL(), expectedUrl);
DestroySucceededTestSoon();
if (!started())
return;
switch(test_type_) {
case OSR_TEST_KEY_EVENTS:
EXPECT_EQ(frame->GetURL(), std::string(kTestUrl) + "?k=" + kKeyTestWord);
DestroySucceededTestSoon();
break;
default:
// Intentionally left blank
break;
}
}
virtual bool OnProcessMessageReceived(
CefRefPtr<CefBrowser> browser,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message) OVERRIDE {
EXPECT_TRUE(browser.get());
EXPECT_EQ(PID_RENDERER, source_process);
EXPECT_TRUE(message.get());
EXPECT_TRUE(message->IsReadOnly());
if (!started())
return false;
const CefString kMessageName = "osrtest";
EXPECT_EQ(kMessageName, message->GetName());
CefString stringParam = message->GetArgumentList()->GetString(0);
switch(test_type_) {
case OSR_TEST_FOCUS:
EXPECT_EQ(stringParam, std::string("focus"));
DestroySucceededTestSoon();
break;
case OSR_TEST_CLICK_LEFT:
EXPECT_EQ(stringParam, std::string("click0"));
DestroySucceededTestSoon();
break;
case OSR_TEST_CLICK_MIDDLE:
EXPECT_EQ(stringParam, std::string("click1"));
DestroySucceededTestSoon();
break;
case OSR_TEST_MOUSE_MOVE:
EXPECT_EQ(stringParam, std::string("mousemove"));
DestroySucceededTestSoon();
break;
default:
// Intentionally left blank
break;
}
return true;
}
// CefClient methods, providing handlers
virtual CefRefPtr<CefRenderHandler> GetRenderHandler() OVERRIDE {
return this;
@ -212,6 +270,26 @@ class OSRTestHandler : public TestHandler,
return this;
}
virtual CefRefPtr<CefRequestHandler> GetRequestHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefResourceHandler> GetResourceHandler(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) OVERRIDE {
std::string url = request->GetURL();
if (url.find("http://tests/osrtest") == 0) {
// Show the osr test contents
CefRefPtr<CefStreamReader> stream =
GetBinaryResourceReader("osr_test.html");
return new CefStreamResourceHandler("text/html", stream);
}
return NULL;
}
// CefRenderHandler methods
virtual bool GetViewRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) OVERRIDE {
@ -232,11 +310,29 @@ class OSRTestHandler : public TestHandler,
EXPECT_EQ(viewX, MiddleX(ExpectedRect(4)));
EXPECT_EQ(viewY, MiddleY(ExpectedRect(4)));
DestroySucceededTestSoon();
} else if (test_type_ == OSR_TEST_CONTEXT_MENU && started()){
screenX = 0;
screenY = 0;
return true;
}
// we don't want to see a contextual menu. stop here.
return false;
}
virtual bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) {
screen_info.device_scale_factor = 1;
// The screen info rectangles are used by the renderer to create and
// position popups. If not overwritten in this function, the rectangle from
// returned GetViewRect will be used to popuplate them.
// The popup in the test fits without modifications in the test window, so
// setting the screen to the test window size does not affect its rectangle.
screen_info.rect = CefRect(0, 0, kOsrWidth, kOsrHeight);
screen_info.available_rect = CefRect(0, 0, kOsrWidth, kOsrHeight);
return true;
}
virtual void OnPopupShow(CefRefPtr<CefBrowser> browser,
bool show) OVERRIDE {
if (show && started()) {
@ -247,6 +343,8 @@ class OSRTestHandler : public TestHandler,
DestroySucceededTestSoon();
}
break;
default:
break;
}
}
if (!show && started()) {
@ -257,6 +355,8 @@ class OSRTestHandler : public TestHandler,
case OSR_TEST_POPUP_HIDE_ON_SCROLL:
DestroySucceededTestSoon();
break;
default:
break;
}
}
}
@ -269,6 +369,8 @@ class OSRTestHandler : public TestHandler,
EXPECT_EQ(kExpandedSelectRect, rect);
DestroySucceededTestSoon();
break;
default:
break;
}
}
}
@ -301,26 +403,22 @@ class OSRTestHandler : public TestHandler,
switch (test_type_) {
case OSR_TEST_PAINT:
// test that we have a full repaint
EXPECT_EQ(dirtyRects.size(), 1);
EXPECT_EQ(dirtyRects.size(), 1U);
EXPECT_TRUE(IsFullRepaint(dirtyRects[0]));
EXPECT_EQ(*(reinterpret_cast<const uint32*>(buffer)), 0xffff8080);
DestroySucceededTestSoon();
break;
case OSR_TEST_TRANSPARENCY:
// test that we have a full repaint
EXPECT_EQ(dirtyRects.size(), 1);
EXPECT_EQ(dirtyRects.size(), 1U);
EXPECT_TRUE(IsFullRepaint(dirtyRects[0]));
EXPECT_EQ(*(reinterpret_cast<const uint32*>(buffer)), 0x7f7f0000);
EXPECT_EQ(*(reinterpret_cast<const uint32*>(buffer)), 0x7f7f0000U);
DestroySucceededTestSoon();
break;
case OSR_TEST_FOCUS:
if (StartTest()) {
// body.onfocus will make LI00 red
browser->GetHost()->SendFocusEvent(true);
} else {
EXPECT_EQ(dirtyRects.size(), 1);
EXPECT_EQ(dirtyRects[0], ExpectedRect(0));
DestroySucceededTestSoon();
}
break;
case OSR_TEST_CURSOR:
@ -344,14 +442,11 @@ class OSRTestHandler : public TestHandler,
mouse_event.y = MiddleY(ExpectedRect(3));
mouse_event.modifiers = 0;
browser->GetHost()->SendMouseMoveEvent(mouse_event, false);
} else {
EXPECT_EQ(dirtyRects.size(), 1);
EXPECT_EQ(dirtyRects[0], ExpectedRect(3));
DestroySucceededTestSoon();
}
break;
case OSR_TEST_CLICK_RIGHT:
case OSR_TEST_SCREEN_POINT:
case OSR_TEST_CONTEXT_MENU:
if (StartTest()) {
CefMouseEvent mouse_event;
mouse_event.x = MiddleX(ExpectedRect(4));
@ -366,17 +461,14 @@ class OSRTestHandler : public TestHandler,
case OSR_TEST_CLICK_LEFT:
if (StartTest()) {
CefMouseEvent mouse_event;
mouse_event.x = MiddleX(kEditBoxRect);
mouse_event.y = MiddleY(kEditBoxRect);
mouse_event.x = MiddleX(ExpectedRect(0));
mouse_event.y = MiddleY(ExpectedRect(0));
mouse_event.modifiers = 0;
browser->GetHost()->SendMouseClickEvent(
mouse_event, MBT_LEFT, false, 1);
browser->GetHost()->SendMouseClickEvent(
mouse_event, MBT_LEFT, true, 1);
} else {
EXPECT_EQ(dirtyRects.size(), 1);
EXPECT_EQ(dirtyRects[0], kEditBoxRect);
DestroySucceededTestSoon();
}
break;
case OSR_TEST_CLICK_MIDDLE:
@ -390,7 +482,7 @@ class OSRTestHandler : public TestHandler,
browser->GetHost()->SendMouseClickEvent(
mouse_event, MBT_MIDDLE, true, 1);
} else {
EXPECT_EQ(dirtyRects.size(), 1);
EXPECT_EQ(dirtyRects.size(), 1U);
CefRect expectedRect(
MiddleX(ExpectedRect(0)) - kMiddleButtonIconWidth / 2,
MiddleY(ExpectedRect(0)) - kMiddleButtonIconWidth / 2,
@ -405,7 +497,7 @@ class OSRTestHandler : public TestHandler,
} else {
EXPECT_EQ(kOsrWidth * 2, width);
EXPECT_EQ(kOsrHeight * 2, height);
EXPECT_EQ(dirtyRects.size(), 1);
EXPECT_EQ(dirtyRects.size(), 1U);
EXPECT_TRUE(IsFullRepaint(dirtyRects[0], width, height));
DestroySucceededTestSoon();
}
@ -419,7 +511,7 @@ class OSRTestHandler : public TestHandler,
invalidating = false;
} else {
EXPECT_TRUE(invalidating);
EXPECT_EQ(dirtyRects.size(), 1);
EXPECT_EQ(dirtyRects.size(), 1U);
EXPECT_EQ(dirtyRects[0], invalidate_rect);
DestroySucceededTestSoon();
}
@ -442,21 +534,35 @@ class OSRTestHandler : public TestHandler,
event.is_system_key = false;
event.modifiers = 0;
size_t word_lenght = strlen(kKeyTestWord);
for (size_t i = 0; i < word_lenght; ++i) {
size_t word_length = strlen(kKeyTestWord);
for (size_t i = 0; i < word_length; ++i) {
#if defined(OS_WIN)
BYTE VkCode = LOBYTE(VkKeyScanA(kKeyTestWord[i]));
UINT scanCode = MapVirtualKey(VkCode, MAPVK_VK_TO_VSC);
event.native_key_code = (scanCode << 16) | // key scan code
1; // key repeat count
1; // key repeat count
event.windows_key_code = VkCode;
#elif defined(OS_MACOSX)
osr_unittests::GetKeyEvent(event, kKeyTestCodes[i], 0);
#else
NOTREACHED();
#endif
event.type = KEYEVENT_RAWKEYDOWN;
browser->GetHost()->SendKeyEvent(event);
#if defined(OS_WIN)
event.windows_key_code = kKeyTestWord[i];
#elif defined(OS_MACOSX)
osr_unittests::GetKeyEvent(event, kKeyTestCodes[i], 0);
#endif
event.type = KEYEVENT_CHAR;
browser->GetHost()->SendKeyEvent(event);
#if defined(OS_WIN)
event.windows_key_code = VkCode;
// bits 30 and 31 should be always 1 for WM_KEYUP
event.native_key_code |= 0xC0000000;
#elif defined(OS_MACOSX)
osr_unittests::GetKeyEvent(event, kKeyTestCodes[i], 0);
#endif
event.type = KEYEVENT_KEYUP;
browser->GetHost()->SendKeyEvent(event);
}
@ -488,20 +594,38 @@ class OSRTestHandler : public TestHandler,
mouse_event.modifiers = 0;
browser->GetHost()->SendMouseWheelEvent(mouse_event, 0, - deltaY);
} else {
#if defined(OS_WIN)
// there should be 3 update areas:
// 1) vertical scrollbar
// 2) discovered new area (bottom side)
// 3) the whole visible rect.
EXPECT_EQ(dirtyRects.size(), 3);
EXPECT_EQ(dirtyRects.size(), 3U);
EXPECT_EQ(dirtyRects[0], CefRect(0, 0,
kOsrWidth - kVerticalScrollbarWidth, kHorizontalScrollbarWidth));
EXPECT_EQ(dirtyRects[1], CefRect(0, kHorizontalScrollbarWidth,
kOsrWidth, kOsrHeight - 2 * kHorizontalScrollbarWidth));
EXPECT_EQ(dirtyRects[2],
CefRect(0, kOsrHeight - kHorizontalScrollbarWidth,
kOsrWidth - kVerticalScrollbarWidth,
kHorizontalScrollbarWidth));
DestroySucceededTestSoon();
#elif defined(OS_MACOSX)
// On Mac, when scrollbars are Always on, there is a single update of
// the whole view
// When scrollbars are set to appear 'When scrolling', the first
// rectangle is of the whole view, and next comes a longer sequence of
// updates, each with one rectangle update for the whole scrollbar
// rectangle(584,0,16,400)
// Validating the first, full update passes in both cases
EXPECT_EQ(dirtyRects.size(), 1U);
EXPECT_EQ(dirtyRects[0], CefRect(0, 0,
kOsrWidth, kOsrHeight));
DestroySucceededTestSoon();
#else
#error "Unsupported platform"
#endif // defined(OS_WIN)
}
break;
}
@ -544,11 +668,17 @@ class OSRTestHandler : public TestHandler,
} else if (type == PET_POPUP) {
CefKeyEvent event;
event.is_system_key = false;
#if defined(OS_WIN)
BYTE VkCode = LOBYTE(VK_ESCAPE);
UINT scanCode = MapVirtualKey(VkCode, MAPVK_VK_TO_VSC);
event.native_key_code = (scanCode << 16) | // key scan code
1; // key repeat count
event.windows_key_code = VkCode;
#elif defined(OS_MACOSX)
osr_unittests::GetKeyEvent(event, ui::VKEY_ESCAPE, 0);
#else
#error "Unsupported platform"
#endif // defined(OS_WIN)
event.type = KEYEVENT_CHAR;
browser->GetHost()->SendKeyEvent(event);
}
@ -563,7 +693,7 @@ class OSRTestHandler : public TestHandler,
if (StartTest()) {
ExpandDropDown();
} else if (type == PET_POPUP) {
EXPECT_EQ(dirtyRects.size(), 1);
EXPECT_EQ(dirtyRects.size(), 1U);
EXPECT_EQ(dirtyRects[0],
CefRect(0, 0,
kExpandedSelectRect.width,
@ -576,28 +706,46 @@ class OSRTestHandler : public TestHandler,
}
break;
case OSR_TEST_POPUP_SCROLL_INSIDE:
static enum {NotStarted, Started, Scrolled}
scroll_inside_state = NotStarted;
if (StartTest()) {
ExpandDropDown();
scroll_inside_state = Started;
} else if (type == PET_POPUP) {
if (scroll_inside_state == Started) {
CefMouseEvent mouse_event;
mouse_event.x = MiddleX(kExpandedSelectRect);
mouse_event.y = MiddleY(kExpandedSelectRect);
mouse_event.modifiers = 0;
browser->GetHost()->SendMouseWheelEvent(mouse_event, 0, -10);
scroll_inside_state = Scrolled;
} else if (scroll_inside_state == Scrolled) {
EXPECT_EQ(dirtyRects.size(), 1);
// border is not redrawn
EXPECT_EQ(dirtyRects[0], CefRect(1, 1,
kExpandedSelectRect.width - 3,
kExpandedSelectRect.height - 2));
DestroySucceededTestSoon();
{
static enum {NotStarted, Started, Scrolled}
scroll_inside_state = NotStarted;
if (StartTest()) {
ExpandDropDown();
scroll_inside_state = Started;
} else if (type == PET_POPUP) {
if (scroll_inside_state == Started) {
CefMouseEvent mouse_event;
mouse_event.x = MiddleX(kExpandedSelectRect);
mouse_event.y = MiddleY(kExpandedSelectRect);
mouse_event.modifiers = 0;
browser->GetHost()->SendMouseWheelEvent(mouse_event, 0, -10);
scroll_inside_state = Scrolled;
} else if (scroll_inside_state == Scrolled) {
EXPECT_EQ(dirtyRects.size(), 1U);
#if defined(OS_WIN)
// border is not redrawn
EXPECT_EQ(dirtyRects[0],
CefRect(1,
1,
kExpandedSelectRect.width - 3,
kExpandedSelectRect.height - 2));
#elif defined(OS_MACOSX)
EXPECT_EQ(dirtyRects[0],
CefRect(1,
0,
kExpandedSelectRect.width - 3,
kExpandedSelectRect.height - 1));
#else
#error "Unsupported platform"
#endif // defined(OS_WIN)
DestroySucceededTestSoon();
}
}
}
break;
default:
break;
}
}
@ -621,10 +769,15 @@ class OSRTestHandler : public TestHandler,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefContextMenuParams> params,
CefRefPtr<CefMenuModel> model) OVERRIDE {
if (test_type_ == OSR_TEST_CLICK_RIGHT && started()) {
if (!started())
return;
if (test_type_ == OSR_TEST_CLICK_RIGHT) {
EXPECT_EQ(params->GetXCoord(), MiddleX(ExpectedRect(4)));
EXPECT_EQ(params->GetYCoord(), MiddleY(ExpectedRect(4)));
DestroySucceededTestSoon();
} else if (test_type_ == OSR_TEST_CONTEXT_MENU) {
// This test will pass if it does not crash on destruction
DestroySucceededTestSoon();
}
}
@ -632,7 +785,18 @@ class OSRTestHandler : public TestHandler,
void CreateOSRBrowser(const CefString& url) {
CefWindowInfo windowInfo;
CefBrowserSettings settings;
#if defined(OS_WIN)
windowInfo.SetAsOffScreen(GetDesktopWindow());
#elif defined(OS_MACOSX)
// An actual vies is needed only for the ContextMenu test. The menu runner
// checks if the view is not nil before showing the context menu.
if (test_type_ == OSR_TEST_CONTEXT_MENU)
windowInfo.SetAsOffScreen(osr_unittests::GetFakeView());
else
windowInfo.SetAsOffScreen(NULL);
#else
#error "Unsupported platform"
#endif
if (test_type_ == OSR_TEST_TRANSPARENCY)
windowInfo.SetTransparentPainting(TRUE);
CefBrowserHost::CreateBrowser(windowInfo, this, url, settings);
@ -727,6 +891,7 @@ OSR_TEST(Invalidate, OSR_TEST_INVALIDATE);
OSR_TEST(KeyEvents, OSR_TEST_KEY_EVENTS);
OSR_TEST(Tooltip, OSR_TEST_TOOLTIP);
OSR_TEST(Scrolling, OSR_TEST_SCROLLING);
OSR_TEST(ContextMenu, OSR_TEST_CONTEXT_MENU);
OSR_TEST(PopupPaint, OSR_TEST_POPUP_PAINT);
OSR_TEST(PopupShow, OSR_TEST_POPUP_SHOW);
OSR_TEST(PopupSize, OSR_TEST_POPUP_SIZE);

View File

@ -0,0 +1,18 @@
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
#ifndef CEF_TESTS_UNITTESTS_OS_RENDERING_UNITTEST_MAC_H_
#define CEF_TESTS_UNITTESTS_OS_RENDERING_UNITTEST_MAC_H_
#include "include/cef_base.h"
#include "ui/base/keycodes/keyboard_codes.h"
namespace osr_unittests {
CefWindowHandle GetFakeView();
void GetKeyEvent(CefKeyEvent& event, ui::KeyboardCode keyCode, int modifiers);
} // namespace osr_unittests
#endif

View File

@ -0,0 +1,39 @@
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
#import <AppKit/AppKit.h>
#import <Cocoa/Cocoa.h>
#include "os_rendering_unittest_mac.h"
#include "ui/base/keycodes/keyboard_code_conversion_mac.h"
#include "include/cef_base.h"
namespace osr_unittests {
CefWindowHandle GetFakeView() {
NSScreen *mainScreen = [NSScreen mainScreen];
NSRect screenRect = [mainScreen visibleFrame];
NSView* fakeView = [[NSView alloc] initWithFrame: screenRect];
return fakeView;
}
void GetKeyEvent(CefKeyEvent& event, ui::KeyboardCode keyCode, int modifiers) {
unichar character;
unichar unmodified_character;
// TODO(port): translate modifiers from the input format to NSFlags
// MacKeyCodeForWindowsKeyCode takes a NSUinteger as flags.
int macKeyCode = ui::MacKeyCodeForWindowsKeyCode(keyCode,
modifiers,
&character,
&unmodified_character);
event.native_key_code = macKeyCode;
event.character = character;
event.unmodified_character = unmodified_character;
}
} // namespace osr_unittests

View File

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