Implement off-screen rendering support using delegated rendering (issue #1257).

This implementation supports both GPU compositing and software compositing (used when GPU is not supported or when passing `--disable-gpu --disable-gpu-compositing` command-line flags). GPU-accelerated features (WebGL and 3D CSS) that did not work with the previous off-screen rendering implementation do work with this implementation when GPU support is available.

Rendering now operates on a per-frame basis. The frame rate is configurable via CefBrowserSettings.windowless_frame_rate up to a maximum of 60fps (potentially limited by how fast the system can generate new frames). CEF generates a bitmap from the compositor backing and passes it to CefRenderHandler::OnPaint.

The previous CefRenderHandler/CefBrowserHost API for off-screen rendering has been restored mostly as-is with some minor changes:

- CefBrowserHost::Invalidate no longer accepts a CefRect region argument. Instead of invalidating a specific region it now triggers generation of a new frame.
- The |dirtyRects| argument to CefRenderHandler::OnPaint will now always be a single CefRect representing the whole view (frame) size. Previously, invalidated regions were listed separately.
- Linux: CefBrowserHost::SendKeyEvent now expects X11 event information instead of GTK event information. See cefclient for an example of converting GTK events to the necessary format.
- Sizes passed to the CefRenderHandler OnPaint and OnPopupSize methods are now already DPI scaled. Previously, the client had to perform DPI scaling.
- Includes drag&drop implementation from issue #1032.
- Includes unit test fixes from issue #1245.

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1751 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt
2014-06-30 22:30:29 +00:00
parent 133317eeec
commit dea4daffd7
106 changed files with 13053 additions and 176 deletions

View File

@@ -19,8 +19,10 @@
#include "libcef/browser/media_capture_devices_dispatcher.h"
#include "libcef/browser/navigate_params.h"
#include "libcef/browser/printing/print_view_manager.h"
#include "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/browser/request_context_impl.h"
#include "libcef/browser/scheme_handler.h"
#include "libcef/browser/web_contents_view_osr.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/cef_messages.h"
#include "libcef/common/cef_switches.h"
@@ -33,6 +35,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/view_messages.h"
#include "content/public/browser/download_manager.h"
@@ -284,6 +287,18 @@ bool CefBrowserHost::CreateBrowser(
return false;
}
// Verify windowless rendering requirements.
if (windowInfo.windowless_rendering_enabled) {
if (!client->GetRenderHandler().get()) {
NOTREACHED() << "CefRenderHandler implementation is required";
return false;
}
if (!content::IsDelegatedRendererEnabled()) {
NOTREACHED() << "Delegated renderer must be enabled";
return false;
}
}
// Create the browser on the UI thread.
CreateBrowserHelper* helper =
new CreateBrowserHelper(windowInfo, client, url, settings,
@@ -337,8 +352,22 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::Create(
CefWindowHandle opener,
bool is_popup,
CefRefPtr<CefRequestContext> request_context) {
// Verify windowless rendering requirements.
if (windowInfo.windowless_rendering_enabled) {
if (!client->GetRenderHandler().get()) {
NOTREACHED() << "CefRenderHandler implementation is required";
return NULL;
}
if (!content::IsDelegatedRendererEnabled()) {
NOTREACHED() << "Delegated renderer must be enabled";
return NULL;
}
}
scoped_refptr<CefBrowserInfo> info =
CefContentBrowserClient::Get()->CreateBrowserInfo(is_popup);
info->set_windowless(windowInfo.windowless_rendering_enabled ? true : false);
CefRefPtr<CefBrowserHostImpl> browser =
CefBrowserHostImpl::CreateInternal(windowInfo, settings, client, NULL,
info, opener, request_context);
@@ -377,15 +406,24 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::CreateInternal(
content::WebContents::CreateParams create_params(
browser_context);
if (window_info.windowless_rendering_enabled) {
// Use the OSR view instead of the default view.
CefWebContentsViewOSR* view_or = new CefWebContentsViewOSR(
web_contents,
CefContentBrowserClient::Get()->GetWebContentsViewDelegate(
web_contents));
create_params.view = view_or;
create_params.delegate_view = view_or;
}
web_contents = content::WebContents::Create(create_params);
}
CefRefPtr<CefBrowserHostImpl> browser =
new CefBrowserHostImpl(window_info, settings, client, web_contents,
browser_info, opener);
if (!browser->PlatformCreateWindow()) {
if (!browser->IsWindowless() && !browser->PlatformCreateWindow())
return NULL;
}
#if defined(OS_LINUX) || defined(OS_ANDROID)
content::RendererPreferences* prefs = web_contents->GetMutableRendererPrefs();
@@ -606,7 +644,8 @@ void CefBrowserHostImpl::CloseBrowser(bool force_close) {
if (CEF_CURRENTLY_ON_UIT()) {
// Exit early if a close attempt is already pending and this method is
// called again from somewhere other than WindowDestroyed().
if (destruction_state_ >= DESTRUCTION_STATE_PENDING && !window_destroyed_) {
if (destruction_state_ >= DESTRUCTION_STATE_PENDING &&
(IsWindowless() || !window_destroyed_)) {
if (force_close && destruction_state_ == DESTRUCTION_STATE_PENDING) {
// Upgrade the destruction state.
destruction_state_ = DESTRUCTION_STATE_ACCEPTED;
@@ -856,6 +895,101 @@ bool CefBrowserHostImpl::IsMouseCursorChangeDisabled() {
return mouse_cursor_change_disabled_;
}
bool CefBrowserHostImpl::IsWindowRenderingDisabled() {
return IsWindowless();
}
void CefBrowserHostImpl::WasResized() {
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT, base::Bind(&CefBrowserHostImpl::WasResized, this));
return;
}
if (!web_contents())
return;
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(
web_contents()->GetRenderViewHost()->GetView());
if (view)
view->WasResized();
}
void CefBrowserHostImpl::WasHidden(bool hidden) {
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHost::WasHidden, this, hidden));
return;
}
if (!web_contents())
return;
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(
web_contents()->GetRenderViewHost()->GetView());
if (view) {
if (hidden)
view->WasHidden();
else
view->WasShown();
}
}
void CefBrowserHostImpl::NotifyScreenInfoChanged() {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::NotifyScreenInfoChanged, this));
return;
}
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
if (!web_contents())
return;
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(
web_contents()->GetRenderViewHost()->GetView());
if (view)
view->OnScreenInfoChanged();
}
void CefBrowserHostImpl::Invalidate(PaintElementType type) {
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::Invalidate, this, type));
return;
}
if (!web_contents())
return;
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(
web_contents()->GetRenderViewHost()->GetView());
if (view)
view->Invalidate(type);
}
void CefBrowserHostImpl::SendKeyEvent(const CefKeyEvent& event) {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
@@ -866,9 +1000,20 @@ void CefBrowserHostImpl::SendKeyEvent(const CefKeyEvent& event) {
content::NativeWebKeyboardEvent web_event;
PlatformTranslateKeyEvent(web_event, event);
content::RenderWidgetHost* widget = web_contents()->GetRenderViewHost();
if (widget)
widget->ForwardKeyboardEvent(web_event);
if (!IsWindowless()) {
content::RenderWidgetHost* widget = web_contents()->GetRenderViewHost();
if (widget)
widget->ForwardKeyboardEvent(web_event);
} else {
if (!web_contents())
return;
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(
web_contents()->GetRenderViewHost()->GetView());
if (view)
view->SendKeyEvent(web_event);
}
}
void CefBrowserHostImpl::SendMouseClickEvent(const CefMouseEvent& event,
@@ -913,9 +1058,20 @@ void CefBrowserHostImpl::SendMouseWheelEvent(const CefMouseEvent& event,
blink::WebMouseWheelEvent web_event;
PlatformTranslateWheelEvent(web_event, event, deltaX, deltaY);
content::RenderWidgetHost* widget = web_contents()->GetRenderViewHost();
if (widget)
widget->ForwardWheelEvent(web_event);
if (!IsWindowless()) {
content::RenderWidgetHost* widget = web_contents()->GetRenderViewHost();
if (widget)
widget->ForwardWheelEvent(web_event);
} else {
if (!web_contents())
return;
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(
web_contents()->GetRenderViewHost()->GetView());
if (view)
view->SendMouseWheelEvent(web_event);
}
}
int CefBrowserHostImpl::TranslateModifiers(uint32 cef_modifiers) {
@@ -949,9 +1105,20 @@ int CefBrowserHostImpl::TranslateModifiers(uint32 cef_modifiers) {
}
void CefBrowserHostImpl::SendMouseEvent(const blink::WebMouseEvent& event) {
content::RenderWidgetHost* widget = web_contents()->GetRenderViewHost();
if (widget)
widget->ForwardMouseEvent(event);
if (!IsWindowless()) {
content::RenderWidgetHost* widget = web_contents()->GetRenderViewHost();
if (widget)
widget->ForwardMouseEvent(event);
} else {
if (!web_contents())
return;
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(
web_contents()->GetRenderViewHost()->GetView());
if (view)
view->SendMouseEvent(event);
}
}
void CefBrowserHostImpl::SendFocusEvent(bool setFocus) {
@@ -961,19 +1128,17 @@ void CefBrowserHostImpl::SendFocusEvent(bool setFocus) {
return;
}
if (!web_contents())
return;
content::RenderWidgetHostImpl* widget =
content::RenderWidgetHostImpl::From(web_contents()->GetRenderViewHost());
if (!widget)
return;
if (setFocus) {
widget->GotFocus();
widget->SetActive(true);
if (!IsWindowless()) {
SetFocus(setFocus);
} else {
widget->SetActive(false);
widget->Blur();
if (!web_contents())
return;
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(
web_contents()->GetRenderViewHost()->GetView());
if (view)
view->SendFocusEvent(setFocus);
}
}
@@ -989,9 +1154,8 @@ void CefBrowserHostImpl::SendCaptureLostEvent() {
content::RenderWidgetHostImpl* widget =
content::RenderWidgetHostImpl::From(web_contents()->GetRenderViewHost());
if (!widget)
return;
widget->LostCapture();
if (widget)
widget->LostCapture();
}
// CefBrowser methods.
@@ -1180,6 +1344,14 @@ bool CefBrowserHostImpl::SendProcessMessage(
// CefBrowserHostImpl public methods.
// -----------------------------------------------------------------------------
bool CefBrowserHostImpl::IsWindowless() const {
return window_info_.windowless_rendering_enabled ? true : false;
}
bool CefBrowserHostImpl::IsTransparent() const {
return window_info_.transparent_painting_enabled ? true : false;
}
void CefBrowserHostImpl::WindowDestroyed() {
CEF_REQUIRE_UIT();
DCHECK(!window_destroyed_);
@@ -1234,6 +1406,16 @@ gfx::NativeView CefBrowserHostImpl::GetContentView() const {
#endif
}
void CefBrowserHostImpl::CancelContextMenu() {
#if defined(OS_LINUX) && defined(USE_AURA)
CEF_REQUIRE_UIT();
// Special case for dismissing views-based context menus on Linux Aura
// when using windowless rendering.
if (IsWindowless() && menu_creator_)
menu_creator_->CancelContextMenu();
#endif
}
content::WebContents* CefBrowserHostImpl::GetWebContents() const {
CEF_REQUIRE_UIT();
return web_contents_.get();
@@ -1533,6 +1715,208 @@ void CefBrowserHostImpl::RunFileChooser(
callback));
}
#if !defined(OS_MACOSX)
CefTextInputContext CefBrowserHostImpl::GetNSTextInputContext() {
NOTREACHED();
return NULL;
}
void CefBrowserHostImpl::HandleKeyEventBeforeTextInputClient(
CefEventHandle keyEvent) {
NOTREACHED();
}
void CefBrowserHostImpl::HandleKeyEventAfterTextInputClient(
CefEventHandle keyEvent) {
NOTREACHED();
}
#endif // !defined(OS_MACOSX)
void CefBrowserHostImpl::DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,
const CefMouseEvent& event,
CefBrowserHost::DragOperationsMask allowed_ops) {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::DragTargetDragEnter, this, drag_data,
event, allowed_ops));
return;
}
if (!drag_data.get()) {
NOTREACHED();
return;
}
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
content::RenderViewHost* rvh =
web_contents() ? web_contents()->GetRenderViewHost() : NULL;
if (!rvh)
return;
int screenX, screenY;
if (!client_->GetRenderHandler()->GetScreenPoint(
this, event.x, event.y, screenX, screenY)) {
screenX = event.x;
screenY = event.y;
}
CefDragDataImpl* data_impl = static_cast<CefDragDataImpl*>(drag_data.get());
CefDragDataImpl::AutoLock lock_scope(data_impl);
const content::DropData& drop_data = data_impl->drop_data();
gfx::Point client_pt(event.x, event.y);
gfx::Point screen_pt(screenX, screenY);
blink::WebDragOperationsMask ops =
static_cast<blink::WebDragOperationsMask>(allowed_ops);
int modifiers = CefBrowserHostImpl::TranslateModifiers(event.modifiers);
rvh->DragTargetDragEnter(drop_data, client_pt, screen_pt, ops, modifiers);
}
void CefBrowserHostImpl::DragTargetDragOver(const CefMouseEvent& event,
CefBrowserHost::DragOperationsMask allowed_ops) {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::DragTargetDragOver, this, event,
allowed_ops));
return;
}
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
content::RenderViewHost* rvh =
web_contents() ? web_contents()->GetRenderViewHost() : NULL;
if (!rvh)
return;
int screenX, screenY;
if (!client_->GetRenderHandler()->GetScreenPoint(
this, event.x, event.y, screenX, screenY)) {
screenX = event.x;
screenY = event.y;
}
gfx::Point client_pt(event.x, event.y);
gfx::Point screen_pt(screenX, screenY);
blink::WebDragOperationsMask ops =
static_cast<blink::WebDragOperationsMask>(allowed_ops);
int modifiers = CefBrowserHostImpl::TranslateModifiers(event.modifiers);
rvh->DragTargetDragOver(client_pt, screen_pt, ops, modifiers);
}
void CefBrowserHostImpl::DragTargetDragLeave() {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::DragTargetDragLeave, this));
return;
}
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
content::RenderViewHost* rvh =
web_contents() ? web_contents()->GetRenderViewHost() : NULL;
if (!rvh)
return;
rvh->DragTargetDragLeave();
}
void CefBrowserHostImpl::DragTargetDrop(const CefMouseEvent& event) {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::DragTargetDrop, this, event));
return;
}
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
content::RenderViewHost* rvh =
web_contents() ? web_contents()->GetRenderViewHost() : NULL;
if (!rvh)
return;
int screenX, screenY;
if (!client_->GetRenderHandler()->GetScreenPoint(
this, event.x, event.y, screenX, screenY)) {
screenX = event.x;
screenY = event.y;
}
gfx::Point client_pt(event.x, event.y);
gfx::Point screen_pt(screenX, screenY);
int modifiers = CefBrowserHostImpl::TranslateModifiers(event.modifiers);
rvh->DragTargetDrop(client_pt, screen_pt, modifiers);
}
void CefBrowserHostImpl::DragSourceSystemDragEnded() {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::DragSourceSystemDragEnded, this));
return;
}
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
content::RenderViewHost* rvh =
web_contents() ? web_contents()->GetRenderViewHost() : NULL;
if (!rvh)
return;
rvh->DragSourceSystemDragEnded();
}
void CefBrowserHostImpl::DragSourceEndedAt(
int x, int y, CefBrowserHost::DragOperationsMask op) {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::DragSourceEndedAt, this, x, y, op));
return;
}
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
content::RenderViewHost* rvh =
web_contents() ? web_contents()->GetRenderViewHost() : NULL;
if (!rvh)
return;
int screenX, screenY;
if (!client_->GetRenderHandler()->GetScreenPoint(
this, x, y, screenX, screenY)) {
screenX = x;
screenY = y;
}
blink::WebDragOperation drag_op = static_cast<blink::WebDragOperation>(op);
rvh->DragSourceEndedAt(x, y, screenX, screenY, drag_op);
}
// content::WebContentsDelegate methods.
// -----------------------------------------------------------------------------
@@ -1579,7 +1963,7 @@ void CefBrowserHostImpl::CloseContents(content::WebContents* source) {
// If this method is called in response to something other than
// WindowDestroyed() ask the user if the browser should close.
if (client_.get() && !window_destroyed_) {
if (client_.get() && (IsWindowless() || !window_destroyed_)) {
CefRefPtr<CefLifeSpanHandler> handler =
client_->GetLifeSpanHandler();
if (handler.get()) {
@@ -1591,7 +1975,7 @@ void CefBrowserHostImpl::CloseContents(content::WebContents* source) {
if (destruction_state_ != DESTRUCTION_STATE_ACCEPTED)
destruction_state_ = DESTRUCTION_STATE_ACCEPTED;
if (!window_destroyed_) {
if (!IsWindowless() && !window_destroyed_) {
// A window exists so try to close it using the platform method. Will
// result in a call to WindowDestroyed() if/when the window is destroyed
// via the platform window destruction mechanism.
@@ -1603,8 +1987,10 @@ void CefBrowserHostImpl::CloseContents(content::WebContents* source) {
// No window exists. Destroy the browser immediately.
DestroyBrowser();
// Release the reference added in PlatformCreateWindow().
Release();
if (!IsWindowless()) {
// Release the reference added in PlatformCreateWindow().
Release();
}
}
} else if (destruction_state_ != DESTRUCTION_STATE_NONE) {
destruction_state_ = DESTRUCTION_STATE_NONE;
@@ -1722,15 +2108,47 @@ bool CefBrowserHostImpl::CanDragEnter(
blink::WebDragOperationsMask mask) {
CefRefPtr<CefDragHandler> handler = client_->GetDragHandler();
if (handler.get()) {
CefRefPtr<CefDragData> drag_data(new CefDragDataImpl(data));
if (handler->OnDragEnter(this, drag_data,
static_cast<CefDragHandler::DragOperationsMask>(mask))) {
CefRefPtr<CefDragDataImpl> drag_data(new CefDragDataImpl(data));
drag_data->SetReadOnly(true);
if (handler->OnDragEnter(
this,
drag_data.get(),
static_cast<CefDragHandler::DragOperationsMask>(mask))) {
return false;
}
}
return true;
}
bool CefBrowserHostImpl::ShouldCreateWebContents(
content::WebContents* web_contents,
int route_id,
WindowContainerType window_container_type,
const base::string16& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace,
content::WebContentsView** view,
content::RenderViewHostDelegateView** delegate_view) {
// In cases where the navigation will occur in a new render process the
// |route_id| value will be MSG_ROUTING_NONE here (because the existing
// renderer will not be able to communicate with the new renderer) and
// OpenURLFromTab will be called after WebContentsCreated.
base::AutoLock lock_scope(pending_popup_info_lock_);
DCHECK(pending_popup_info_.get());
if (pending_popup_info_->window_info.windowless_rendering_enabled) {
// Use the OSR view instead of the default view.
CefWebContentsViewOSR* view_or = new CefWebContentsViewOSR(
web_contents,
CefContentBrowserClient::Get()->GetWebContentsViewDelegate(
web_contents));
*view = view_or;
*delegate_view = view_or;
}
return true;
}
void CefBrowserHostImpl::WebContentsCreated(
content::WebContents* source_contents,
int opener_render_frame_id,
@@ -1827,7 +2245,7 @@ void CefBrowserHostImpl::RequestMediaAccessPermission(
// Based on chrome/browser/media/media_stream_devices_controller.cc
bool microphone_requested =
(request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE);
bool webcam_requested =
bool webcam_requested =
(request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE);
if (microphone_requested || webcam_requested) {
switch (request.request_type) {
@@ -1870,8 +2288,9 @@ void CefBrowserHostImpl::RenderFrameCreated(
void CefBrowserHostImpl::RenderFrameDeleted(
content::RenderFrameHost* render_frame_host) {
browser_info_->remove_render_frame_id(render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID());
browser_info_->remove_render_frame_id(
render_frame_host->GetProcess()->GetID(),
render_frame_host->GetRoutingID());
}
void CefBrowserHostImpl::RenderViewCreated(
@@ -2208,6 +2627,14 @@ CefBrowserHostImpl::CefBrowserHostImpl(
// Make sure RenderViewCreated is called at least one time.
RenderViewCreated(web_contents->GetRenderViewHost());
if (IsWindowless()) {
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(
web_contents->GetRenderViewHost()->GetView());
if (view)
view->set_browser_impl(this);
}
}
CefRefPtr<CefFrame> CefBrowserHostImpl::GetOrCreateFrame(
@@ -2291,7 +2718,7 @@ void CefBrowserHostImpl::DetachAllFrames() {
void CefBrowserHostImpl::SetFocusedFrame(int64 frame_id) {
CefRefPtr<CefFrameHostImpl> unfocused_frame;
CefRefPtr<CefFrameHostImpl> focused_frame;
{
base::AutoLock lock_scope(state_lock_);

View File

@@ -35,6 +35,10 @@
#include "ui/base/cursor/cursor.h"
#endif
#if defined(USE_X11)
#include "ui/base/x/x11_util.h"
#endif
namespace content {
struct NativeWebKeyboardEvent;
}
@@ -152,6 +156,11 @@ class CefBrowserHostImpl : public CefBrowserHost,
virtual void CloseDevTools() OVERRIDE;
virtual void SetMouseCursorChangeDisabled(bool disabled) OVERRIDE;
virtual bool IsMouseCursorChangeDisabled() OVERRIDE;
virtual bool IsWindowRenderingDisabled() OVERRIDE;
virtual void WasResized() OVERRIDE;
virtual void WasHidden(bool hidden) OVERRIDE;
virtual void NotifyScreenInfoChanged() OVERRIDE;
virtual void Invalidate(PaintElementType type) OVERRIDE;
virtual void SendKeyEvent(const CefKeyEvent& event) OVERRIDE;
virtual void SendMouseClickEvent(const CefMouseEvent& event,
MouseButtonType type,
@@ -162,6 +171,20 @@ class CefBrowserHostImpl : public CefBrowserHost,
int deltaX, int deltaY) OVERRIDE;
virtual void SendFocusEvent(bool setFocus) OVERRIDE;
virtual void SendCaptureLostEvent() OVERRIDE;
virtual CefTextInputContext GetNSTextInputContext() OVERRIDE;
virtual void HandleKeyEventBeforeTextInputClient(CefEventHandle keyEvent)
OVERRIDE;
virtual void HandleKeyEventAfterTextInputClient(CefEventHandle keyEvent)
OVERRIDE;
virtual void DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,
const CefMouseEvent& event,
DragOperationsMask allowed_ops);
virtual void DragTargetDragOver(const CefMouseEvent& event,
DragOperationsMask allowed_ops);
virtual void DragTargetDragLeave();
virtual void DragTargetDrop(const CefMouseEvent& event);
virtual void DragSourceSystemDragEnded();
virtual void DragSourceEndedAt(int x, int y, DragOperationsMask op);
// CefBrowser methods.
virtual CefRefPtr<CefBrowserHost> GetHost() OVERRIDE;
@@ -188,6 +211,11 @@ class CefBrowserHostImpl : public CefBrowserHost,
CefProcessId target_process,
CefRefPtr<CefProcessMessage> message) OVERRIDE;
// Returns true if windowless rendering is enabled.
bool IsWindowless() const;
// Returns true if transparent painting is enabled.
bool IsTransparent() const;
// Called when the OS window hosting the browser is destroyed.
void WindowDestroyed();
@@ -195,6 +223,9 @@ class CefBrowserHostImpl : public CefBrowserHost,
// native browser window is not longer processing messages.
void DestroyBrowser();
// Cancel display of the context menu, if any.
void CancelContextMenu();
// Returns the native view for the WebContents.
gfx::NativeView GetContentView() const;
@@ -340,6 +371,16 @@ class CefBrowserHostImpl : public CefBrowserHost,
content::WebContents* source,
const content::DropData& data,
blink::WebDragOperationsMask operations_allowed) OVERRIDE;
virtual bool ShouldCreateWebContents(
content::WebContents* web_contents,
int route_id,
WindowContainerType window_container_type,
const base::string16& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace,
content::WebContentsView** view,
content::RenderViewHostDelegateView** delegate_view) OVERRIDE;
virtual void WebContentsCreated(content::WebContents* source_contents,
int opener_render_frame_id,
const base::string16& frame_name,
@@ -608,6 +649,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
#endif // defined(USE_AURA)
#if defined(USE_X11)
CefWindowX11* window_x11_;
scoped_ptr<ui::XScopedCursor> invisible_cursor_;
#endif // defined(USE_X11)
IMPLEMENT_REFCOUNTING(CefBrowserHostImpl);

View File

@@ -6,6 +6,7 @@
#include "libcef/browser/browser_host_impl.h"
#include <sys/sysinfo.h>
#include <X11/cursorfont.h>
#include "libcef/browser/context.h"
#include "libcef/browser/window_delegate_view.h"
@@ -29,8 +30,120 @@ long GetSystemUptime() {
return 0;
}
// Based on ui/base/cursor/cursor_loader_x11.cc.
using blink::WebCursorInfo;
int ToCursorID(WebCursorInfo::Type type) {
switch (type) {
case WebCursorInfo::TypePointer:
return XC_left_ptr;
case WebCursorInfo::TypeCross:
return XC_crosshair;
case WebCursorInfo::TypeHand:
return XC_hand2;
case WebCursorInfo::TypeIBeam:
return XC_xterm;
case WebCursorInfo::TypeWait:
return XC_watch;
case WebCursorInfo::TypeHelp:
return XC_question_arrow;
case WebCursorInfo::TypeEastResize:
return XC_right_side;
case WebCursorInfo::TypeNorthResize:
return XC_top_side;
case WebCursorInfo::TypeNorthEastResize:
return XC_top_right_corner;
case WebCursorInfo::TypeNorthWestResize:
return XC_top_left_corner;
case WebCursorInfo::TypeSouthResize:
return XC_bottom_side;
case WebCursorInfo::TypeSouthEastResize:
return XC_bottom_right_corner;
case WebCursorInfo::TypeSouthWestResize:
return XC_bottom_left_corner;
case WebCursorInfo::TypeWestResize:
return XC_left_side;
case WebCursorInfo::TypeNorthSouthResize:
return XC_sb_v_double_arrow;
case WebCursorInfo::TypeEastWestResize:
return XC_sb_h_double_arrow;
case WebCursorInfo::TypeNorthEastSouthWestResize:
return XC_left_ptr;
case WebCursorInfo::TypeNorthWestSouthEastResize:
return XC_left_ptr;
case WebCursorInfo::TypeColumnResize:
return XC_sb_h_double_arrow;
case WebCursorInfo::TypeRowResize:
return XC_sb_v_double_arrow;
case WebCursorInfo::TypeMiddlePanning:
return XC_fleur;
case WebCursorInfo::TypeEastPanning:
return XC_sb_right_arrow;
case WebCursorInfo::TypeNorthPanning:
return XC_sb_up_arrow;
case WebCursorInfo::TypeNorthEastPanning:
return XC_top_right_corner;
case WebCursorInfo::TypeNorthWestPanning:
return XC_top_left_corner;
case WebCursorInfo::TypeSouthPanning:
return XC_sb_down_arrow;
case WebCursorInfo::TypeSouthEastPanning:
return XC_bottom_right_corner;
case WebCursorInfo::TypeSouthWestPanning:
return XC_bottom_left_corner;
case WebCursorInfo::TypeWestPanning:
return XC_sb_left_arrow;
case WebCursorInfo::TypeMove:
return XC_fleur;
case WebCursorInfo::TypeVerticalText:
return XC_left_ptr;
case WebCursorInfo::TypeCell:
return XC_left_ptr;
case WebCursorInfo::TypeContextMenu:
return XC_left_ptr;
case WebCursorInfo::TypeAlias:
return XC_left_ptr;
case WebCursorInfo::TypeProgress:
return XC_left_ptr;
case WebCursorInfo::TypeNoDrop:
return XC_left_ptr;
case WebCursorInfo::TypeCopy:
return XC_left_ptr;
case WebCursorInfo::TypeNotAllowed:
return XC_left_ptr;
case WebCursorInfo::TypeZoomIn:
return XC_left_ptr;
case WebCursorInfo::TypeZoomOut:
return XC_left_ptr;
case WebCursorInfo::TypeGrab:
return XC_left_ptr;
case WebCursorInfo::TypeGrabbing:
return XC_left_ptr;
case WebCursorInfo::TypeCustom:
case WebCursorInfo::TypeNone:
break;
}
NOTREACHED();
return 0;
}
} // namespace
ui::PlatformCursor CefBrowserHostImpl::GetPlatformCursor(
blink::WebCursorInfo::Type type) {
if (type == WebCursorInfo::TypeNone) {
if (!invisible_cursor_) {
invisible_cursor_.reset(
new ui::XScopedCursor(ui::CreateInvisibleCursor(),
gfx::GetXDisplay()));
}
return invisible_cursor_->get();
} else {
return ui::GetXCursor(ToCursorID(type));
}
}
bool CefBrowserHostImpl::PlatformCreateWindow() {
DCHECK(!window_x11_);
DCHECK(!window_widget_);
@@ -119,7 +232,7 @@ void CefBrowserHostImpl::PlatformSetFocus(bool focus) {
}
CefWindowHandle CefBrowserHostImpl::PlatformGetWindowHandle() {
return window_info_.window;
return IsWindowless() ? window_info_.parent_window : window_info_.window;
}
bool CefBrowserHostImpl::PlatformViewText(const std::string& text) {
@@ -175,7 +288,32 @@ void CefBrowserHostImpl::PlatformHandleExternalProtocol(const GURL& url) {
void CefBrowserHostImpl::PlatformTranslateKeyEvent(
content::NativeWebKeyboardEvent& result,
const CefKeyEvent& key_event) {
NOTIMPLEMENTED();
result.timeStampSeconds = GetSystemUptime();
result.windowsKeyCode = key_event.windows_key_code;
result.nativeKeyCode = key_event.native_key_code;
result.isSystemKey = key_event.is_system_key ? 1 : 0;
switch (key_event.type) {
case KEYEVENT_RAWKEYDOWN:
case KEYEVENT_KEYDOWN:
result.type = blink::WebInputEvent::RawKeyDown;
break;
case KEYEVENT_KEYUP:
result.type = blink::WebInputEvent::KeyUp;
break;
case KEYEVENT_CHAR:
result.type = blink::WebInputEvent::Char;
break;
default:
NOTREACHED();
}
result.text[0] = key_event.character;
result.unmodifiedText[0] = key_event.unmodified_character;
result.setKeyIdentifierFromWindowsKeyCode();
result.modifiers |= TranslateModifiers(key_event.modifiers);
}
void CefBrowserHostImpl::PlatformTranslateClickEvent(
@@ -274,7 +412,14 @@ void CefBrowserHostImpl::PlatformTranslateMouseEvent(
result.globalX = result.x;
result.globalY = result.y;
// TODO(linux): Convert global{X,Y} to screen coordinates.
if (IsWindowless()) {
GetClient()->GetRenderHandler()->GetScreenPoint(
GetBrowser(),
result.x, result.y,
result.globalX, result.globalY);
} else {
// TODO(linux): Convert global{X,Y} to screen coordinates.
}
// modifiers
result.modifiers |= TranslateModifiers(mouse_event.modifiers);

View File

@@ -8,6 +8,8 @@
#import <Cocoa/Cocoa.h>
#import <CoreServices/CoreServices.h>
#include "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/browser/text_input_client_osr_mac.h"
#include "libcef/browser/thread_util.h"
#include "base/file_util.h"
@@ -286,6 +288,59 @@ bool CefBrowserHostImpl::PlatformViewText(const std::string& text) {
return false;
}
CefTextInputContext CefBrowserHostImpl::GetNSTextInputContext() {
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return NULL;
}
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "Called on invalid thread";
return NULL;
}
CefRenderWidgetHostViewOSR* rwhv = static_cast<CefRenderWidgetHostViewOSR*>(
GetWebContents()->GetRenderWidgetHostView());
return rwhv->GetNSTextInputContext();
}
void CefBrowserHostImpl::HandleKeyEventBeforeTextInputClient(
CefEventHandle keyEvent) {
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "Called on invalid thread";
return;
}
CefRenderWidgetHostViewOSR* rwhv = static_cast<CefRenderWidgetHostViewOSR*>(
GetWebContents()->GetRenderWidgetHostView());
rwhv->HandleKeyEventBeforeTextInputClient(keyEvent);
}
void CefBrowserHostImpl::HandleKeyEventAfterTextInputClient(
CefEventHandle keyEvent) {
if (!IsWindowless()) {
NOTREACHED() << "Window rendering is not disabled";
return;
}
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "Called on invalid thread";
return;
}
CefRenderWidgetHostViewOSR* rwhv = static_cast<CefRenderWidgetHostViewOSR*>(
GetWebContents()->GetRenderWidgetHostView());
rwhv->HandleKeyEventAfterTextInputClient(keyEvent);
}
bool CefBrowserHostImpl::PlatformCreateWindow() {
base::mac::ScopedNSAutoreleasePool autorelease_pool;
@@ -382,7 +437,7 @@ void CefBrowserHostImpl::PlatformSetFocus(bool focus) {
web_contents_->GetRenderWidgetHostView()) {
view->SetActive(focus);
if (focus) {
if (focus && !IsWindowless()) {
// Give keyboard focus to the native view.
NSView* view = web_contents_->GetContentNativeView();
DCHECK([view canBecomeKeyView]);
@@ -402,7 +457,7 @@ void CefBrowserHostImpl::PlatformSetWindowVisibility(bool visible) {
}
CefWindowHandle CefBrowserHostImpl::PlatformGetWindowHandle() {
return window_info_.view;
return IsWindowless() ? window_info_.parent_view : window_info_.view;
}
void CefBrowserHostImpl::PlatformHandleKeyboardEvent(
@@ -616,14 +671,21 @@ void CefBrowserHostImpl::PlatformTranslateMouseEvent(
result.globalX = result.x;
result.globalY = result.y;
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;
if (IsWindowless()) {
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

View File

@@ -716,7 +716,7 @@ void CefBrowserHostImpl::PlatformSetFocus(bool focus) {
}
CefWindowHandle CefBrowserHostImpl::PlatformGetWindowHandle() {
return window_info_.window;
return IsWindowless() ? window_info_.parent_window : window_info_.window;
}
bool CefBrowserHostImpl::PlatformViewText(const std::string& text) {
@@ -922,11 +922,17 @@ void CefBrowserHostImpl::PlatformTranslateMouseEvent(
result.globalX = result.x;
result.globalY = result.y;
// global position
POINT globalPoint = { result.x, result.y };
ClientToScreen(GetWindowHandle(), &globalPoint);
result.globalX = globalPoint.x;
result.globalY = globalPoint.y;
if (IsWindowless()) {
GetClient()->GetRenderHandler()->GetScreenPoint(
GetBrowser(),
result.x, result.y,
result.globalX, result.globalY);
} else {
POINT globalPoint = { result.x, result.y };
ClientToScreen(GetWindowHandle(), &globalPoint);
result.globalX = globalPoint.x;
result.globalY = globalPoint.y;
}
// modifiers
result.modifiers |= TranslateModifiers(mouse_event.modifiers);

View File

@@ -7,13 +7,18 @@
CefBrowserInfo::CefBrowserInfo(int browser_id, bool is_popup)
: browser_id_(browser_id),
is_popup_(is_popup) {
is_popup_(is_popup),
is_windowless_(false) {
DCHECK_GT(browser_id, 0);
}
CefBrowserInfo::~CefBrowserInfo() {
}
void CefBrowserInfo::set_windowless(bool windowless) {
is_windowless_ = windowless;
}
void CefBrowserInfo::add_render_view_id(
int render_process_id, int render_routing_id) {
add_render_id(&render_view_id_set_, render_process_id, render_routing_id);

View File

@@ -24,6 +24,9 @@ class CefBrowserInfo : public base::RefCountedThreadSafe<CefBrowserInfo> {
int browser_id() const { return browser_id_; };
bool is_popup() const { return is_popup_; }
bool is_windowless() const { return is_windowless_; }
void set_windowless(bool windowless);
// Adds an ID pair if it doesn't already exist.
void add_render_view_id(int render_process_id, int render_routing_id);
@@ -55,6 +58,7 @@ class CefBrowserInfo : public base::RefCountedThreadSafe<CefBrowserInfo> {
int browser_id_;
bool is_popup_;
bool is_windowless_;
base::Lock lock_;

View File

@@ -91,6 +91,7 @@ void CefBrowserMessageFilter::OnGetNewBrowserInfo(
render_frame_routing_id);
params->browser_id = info->browser_id();
params->is_popup = info->is_popup();
params->is_windowless = info->is_windowless();
}
void CefBrowserMessageFilter::OnCreateWindow(

View File

@@ -74,6 +74,8 @@ class CefAccessTokenStore : public content::AccessTokenStore {
private:
AccessTokenSet access_token_set_;
DISALLOW_COPY_AND_ASSIGN(CefAccessTokenStore);
};
class CefQuotaCallbackImpl : public CefQuotaCallback {
@@ -134,6 +136,7 @@ class CefQuotaCallbackImpl : public CefQuotaCallback {
content::QuotaPermissionContext::PermissionCallback callback_;
IMPLEMENT_REFCOUNTING(CefQuotaCallbackImpl);
DISALLOW_COPY_AND_ASSIGN(CefQuotaCallbackImpl);
};
class CefAllowCertificateErrorCallbackImpl
@@ -164,6 +167,7 @@ class CefAllowCertificateErrorCallbackImpl
base::Callback<void(bool)> callback_;
IMPLEMENT_REFCOUNTING(CefAllowCertificateErrorCallbackImpl);
DISALLOW_COPY_AND_ASSIGN(CefAllowCertificateErrorCallbackImpl);
};
class CefQuotaPermissionContext : public content::QuotaPermissionContext {
@@ -214,6 +218,8 @@ class CefQuotaPermissionContext : public content::QuotaPermissionContext {
private:
virtual ~CefQuotaPermissionContext() {
}
DISALLOW_COPY_AND_ASSIGN(CefQuotaPermissionContext);
};
class CefPluginServiceFilter : public content::PluginServiceFilter {
@@ -255,6 +261,8 @@ class CefPluginServiceFilter : public content::PluginServiceFilter {
const base::FilePath& path) OVERRIDE {
return true;
}
DISALLOW_COPY_AND_ASSIGN(CefPluginServiceFilter);
};
void TranslatePopupFeatures(const blink::WebWindowFeatures& webKitFeatures,

View File

@@ -103,6 +103,11 @@ bool CefMenuCreator::CreateContextMenu(
return runner_->RunContextMenu(this);
}
void CefMenuCreator::CancelContextMenu() {
if (IsShowingContextMenu())
runner_->CancelContextMenu();
}
bool CefMenuCreator::CreateRunner() {
if (!runner_.get()) {
// Create the menu runner.

View File

@@ -24,6 +24,7 @@ class CefMenuCreator : public CefMenuModelImpl::Delegate {
public:
virtual ~Runner() {}
virtual bool RunContextMenu(CefMenuCreator* manager) =0;
virtual void CancelContextMenu() {}
virtual bool FormatLabel(base::string16& label) { return false; }
};
@@ -35,6 +36,7 @@ class CefMenuCreator : public CefMenuModelImpl::Delegate {
// Create the context menu.
bool CreateContextMenu(const content::ContextMenuParams& params);
void CancelContextMenu();
CefBrowserHostImpl* browser() { return browser_; }
ui::MenuModel* model() { return model_->model(); }

View File

@@ -24,14 +24,34 @@ CefMenuCreatorRunnerLinux::~CefMenuCreatorRunnerLinux() {
bool CefMenuCreatorRunnerLinux::RunContextMenu(CefMenuCreator* manager) {
menu_.reset(new views::MenuRunner(manager->model()));
// We can't use aura::Window::GetBoundsInScreen on Linux because it will
// return bounds from DesktopWindowTreeHostX11 which in our case is relative
// to the parent window instead of the root window (screen).
const gfx::Rect& bounds_in_screen =
manager->browser()->window_x11()->GetBoundsInScreen();
gfx::Point screen_point =
gfx::Point(bounds_in_screen.x() + manager->params().x,
bounds_in_screen.y() + manager->params().y);
gfx::Point screen_point;
if (manager->browser()->IsWindowless()) {
CefRefPtr<CefClient> client = manager->browser()->GetClient();
if (!client.get())
return false;
CefRefPtr<CefRenderHandler> handler = client->GetRenderHandler();
if (!handler.get())
return false;
int screenX = 0, screenY = 0;
if (!handler->GetScreenPoint(manager->browser(),
manager->params().x, manager->params().y,
screenX, screenY)) {
return false;
}
screen_point = gfx::Point(screenX, screenY);
} else {
// We can't use aura::Window::GetBoundsInScreen on Linux because it will
// return bounds from DesktopWindowTreeHostX11 which in our case is relative
// to the parent window instead of the root window (screen).
const gfx::Rect& bounds_in_screen =
manager->browser()->window_x11()->GetBoundsInScreen();
screen_point = gfx::Point(bounds_in_screen.x() + manager->params().x,
bounds_in_screen.y() + manager->params().y);
}
views::MenuRunner::RunResult result =
menu_->RunMenuAt(manager->browser()->window_widget(),
@@ -44,6 +64,11 @@ bool CefMenuCreatorRunnerLinux::RunContextMenu(CefMenuCreator* manager) {
return true;
}
void CefMenuCreatorRunnerLinux::CancelContextMenu() {
if (menu_)
menu_->Cancel();
}
bool CefMenuCreatorRunnerLinux::FormatLabel(base::string16& label) {
// Remove the accelerator indicator (&) from label strings.
const char16 replace[] = {L'&', 0};

View File

@@ -18,6 +18,7 @@ class CefMenuCreatorRunnerLinux: public CefMenuCreator::Runner {
// CefMemoryManager::Runner methods.
virtual bool RunContextMenu(CefMenuCreator* manager) OVERRIDE;
virtual void CancelContextMenu() OVERRIDE;
virtual bool FormatLabel(base::string16& label) OVERRIDE;
private:

View File

@@ -61,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()->IsWindowless()) {
// Showing the menu in OSR is pretty much self contained, only using
// the initialized menu_controller_ in this function, and the scoped
// variables in this block.
int screenX = 0, screenY = 0;
CefRefPtr<CefRenderHandler> handler =
manager->browser()->GetClient()->GetRenderHandler();
if (!handler->GetScreenPoint(manager->browser(),
manager->params().x, manager->params().y,
screenX, screenY)) {
return false;
}
// Don't show the menu unless there is a parent native window to tie it to
if (!manager->browser()->GetWindowHandle())
return false;
NSPoint screen_position =
NSPointFromCGPoint(gfx::Point(screenX, screenY).ToCGPoint());
[[menu_controller_ menu] popUpMenuPositioningItem:nil
atLocation:screen_position
inView:nil];
} else {
[NSMenu popUpContextMenu:[menu_controller_ menu]
withEvent:clickEvent
forView:parent_view];
}
}
return true;

View File

@@ -24,10 +24,29 @@ bool CefMenuCreatorRunnerWin::RunContextMenu(CefMenuCreator* manager) {
gfx::Point screen_point;
aura::Window* window = manager->browser()->GetContentView();
const gfx::Rect& bounds_in_screen = window->GetBoundsInScreen();
screen_point = gfx::Point(bounds_in_screen.x() + manager->params().x,
bounds_in_screen.y() + manager->params().y);
if (manager->browser()->IsWindowless()) {
CefRefPtr<CefClient> client = manager->browser()->GetClient();
if (!client.get())
return false;
CefRefPtr<CefRenderHandler> handler = client->GetRenderHandler();
if (!handler.get())
return false;
int screenX = 0, screenY = 0;
if (!handler->GetScreenPoint(manager->browser(),
manager->params().x, manager->params().y,
screenX, screenY)) {
return false;
}
screen_point = gfx::Point(screenX, screenY);
} else {
aura::Window* window = manager->browser()->GetContentView();
const gfx::Rect& bounds_in_screen = window->GetBoundsInScreen();
screen_point = gfx::Point(bounds_in_screen.x() + manager->params().x,
bounds_in_screen.y() + manager->params().y);
}
// Show the menu. Blocks until the menu is dismissed.
menu_->RunMenuAt(screen_point, views::Menu2::ALIGN_TOPLEFT);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,341 @@
// Copyright (c) 2014 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_RENDER_WIDGET_HOST_VIEW_OSR_H_
#define CEF_LIBCEF_BROWSER_RENDER_WIDGET_HOST_VIEW_OSR_H_
#pragma once
#include <vector>
#include "include/cef_base.h"
#include "include/cef_browser.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/compositor/delegated_frame_host.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "ui/compositor/compositor.h"
#if defined(OS_WIN)
#include "ui/gfx/win/window_impl.h"
#endif
namespace content {
class RenderWidgetHost;
class RenderWidgetHostImpl;
class BackingStore;
}
class CefBrowserHostImpl;
class CefWebContentsViewOSR;
#if defined(OS_MACOSX)
#ifdef __OBJC__
@class NSWindow;
#else
class NSWindow;
#endif
#endif
#if defined(USE_X11)
class CefWindowX11;
#endif
///////////////////////////////////////////////////////////////////////////////
// CefRenderWidgetHostViewOSR
//
// An object representing the "View" of a rendered web page. This object is
// responsible for sending paint events to the the CefRenderHandler
// when window rendering is disabled. It is the implementation of the
// RenderWidgetHostView that the cross-platform RenderWidgetHost object uses
// to display the data.
//
// Comment excerpted from render_widget_host.h:
//
// "The lifetime of the RenderWidgetHostView is tied to the render process.
// If the render process dies, the RenderWidgetHostView goes away and all
// references to it must become NULL."
//
// RenderWidgetHostView class hierarchy described in render_widget_host_view.h.
///////////////////////////////////////////////////////////////////////////////
class CefRenderWidgetHostViewOSR
: public content::RenderWidgetHostViewBase,
public content::DelegatedFrameHostClient {
public:
explicit CefRenderWidgetHostViewOSR(content::RenderWidgetHost* widget);
virtual ~CefRenderWidgetHostViewOSR();
// RenderWidgetHostView implementation.
virtual void InitAsChild(gfx::NativeView parent_view) OVERRIDE;
virtual content::RenderWidgetHost* GetRenderWidgetHost() const OVERRIDE;
virtual void SetSize(const gfx::Size& size) OVERRIDE;
virtual void SetBounds(const gfx::Rect& rect) OVERRIDE;
virtual gfx::NativeView GetNativeView() const OVERRIDE;
virtual gfx::NativeViewId GetNativeViewId() const OVERRIDE;
virtual gfx::NativeViewAccessible GetNativeViewAccessible() OVERRIDE;
virtual ui::TextInputClient* GetTextInputClient() OVERRIDE;
virtual void Focus() OVERRIDE;
virtual bool HasFocus() const OVERRIDE;
virtual bool IsSurfaceAvailableForCopy() const OVERRIDE;
virtual void Show() OVERRIDE;
virtual void Hide() OVERRIDE;
virtual bool IsShowing() OVERRIDE;
virtual gfx::Rect GetViewBounds() const OVERRIDE;
virtual void SetBackgroundOpaque(bool opaque) OVERRIDE;
virtual bool LockMouse() OVERRIDE;
virtual void UnlockMouse() 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)
// RenderWidgetHostViewBase implementation.
virtual void OnSwapCompositorFrame(
uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame) OVERRIDE;
virtual void InitAsPopup(content::RenderWidgetHostView* parent_host_view,
const gfx::Rect& pos) OVERRIDE;
virtual void InitAsFullscreen(
content::RenderWidgetHostView* reference_host_view) OVERRIDE;
virtual void WasShown() OVERRIDE;
virtual void WasHidden() OVERRIDE;
virtual void MovePluginWindows(
const std::vector<content::WebPluginGeometry>& moves) OVERRIDE;
virtual void Blur() OVERRIDE;
virtual void UpdateCursor(const content::WebCursor& cursor) OVERRIDE;
virtual void SetIsLoading(bool is_loading) OVERRIDE;
virtual void TextInputTypeChanged(ui::TextInputType type,
ui::TextInputMode input_mode,
bool can_compose_inline) OVERRIDE;
virtual void ImeCancelComposition() OVERRIDE;
virtual void RenderProcessGone(base::TerminationStatus status,
int error_code) OVERRIDE;
virtual void Destroy() OVERRIDE;
virtual void SetTooltipText(const base::string16& tooltip_text) OVERRIDE;
virtual void SelectionChanged(const base::string16& text,
size_t offset,
const gfx::Range& range) OVERRIDE;
virtual gfx::Size GetRequestedRendererSize() const OVERRIDE;
virtual gfx::Size GetPhysicalBackingSize() const OVERRIDE;
virtual void SelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params& params) OVERRIDE;
virtual void ScrollOffsetChanged() OVERRIDE;
virtual void CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const base::Callback<void(bool, const SkBitmap&)>& callback,
const SkBitmap::Config config) OVERRIDE;
virtual void CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
const base::Callback<void(bool)>& callback) OVERRIDE;
virtual bool CanCopyToVideoFrame() const OVERRIDE;
virtual bool CanSubscribeFrame() const OVERRIDE;
virtual void BeginFrameSubscription(
scoped_ptr<content::RenderWidgetHostViewFrameSubscriber> subscriber)
OVERRIDE;
virtual void EndFrameSubscription() OVERRIDE;
virtual void AcceleratedSurfaceInitialized(int host_id,
int route_id) OVERRIDE;
virtual void AcceleratedSurfaceBuffersSwapped(
const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params_in_pixel,
int gpu_host_id) OVERRIDE;
virtual void AcceleratedSurfacePostSubBuffer(
const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params_in_pixel,
int gpu_host_id) OVERRIDE;
virtual void AcceleratedSurfaceSuspend() OVERRIDE;
virtual void AcceleratedSurfaceRelease() OVERRIDE;
virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) OVERRIDE;
virtual void GetScreenInfo(blink::WebScreenInfo* results) OVERRIDE;
virtual gfx::Rect GetBoundsInRootWindow() OVERRIDE;
virtual gfx::GLSurfaceHandle GetCompositingSurface() OVERRIDE;
virtual void SetScrollOffsetPinning(
bool is_pinned_to_left,
bool is_pinned_to_right) OVERRIDE;
#if defined(OS_MACOSX)
virtual bool PostProcessEventForPluginIme(
const content::NativeWebKeyboardEvent& event) OVERRIDE;
#endif
#if defined(OS_MACOSX) || defined(USE_AURA)
virtual void ImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds) OVERRIDE;
#endif
#if defined(OS_WIN)
virtual void SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) OVERRIDE;
virtual gfx::NativeViewId GetParentForWindowlessPlugin() const OVERRIDE;
#endif
// DelegatedFrameHost implementation.
virtual ui::Compositor* GetCompositor() const OVERRIDE;
virtual ui::Layer* GetLayer() OVERRIDE;
virtual content::RenderWidgetHostImpl* GetHost() OVERRIDE;
virtual void SchedulePaintInRect(
const gfx::Rect& damage_rect_in_dip) OVERRIDE;
virtual void DelegatedCompositorDidSwapBuffers() OVERRIDE;
virtual void DelegatedCompositorAbortedSwapBuffers() OVERRIDE;
virtual bool IsVisible() OVERRIDE;
virtual scoped_ptr<content::ResizeLock> CreateResizeLock(
bool defer_compositor_lock) OVERRIDE;
virtual gfx::Size DesiredFrameSize() OVERRIDE;
virtual float CurrentDeviceScaleFactor() OVERRIDE;
virtual gfx::Size ConvertViewSizeToPixel(const gfx::Size& size) OVERRIDE;
virtual content::DelegatedFrameHost* GetDelegatedFrameHost() const OVERRIDE;
bool InstallTransparency();
void WasResized();
void OnScreenInfoChanged();
void Invalidate(CefBrowserHost::PaintElementType type);
void SendKeyEvent(const content::NativeWebKeyboardEvent& event);
void SendMouseEvent(const blink::WebMouseEvent& event);
void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event);
void SendFocusEvent(bool focus);
void HoldResize();
void ReleaseResize();
bool IsPopupWidget() const {
return popup_type_ != blink::WebPopupTypeNone;
}
#if defined(OS_MACOSX)
NSTextInputContext* GetNSTextInputContext();
void HandleKeyEventBeforeTextInputClient(CefEventHandle keyEvent);
void HandleKeyEventAfterTextInputClient(CefEventHandle keyEvent);
bool GetCachedFirstRectForCharacterRange(gfx::Range range, gfx::Rect* rect,
gfx::Range* actual_range) const;
#endif // defined(OS_MACOSX)
CefRefPtr<CefBrowserHostImpl> browser_impl() const { return browser_impl_; }
void set_browser_impl(CefRefPtr<CefBrowserHostImpl> browser) {
browser_impl_ = browser;
}
void set_popup_host_view(CefRenderWidgetHostViewOSR* popup_view) {
popup_host_view_ = popup_view;
}
ui::Compositor* compositor() const { return compositor_.get(); }
content::RenderWidgetHostImpl* render_widget_host() const
{ return render_widget_host_; }
private:
void SetFrameRate();
void ResizeRootLayer();
// Implementation based on RendererOverridesHandler::InnerSwapCompositorFrame
// and DelegatedFrameHost::CopyFromCompositingSurface.
void GenerateFrame(bool force_frame);
void InternalGenerateFrame();
void CopyFromCompositingSurfaceHasResult(
scoped_ptr<cc::CopyOutputResult> result);
void PrepareTextureCopyOutputResult(
scoped_ptr<cc::CopyOutputResult> result);
static void CopyFromCompositingSurfaceFinishedProxy(
base::WeakPtr<CefRenderWidgetHostViewOSR> view,
scoped_ptr<cc::SingleReleaseCallback> release_callback,
scoped_ptr<SkBitmap> bitmap,
scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
bool result);
void CopyFromCompositingSurfaceFinished(
scoped_ptr<SkBitmap> bitmap,
scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
bool result);
void PrepareBitmapCopyOutputResult(
scoped_ptr<cc::CopyOutputResult> result);
void OnFrameCaptureFailure();
void OnFrameCaptureSuccess(
const SkBitmap& bitmap,
scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock);
void OnFrameCaptureCompletion(bool force_frame);
void CancelPopupWidget();
#if defined(OS_MACOSX)
// Returns composition character boundary rectangle. The |range| is
// composition based range. Also stores |actual_range| which is corresponding
// to actually used range for returned rectangle.
gfx::Rect GetFirstRectForCompositionRange(const gfx::Range& range,
gfx::Range* actual_range) const;
// Converts from given whole character range to composition oriented range. If
// the conversion failed, return gfx::Range::InvalidRange.
gfx::Range ConvertCharacterRangeToCompositionRange(
const gfx::Range& request_range) const;
// Returns true if there is line break in |range| and stores line breaking
// point to |line_breaking_point|. The |line_break_point| is valid only if
// this function returns true.
static bool GetLineBreakIndex(const std::vector<gfx::Rect>& bounds,
const gfx::Range& range,
size_t* line_break_point);
void DestroyNSTextInputOSR();
#endif // defined(OS_MACOSX)
void PlatformCreateCompositorWidget();
void PlatformDestroyCompositorWidget();
scoped_ptr<content::DelegatedFrameHost> delegated_frame_host_;
scoped_ptr<ui::Compositor> compositor_;
gfx::AcceleratedWidget compositor_widget_;
scoped_ptr<ui::Layer> root_layer_;
#if defined(OS_WIN)
scoped_ptr<gfx::WindowImpl> window_;
#elif defined(OS_MACOSX)
NSWindow* window_;
#elif defined(USE_X11)
CefWindowX11* window_;
#endif
int frame_rate_threshold_ms_;
base::TimeTicks frame_start_time_;
bool frame_pending_;
bool frame_in_progress_;
int frame_retry_count_;
scoped_ptr<SkBitmap> bitmap_;
bool hold_resize_;
bool pending_resize_;
// The associated Model. While |this| is being Destroyed,
// |render_widget_host_| is NULL and the message loop is run one last time
// Message handlers must check for a NULL |render_widget_host_|.
content::RenderWidgetHostImpl* render_widget_host_;
CefRenderWidgetHostViewOSR* parent_host_view_;
CefRenderWidgetHostViewOSR* popup_host_view_;
CefRefPtr<CefBrowserHostImpl> browser_impl_;
bool is_showing_;
bool is_destroyed_;
gfx::Rect popup_position_;
#if defined(OS_MACOSX)
NSTextInputContext* text_input_context_osr_mac_;
#endif
base::WeakPtrFactory<CefRenderWidgetHostViewOSR> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CefRenderWidgetHostViewOSR);
};
#endif // CEF_LIBCEF_BROWSER_RENDER_WIDGET_HOST_VIEW_OSR_H_

View File

@@ -0,0 +1,25 @@
// Copyright (c) 2014 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/render_widget_host_view_osr.h"
#include <X11/Xlib.h>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/window_x11.h"
#include "ui/gfx/x/x11_types.h"
void CefRenderWidgetHostViewOSR::PlatformCreateCompositorWidget() {
// Create a hidden 1x1 window. It will delete itself on close.
window_ = new CefWindowX11(NULL, None, gfx::Rect(0, 0, 1, 1));
compositor_widget_ = window_->xwindow();
}
void CefRenderWidgetHostViewOSR::PlatformDestroyCompositorWidget() {
DCHECK(window_);
window_->Close();
compositor_widget_ = gfx::kNullAcceleratedWidget;
}

View File

@@ -0,0 +1,283 @@
// Copyright (c) 2014 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/render_widget_host_view_osr.h"
#import <Cocoa/Cocoa.h>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/text_input_client_osr_mac.h"
#include "content/browser/compositor/browser_compositor_view_mac.h"
#if !defined(UNUSED)
#define UNUSED(x) ((void)(x)) /* to avoid warnings */
#endif
namespace {
CefTextInputClientOSRMac* GetInputClientFromContext(
const NSTextInputContext* context) {
if (!context)
return NULL;
return reinterpret_cast<CefTextInputClientOSRMac*>([context client]);
}
} // namespace
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() {
}
void CefRenderWidgetHostViewOSR::TextInputTypeChanged(
ui::TextInputType type,
ui::TextInputMode mode,
bool can_compose_inline) {
[NSApp updateWindows];
}
void CefRenderWidgetHostViewOSR::ImeCancelComposition() {
CefTextInputClientOSRMac* client = GetInputClientFromContext(
text_input_context_osr_mac_);
if (client)
[client cancelComposition];
}
bool CefRenderWidgetHostViewOSR::PostProcessEventForPluginIme(
const content::NativeWebKeyboardEvent& event) {
return false;
}
void CefRenderWidgetHostViewOSR::ImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds) {
CefTextInputClientOSRMac* client = GetInputClientFromContext(
text_input_context_osr_mac_);
if (!client)
return;
client->markedRange_ = range.ToNSRange();
client->composition_range_ = range;
client->composition_bounds_ = character_bounds;
}
CefTextInputContext CefRenderWidgetHostViewOSR::GetNSTextInputContext() {
if (!text_input_context_osr_mac_) {
CefTextInputClientOSRMac* text_input_client_osr_mac =
[[CefTextInputClientOSRMac alloc] initWithRenderWidgetHostViewOSR:
this];
text_input_context_osr_mac_ = [[NSTextInputContext alloc] initWithClient:
text_input_client_osr_mac];
}
return text_input_context_osr_mac_;
}
void CefRenderWidgetHostViewOSR::HandleKeyEventBeforeTextInputClient(
CefEventHandle keyEvent) {
CefTextInputClientOSRMac* client = GetInputClientFromContext(
text_input_context_osr_mac_);
if (client)
[client HandleKeyEventBeforeTextInputClient: keyEvent];
}
void CefRenderWidgetHostViewOSR::HandleKeyEventAfterTextInputClient(
CefEventHandle keyEvent) {
CefTextInputClientOSRMac* client = GetInputClientFromContext(
text_input_context_osr_mac_);
if (client)
[client HandleKeyEventAfterTextInputClient: keyEvent];
}
bool CefRenderWidgetHostViewOSR::GetCachedFirstRectForCharacterRange(
gfx::Range range, gfx::Rect* rect, gfx::Range* actual_range) const {
DCHECK(rect);
CefTextInputClientOSRMac* client = GetInputClientFromContext(
text_input_context_osr_mac_);
// If requested range is same as caret location, we can just return it.
if (selection_range_.is_empty() && gfx::Range(range) == selection_range_) {
if (actual_range)
*actual_range = range;
*rect = client->caret_rect_;
return true;
}
const gfx::Range request_range_in_composition =
ConvertCharacterRangeToCompositionRange(gfx::Range(range));
if (request_range_in_composition == gfx::Range::InvalidRange())
return false;
// If firstRectForCharacterRange in WebFrame is failed in renderer,
// ImeCompositionRangeChanged will be sent with empty vector.
if (client->composition_bounds_.empty())
return false;
DCHECK_EQ(client->composition_bounds_.size(),
client->composition_range_.length());
gfx::Range ui_actual_range;
*rect = GetFirstRectForCompositionRange(request_range_in_composition,
&ui_actual_range);
if (actual_range) {
*actual_range = gfx::Range(
client->composition_range_.start() + ui_actual_range.start(),
client->composition_range_.start() + ui_actual_range.end()).ToNSRange();
}
return true;
}
gfx::Rect CefRenderWidgetHostViewOSR::GetFirstRectForCompositionRange(
const gfx::Range& range, gfx::Range* actual_range) const {
CefTextInputClientOSRMac* client = GetInputClientFromContext(
text_input_context_osr_mac_);
DCHECK(client);
DCHECK(actual_range);
DCHECK(!client->composition_bounds_.empty());
DCHECK_LE(range.start(), client->composition_bounds_.size());
DCHECK_LE(range.end(), client->composition_bounds_.size());
if (range.is_empty()) {
*actual_range = range;
if (range.start() == client->composition_bounds_.size()) {
return gfx::Rect(client->composition_bounds_[range.start() - 1].right(),
client->composition_bounds_[range.start() - 1].y(),
0,
client->composition_bounds_[range.start() - 1].height());
} else {
return gfx::Rect(client->composition_bounds_[range.start()].x(),
client->composition_bounds_[range.start()].y(),
0,
client->composition_bounds_[range.start()].height());
}
}
size_t end_idx;
if (!GetLineBreakIndex(client->composition_bounds_,
range, &end_idx)) {
end_idx = range.end();
}
*actual_range = gfx::Range(range.start(), end_idx);
gfx::Rect rect = client->composition_bounds_[range.start()];
for (size_t i = range.start() + 1; i < end_idx; ++i) {
rect.Union(client->composition_bounds_[i]);
}
return rect;
}
gfx::Range CefRenderWidgetHostViewOSR::ConvertCharacterRangeToCompositionRange(
const gfx::Range& request_range) const {
CefTextInputClientOSRMac* client = GetInputClientFromContext(
text_input_context_osr_mac_);
DCHECK(client);
if (client->composition_range_.is_empty())
return gfx::Range::InvalidRange();
if (request_range.is_reversed())
return gfx::Range::InvalidRange();
if (request_range.start() < client->composition_range_.start()
|| request_range.start() > client->composition_range_.end()
|| request_range.end() > client->composition_range_.end())
return gfx::Range::InvalidRange();
return gfx::Range(request_range.start() - client->composition_range_.start(),
request_range.end() - client->composition_range_.start());
}
bool CefRenderWidgetHostViewOSR::GetLineBreakIndex(
const std::vector<gfx::Rect>& bounds,
const gfx::Range& range,
size_t* line_break_point) {
DCHECK(line_break_point);
if (range.start() >= bounds.size() || range.is_reversed() || range.is_empty())
return false;
// We can't check line breaking completely from only rectangle array. Thus we
// assume the line breaking as the next character's y offset is larger than
// a threshold. Currently the threshold is determined as minimum y offset plus
// 75% of maximum height.
const size_t loop_end_idx = std::min(bounds.size(), range.end());
int max_height = 0;
int min_y_offset = kint32max;
for (size_t idx = range.start(); idx < loop_end_idx; ++idx) {
max_height = std::max(max_height, bounds[idx].height());
min_y_offset = std::min(min_y_offset, bounds[idx].y());
}
int line_break_threshold = min_y_offset + (max_height * 3 / 4);
for (size_t idx = range.start(); idx < loop_end_idx; ++idx) {
if (bounds[idx].y() > line_break_threshold) {
*line_break_point = idx;
return true;
}
}
return false;
}
void CefRenderWidgetHostViewOSR::DestroyNSTextInputOSR() {
CefTextInputClientOSRMac* client = GetInputClientFromContext(
text_input_context_osr_mac_);
if (client) {
[client release];
client = NULL;
}
[text_input_context_osr_mac_ release];
text_input_context_osr_mac_ = NULL;
}
void CefRenderWidgetHostViewOSR::PlatformCreateCompositorWidget() {
// Create a borderless non-visible 1x1 window.
window_ = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 1, 1)
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
BrowserCompositorViewMac* view =
[[BrowserCompositorViewMac alloc] initWithSuperview:[window_ contentView]
withClient:NULL];
compositor_.reset([view compositor]);
DCHECK(compositor_);
compositor_widget_ = view;
}
void CefRenderWidgetHostViewOSR::PlatformDestroyCompositorWidget() {
DCHECK(window_);
// Compositor is owned by and will be freed by BrowserCompositorViewMac.
ui::Compositor* compositor = compositor_.release();
UNUSED(compositor);
[window_ close];
window_ = nil;
compositor_widget_ = gfx::kNullAcceleratedWidget;
}

View File

@@ -0,0 +1,59 @@
// Copyright (c) 2014 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/browser/browser_host_impl.h"
namespace {
class CefCompositorHostWin : public gfx::WindowImpl {
public:
CefCompositorHostWin() {
// Create a hidden 1x1 borderless window.
set_window_style(WS_POPUP | WS_SYSMENU);
Init(NULL, gfx::Rect(0, 0, 1, 1));
}
virtual ~CefCompositorHostWin() {
DestroyWindow(hwnd());
}
private:
CR_BEGIN_MSG_MAP_EX(CompositorHostWin)
CR_MSG_WM_PAINT(OnPaint)
CR_END_MSG_MAP()
void OnPaint(HDC dc) {
ValidateRect(hwnd(), NULL);
}
DISALLOW_COPY_AND_ASSIGN(CefCompositorHostWin);
};
} // namespace
void CefRenderWidgetHostViewOSR::SetParentNativeViewAccessible(
gfx::NativeViewAccessible accessible_parent) {
}
gfx::NativeViewId
CefRenderWidgetHostViewOSR::GetParentForWindowlessPlugin() const {
if (browser_impl_.get()) {
return reinterpret_cast<gfx::NativeViewId>(
browser_impl_->GetWindowHandle());
}
return NULL;
}
void CefRenderWidgetHostViewOSR::PlatformCreateCompositorWidget() {
DCHECK(!window_);
window_.reset(new CefCompositorHostWin());
compositor_widget_ = window_->hwnd();
}
void CefRenderWidgetHostViewOSR::PlatformDestroyCompositorWidget() {
window_.reset(NULL);
compositor_widget_ = gfx::kNullAcceleratedWidget;
}

View File

@@ -0,0 +1,89 @@
// 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_LIBCEF_BROWSER_TEXT_INPUT_CLIENT_OSR_MAC_H_
#define CEF_LIBCEF_BROWSER_TEXT_INPUT_CLIENT_OSR_MAC_H_
#pragma once
#import <Cocoa/Cocoa.h>
#include <vector>
#include "libcef/browser/render_widget_host_view_osr.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/string16.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/edit_command.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
// Implementation for the NSTextInputClient protocol used for enabling IME on
// mac when window rendering is disabled.
@interface CefTextInputClientOSRMac : NSObject<NSTextInputClient> {
@public
// The range of current marked text inside the whole content of the DOM node
// being edited.
NSRange markedRange_;
// The current composition character range and its bounds.
gfx::Range composition_range_;
std::vector<gfx::Rect> composition_bounds_;
// The current caret bounds.
gfx::Rect caret_rect_;
@private
// Represents the input-method attributes supported by this object.
base::scoped_nsobject<NSArray> validAttributesForMarkedText_;
// Indicates if we are currently handling a key down event.
BOOL handlingKeyDown_;
// Indicates if there is any marked text.
BOOL hasMarkedText_;
// Indicates whether there was any marked text prior to handling
// the current key event.
BOOL oldHasMarkedText_;
// Indicates if unmarkText is called or not when handling a keyboard
// event.
BOOL unmarkTextCalled_;
// The selected range, cached from a message sent by the renderer.
NSRange selectedRange_;
// Text to be inserted which was generated by handling a key down event.
base::string16 textToBeInserted_;
// Marked text which was generated by handling a key down event.
base::string16 markedText_;
// Underline information of the |markedText_|.
std::vector<blink::WebCompositionUnderline> underlines_;
// Indicates if doCommandBySelector method receives any edit command when
// handling a key down event.
BOOL hasEditCommands_;
// Contains edit commands received by the -doCommandBySelector: method when
// handling a key down event, not including inserting commands, eg. insertTab,
// etc.
content::EditCommands editCommands_;
CefRenderWidgetHostViewOSR* renderWidgetHostView_;
}
@property(nonatomic, readonly) NSRange selectedRange;
@property(nonatomic) BOOL handlingKeyDown;
- (id)initWithRenderWidgetHostViewOSR:(CefRenderWidgetHostViewOSR*) rwhv;
- (void)HandleKeyEventBeforeTextInputClient:(NSEvent*)keyEvent;
- (void)HandleKeyEventAfterTextInputClient:(NSEvent*)keyEvent;
- (void)cancelComposition;
@end
#endif // CEF_LIBCEF_BROWSER_TEXT_INPUT_CLIENT_OSR_MAC_H_

View File

@@ -0,0 +1,359 @@
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "libcef/browser/text_input_client_osr_mac.h"
#include "libcef/browser/browser_host_impl.h"
#include "base/strings/sys_string_conversions.h"
#import "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h"
#import "content/browser/renderer_host/text_input_client_mac.h"
#include "content/common/input_messages.h"
namespace {
// TODO(suzhe): Upstream this function.
blink::WebColor WebColorFromNSColor(NSColor *color) {
CGFloat r, g, b, a;
[color getRed:&r green:&g blue:&b alpha:&a];
return
std::max(0, std::min(static_cast<int>(lroundf(255.0f * a)), 255)) << 24 |
std::max(0, std::min(static_cast<int>(lroundf(255.0f * r)), 255)) << 16 |
std::max(0, std::min(static_cast<int>(lroundf(255.0f * g)), 255)) << 8 |
std::max(0, std::min(static_cast<int>(lroundf(255.0f * b)), 255));
}
// Extract underline information from an attributed string. Mostly copied from
// third_party/WebKit/Source/WebKit/mac/WebView/WebHTMLView.mm
void ExtractUnderlines(NSAttributedString* string,
std::vector<blink::WebCompositionUnderline>* underlines) {
int length = [[string string] length];
int i = 0;
while (i < length) {
NSRange range;
NSDictionary* attrs = [string attributesAtIndex:i
longestEffectiveRange:&range
inRange:NSMakeRange(i, length - i)];
NSNumber *style = [attrs objectForKey: NSUnderlineStyleAttributeName];
if (style) {
blink::WebColor color = SK_ColorBLACK;
if (NSColor *colorAttr =
[attrs objectForKey:NSUnderlineColorAttributeName]) {
color = WebColorFromNSColor(
[colorAttr colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
}
underlines->push_back(blink::WebCompositionUnderline(
range.location, NSMaxRange(range), color, [style intValue] > 1));
}
i = range.location + range.length;
}
}
} // namespace
extern "C" {
extern NSString* NSTextInputReplacementRangeAttributeName;
}
@implementation CefTextInputClientOSRMac
@synthesize selectedRange = selectedRange_;
@synthesize handlingKeyDown = handlingKeyDown_;
- (id)initWithRenderWidgetHostViewOSR:(CefRenderWidgetHostViewOSR*)rwhv {
self = [super init];
renderWidgetHostView_ = rwhv;
return self;
}
- (NSArray*)validAttributesForMarkedText {
if (!validAttributesForMarkedText_) {
validAttributesForMarkedText_.reset([[NSArray alloc] initWithObjects:
NSUnderlineStyleAttributeName,
NSUnderlineColorAttributeName,
NSMarkedClauseSegmentAttributeName,
NSTextInputReplacementRangeAttributeName,
nil]);
}
return validAttributesForMarkedText_.get();
}
- (NSRange)markedRange {
return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0);
}
- (BOOL)hasMarkedText {
return hasMarkedText_;
}
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange {
BOOL isAttributedString = [aString isKindOfClass:[NSAttributedString class]];
NSString* im_text = isAttributedString ? [aString string] : aString;
if (handlingKeyDown_) {
textToBeInserted_.append(base::SysNSStringToUTF16(im_text));
} else {
gfx::Range replacement_range(replacementRange);
renderWidgetHostView_->render_widget_host()->ImeConfirmComposition(
base::SysNSStringToUTF16(im_text), replacement_range, false);
}
// Inserting text will delete all marked text automatically.
hasMarkedText_ = NO;
}
- (void)doCommandBySelector:(SEL)aSelector {
// An input method calls this function to dispatch an editing command to be
// handled by this view.
if (aSelector == @selector(noop:))
return;
std::string command([content::RenderWidgetHostViewMacEditCommandHelper::
CommandNameForSelector(aSelector) UTF8String]);
// If this method is called when handling a key down event, then we need to
// handle the command in the key event handler. Otherwise we can just handle
// it here.
if (handlingKeyDown_) {
hasEditCommands_ = YES;
// We ignore commands that insert characters, because this was causing
// strange behavior (e.g. tab always inserted a tab rather than moving to
// the next field on the page).
if (!StartsWithASCII(command, "insert", false))
editCommands_.push_back(content::EditCommand(command, ""));
} else {
renderWidgetHostView_->render_widget_host()->Send(
new InputMsg_ExecuteEditCommand(
renderWidgetHostView_->render_widget_host()->GetRoutingID(),
command, ""));
}
}
- (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelRange
replacementRange:(NSRange)replacementRange {
// An input method updates the composition string.
// We send the given text and range to the renderer so it can update the
// composition node of WebKit.
BOOL isAttributedString = [aString isKindOfClass:[NSAttributedString class]];
NSString* im_text = isAttributedString ? [aString string] : aString;
int length = [im_text length];
// |markedRange_| will get set on a callback from ImeSetComposition().
selectedRange_ = newSelRange;
markedText_ = base::SysNSStringToUTF16(im_text);
hasMarkedText_ = (length > 0);
underlines_.clear();
if (isAttributedString) {
ExtractUnderlines(aString, &underlines_);
} else {
// Use a thin black underline by default.
underlines_.push_back(blink::WebCompositionUnderline(0, length,
SK_ColorBLACK, false));
}
// If we are handling a key down event, then SetComposition() will be
// called in keyEvent: method.
// Input methods of Mac use setMarkedText calls with an empty text to cancel
// an ongoing composition. So, we should check whether or not the given text
// is empty to update the input method state. (Our input method backend can
// automatically cancels an ongoing composition when we send an empty text.
// So, it is OK to send an empty text to the renderer.)
if (!handlingKeyDown_) {
renderWidgetHostView_->render_widget_host()->ImeSetComposition(
markedText_, underlines_, newSelRange.location,
NSMaxRange(newSelRange));
}
}
- (void)unmarkText {
// Delete the composition node of the renderer and finish an ongoing
// composition.
// It seems an input method calls the setMarkedText method and set an empty
// text when it cancels an ongoing composition, i.e. I have never seen an
// input method calls this method.
hasMarkedText_ = NO;
markedText_.clear();
underlines_.clear();
// If we are handling a key down event, then ConfirmComposition() will be
// called in keyEvent: method.
if (!handlingKeyDown_) {
renderWidgetHostView_->render_widget_host()->ImeConfirmComposition(
base::string16(), gfx::Range::InvalidRange(), false);
} else {
unmarkTextCalled_ = YES;
}
}
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range
actualRange:(NSRangePointer)actualRange {
if (actualRange)
*actualRange = range;
NSAttributedString* str = content::TextInputClientMac::GetInstance()->
GetAttributedSubstringFromRange(
renderWidgetHostView_->GetRenderWidgetHost(), range);
return str;
}
- (NSRect)firstViewRectForCharacterRange:(NSRange)theRange
actualRange:(NSRangePointer)actualRange {
NSRect rect;
gfx::Rect gfxRect;
gfx::Range range(theRange);
gfx::Range actual_range;
if (!renderWidgetHostView_->GetCachedFirstRectForCharacterRange(range,
&gfxRect, &actual_range)) {
rect = content::TextInputClientMac::GetInstance()->
GetFirstRectForRange(renderWidgetHostView_->GetRenderWidgetHost(),
range.ToNSRange());
if (actualRange)
*actualRange = range.ToNSRange();
} else {
rect = NSRectFromCGRect(gfxRect.ToCGRect());
}
return rect;
}
- (NSRect) screenRectFromViewRect:(NSRect)rect {
NSRect screenRect;
int screenX, screenY;
renderWidgetHostView_->browser_impl()->GetClient()->GetRenderHandler()->
GetScreenPoint(renderWidgetHostView_->browser_impl()->GetBrowser(),
rect.origin.x, rect.origin.y, screenX, screenY);
screenRect.origin = NSMakePoint(screenX, screenY);
screenRect.size = rect.size;
return screenRect;
}
- (NSRect)firstRectForCharacterRange:(NSRange)theRange
actualRange:(NSRangePointer)actualRange {
NSRect rect = [self firstViewRectForCharacterRange:theRange
actualRange:actualRange];
// Convert into screen coordinates for return.
rect = [self screenRectFromViewRect:rect];
if (rect.origin.y >= rect.size.height)
rect.origin.y -= rect.size.height;
else
rect.origin.y = 0;
return rect;
}
- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint {
// |thePoint| is in screen coordinates, but needs to be converted to WebKit
// coordinates (upper left origin). Scroll offsets will be taken care of in
// the renderer.
CefRect view_rect;
renderWidgetHostView_->browser_impl()->GetClient()->GetRenderHandler()->
GetViewRect(renderWidgetHostView_->browser_impl()->GetBrowser(),
view_rect);
thePoint.x -= view_rect.x;
thePoint.y -= view_rect.y;
thePoint.y = view_rect.height - thePoint.y;
NSUInteger index = content::TextInputClientMac::GetInstance()->
GetCharacterIndexAtPoint(renderWidgetHostView_->GetRenderWidgetHost(),
gfx::Point(thePoint.x, thePoint.y));
return index;
}
- (void)HandleKeyEventBeforeTextInputClient:(NSEvent*)keyEvent {
DCHECK([keyEvent type] == NSKeyDown);
// Don't call this method recursively.
DCHECK(!handlingKeyDown_);
oldHasMarkedText_ = hasMarkedText_;
handlingKeyDown_ = YES;
// These variables might be set when handling the keyboard event.
// Clear them here so that we can know whether they have changed afterwards.
textToBeInserted_.clear();
markedText_.clear();
underlines_.clear();
unmarkTextCalled_ = NO;
hasEditCommands_ = NO;
editCommands_.clear();
}
- (void)HandleKeyEventAfterTextInputClient:(NSEvent*)keyEvent {
handlingKeyDown_ = NO;
// Then send keypress and/or composition related events.
// If there was a marked text or the text to be inserted is longer than 1
// character, then we send the text by calling ConfirmComposition().
// Otherwise, if the text to be inserted only contains 1 character, then we
// can just send a keypress event which is fabricated by changing the type of
// the keydown event, so that we can retain all necessary informations, such
// as unmodifiedText, etc. And we need to set event.skip_in_browser to true to
// prevent the browser from handling it again.
// Note that, |textToBeInserted_| is a UTF-16 string, but it's fine to only
// handle BMP characters here, as we can always insert non-BMP characters as
// text.
if (!hasMarkedText_ && !oldHasMarkedText_ &&
textToBeInserted_.length() <= 1) {
content::NativeWebKeyboardEvent event(keyEvent);
if (textToBeInserted_.length() == 1) {
event.type = blink::WebInputEvent::Type::Char;
event.text[0] = textToBeInserted_[0];
event.text[1] = 0;
}
renderWidgetHostView_->SendKeyEvent(event);
}
BOOL textInserted = NO;
if (textToBeInserted_.length() >
((hasMarkedText_ || oldHasMarkedText_) ? 0u : 1u)) {
renderWidgetHostView_->render_widget_host()->ImeConfirmComposition(
textToBeInserted_, gfx::Range::InvalidRange(), false);
textToBeInserted_ = YES;
}
// Updates or cancels the composition. If some text has been inserted, then
// we don't need to cancel the composition explicitly.
if (hasMarkedText_ && markedText_.length()) {
// Sends the updated marked text to the renderer so it can update the
// composition node in WebKit.
// When marked text is available, |selectedRange_| will be the range being
// selected inside the marked text.
renderWidgetHostView_->render_widget_host()->ImeSetComposition(
markedText_, underlines_, selectedRange_.location,
NSMaxRange(selectedRange_));
} else if (oldHasMarkedText_ && !hasMarkedText_ && !textInserted) {
if (unmarkTextCalled_) {
renderWidgetHostView_->render_widget_host()->ImeConfirmComposition(
base::string16(), gfx::Range::InvalidRange(), false);
} else {
renderWidgetHostView_->render_widget_host()->ImeCancelComposition();
}
}
}
- (void)cancelComposition {
if (!hasMarkedText_)
return;
// Cancel the ongoing composition. [NSInputManager markedTextAbandoned:]
// doesn't call any NSTextInput functions, such as setMarkedText or
// insertText. So, we need to send an IPC message to a renderer so it can
// delete the composition node.
NSInputManager *currentInputManager = [NSInputManager currentInputManager];
[currentInputManager markedTextAbandoned:self];
hasMarkedText_ = NO;
// Should not call [self unmarkText] here, because it'll send unnecessary
// cancel composition IPC message to the renderer.
}
@end

View File

@@ -0,0 +1,167 @@
// Copyright (c) 2014 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/web_contents_view_osr.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/common/drag_data_impl.h"
#include "content/public/browser/render_widget_host.h"
CefWebContentsViewOSR::CefWebContentsViewOSR(
content::WebContents* web_contents,
content::WebContentsViewDelegate* delegate)
: web_contents_(web_contents),
view_(NULL) {
}
CefWebContentsViewOSR::~CefWebContentsViewOSR() {
}
gfx::NativeView CefWebContentsViewOSR::GetNativeView() const {
return gfx::NativeView();
}
gfx::NativeView CefWebContentsViewOSR::GetContentNativeView() const {
return gfx::NativeView();
}
gfx::NativeWindow CefWebContentsViewOSR::GetTopLevelNativeWindow() const {
return gfx::NativeWindow();
}
void CefWebContentsViewOSR::GetContainerBounds(gfx::Rect* out) const {
*out = GetViewBounds();
}
void CefWebContentsViewOSR::SizeContents(const gfx::Size& size) {
}
void CefWebContentsViewOSR::Focus() {
}
void CefWebContentsViewOSR::SetInitialFocus() {
}
void CefWebContentsViewOSR::StoreFocus() {
}
void CefWebContentsViewOSR::RestoreFocus() {
}
content::DropData* CefWebContentsViewOSR::GetDropData() const {
return NULL;
}
gfx::Rect CefWebContentsViewOSR::GetViewBounds() const {
return view_ ? view_->GetViewBounds() : gfx::Rect();
}
void CefWebContentsViewOSR::CreateView(const gfx::Size& initial_size,
gfx::NativeView context) {
}
content::RenderWidgetHostViewBase* CefWebContentsViewOSR::CreateViewForWidget(
content::RenderWidgetHost* render_widget_host) {
if (render_widget_host->GetView()) {
return static_cast<content::RenderWidgetHostViewBase*>(
render_widget_host->GetView());
}
view_ = new CefRenderWidgetHostViewOSR(render_widget_host);
return view_;
}
content::RenderWidgetHostViewBase*
CefWebContentsViewOSR::CreateViewForPopupWidget(
content::RenderWidgetHost* render_widget_host) {
return new CefRenderWidgetHostViewOSR(render_widget_host);
}
void CefWebContentsViewOSR::SetPageTitle(const base::string16& title) {
}
void CefWebContentsViewOSR::RenderViewCreated(content::RenderViewHost* host) {
if (view_)
view_->InstallTransparency();
}
void CefWebContentsViewOSR::RenderViewSwappedIn(
content::RenderViewHost* host) {
}
void CefWebContentsViewOSR::SetOverscrollControllerEnabled(bool enabled) {
}
#if defined(OS_MACOSX)
void CefWebContentsViewOSR::SetAllowOverlappingViews(bool overlapping) {
}
bool CefWebContentsViewOSR::GetAllowOverlappingViews() const {
return false;
}
void CefWebContentsViewOSR::SetOverlayView(
content::WebContentsView* overlay,
const gfx::Point& offset) {
}
void CefWebContentsViewOSR::RemoveOverlayView() {
}
bool CefWebContentsViewOSR::IsEventTracking() const {
return false;
}
void CefWebContentsViewOSR::CloseTabAfterEventTracking() {
}
#endif // defined(OS_MACOSX)
void CefWebContentsViewOSR::StartDragging(
const content::DropData& drop_data,
blink::WebDragOperationsMask allowed_ops,
const gfx::ImageSkia& image,
const gfx::Vector2d& image_offset,
const content::DragEventSourceInfo& event_info) {
CefRefPtr<CefBrowserHostImpl> browser;
CefRefPtr<CefRenderHandler> handler;
bool handled = false;
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(view_);
if (view)
browser = view->browser_impl();
if (browser.get())
handler = browser->GetClient()->GetRenderHandler();
DCHECK(handler.get());
if (handler.get()) {
CefRefPtr<CefDragDataImpl> drag_data(new CefDragDataImpl(drop_data));
drag_data->SetReadOnly(true);
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
handled = handler->StartDragging(browser->GetBrowser(),
drag_data.get(),
static_cast<CefRenderHandler::DragOperationsMask>(allowed_ops),
event_info.event_location.x(),
event_info.event_location.y());
}
if (!handled && web_contents_)
web_contents_->SystemDragEnded();
}
void CefWebContentsViewOSR::UpdateDragCursor(
blink::WebDragOperation operation) {
CefRefPtr<CefBrowserHostImpl> browser;
CefRefPtr<CefRenderHandler> handler;
CefRenderWidgetHostViewOSR* view =
static_cast<CefRenderWidgetHostViewOSR*>(view_);
if (view)
browser = view->browser_impl();
if (browser.get())
handler = browser->GetClient()->GetRenderHandler();
DCHECK(handler.get());
if (handler.get()) {
handler->UpdateDragCursor(browser->GetBrowser(),
static_cast<CefRenderHandler::DragOperation>(operation));
}
}

View File

@@ -0,0 +1,76 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_WEB_CONTENTS_VIEW_OSR_H_
#define CEF_LIBCEF_BROWSER_WEB_CONTENTS_VIEW_OSR_H_
#include "content/browser/renderer_host/render_view_host_delegate_view.h"
#include "content/browser/web_contents/web_contents_view.h"
namespace content {
class WebContents;
class WebContentsViewDelegate;
}
class CefRenderWidgetHostViewOSR;
// An implementation of WebContentsView for off-screen rendering.
class CefWebContentsViewOSR : public content::WebContentsView,
public content::RenderViewHostDelegateView {
public:
CefWebContentsViewOSR(content::WebContents* web_contents,
content::WebContentsViewDelegate* delegate);
virtual ~CefWebContentsViewOSR();
// WebContentsView methods.
virtual gfx::NativeView GetNativeView() const OVERRIDE;
virtual gfx::NativeView GetContentNativeView() const OVERRIDE;
virtual gfx::NativeWindow GetTopLevelNativeWindow() const OVERRIDE;
virtual void GetContainerBounds(gfx::Rect* out) const OVERRIDE;
virtual void SizeContents(const gfx::Size& size) OVERRIDE;
virtual void Focus() OVERRIDE;
virtual void SetInitialFocus() OVERRIDE;
virtual void StoreFocus() OVERRIDE;
virtual void RestoreFocus() OVERRIDE;
virtual content::DropData* GetDropData() const OVERRIDE;
virtual gfx::Rect GetViewBounds() const OVERRIDE;
virtual void CreateView(const gfx::Size& initial_size,
gfx::NativeView context) OVERRIDE;
virtual content::RenderWidgetHostViewBase* CreateViewForWidget(
content::RenderWidgetHost* render_widget_host) OVERRIDE;
virtual content::RenderWidgetHostViewBase* CreateViewForPopupWidget(
content::RenderWidgetHost* render_widget_host) OVERRIDE;
virtual void SetPageTitle(const base::string16& title) OVERRIDE;
virtual void RenderViewCreated(content::RenderViewHost* host) OVERRIDE;
virtual void RenderViewSwappedIn(content::RenderViewHost* host) OVERRIDE;
virtual void SetOverscrollControllerEnabled(bool enabled) OVERRIDE;
#if defined(OS_MACOSX)
virtual void SetAllowOverlappingViews(bool overlapping) OVERRIDE;
virtual bool GetAllowOverlappingViews() const OVERRIDE;
virtual void SetOverlayView(content::WebContentsView* overlay,
const gfx::Point& offset) OVERRIDE;
virtual void RemoveOverlayView() OVERRIDE;
virtual bool IsEventTracking() const OVERRIDE;
virtual void CloseTabAfterEventTracking() OVERRIDE;
#endif
// RenderViewHostDelegateView methods.
virtual void StartDragging(
const content::DropData& drop_data,
blink::WebDragOperationsMask allowed_ops,
const gfx::ImageSkia& image,
const gfx::Vector2d& image_offset,
const content::DragEventSourceInfo& event_info) OVERRIDE;
virtual void UpdateDragCursor(blink::WebDragOperation operation) OVERRIDE;
private:
content::WebContents* web_contents_;
CefRenderWidgetHostViewOSR* view_;
DISALLOW_COPY_AND_ASSIGN(CefWebContentsViewOSR);
};
#endif // CEF_LIBCEF_BROWSER_WEB_CONTENTS_VIEW_OSR_H_

View File

@@ -173,10 +173,14 @@ void CefWindowX11::Focus() {
if (xwindow_ == None || !window_mapped_)
return;
::Window child = FindChild(xdisplay_, xwindow_);
if (child && ui::IsWindowVisible(child)) {
// Give focus to the child DesktopWindowTreeHostX11.
XSetInputFocus(xdisplay_, child, RevertToParent, CurrentTime);
if (browser_) {
::Window child = FindChild(xdisplay_, xwindow_);
if (child && ui::IsWindowVisible(child)) {
// Give focus to the child DesktopWindowTreeHostX11.
XSetInputFocus(xdisplay_, child, RevertToParent, CurrentTime);
}
} else {
XSetInputFocus(xdisplay_, xwindow_, RevertToParent, CurrentTime);
}
}
@@ -233,13 +237,15 @@ uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) {
xev->xconfigure.width, xev->xconfigure.height);
bounds_ = bounds;
::Window child = FindChild(xdisplay_, xwindow_);
if (child) {
// Resize the child DesktopWindowTreeHostX11 to match this window.
XWindowChanges changes = {0};
changes.width = bounds.width();
changes.height = bounds.height();
XConfigureWindow(xdisplay_, child, CWHeight | CWWidth, &changes);
if (browser_) {
::Window child = FindChild(xdisplay_, xwindow_);
if (child) {
// Resize the child DesktopWindowTreeHostX11 to match this window.
XWindowChanges changes = {0};
changes.width = bounds.width();
changes.height = bounds.height();
XConfigureWindow(xdisplay_, child, CWHeight | CWWidth, &changes);
}
}
break;
}
@@ -247,7 +253,7 @@ uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) {
Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]);
if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
// We have received a close message from the window manager.
if (browser_->destruction_state() <=
if (browser_ && browser_->destruction_state() <=
CefBrowserHostImpl::DESTRUCTION_STATE_PENDING) {
if (browser_->destruction_state() ==
CefBrowserHostImpl::DESTRUCTION_STATE_NONE) {
@@ -276,9 +282,11 @@ uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) {
case DestroyNotify:
xwindow_ = None;
// Force the browser to be destroyed and release the reference added
// in PlatformCreateWindow().
browser_->WindowDestroyed();
if (browser_) {
// Force the browser to be destroyed and release the reference added
// in PlatformCreateWindow().
browser_->WindowDestroyed();
}
delete this;
break;
@@ -311,8 +319,7 @@ uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) {
void CefWindowX11::ContinueFocus() {
if (!focus_pending_)
return;
browser_->SetFocus(true);
if (browser_)
browser_->SetFocus(true);
focus_pending_ = false;
}

View File

@@ -151,6 +151,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_windowless)
IPC_STRUCT_END()
// Retrieve information about a newly created browser.

View File

@@ -2,55 +2,127 @@
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include <string>
#include "libcef/browser/stream_impl.h"
#include "libcef/common/drag_data_impl.h"
#include "base/files/file_path.h"
#include "net/base/filename_util.h"
#include "net/base/net_util.h"
#define CHECK_READONLY_RETURN_VOID() \
if (read_only_) { \
NOTREACHED() << "object is read only"; \
return; \
}
CefDragDataImpl::CefDragDataImpl(const content::DropData& data)
: data_(data) {
: data_(data),
read_only_(false) {
}
CefDragDataImpl::CefDragDataImpl()
: read_only_(false) {
}
CefRefPtr<CefDragData> CefDragData::Create() {
return new CefDragDataImpl();
}
CefRefPtr<CefDragData> CefDragDataImpl::Clone() {
CefDragDataImpl* drag_data = NULL;
{
AutoLock lock_scope(this);
drag_data = new CefDragDataImpl(data_);
}
return drag_data;
}
bool CefDragDataImpl::IsReadOnly() {
AutoLock lock_scope(this);
return read_only_;
}
bool CefDragDataImpl::IsLink() {
AutoLock lock_scope(this);
return (data_.url.is_valid() && data_.file_description_filename.empty());
}
bool CefDragDataImpl::IsFragment() {
AutoLock lock_scope(this);
return (!data_.url.is_valid() && data_.file_description_filename.empty() &&
data_.filenames.empty());
}
bool CefDragDataImpl::IsFile() {
AutoLock lock_scope(this);
return (!data_.file_description_filename.empty() || !data_.filenames.empty());
}
CefString CefDragDataImpl::GetLinkURL() {
AutoLock lock_scope(this);
return data_.url.spec();
}
CefString CefDragDataImpl::GetLinkTitle() {
AutoLock lock_scope(this);
return data_.url_title;
}
CefString CefDragDataImpl::GetLinkMetadata() {
AutoLock lock_scope(this);
return data_.download_metadata;
}
CefString CefDragDataImpl::GetFragmentText() {
AutoLock lock_scope(this);
return data_.text.is_null() ? CefString() : CefString(data_.text.string());
}
CefString CefDragDataImpl::GetFragmentHtml() {
AutoLock lock_scope(this);
return data_.html.is_null() ? CefString() : CefString(data_.html.string());
}
CefString CefDragDataImpl::GetFragmentBaseURL() {
AutoLock lock_scope(this);
return data_.html_base_url.spec();
}
CefString CefDragDataImpl::GetFileName() {
return data_.file_description_filename;
AutoLock lock_scope(this);
if (data_.file_description_filename.empty())
return CefString();
base::FilePath file_name(CefString(data_.file_description_filename));
// Images without ALT text will only have a file extension so we need to
// synthesize one from the provided extension and URL.
if (file_name.BaseName().RemoveExtension().empty()) {
CefString extension = file_name.Extension();
// Retrieve the name from the URL.
CefString suggested_file_name =
net::GetSuggestedFilename(data_.url, "", "", "", "", "");
file_name = base::FilePath(suggested_file_name).ReplaceExtension(extension);
}
return file_name.value();
}
size_t CefDragDataImpl::GetFileContents(CefRefPtr<CefStreamWriter> writer) {
AutoLock lock_scope(this);
if (data_.file_contents.empty())
return 0;
char* data = const_cast<char*>(data_.file_contents.c_str());
size_t size = data_.file_contents.size();
if (!writer.get())
return size;
return writer->Write(data, 1, size);
}
bool CefDragDataImpl::GetFileNames(std::vector<CefString>& names) {
AutoLock lock_scope(this);
if (data_.filenames.empty())
return false;
@@ -61,3 +133,62 @@ bool CefDragDataImpl::GetFileNames(std::vector<CefString>& names) {
return true;
}
void CefDragDataImpl::SetLinkURL(const CefString& url) {
AutoLock lock_scope(this);
CHECK_READONLY_RETURN_VOID();
data_.url = GURL(url.ToString());
}
void CefDragDataImpl::SetLinkTitle(const CefString& title) {
AutoLock lock_scope(this);
CHECK_READONLY_RETURN_VOID();
data_.url_title = title.ToString16();
}
void CefDragDataImpl::SetLinkMetadata(const CefString& data) {
AutoLock lock_scope(this);
CHECK_READONLY_RETURN_VOID();
data_.download_metadata = data.ToString16();
}
void CefDragDataImpl::SetFragmentText(const CefString& text) {
AutoLock lock_scope(this);
CHECK_READONLY_RETURN_VOID();
data_.text = base::NullableString16(text.ToString16(), false);
}
void CefDragDataImpl::SetFragmentHtml(const CefString& fragment) {
AutoLock lock_scope(this);
CHECK_READONLY_RETURN_VOID();
data_.html = base::NullableString16(fragment.ToString16(), false);
}
void CefDragDataImpl::SetFragmentBaseURL(const CefString& fragment) {
AutoLock lock_scope(this);
CHECK_READONLY_RETURN_VOID();
data_.html_base_url = GURL(fragment.ToString());
}
void CefDragDataImpl::ResetFileContents() {
AutoLock lock_scope(this);
CHECK_READONLY_RETURN_VOID();
data_.file_contents.erase();
data_.file_description_filename.erase();
}
void CefDragDataImpl::AddFile(const CefString& path,
const CefString& display_name) {
AutoLock lock_scope(this);
CHECK_READONLY_RETURN_VOID();
data_.filenames.push_back(ui::FileInfo(base::FilePath(path),
base::FilePath(display_name)));
}
void CefDragDataImpl::SetReadOnly(bool read_only) {
AutoLock lock_scope(this);
if (read_only_ == read_only)
return;
read_only_ = read_only;
}

View File

@@ -14,7 +14,10 @@
// Implementation of CefDragData.
class CefDragDataImpl : public CefDragData {
public:
CefDragDataImpl();
explicit CefDragDataImpl(const content::DropData& data);
virtual CefRefPtr<CefDragData> Clone();
virtual bool IsReadOnly();
virtual bool IsLink();
virtual bool IsFragment();
@@ -26,12 +29,33 @@ class CefDragDataImpl : public CefDragData {
virtual CefString GetFragmentHtml();
virtual CefString GetFragmentBaseURL();
virtual CefString GetFileName();
virtual size_t GetFileContents(CefRefPtr<CefStreamWriter> writer);
virtual bool GetFileNames(std::vector<CefString>& names);
virtual void SetLinkURL(const CefString& url);
virtual void SetLinkTitle(const CefString& title);
virtual void SetLinkMetadata(const CefString& data);
virtual void SetFragmentText(const CefString& text);
virtual void SetFragmentHtml(const CefString& fragment);
virtual void SetFragmentBaseURL(const CefString& fragment);
virtual void ResetFileContents();
virtual void AddFile(const CefString& path, const CefString& display_name);
// This method is not safe. Use Lock/Unlock to get mutually exclusive access.
const content::DropData& drop_data() {
return data_;
}
void SetReadOnly(bool read_only);
protected:
content::DropData data_;
// True if this object is read-only.
bool read_only_;
IMPLEMENT_REFCOUNTING(CefDragDataImpl);
IMPLEMENT_LOCKING(CefDragDataImpl);
};
#endif // CEF_LIBCEF_COMMON_DRAG_DATA_IMPL_H_

View File

@@ -288,6 +288,13 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
command_line->AppendSwitchASCII(switches::kContextSafetyImplementation,
base::IntToString(settings.context_safety_implementation));
}
if (settings.windowless_rendering_enabled) {
#if defined(OS_MACOSX)
// The delegated renderer is not yet enabled by default on OS X.
command_line->AppendSwitch(switches::kEnableDelegatedRenderer);
#endif
}
}
if (content_client_.application().get()) {

View File

@@ -268,10 +268,12 @@ bool CefBrowserImpl::SendProcessMessage(CefProcessId target_process,
CefBrowserImpl::CefBrowserImpl(content::RenderView* render_view,
int browser_id,
bool is_popup)
bool is_popup,
bool is_windowless)
: content::RenderViewObserver(render_view),
browser_id_(browser_id),
is_popup_(is_popup),
is_windowless_(is_windowless),
last_focused_frame_id_(webkit_glue::kInvalidFrameId) {
response_manager_.reset(new CefResponseManager);
}

View File

@@ -75,7 +75,8 @@ class CefBrowserImpl : public CefBrowser,
CefBrowserImpl(content::RenderView* render_view,
int browser_id,
bool is_popup);
bool is_popup,
bool is_windowless);
virtual ~CefBrowserImpl();
void LoadRequest(const CefMsg_LoadRequest_Params& params);
@@ -95,6 +96,7 @@ class CefBrowserImpl : public CefBrowser,
int browser_id() const { return browser_id_; }
bool is_popup() const { return is_popup_; }
bool is_windowless() const { return is_windowless_; }
content::RenderView* render_view() const {
return content::RenderViewObserver::render_view();
}
@@ -137,6 +139,7 @@ class CefBrowserImpl : public CefBrowser,
// same browser ID.
int browser_id_;
bool is_popup_;
bool is_windowless_;
// Id of the last frame that had focus.
int64 last_focused_frame_id_;

View File

@@ -54,6 +54,7 @@ MSVC_POP_WARNING();
#include "third_party/WebKit/public/platform/WebWorkerRunLoop.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebPluginParams.h"
#include "third_party/WebKit/public/web/WebPrerendererClient.h"
@@ -434,6 +435,90 @@ void CefContentRendererClient::RenderViewCreated(
BrowserCreated(render_view, render_view->GetMainRenderFrame());
}
bool CefContentRendererClient::OverrideCreatePlugin(
content::RenderFrame* render_frame,
blink::WebLocalFrame* frame,
const blink::WebPluginParams& params,
blink::WebPlugin** plugin) {
CefRefPtr<CefBrowserImpl> browser =
CefBrowserImpl::GetBrowserForMainFrame(frame->top());
if (!browser || !browser->is_windowless())
return false;
#if defined(ENABLE_PLUGINS)
if (base::UTF16ToASCII(params.mimeType) == content::kBrowserPluginMimeType)
return false;
content::RenderFrameImpl* render_frame_impl =
static_cast<content::RenderFrameImpl*>(render_frame);
content::WebPluginInfo info;
std::string mime_type;
bool found = false;
render_frame_impl->Send(
new FrameHostMsg_GetPluginInfo(
render_frame_impl->GetRoutingID(),
params.url,
frame->top()->document().url(),
params.mimeType.utf8(),
&found,
&info,
&mime_type));
if (!found)
return false;
bool flash = LowerCaseEqualsASCII(mime_type,
"application/x-shockwave-flash");
bool silverlight = StartsWithASCII(mime_type,
"application/x-silverlight", false);
if (flash) {
// "wmode" values of "opaque" or "transparent" are allowed.
size_t size = params.attributeNames.size();
for (size_t i = 0; i < size; ++i) {
std::string name = params.attributeNames[i].utf8();
if (name == "wmode") {
std::string value = params.attributeValues[i].utf8();
if (value == "opaque" || value == "transparent")
flash = false;
break;
}
}
}
if (flash || silverlight) {
// Force Flash and Silverlight plugins to use windowless mode.
blink::WebPluginParams params_to_use = params;
params_to_use.mimeType = blink::WebString::fromUTF8(mime_type);
size_t size = params.attributeNames.size();
blink::WebVector<blink::WebString> new_names(size+1),
new_values(size+1);
for (size_t i = 0; i < size; ++i) {
new_names[i] = params.attributeNames[i];
new_values[i] = params.attributeValues[i];
}
if (flash) {
new_names[size] = "wmode";
new_values[size] = "opaque";
} else if (silverlight) {
new_names[size] = "windowless";
new_values[size] = "true";
}
params_to_use.attributeNames.swap(new_names);
params_to_use.attributeValues.swap(new_values);
*plugin = render_frame_impl->CreatePlugin(frame, info, params_to_use);
return true;
}
#endif // defined(ENABLE_PLUGINS)
return false;
}
bool CefContentRendererClient::HandleNavigation(
content::RenderFrame* render_frame,
content::DocumentState* document_state,
@@ -578,8 +663,18 @@ void CefContentRendererClient::BrowserCreated(
if (GetBrowserForView(render_view))
return;
#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_windowless);
#endif
CefRefPtr<CefBrowserImpl> browser =
new CefBrowserImpl(render_view, params.browser_id, params.is_popup);
new CefBrowserImpl(render_view, params.browser_id, params.is_popup,
params.is_windowless);
browsers_.insert(std::make_pair(render_view, browser));
new CefPrerendererClient(render_view);

View File

@@ -76,6 +76,11 @@ class CefContentRendererClient : public content::ContentRendererClient,
virtual void RenderThreadStarted() OVERRIDE;
virtual void RenderFrameCreated(content::RenderFrame* render_frame) OVERRIDE;
virtual void RenderViewCreated(content::RenderView* render_view) OVERRIDE;
virtual bool OverrideCreatePlugin(
content::RenderFrame* render_frame,
blink::WebLocalFrame* frame,
const blink::WebPluginParams& params,
blink::WebPlugin** plugin) OVERRIDE;
virtual bool HandleNavigation(content::RenderFrame* render_frame,
content::DocumentState* document_state,
int opener_id,