cef/libcef/browser/render_widget_host_view_osr.cc

1095 lines
32 KiB
C++

// 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"
#include "libcef/browser/thread_util.h"
#include "base/callback_helpers.h"
#include "cc/output/copy_output_request.h"
#include "content/browser/compositor/image_transport_factory.h"
#include "content/browser/compositor/resize_lock.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/public/browser/context_factory.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
#include "third_party/WebKit/public/platform/WebScreenInfo.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/image/image_skia_operations.h"
namespace {
const float kDefaultScaleFactor = 1.0;
// The rate at which new calls to OnPaint will be generated.
const int kDefaultFrameRate = 30;
const int kMaximumFrameRate = 60;
// The maximum number of retry counts if frame capture fails.
const int kFrameRetryLimit = 2;
// When accelerated compositing is enabled and a widget resize is pending,
// we delay further resizes of the UI. The following constant is the maximum
// length of time that we should delay further UI resizes while waiting for a
// resized frame from a renderer.
const int kResizeLockTimeoutMs = 67;
static blink::WebScreenInfo webScreenInfoFrom(const CefScreenInfo& src) {
blink::WebScreenInfo webScreenInfo;
webScreenInfo.deviceScaleFactor = src.device_scale_factor;
webScreenInfo.depth = src.depth;
webScreenInfo.depthPerComponent = src.depth_per_component;
webScreenInfo.isMonochrome = src.is_monochrome ? true : false;
webScreenInfo.rect = blink::WebRect(src.rect.x, src.rect.y,
src.rect.width, src.rect.height);
webScreenInfo.availableRect = blink::WebRect(src.available_rect.x,
src.available_rect.y,
src.available_rect.width,
src.available_rect.height);
return webScreenInfo;
}
// Root layer passed to the ui::Compositor.
class CefRootLayer : public ui::Layer, public ui::LayerDelegate {
public:
CefRootLayer()
: Layer(ui::LAYER_TEXTURED) {
set_delegate(this);
}
virtual ~CefRootLayer() { }
// Overridden from LayerDelegate:
virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE {
}
virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {
}
virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE {
return base::Closure();
}
private:
DISALLOW_COPY_AND_ASSIGN(CefRootLayer);
};
// Used to prevent further resizes while a resize is pending.
class CefResizeLock : public content::ResizeLock {
public:
CefResizeLock(CefRenderWidgetHostViewOSR* host,
const gfx::Size new_size,
bool defer_compositor_lock,
double timeout)
: ResizeLock(new_size, defer_compositor_lock),
host_(host),
cancelled_(false),
weak_ptr_factory_(this) {
DCHECK(host_);
host_->HoldResize();
CEF_POST_DELAYED_TASK(
CEF_UIT,
base::Bind(&CefResizeLock::CancelLock,
weak_ptr_factory_.GetWeakPtr()),
timeout);
}
virtual ~CefResizeLock() {
CancelLock();
}
virtual bool GrabDeferredLock() OVERRIDE {
return ResizeLock::GrabDeferredLock();
}
virtual void UnlockCompositor() OVERRIDE {
ResizeLock::UnlockCompositor();
compositor_lock_ = NULL;
}
protected:
virtual void LockCompositor() OVERRIDE {
ResizeLock::LockCompositor();
compositor_lock_ = host_->compositor()->GetCompositorLock();
}
void CancelLock() {
if (cancelled_)
return;
cancelled_ = true;
UnlockCompositor();
host_->ReleaseResize();
}
private:
CefRenderWidgetHostViewOSR* host_;
scoped_refptr<ui::CompositorLock> compositor_lock_;
bool cancelled_;
base::WeakPtrFactory<CefResizeLock> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CefResizeLock);
};
} // namespace
CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR(
content::RenderWidgetHost* widget)
: delegated_frame_host_(new content::DelegatedFrameHost(this)),
compositor_widget_(gfx::kNullAcceleratedWidget),
frame_rate_threshold_ms_(1000 / kDefaultFrameRate),
frame_pending_(false),
frame_in_progress_(false),
frame_retry_count_(0),
hold_resize_(false),
pending_resize_(false),
render_widget_host_(content::RenderWidgetHostImpl::From(widget)),
parent_host_view_(NULL),
popup_host_view_(NULL),
is_showing_(false),
is_destroyed_(false),
#if defined(OS_MACOSX)
text_input_context_osr_mac_(NULL),
#endif
weak_ptr_factory_(this) {
DCHECK(render_widget_host_);
render_widget_host_->SetView(this);
// CefBrowserHostImpl might not be created at this time for popups.
if (render_widget_host_->IsRenderView()) {
browser_impl_ = CefBrowserHostImpl::GetBrowserForHost(
content::RenderViewHost::From(render_widget_host_));
}
root_layer_.reset(new CefRootLayer);
PlatformCreateCompositorWidget();
#if !defined(OS_MACOSX)
// On OS X the ui::Compositor is created/owned by the platform view.
compositor_.reset(
new ui::Compositor(compositor_widget_, content::GetContextFactory()));
#endif
compositor_->SetRootLayer(root_layer_.get());
if (browser_impl_) {
SetFrameRate();
ResizeRootLayer();
compositor_->SetScaleAndSize(CurrentDeviceScaleFactor(),
root_layer_->bounds().size());
}
}
CefRenderWidgetHostViewOSR::~CefRenderWidgetHostViewOSR() {
delegated_frame_host_.reset(NULL);
compositor_.reset(NULL);
PlatformDestroyCompositorWidget();
root_layer_.reset(NULL);
}
void CefRenderWidgetHostViewOSR::InitAsChild(gfx::NativeView parent_view) {
}
content::RenderWidgetHost*
CefRenderWidgetHostViewOSR::GetRenderWidgetHost() const {
return render_widget_host_;
}
void CefRenderWidgetHostViewOSR::SetSize(const gfx::Size& size) {
}
void CefRenderWidgetHostViewOSR::SetBounds(const gfx::Rect& rect) {
}
gfx::NativeView CefRenderWidgetHostViewOSR::GetNativeView() const {
return gfx::NativeView();
}
gfx::NativeViewId CefRenderWidgetHostViewOSR::GetNativeViewId() const {
return gfx::NativeViewId();
}
gfx::NativeViewAccessible
CefRenderWidgetHostViewOSR::GetNativeViewAccessible() {
return gfx::NativeViewAccessible();
}
ui::TextInputClient* CefRenderWidgetHostViewOSR::GetTextInputClient() {
return NULL;
}
void CefRenderWidgetHostViewOSR::Focus() {
}
bool CefRenderWidgetHostViewOSR::HasFocus() const {
return false;
}
bool CefRenderWidgetHostViewOSR::IsSurfaceAvailableForCopy() const {
return delegated_frame_host_->CanCopyToBitmap();
}
void CefRenderWidgetHostViewOSR::Show() {
WasShown();
}
void CefRenderWidgetHostViewOSR::Hide() {
WasHidden();
}
bool CefRenderWidgetHostViewOSR::IsShowing() {
return is_showing_;
}
gfx::Rect CefRenderWidgetHostViewOSR::GetViewBounds() const {
if (IsPopupWidget())
return popup_position_;
if (!browser_impl_)
return gfx::Rect();
CefRect rc;
browser_impl_->GetClient()->GetRenderHandler()->GetViewRect(
browser_impl_.get(), rc);
return gfx::Rect(rc.x, rc.y, rc.width, rc.height);
}
void CefRenderWidgetHostViewOSR::SetBackgroundOpaque(bool opaque) {
content::RenderWidgetHostViewBase::SetBackgroundOpaque(opaque);
if (render_widget_host_)
render_widget_host_->SetBackgroundOpaque(opaque);
}
bool CefRenderWidgetHostViewOSR::LockMouse() {
return false;
}
void CefRenderWidgetHostViewOSR::UnlockMouse() {
}
void CefRenderWidgetHostViewOSR::OnSwapCompositorFrame(
uint32 output_surface_id,
scoped_ptr<cc::CompositorFrame> frame) {
TRACE_EVENT0("libcef", "CefRenderWidgetHostViewOSR::OnSwapCompositorFrame");
if (frame->delegated_frame_data) {
delegated_frame_host_->SwapDelegatedFrame(
output_surface_id,
frame->delegated_frame_data.Pass(),
frame->metadata.device_scale_factor,
frame->metadata.latency_info);
GenerateFrame(true);
return;
}
if (frame->software_frame_data) {
DLOG(ERROR) << "Unable to use software frame in CEF windowless rendering";
if (render_widget_host_)
render_widget_host_->GetProcess()->ReceivedBadMessage();
return;
}
}
void CefRenderWidgetHostViewOSR::InitAsPopup(
content::RenderWidgetHostView* parent_host_view,
const gfx::Rect& pos) {
parent_host_view_ = static_cast<CefRenderWidgetHostViewOSR*>(
parent_host_view);
browser_impl_ = parent_host_view_->browser_impl();
if (!browser_impl_)
return;
if (parent_host_view_->popup_host_view_) {
// Cancel the previous popup widget.
parent_host_view_->popup_host_view_->CancelPopupWidget();
}
parent_host_view_->set_popup_host_view(this);
browser_impl_->GetClient()->GetRenderHandler()->OnPopupShow(
browser_impl_.get(), true);
popup_position_ = pos;
const float scale_factor = CurrentDeviceScaleFactor();
const gfx::Rect scaled_size =
gfx::ToNearestRect(gfx::ScaleRect(pos, scale_factor));
CefRect widget_pos(scaled_size.x(), scaled_size.y(),
scaled_size.width(), scaled_size.height());
browser_impl_->GetClient()->GetRenderHandler()->OnPopupSize(
browser_impl_.get(), widget_pos);
SetFrameRate();
ResizeRootLayer();
compositor_->SetScaleAndSize(scale_factor, root_layer_->bounds().size());
WasShown();
}
void CefRenderWidgetHostViewOSR::InitAsFullscreen(
content::RenderWidgetHostView* reference_host_view) {
NOTREACHED() << "Fullscreen widgets are not supported in OSR";
}
void CefRenderWidgetHostViewOSR::WasShown() {
if (is_showing_)
return;
is_showing_ = true;
if (render_widget_host_)
render_widget_host_->WasShown();
delegated_frame_host_->AddedToWindow();
delegated_frame_host_->WasShown();
}
void CefRenderWidgetHostViewOSR::WasHidden() {
if (!is_showing_)
return;
if (browser_impl_)
browser_impl_->CancelContextMenu();
if (render_widget_host_)
render_widget_host_->WasHidden();
delegated_frame_host_->WasHidden();
delegated_frame_host_->RemovingFromWindow();
is_showing_ = false;
}
void CefRenderWidgetHostViewOSR::MovePluginWindows(
const std::vector<content::WebPluginGeometry>& moves) {
}
void CefRenderWidgetHostViewOSR::Blur() {
}
void CefRenderWidgetHostViewOSR::UpdateCursor(
const content::WebCursor& cursor) {
TRACE_EVENT0("libcef", "CefRenderWidgetHostViewOSR::UpdateCursor");
if (!browser_impl_)
return;
#if defined(USE_AURA)
content::WebCursor web_cursor = cursor;
ui::PlatformCursor platform_cursor;
if (web_cursor.IsCustom()) {
// |web_cursor| owns the resulting |platform_cursor|.
platform_cursor = web_cursor.GetPlatformCursor();
} else {
content::WebCursor::CursorInfo cursor_info;
cursor.GetCursorInfo(&cursor_info);
platform_cursor = browser_impl_->GetPlatformCursor(cursor_info.type);
}
browser_impl_->GetClient()->GetRenderHandler()->OnCursorChange(
browser_impl_.get(), platform_cursor);
#elif defined(OS_MACOSX)
// |web_cursor| owns the resulting |native_cursor|.
content::WebCursor web_cursor = cursor;
CefCursorHandle native_cursor = web_cursor.GetNativeCursor();
browser_impl_->GetClient()->GetRenderHandler()->OnCursorChange(
browser_impl_.get(), native_cursor);
#else
// TODO(port): Implement this method to work on other platforms as part of
// off-screen rendering support.
NOTREACHED();
#endif
}
void CefRenderWidgetHostViewOSR::SetIsLoading(bool is_loading) {
}
#if !defined(OS_MACOSX)
void CefRenderWidgetHostViewOSR::TextInputTypeChanged(
ui::TextInputType type,
ui::TextInputMode input_mode,
bool can_compose_inline) {
}
void CefRenderWidgetHostViewOSR::ImeCancelComposition() {
}
#endif // !defined(OS_MACOSX)
void CefRenderWidgetHostViewOSR::RenderProcessGone(
base::TerminationStatus status,
int error_code) {
// TODO(OSR): Need to also clear WebContentsViewOSR::view_?
render_widget_host_ = NULL;
parent_host_view_ = NULL;
popup_host_view_ = NULL;
}
void CefRenderWidgetHostViewOSR::Destroy() {
if (!is_destroyed_) {
is_destroyed_ = true;
if (IsPopupWidget()) {
CancelPopupWidget();
} else {
if (popup_host_view_)
popup_host_view_->CancelPopupWidget();
WasHidden();
}
}
delete this;
}
void CefRenderWidgetHostViewOSR::SetTooltipText(
const base::string16& tooltip_text) {
if (!browser_impl_)
return;
CefString tooltip(tooltip_text);
CefRefPtr<CefDisplayHandler> handler =
browser_impl_->GetClient()->GetDisplayHandler();
if (handler.get()) {
handler->OnTooltip(browser_impl_.get(), tooltip);
}
}
void CefRenderWidgetHostViewOSR::SelectionChanged(
const base::string16& text,
size_t offset,
const gfx::Range& range) {
}
gfx::Size CefRenderWidgetHostViewOSR::GetRequestedRendererSize() const {
return delegated_frame_host_->GetRequestedRendererSize();
}
gfx::Size CefRenderWidgetHostViewOSR::GetPhysicalBackingSize() const {
float scale_factor = const_cast<CefRenderWidgetHostViewOSR*>(this)->
CurrentDeviceScaleFactor();
return gfx::ToCeiledSize(gfx::ScaleSize(GetRequestedRendererSize(),
scale_factor));
}
void CefRenderWidgetHostViewOSR::SelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params& params) {
}
void CefRenderWidgetHostViewOSR::ScrollOffsetChanged() {
if (!browser_impl_)
return;
browser_impl_->GetClient()->GetRenderHandler()->
OnScrollOffsetChanged(browser_impl_.get());
}
void CefRenderWidgetHostViewOSR::CopyFromCompositingSurface(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const base::Callback<void(bool, const SkBitmap&)>& callback,
const SkBitmap::Config config) {
delegated_frame_host_->CopyFromCompositingSurface(
src_subrect, dst_size, callback, config);
}
void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceToVideoFrame(
const gfx::Rect& src_subrect,
const scoped_refptr<media::VideoFrame>& target,
const base::Callback<void(bool)>& callback) {
delegated_frame_host_->CopyFromCompositingSurfaceToVideoFrame(
src_subrect, target, callback);
}
bool CefRenderWidgetHostViewOSR::CanCopyToVideoFrame() const {
return delegated_frame_host_->CanCopyToVideoFrame();
}
bool CefRenderWidgetHostViewOSR::CanSubscribeFrame() const {
return delegated_frame_host_->CanSubscribeFrame();
}
void CefRenderWidgetHostViewOSR::BeginFrameSubscription(
scoped_ptr<content::RenderWidgetHostViewFrameSubscriber> subscriber) {
delegated_frame_host_->BeginFrameSubscription(subscriber.Pass());
}
void CefRenderWidgetHostViewOSR::EndFrameSubscription() {
delegated_frame_host_->EndFrameSubscription();
}
void CefRenderWidgetHostViewOSR::AcceleratedSurfaceInitialized(
int host_id,
int route_id) {
}
void CefRenderWidgetHostViewOSR::AcceleratedSurfaceBuffersSwapped(
const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params_in_pixel,
int gpu_host_id) {
// Oldschool composited mode is no longer supported.
}
void CefRenderWidgetHostViewOSR::AcceleratedSurfacePostSubBuffer(
const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params_in_pixel,
int gpu_host_id) {
// Oldschool composited mode is no longer supported.
}
void CefRenderWidgetHostViewOSR::AcceleratedSurfaceSuspend() {
}
void CefRenderWidgetHostViewOSR::AcceleratedSurfaceRelease() {
}
bool CefRenderWidgetHostViewOSR::HasAcceleratedSurface(
const gfx::Size& desired_size) {
// CEF doesn't use GetBackingStore for accelerated pages, so it doesn't
// matter what is returned here as GetBackingStore is the only caller of this
// method.
NOTREACHED();
return false;
}
void CefRenderWidgetHostViewOSR::GetScreenInfo(blink::WebScreenInfo* results) {
if (!browser_impl_)
return;
CefScreenInfo screen_info(
kDefaultScaleFactor, 0, 0, false, CefRect(), CefRect());
CefRefPtr<CefRenderHandler> handler =
browser_impl_->client()->GetRenderHandler();
if (!handler->GetScreenInfo(browser_impl_.get(), screen_info) ||
screen_info.rect.width == 0 ||
screen_info.rect.height == 0 ||
screen_info.available_rect.width == 0 ||
screen_info.available_rect.height == 0) {
// If a screen rectangle was not provided, try using the view rectangle
// instead. Otherwise, popup views may be drawn incorrectly, or not at all.
CefRect screenRect;
if (!handler->GetViewRect(browser_impl_.get(), screenRect)) {
NOTREACHED();
screenRect = CefRect();
}
if (screen_info.rect.width == 0 && screen_info.rect.height == 0)
screen_info.rect = screenRect;
if (screen_info.available_rect.width == 0 &&
screen_info.available_rect.height == 0)
screen_info.available_rect = screenRect;
}
*results = webScreenInfoFrom(screen_info);
}
gfx::Rect CefRenderWidgetHostViewOSR::GetBoundsInRootWindow() {
if (!browser_impl_)
return gfx::Rect();
CefRect rc;
if (browser_impl_->GetClient()->GetRenderHandler()->GetRootScreenRect(
browser_impl_.get(), rc)) {
return gfx::Rect(rc.x, rc.y, rc.width, rc.height);
}
return gfx::Rect();
}
gfx::GLSurfaceHandle CefRenderWidgetHostViewOSR::GetCompositingSurface() {
return content::ImageTransportFactory::GetInstance()->
GetSharedSurfaceHandle();
}
void CefRenderWidgetHostViewOSR::SetScrollOffsetPinning(
bool is_pinned_to_left,
bool is_pinned_to_right) {
}
#if !defined(OS_MACOSX) && defined(USE_AURA)
void CefRenderWidgetHostViewOSR::ImeCompositionRangeChanged(
const gfx::Range& range,
const std::vector<gfx::Rect>& character_bounds) {
}
#endif
ui::Compositor* CefRenderWidgetHostViewOSR::GetCompositor() const {
return compositor_.get();
}
ui::Layer* CefRenderWidgetHostViewOSR::GetLayer() {
return root_layer_.get();
}
content::RenderWidgetHostImpl* CefRenderWidgetHostViewOSR::GetHost() {
return render_widget_host_;
}
void CefRenderWidgetHostViewOSR::SchedulePaintInRect(
const gfx::Rect& damage_rect_in_dip) {
root_layer_->SchedulePaint(damage_rect_in_dip);
}
void CefRenderWidgetHostViewOSR::DelegatedCompositorDidSwapBuffers() {
}
void CefRenderWidgetHostViewOSR::DelegatedCompositorAbortedSwapBuffers() {
}
bool CefRenderWidgetHostViewOSR::IsVisible() {
return IsShowing();
}
scoped_ptr<content::ResizeLock> CefRenderWidgetHostViewOSR::CreateResizeLock(
bool defer_compositor_lock) {
const gfx::Size& desired_size = root_layer_->bounds().size();
return scoped_ptr<content::ResizeLock>(new CefResizeLock(
this,
desired_size,
defer_compositor_lock,
kResizeLockTimeoutMs));
}
gfx::Size CefRenderWidgetHostViewOSR::DesiredFrameSize() {
return root_layer_->bounds().size();
}
float CefRenderWidgetHostViewOSR::CurrentDeviceScaleFactor() {
if (!browser_impl_)
return kDefaultScaleFactor;
CefScreenInfo screen_info(
kDefaultScaleFactor, 0, 0, false, CefRect(), CefRect());
if (!browser_impl_->GetClient()->GetRenderHandler()->GetScreenInfo(
browser_impl_.get(), screen_info)) {
// Use the default
return kDefaultScaleFactor;
}
return screen_info.device_scale_factor;
}
gfx::Size CefRenderWidgetHostViewOSR::ConvertViewSizeToPixel(
const gfx::Size& size) {
return content::ConvertViewSizeToPixel(this, size);
}
content::DelegatedFrameHost*
CefRenderWidgetHostViewOSR::GetDelegatedFrameHost() const {
return delegated_frame_host_.get();
}
bool CefRenderWidgetHostViewOSR::InstallTransparency() {
if (browser_impl_ && browser_impl_->IsTransparent()) {
SetBackgroundOpaque(false);
return true;
}
return false;
}
void CefRenderWidgetHostViewOSR::WasResized() {
if (hold_resize_) {
if (!pending_resize_)
pending_resize_ = true;
return;
}
ResizeRootLayer();
if (render_widget_host_)
render_widget_host_->WasResized();
delegated_frame_host_->WasResized();
}
void CefRenderWidgetHostViewOSR::OnScreenInfoChanged() {
TRACE_EVENT0("libcef", "CefRenderWidgetHostViewOSR::OnScreenInfoChanged");
if (!render_widget_host_)
return;
// TODO(OSR): Update the backing store.
render_widget_host_->NotifyScreenInfoChanged();
// We might want to change the cursor scale factor here as well - see the
// cache for the current_cursor_, as passed by UpdateCursor from the renderer
// in the rwhv_aura (current_cursor_.SetScaleFactor)
}
void CefRenderWidgetHostViewOSR::Invalidate(
CefBrowserHost::PaintElementType type) {
TRACE_EVENT1("libcef", "CefRenderWidgetHostViewOSR::Invalidate", "type",
type);
if (!IsPopupWidget() && type == PET_POPUP) {
if (popup_host_view_)
popup_host_view_->Invalidate(type);
return;
}
GenerateFrame(true);
}
void CefRenderWidgetHostViewOSR::SendKeyEvent(
const content::NativeWebKeyboardEvent& event) {
TRACE_EVENT0("libcef", "CefRenderWidgetHostViewOSR::SendKeyEvent");
if (!render_widget_host_)
return;
render_widget_host_->ForwardKeyboardEvent(event);
}
void CefRenderWidgetHostViewOSR::SendMouseEvent(
const blink::WebMouseEvent& event) {
TRACE_EVENT0("libcef", "CefRenderWidgetHostViewOSR::SendMouseEvent");
if (!IsPopupWidget()) {
if (browser_impl_ && event.type == blink::WebMouseEvent::MouseDown)
browser_impl_->CancelContextMenu();
if (popup_host_view_ &&
popup_host_view_->popup_position_.Contains(event.x, event.y)) {
blink::WebMouseEvent popup_event(event);
popup_event.x -= popup_host_view_->popup_position_.x();
popup_event.y -= popup_host_view_->popup_position_.y();
popup_event.windowX = popup_event.x;
popup_event.windowY = popup_event.y;
popup_host_view_->SendMouseEvent(popup_event);
return;
}
}
if (!render_widget_host_)
return;
render_widget_host_->ForwardMouseEvent(event);
}
void CefRenderWidgetHostViewOSR::SendMouseWheelEvent(
const blink::WebMouseWheelEvent& event) {
TRACE_EVENT0("libcef", "CefRenderWidgetHostViewOSR::SendMouseWheelEvent");
if (!IsPopupWidget()) {
if (browser_impl_)
browser_impl_->CancelContextMenu();
if (popup_host_view_) {
if (popup_host_view_->popup_position_.Contains(event.x, event.y)) {
blink::WebMouseWheelEvent popup_event(event);
popup_event.x -= popup_host_view_->popup_position_.x();
popup_event.y -= popup_host_view_->popup_position_.y();
popup_event.windowX = popup_event.x;
popup_event.windowY = popup_event.y;
popup_host_view_->SendMouseWheelEvent(popup_event);
return;
} else {
// Scrolling outside of the popup widget so destroy it.
// Execute asynchronously to avoid deleting the widget from inside some
// other callback.
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefRenderWidgetHostViewOSR::CancelPopupWidget,
popup_host_view_->weak_ptr_factory_.GetWeakPtr()));
}
}
}
if (!render_widget_host_)
return;
render_widget_host_->ForwardWheelEvent(event);
}
void CefRenderWidgetHostViewOSR::SendFocusEvent(bool focus) {
if (!render_widget_host_)
return;
content::RenderWidgetHostImpl* widget =
content::RenderWidgetHostImpl::From(render_widget_host_);
if (focus) {
widget->GotFocus();
widget->SetActive(true);
} else {
if (browser_impl_)
browser_impl_->CancelContextMenu();
widget->SetActive(false);
widget->Blur();
}
}
void CefRenderWidgetHostViewOSR::HoldResize() {
if (!hold_resize_)
hold_resize_ = true;
}
void CefRenderWidgetHostViewOSR::ReleaseResize() {
if (!hold_resize_)
return;
hold_resize_ = false;
if (pending_resize_) {
pending_resize_ = false;
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefRenderWidgetHostViewOSR::WasResized,
weak_ptr_factory_.GetWeakPtr()));
}
}
void CefRenderWidgetHostViewOSR::SetFrameRate() {
if (!browser_impl_)
return;
int frame_rate = browser_impl_->settings().windowless_frame_rate;
if (frame_rate < 1)
frame_rate = kDefaultFrameRate;
else if (frame_rate > kMaximumFrameRate)
frame_rate = kMaximumFrameRate;
frame_rate_threshold_ms_ = 1000 / frame_rate;
}
void CefRenderWidgetHostViewOSR::ResizeRootLayer() {
gfx::Size size;
if (!IsPopupWidget())
size = GetViewBounds().size();
else
size = popup_position_.size();
root_layer_->SetBounds(gfx::Rect(0, 0, size.width(), size.height()));
}
void CefRenderWidgetHostViewOSR::GenerateFrame(bool force_frame) {
if (force_frame && !frame_pending_)
frame_pending_ = true;
// No frame needs to be generated at this time.
if (!frame_pending_)
return;
// Don't attempt to generate a frame while one is currently in-progress.
if (frame_in_progress_)
return;
frame_in_progress_ = true;
// Don't exceed the frame rate threshold.
const int64 frame_rate_delta =
(base::TimeTicks::Now() - frame_start_time_).InMilliseconds();
if (frame_rate_delta < frame_rate_threshold_ms_) {
// Generate the frame after the necessary time has passed.
CEF_POST_DELAYED_TASK(CEF_UIT,
base::Bind(&CefRenderWidgetHostViewOSR::InternalGenerateFrame,
weak_ptr_factory_.GetWeakPtr()),
frame_rate_threshold_ms_ - frame_rate_delta);
return;
}
InternalGenerateFrame();
}
void CefRenderWidgetHostViewOSR::InternalGenerateFrame() {
frame_pending_ = false;
frame_start_time_ = base::TimeTicks::Now();
// The below code is similar in functionality to
// DelegatedFrameHost::CopyFromCompositingSurface but we reuse the same
// SkBitmap in the GPU codepath and avoid scaling where possible.
scoped_ptr<cc::CopyOutputRequest> request =
cc::CopyOutputRequest::CreateRequest(base::Bind(
&CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceHasResult,
weak_ptr_factory_.GetWeakPtr()));
const gfx::Rect& src_subrect_in_pixel =
content::ConvertRectToPixel(CurrentDeviceScaleFactor(),
root_layer_->bounds());
request->set_area(src_subrect_in_pixel);
RequestCopyOfOutput(request.Pass());
}
void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceHasResult(
scoped_ptr<cc::CopyOutputResult> result) {
if (result->IsEmpty() || result->size().IsEmpty()) {
OnFrameCaptureFailure();
return;
}
if (result->HasTexture()) {
PrepareTextureCopyOutputResult(result.Pass());
return;
}
DCHECK(result->HasBitmap());
PrepareBitmapCopyOutputResult(result.Pass());
}
void CefRenderWidgetHostViewOSR::PrepareTextureCopyOutputResult(
scoped_ptr<cc::CopyOutputResult> result) {
DCHECK(result->HasTexture());
base::ScopedClosureRunner scoped_callback_runner(
base::Bind(&CefRenderWidgetHostViewOSR::OnFrameCaptureFailure,
weak_ptr_factory_.GetWeakPtr()));
const gfx::Size& result_size = result->size();
SkIRect bitmap_size;
if (bitmap_)
bitmap_->getBounds(&bitmap_size);
if (!bitmap_ ||
bitmap_size.width() != result_size.width() ||
bitmap_size.height() != result_size.height()) {
// Create a new bitmap if the size has changed.
bitmap_.reset(new SkBitmap);
bitmap_->setConfig(SkBitmap::kARGB_8888_Config,
result_size.width(),
result_size.height(),
0,
kOpaque_SkAlphaType);
if (!bitmap_->allocPixels())
return;
}
content::ImageTransportFactory* factory =
content::ImageTransportFactory::GetInstance();
content::GLHelper* gl_helper = factory->GetGLHelper();
if (!gl_helper)
return;
scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock(
new SkAutoLockPixels(*bitmap_));
uint8* pixels = static_cast<uint8*>(bitmap_->getPixels());
cc::TextureMailbox texture_mailbox;
scoped_ptr<cc::SingleReleaseCallback> release_callback;
result->TakeTexture(&texture_mailbox, &release_callback);
DCHECK(texture_mailbox.IsTexture());
if (!texture_mailbox.IsTexture())
return;
ignore_result(scoped_callback_runner.Release());
gl_helper->CropScaleReadbackAndCleanMailbox(
texture_mailbox.mailbox(),
texture_mailbox.sync_point(),
result_size,
gfx::Rect(result_size),
result_size,
pixels,
SkBitmap::kARGB_8888_Config,
base::Bind(
&CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceFinishedProxy,
weak_ptr_factory_.GetWeakPtr(),
base::Passed(&release_callback),
base::Passed(&bitmap_),
base::Passed(&bitmap_pixels_lock)),
content::GLHelper::SCALER_QUALITY_FAST);
}
// static
void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceFinishedProxy(
base::WeakPtr<CefRenderWidgetHostViewOSR> view,
scoped_ptr<cc::SingleReleaseCallback> release_callback,
scoped_ptr<SkBitmap> bitmap,
scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
bool result) {
// This method may be called after the view has been deleted.
uint32 sync_point = 0;
if (result) {
content::GLHelper* gl_helper =
content::ImageTransportFactory::GetInstance()->GetGLHelper();
sync_point = gl_helper->InsertSyncPoint();
}
bool lost_resource = sync_point == 0;
release_callback->Run(sync_point, lost_resource);
if (view) {
view->CopyFromCompositingSurfaceFinished(
bitmap.Pass(), bitmap_pixels_lock.Pass(), result);
} else {
bitmap_pixels_lock.reset();
bitmap.reset();
}
}
void CefRenderWidgetHostViewOSR::CopyFromCompositingSurfaceFinished(
scoped_ptr<SkBitmap> bitmap,
scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
bool result) {
// Restore ownership of the bitmap to the view.
DCHECK(!bitmap_);
bitmap_ = bitmap.Pass();
if (result) {
OnFrameCaptureSuccess(*bitmap_, bitmap_pixels_lock.Pass());
} else {
bitmap_pixels_lock.reset();
OnFrameCaptureFailure();
}
}
void CefRenderWidgetHostViewOSR::PrepareBitmapCopyOutputResult(
scoped_ptr<cc::CopyOutputResult> result) {
DCHECK(result->HasBitmap());
scoped_ptr<SkBitmap> source = result->TakeBitmap();
DCHECK(source);
if (source) {
scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock(
new SkAutoLockPixels(*source));
OnFrameCaptureSuccess(*source, bitmap_pixels_lock.Pass());
} else {
OnFrameCaptureFailure();
}
}
void CefRenderWidgetHostViewOSR::OnFrameCaptureFailure() {
const bool force_frame = (++frame_retry_count_ <= kFrameRetryLimit);
OnFrameCaptureCompletion(force_frame);
}
void CefRenderWidgetHostViewOSR::OnFrameCaptureSuccess(
const SkBitmap& bitmap,
scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock) {
SkRect bounds;
bitmap.getBounds(&bounds);
CefRenderHandler::RectList rcList;
rcList.push_back(CefRect(0, 0, bounds.width(), bounds.height()));
browser_impl_->GetClient()->GetRenderHandler()->OnPaint(
browser_impl_.get(),
IsPopupWidget() ? PET_POPUP : PET_VIEW,
rcList,
bitmap.getPixels(),
bounds.width(),
bounds.height());
bitmap_pixels_lock.reset();
// Reset the frame retry count on successful frame generation.
if (frame_retry_count_ > 0)
frame_retry_count_ = 0;
OnFrameCaptureCompletion(false);
}
void CefRenderWidgetHostViewOSR::OnFrameCaptureCompletion(bool force_frame) {
frame_in_progress_ = false;
if (frame_pending_) {
// Another frame was requested while the current frame was in-progress.
// Generate the pending frame now.
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefRenderWidgetHostViewOSR::GenerateFrame,
weak_ptr_factory_.GetWeakPtr(), force_frame));
}
}
void CefRenderWidgetHostViewOSR::CancelPopupWidget() {
DCHECK(IsPopupWidget());
if (render_widget_host_)
render_widget_host_->LostCapture();
WasHidden();
if (browser_impl_) {
browser_impl_->GetClient()->GetRenderHandler()->OnPopupShow(
browser_impl_.get(), false);
browser_impl_ = NULL;
}
if (parent_host_view_) {
parent_host_view_->set_popup_host_view(NULL);
parent_host_view_ = NULL;
}
if (render_widget_host_ && !is_destroyed_) {
is_destroyed_ = true;
// Results in a call to Destroy().
render_widget_host_->Shutdown();
}
}