Add support for child and popup windows in OSR

This commit is contained in:
Heilig Benedek 2017-03-04 03:09:16 +01:00
parent b6319698f1
commit 20d2ab29ab
9 changed files with 541 additions and 55 deletions

View file

@ -48,6 +48,7 @@
#include "chrome/browser/ssl/security_state_tab_helper.h" #include "chrome/browser/ssl/security_state_tab_helper.h"
#include "content/browser/frame_host/navigation_entry_impl.h" #include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/view_messages.h" #include "content/common/view_messages.h"
#include "content/public/browser/favicon_status.h" #include "content/public/browser/favicon_status.h"
@ -315,6 +316,9 @@ WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options)
else if (options.Get("offscreen", &b) && b) else if (options.Get("offscreen", &b) && b)
type_ = OFF_SCREEN; type_ = OFF_SCREEN;
// Init embedder earlier
options.Get("embedder", &embedder_);
// Whether to enable DevTools. // Whether to enable DevTools.
options.Get("devTools", &enable_devtools_); options.Get("devTools", &enable_devtools_);
@ -339,7 +343,18 @@ WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options)
session->browser_context(), site_instance); session->browser_context(), site_instance);
guest_delegate_.reset(new WebViewGuestDelegate); guest_delegate_.reset(new WebViewGuestDelegate);
params.guest_delegate = guest_delegate_.get(); params.guest_delegate = guest_delegate_.get();
web_contents = content::WebContents::Create(params);
if (embedder_ && embedder_->IsOffScreen()) {
auto* view = new OffScreenWebContentsView(false,
base::Bind(&WebContents::OnPaint, base::Unretained(this)));
params.view = view;
params.delegate_view = view;
web_contents = content::WebContents::Create(params);
view->SetWebContents(web_contents);
} else {
web_contents = content::WebContents::Create(params);
}
} else if (IsOffScreen()) { } else if (IsOffScreen()) {
bool transparent = false; bool transparent = false;
options.Get("transparent", &transparent); options.Get("transparent", &transparent);
@ -389,7 +404,7 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
guest_delegate_->Initialize(this); guest_delegate_->Initialize(this);
NativeWindow* owner_window = nullptr; NativeWindow* owner_window = nullptr;
if (options.Get("embedder", &embedder_) && embedder_) { if (embedder_) {
// New WebContents's owner_window is the embedder's owner_window. // New WebContents's owner_window is the embedder's owner_window.
auto relay = auto relay =
NativeWindowRelay::FromWebContents(embedder_->web_contents()); NativeWindowRelay::FromWebContents(embedder_->web_contents());
@ -1402,18 +1417,16 @@ bool WebContents::SendIPCMessage(bool all_frames,
void WebContents::SendInputEvent(v8::Isolate* isolate, void WebContents::SendInputEvent(v8::Isolate* isolate,
v8::Local<v8::Value> input_event) { v8::Local<v8::Value> input_event) {
const auto view = web_contents()->GetRenderWidgetHostView(); const auto view = static_cast<content::RenderWidgetHostViewBase*>(
web_contents()->GetRenderWidgetHostView());
if (!view) if (!view)
return; return;
const auto host = view->GetRenderWidgetHost();
if (!host)
return;
int type = mate::GetWebInputEventType(isolate, input_event); int type = mate::GetWebInputEventType(isolate, input_event);
if (blink::WebInputEvent::isMouseEventType(type)) { if (blink::WebInputEvent::isMouseEventType(type)) {
blink::WebMouseEvent mouse_event; blink::WebMouseEvent mouse_event;
if (mate::ConvertFromV8(isolate, input_event, &mouse_event)) { if (mate::ConvertFromV8(isolate, input_event, &mouse_event)) {
host->ForwardMouseEvent(mouse_event); view->ProcessMouseEvent(mouse_event, ui::LatencyInfo());
return; return;
} }
} else if (blink::WebInputEvent::isKeyboardEventType(type)) { } else if (blink::WebInputEvent::isKeyboardEventType(type)) {
@ -1422,13 +1435,13 @@ void WebContents::SendInputEvent(v8::Isolate* isolate,
blink::WebInputEvent::NoModifiers, blink::WebInputEvent::NoModifiers,
ui::EventTimeForNow()); ui::EventTimeForNow());
if (mate::ConvertFromV8(isolate, input_event, &keyboard_event)) { if (mate::ConvertFromV8(isolate, input_event, &keyboard_event)) {
host->ForwardKeyboardEvent(keyboard_event); view->ProcessKeyboardEvent(keyboard_event);
return; return;
} }
} else if (type == blink::WebInputEvent::MouseWheel) { } else if (type == blink::WebInputEvent::MouseWheel) {
blink::WebMouseWheelEvent mouse_wheel_event; blink::WebMouseWheelEvent mouse_wheel_event;
if (mate::ConvertFromV8(isolate, input_event, &mouse_wheel_event)) { if (mate::ConvertFromV8(isolate, input_event, &mouse_wheel_event)) {
host->ForwardWheelEvent(mouse_wheel_event); view->ProcessMouseEvent(mouse_wheel_event, ui::LatencyInfo());
return; return;
} }
} }
@ -1631,6 +1644,16 @@ void WebContents::Invalidate() {
} }
} }
gfx::Size WebContents::GetSizeForNewRenderView(
content::WebContents* web_contents) const {
auto relay = NativeWindowRelay::FromWebContents(web_contents);
if (relay) {
return relay->window->GetSize();
}
return gfx::Size();
}
void WebContents::SetZoomLevel(double level) { void WebContents::SetZoomLevel(double level) {
zoom_controller_->SetZoomLevel(level); zoom_controller_->SetZoomLevel(level);
} }

View file

@ -183,6 +183,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
void SetFrameRate(int frame_rate); void SetFrameRate(int frame_rate);
int GetFrameRate() const; int GetFrameRate() const;
void Invalidate(); void Invalidate();
gfx::Size GetSizeForNewRenderView(content::WebContents*) const override;
// Methods for zoom handling. // Methods for zoom handling.
void SetZoomLevel(double level); void SetZoomLevel(double level);

View file

@ -147,6 +147,7 @@ class NativeWindow : public base::SupportsUserData,
virtual void SetMenu(AtomMenuModel* menu); virtual void SetMenu(AtomMenuModel* menu);
virtual void SetParentWindow(NativeWindow* parent); virtual void SetParentWindow(NativeWindow* parent);
virtual void SetBrowserView(NativeBrowserView* browser_view) = 0; virtual void SetBrowserView(NativeBrowserView* browser_view) = 0;
virtual gfx::NativeView GetNativeView() = 0;
virtual gfx::NativeWindow GetNativeWindow() = 0; virtual gfx::NativeWindow GetNativeWindow() = 0;
virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0; virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;

View file

@ -924,6 +924,10 @@ void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
#endif #endif
} }
gfx::NativeView NativeWindowViews::GetNativeView() {
return window_->GetNativeView();
}
gfx::NativeWindow NativeWindowViews::GetNativeWindow() { gfx::NativeWindow NativeWindowViews::GetNativeWindow() {
return window_->GetNativeWindow(); return window_->GetNativeWindow();
} }

View file

@ -106,6 +106,7 @@ class NativeWindowViews : public NativeWindow,
void SetMenu(AtomMenuModel* menu_model) override; void SetMenu(AtomMenuModel* menu_model) override;
void SetBrowserView(NativeBrowserView* browser_view) override; void SetBrowserView(NativeBrowserView* browser_view) override;
void SetParentWindow(NativeWindow* parent) override; void SetParentWindow(NativeWindow* parent) override;
gfx::NativeView GetNativeView() override;
gfx::NativeWindow GetNativeWindow() override; gfx::NativeWindow GetNativeWindow() override;
void SetOverlayIcon(const gfx::Image& overlay, void SetOverlayIcon(const gfx::Image& overlay,
const std::string& description) override; const std::string& description) override;

View file

@ -17,6 +17,7 @@
#include "content/browser/renderer_host/render_widget_host_delegate.h" #include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_frame_subscriber.h" #include "content/browser/renderer_host/render_widget_host_view_frame_subscriber.h"
#include "content/browser/renderer_host/resize_lock.h"
#include "content/common/view_messages.h" #include "content/common/view_messages.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/context_factory.h" #include "content/public/browser/context_factory.h"
@ -25,6 +26,7 @@
#include "ui/compositor/layer.h" #include "ui/compositor/layer.h"
#include "ui/compositor/layer_type.h" #include "ui/compositor/layer_type.h"
#include "ui/events/latency_info.h" #include "ui/events/latency_info.h"
#include "ui/gfx/skbitmap_operations.h"
#include "ui/gfx/geometry/dip_util.h" #include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
@ -35,6 +37,66 @@ namespace {
const float kDefaultScaleFactor = 1.0; const float kDefaultScaleFactor = 1.0;
const int kFrameRetryLimit = 2; const int kFrameRetryLimit = 2;
#if !defined(OS_MACOSX)
const int kResizeLockTimeoutMs = 67;
class AtomResizeLock : public content::ResizeLock {
public:
AtomResizeLock(OffScreenRenderWidgetHostView* host,
const gfx::Size new_size,
bool defer_compositor_lock)
: ResizeLock(new_size, defer_compositor_lock),
host_(host),
cancelled_(false),
weak_ptr_factory_(this) {
DCHECK(host_);
host_->HoldResize();
content::BrowserThread::PostDelayedTask(content::BrowserThread::UI,
FROM_HERE, base::Bind(&AtomResizeLock::CancelLock,
weak_ptr_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kResizeLockTimeoutMs));
}
~AtomResizeLock() override {
CancelLock();
}
bool GrabDeferredLock() override {
return ResizeLock::GrabDeferredLock();
}
void UnlockCompositor() override {
ResizeLock::UnlockCompositor();
compositor_lock_ = NULL;
}
protected:
void LockCompositor() override {
ResizeLock::LockCompositor();
compositor_lock_ = host_->GetCompositor()->GetCompositorLock();
}
void CancelLock() {
if (cancelled_)
return;
cancelled_ = true;
UnlockCompositor();
host_->ReleaseResize();
}
private:
OffScreenRenderWidgetHostView* host_;
scoped_refptr<ui::CompositorLock> compositor_lock_;
bool cancelled_;
base::WeakPtrFactory<AtomResizeLock> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(AtomResizeLock);
};
#endif // !defined(OS_MACOSX)
} // namespace } // namespace
class AtomCopyFrameGenerator { class AtomCopyFrameGenerator {
@ -338,24 +400,30 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
bool transparent, bool transparent,
const OnPaintCallback& callback, const OnPaintCallback& callback,
content::RenderWidgetHost* host, content::RenderWidgetHost* host,
bool is_guest_view_hack, OffScreenRenderWidgetHostView* parent_host_view,
NativeWindow* native_window) NativeWindow* native_window)
: render_widget_host_(content::RenderWidgetHostImpl::From(host)), : render_widget_host_(content::RenderWidgetHostImpl::From(host)),
parent_host_view_(parent_host_view),
popup_host_view_(nullptr),
child_host_view_(nullptr),
native_window_(native_window), native_window_(native_window),
software_output_device_(nullptr), software_output_device_(nullptr),
transparent_(transparent), transparent_(transparent),
callback_(callback), callback_(callback),
parent_callback_(nullptr),
frame_rate_(60), frame_rate_(60),
frame_rate_threshold_ms_(0), frame_rate_threshold_ms_(0),
last_time_(base::Time::Now()), last_time_(base::Time::Now()),
scale_factor_(kDefaultScaleFactor), scale_factor_(kDefaultScaleFactor),
is_showing_(!render_widget_host_->is_hidden()),
size_(native_window->GetSize()),
painting_(true), painting_(true),
is_showing_(!render_widget_host_->is_hidden()),
is_destroyed_(false),
popup_position_(gfx::Rect()),
hold_resize_(false),
pending_resize_(false),
size_(native_window->GetSize()),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
DCHECK(render_widget_host_); DCHECK(render_widget_host_);
render_widget_host_->SetView(this);
#if !defined(OS_MACOSX) #if !defined(OS_MACOSX)
delegated_frame_host_ = base::MakeUnique<content::DelegatedFrameHost>( delegated_frame_host_ = base::MakeUnique<content::DelegatedFrameHost>(
AllocateFrameSinkId(is_guest_view_hack), this); AllocateFrameSinkId(is_guest_view_hack), this);
@ -383,6 +451,8 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
native_window_->AddObserver(this); native_window_->AddObserver(this);
ResizeRootLayer(); ResizeRootLayer();
render_widget_host_->SetView(this);
InstallTransparency();
} }
OffScreenRenderWidgetHostView::~OffScreenRenderWidgetHostView() { OffScreenRenderWidgetHostView::~OffScreenRenderWidgetHostView() {
@ -400,8 +470,15 @@ OffScreenRenderWidgetHostView::~OffScreenRenderWidgetHostView() {
delegated_frame_host_->ResetCompositor(); delegated_frame_host_->ResetCompositor();
#endif #endif
if (copy_frame_generator_.get())
copy_frame_generator_.reset(NULL);
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
DestroyPlatformWidget(); DestroyPlatformWidget();
#else
delegated_frame_host_.reset(NULL);
compositor_.reset(NULL);
root_layer_.reset(NULL);
#endif #endif
} }
@ -461,6 +538,17 @@ bool OffScreenRenderWidgetHostView::OnMessageReceived(
} }
void OffScreenRenderWidgetHostView::InitAsChild(gfx::NativeView) { void OffScreenRenderWidgetHostView::InitAsChild(gfx::NativeView) {
DCHECK(parent_host_view_);
if (parent_host_view_->child_host_view_) {
parent_host_view_->child_host_view_->CancelWidget();
}
parent_host_view_->set_child_host_view(this);
parent_host_view_->Hide();
ResizeRootLayer();
Show();
} }
content::RenderWidgetHost* OffScreenRenderWidgetHostView::GetRenderWidgetHost() content::RenderWidgetHost* OffScreenRenderWidgetHostView::GetRenderWidgetHost()
@ -470,14 +558,11 @@ content::RenderWidgetHost* OffScreenRenderWidgetHostView::GetRenderWidgetHost()
void OffScreenRenderWidgetHostView::SetSize(const gfx::Size& size) { void OffScreenRenderWidgetHostView::SetSize(const gfx::Size& size) {
size_ = size; size_ = size;
WasResized();
ResizeRootLayer();
if (render_widget_host_)
render_widget_host_->WasResized();
GetDelegatedFrameHost()->WasResized();
} }
void OffScreenRenderWidgetHostView::SetBounds(const gfx::Rect& new_bounds) { void OffScreenRenderWidgetHostView::SetBounds(const gfx::Rect& new_bounds) {
SetSize(new_bounds.size());
} }
gfx::Vector2dF OffScreenRenderWidgetHostView::GetLastScrollOffset() const { gfx::Vector2dF OffScreenRenderWidgetHostView::GetLastScrollOffset() const {
@ -547,6 +632,9 @@ bool OffScreenRenderWidgetHostView::IsShowing() {
} }
gfx::Rect OffScreenRenderWidgetHostView::GetViewBounds() const { gfx::Rect OffScreenRenderWidgetHostView::GetViewBounds() const {
if (IsPopupWidget())
return popup_position_;
return gfx::Rect(size_); return gfx::Rect(size_);
} }
@ -587,7 +675,7 @@ void OffScreenRenderWidgetHostView::OnSwapCompositorFrame(
if (!frame.render_pass_list.empty()) { if (!frame.render_pass_list.empty()) {
if (software_output_device_) { if (software_output_device_) {
if (!begin_frame_timer_.get()) { if (!begin_frame_timer_.get() || IsPopupWidget()) {
software_output_device_->SetActive(painting_); software_output_device_->SetActive(painting_);
} }
@ -631,10 +719,25 @@ void OffScreenRenderWidgetHostView::ClearCompositorFrame() {
void OffScreenRenderWidgetHostView::InitAsPopup( void OffScreenRenderWidgetHostView::InitAsPopup(
content::RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) { content::RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
DCHECK_EQ(parent_host_view_, parent_host_view);
if (parent_host_view_->popup_host_view_) {
parent_host_view_->popup_host_view_->CancelWidget();
}
parent_host_view_->set_popup_host_view(this);
parent_host_view_->popup_bitmap_.reset(new SkBitmap);
parent_callback_ = base::Bind(&OffScreenRenderWidgetHostView::OnPopupPaint,
parent_host_view_->weak_ptr_factory_.GetWeakPtr());
popup_position_ = pos;
ResizeRootLayer();
Show();
} }
void OffScreenRenderWidgetHostView::InitAsFullscreen( void OffScreenRenderWidgetHostView::InitAsFullscreen(
content::RenderWidgetHostView *) { content::RenderWidgetHostView *) {
} }
void OffScreenRenderWidgetHostView::UpdateCursor(const content::WebCursor &) { void OffScreenRenderWidgetHostView::UpdateCursor(const content::WebCursor &) {
@ -656,6 +759,23 @@ void OffScreenRenderWidgetHostView::RenderProcessGone(base::TerminationStatus,
} }
void OffScreenRenderWidgetHostView::Destroy() { void OffScreenRenderWidgetHostView::Destroy() {
if (!is_destroyed_) {
is_destroyed_ = true;
if (parent_host_view_ != NULL) {
CancelWidget();
} else {
if (popup_host_view_)
popup_host_view_->CancelWidget();
popup_bitmap_.reset();
if (child_host_view_)
child_host_view_->CancelWidget();
for (auto guest_host_view : guest_host_views_)
guest_host_view->CancelWidget();
Hide();
}
}
delete this; delete this;
} }
@ -692,6 +812,13 @@ void OffScreenRenderWidgetHostView::EndFrameSubscription() {
GetDelegatedFrameHost()->EndFrameSubscription(); GetDelegatedFrameHost()->EndFrameSubscription();
} }
void OffScreenRenderWidgetHostView::InitAsGuest(
content::RenderWidgetHostView* parent_host_view,
content::RenderWidgetHostViewGuest* guest_view) {
parent_host_view_->AddGuestHostView(this);
parent_host_view_->RegisterGuestViewFrameSwappedCallback(guest_view);
}
bool OffScreenRenderWidgetHostView::HasAcceleratedSurface(const gfx::Size &) { bool OffScreenRenderWidgetHostView::HasAcceleratedSurface(const gfx::Size &) {
return false; return false;
} }
@ -705,11 +832,11 @@ void OffScreenRenderWidgetHostView::ImeCompositionRangeChanged(
} }
gfx::Size OffScreenRenderWidgetHostView::GetPhysicalBackingSize() const { gfx::Size OffScreenRenderWidgetHostView::GetPhysicalBackingSize() const {
return size_; return gfx::ConvertSizeToPixel(scale_factor_, GetRequestedRendererSize());
} }
gfx::Size OffScreenRenderWidgetHostView::GetRequestedRendererSize() const { gfx::Size OffScreenRenderWidgetHostView::GetRequestedRendererSize() const {
return size_; return GetDelegatedFrameHost()->GetRequestedRendererSize();
} }
#if !defined(OS_MACOSX) #if !defined(OS_MACOSX)
@ -723,22 +850,29 @@ bool OffScreenRenderWidgetHostView::DelegatedFrameHostIsVisible() const {
SkColor OffScreenRenderWidgetHostView::DelegatedFrameHostGetGutterColor( SkColor OffScreenRenderWidgetHostView::DelegatedFrameHostGetGutterColor(
SkColor color) const { SkColor color) const {
if (render_widget_host_->delegate() &&
render_widget_host_->delegate()->IsFullscreenForCurrentTab()) {
return SK_ColorBLACK;
}
return color; return color;
} }
gfx::Size OffScreenRenderWidgetHostView::DelegatedFrameHostDesiredSizeInDIP() gfx::Size OffScreenRenderWidgetHostView::DelegatedFrameHostDesiredSizeInDIP()
const { const {
return size_; return GetRootLayer()->bounds().size();
} }
bool OffScreenRenderWidgetHostView::DelegatedFrameCanCreateResizeLock() const { bool OffScreenRenderWidgetHostView::DelegatedFrameCanCreateResizeLock() const {
return false; return !render_widget_host_->auto_resize_enabled();
} }
std::unique_ptr<content::ResizeLock> std::unique_ptr<content::ResizeLock>
OffScreenRenderWidgetHostView::DelegatedFrameHostCreateResizeLock( OffScreenRenderWidgetHostView::DelegatedFrameHostCreateResizeLock(
bool defer_compositor_lock) { bool defer_compositor_lock) {
return nullptr; return std::unique_ptr<content::ResizeLock>(new AtomResizeLock(
this,
DelegatedFrameHostDesiredSizeInDIP(),
defer_compositor_lock));
} }
void OffScreenRenderWidgetHostView::DelegatedFrameHostResizeLockWasReleased() { void OffScreenRenderWidgetHostView::DelegatedFrameHostResizeLockWasReleased() {
@ -795,6 +929,57 @@ bool OffScreenRenderWidgetHostView::TransformPointToCoordSpaceForView(
point, target_view, transformed_point); point, target_view, transformed_point);
} }
void OffScreenRenderWidgetHostView::CancelWidget() {
if (render_widget_host_)
render_widget_host_->LostCapture();
Hide();
if (parent_host_view_) {
if (parent_host_view_->popup_host_view_ == this) {
parent_host_view_->set_popup_host_view(NULL);
parent_host_view_->popup_bitmap_.reset();
} else if (parent_host_view_->child_host_view_ == this) {
parent_host_view_->set_child_host_view(NULL);
parent_host_view_->Show();
} else {
parent_host_view_->RemoveGuestHostView(this);
}
parent_host_view_ = NULL;
}
if (render_widget_host_ && !is_destroyed_) {
is_destroyed_ = true;
// Results in a call to Destroy().
render_widget_host_->ShutdownAndDestroyWidget(true);
}
}
void OffScreenRenderWidgetHostView::AddGuestHostView(
OffScreenRenderWidgetHostView* guest_host) {
guest_host_views_.insert(guest_host);
}
void OffScreenRenderWidgetHostView::RemoveGuestHostView(
OffScreenRenderWidgetHostView* guest_host) {
guest_host_views_.erase(guest_host);
}
void OffScreenRenderWidgetHostView::RegisterGuestViewFrameSwappedCallback(
content::RenderWidgetHostViewGuest* guest_host_view) {
guest_host_view->RegisterFrameSwappedCallback(base::MakeUnique<base::Closure>(
base::Bind(&OffScreenRenderWidgetHostView::OnGuestViewFrameSwapped,
weak_ptr_factory_.GetWeakPtr(),
base::Unretained(guest_host_view))));
}
void OffScreenRenderWidgetHostView::OnGuestViewFrameSwapped(
content::RenderWidgetHostViewGuest* guest_host_view) {
InvalidateBounds(
gfx::ConvertRectToPixel(scale_factor_, guest_host_view->GetViewBounds()));
RegisterGuestViewFrameSwappedCallback(guest_host_view);
}
std::unique_ptr<cc::SoftwareOutputDevice> std::unique_ptr<cc::SoftwareOutputDevice>
OffScreenRenderWidgetHostView::CreateSoftwareOutputDevice( OffScreenRenderWidgetHostView::CreateSoftwareOutputDevice(
ui::Compositor* compositor) { ui::Compositor* compositor) {
@ -823,7 +1008,7 @@ bool OffScreenRenderWidgetHostView::InstallTransparency() {
} }
bool OffScreenRenderWidgetHostView::IsAutoResizeEnabled() const { bool OffScreenRenderWidgetHostView::IsAutoResizeEnabled() const {
return false; return render_widget_host_->auto_resize_enabled();
} }
void OffScreenRenderWidgetHostView::SetNeedsBeginFrames( void OffScreenRenderWidgetHostView::SetNeedsBeginFrames(
@ -837,10 +1022,143 @@ void OffScreenRenderWidgetHostView::SetNeedsBeginFrames(
} }
} }
void CopyBitmapTo(
const SkBitmap& destination,
const SkBitmap& source,
const gfx::Rect& pos) {
SkAutoLockPixels source_pixels_lock(source);
SkAutoLockPixels destination_pixels_lock(destination);
char* src = static_cast<char*>(source.getPixels());
char* dest = static_cast<char*>(destination.getPixels());
int pixelsize = source.bytesPerPixel();
if (pos.x() + pos.width() <= destination.width() &&
pos.y() + pos.height() <= destination.height()) {
for (int i = 0; i < pos.height(); i++) {
memcpy(dest + ((pos.y() + i) * destination.width() + pos.x()) * pixelsize,
src + (i * source.width()) * pixelsize,
source.width() * pixelsize);
}
}
destination.notifyPixelsChanged();
}
void OffScreenRenderWidgetHostView::OnPaint( void OffScreenRenderWidgetHostView::OnPaint(
const gfx::Rect& damage_rect, const SkBitmap& bitmap) { const gfx::Rect& damage_rect, const SkBitmap& bitmap) {
TRACE_EVENT0("electron", "OffScreenRenderWidgetHostView::OnPaint"); TRACE_EVENT0("electron", "OffScreenRenderWidgetHostView::OnPaint");
callback_.Run(damage_rect, bitmap);
HoldResize();
if (parent_callback_)
parent_callback_.Run(damage_rect, bitmap);
else if (popup_host_view_ && popup_bitmap_.get()) {
gfx::Rect pos = popup_host_view_->popup_position_;
SkBitmap copy = SkBitmapOperations::CreateTiledBitmap(bitmap,
pos.x(), pos.y(), pos.width(), pos.height());
CopyBitmapTo(bitmap, *popup_bitmap_, pos);
callback_.Run(damage_rect, bitmap);
CopyBitmapTo(bitmap, copy, pos);
} else {
callback_.Run(damage_rect, bitmap);
}
ReleaseResize();
}
void OffScreenRenderWidgetHostView::OnPopupPaint(
const gfx::Rect& damage_rect, const SkBitmap& bitmap) {
if (popup_host_view_ && popup_bitmap_.get())
bitmap.deepCopyTo(popup_bitmap_.get());
}
void OffScreenRenderWidgetHostView::HoldResize() {
if (!hold_resize_)
hold_resize_ = true;
}
void OffScreenRenderWidgetHostView::ReleaseResize() {
if (!hold_resize_)
return;
hold_resize_ = false;
if (pending_resize_) {
pending_resize_ = false;
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&OffScreenRenderWidgetHostView::WasResized,
weak_ptr_factory_.GetWeakPtr()));
}
}
void OffScreenRenderWidgetHostView::WasResized() {
if (hold_resize_) {
if (!pending_resize_)
pending_resize_ = true;
return;
}
ResizeRootLayer();
if (render_widget_host_)
render_widget_host_->WasResized();
GetDelegatedFrameHost()->WasResized();
}
void OffScreenRenderWidgetHostView::ProcessKeyboardEvent(
const content::NativeWebKeyboardEvent& event) {
if (!render_widget_host_)
return;
render_widget_host_->ForwardKeyboardEvent(event);
}
void OffScreenRenderWidgetHostView::ProcessMouseEvent(
const blink::WebMouseEvent& event,
const ui::LatencyInfo& latency) {
if (!IsPopupWidget()) {
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_->ProcessMouseEvent(popup_event, latency);
return;
}
}
if (!render_widget_host_)
return;
render_widget_host_->ForwardMouseEvent(event);
}
void OffScreenRenderWidgetHostView::ProcessMouseWheelEvent(
const blink::WebMouseWheelEvent& event,
const ui::LatencyInfo& latency) {
if (!IsPopupWidget()) {
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_->ProcessMouseWheelEvent(popup_event, latency);
return;
} else {
// Scrolling outside of the popup widget so destroy it.
// Execute asynchronously to avoid deleting the widget from inside some
// other callback.
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&OffScreenRenderWidgetHostView::CancelWidget,
popup_host_view_->weak_ptr_factory_.GetWeakPtr()));
}
}
}
if (!render_widget_host_)
return;
render_widget_host_->ForwardWheelEvent(event);
} }
void OffScreenRenderWidgetHostView::SetPainting(bool painting) { void OffScreenRenderWidgetHostView::SetPainting(bool painting) {
@ -856,12 +1174,22 @@ bool OffScreenRenderWidgetHostView::IsPainting() const {
} }
void OffScreenRenderWidgetHostView::SetFrameRate(int frame_rate) { void OffScreenRenderWidgetHostView::SetFrameRate(int frame_rate) {
if (frame_rate <= 0) if (parent_host_view_) {
frame_rate = 1; if (parent_host_view_->GetFrameRate() == GetFrameRate())
if (frame_rate > 60) return;
frame_rate = 60;
frame_rate_ = frame_rate; frame_rate_ = parent_host_view_->GetFrameRate();
} else {
if (frame_rate <= 0)
frame_rate = 1;
if (frame_rate > 60)
frame_rate = 60;
frame_rate_ = frame_rate;
}
for (auto guest_host_view : guest_host_views_)
guest_host_view->SetFrameRate(frame_rate);
SetupFrameRate(true); SetupFrameRate(true);
} }
@ -910,8 +1238,10 @@ void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) {
} }
void OffScreenRenderWidgetHostView::Invalidate() { void OffScreenRenderWidgetHostView::Invalidate() {
const gfx::Rect& bounds_in_pixels = GetViewBounds(); InvalidateBounds(GetViewBounds());
}
void OffScreenRenderWidgetHostView::InvalidateBounds(const gfx::Rect& bounds) {
if (software_output_device_) { if (software_output_device_) {
software_output_device_->OnPaint(bounds_in_pixels); software_output_device_->OnPaint(bounds_in_pixels);
} else if (copy_frame_generator_) { } else if (copy_frame_generator_) {
@ -925,7 +1255,11 @@ void OffScreenRenderWidgetHostView::ResizeRootLayer() {
const float orgScaleFactor = scale_factor_; const float orgScaleFactor = scale_factor_;
const bool scaleFactorDidChange = (orgScaleFactor != scale_factor_); const bool scaleFactorDidChange = (orgScaleFactor != scale_factor_);
gfx::Size size = GetViewBounds().size(); gfx::Size size;
if (!IsPopupWidget())
size = GetViewBounds().size();
else
size = popup_position_.size();
if (!scaleFactorDidChange && size == GetRootLayer()->bounds().size()) if (!scaleFactorDidChange && size == GetRootLayer()->bounds().size())
return; return;

View file

@ -20,10 +20,12 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "cc/output/compositor_frame.h" #include "cc/output/compositor_frame.h"
#include "cc/scheduler/begin_frame_source.h" #include "cc/scheduler/begin_frame_source.h"
#include "content/browser/frame_host/render_widget_host_view_guest.h"
#include "content/browser/renderer_host/delegated_frame_host.h" #include "content/browser/renderer_host/delegated_frame_host.h"
#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/browser/renderer_host/resize_lock.h" #include "content/browser/renderer_host/resize_lock.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/WebKit/public/platform/WebVector.h" #include "third_party/WebKit/public/platform/WebVector.h"
#include "ui/base/ime/text_input_client.h" #include "ui/base/ime/text_input_client.h"
#include "ui/compositor/compositor.h" #include "ui/compositor/compositor.h"
@ -69,7 +71,7 @@ class OffScreenRenderWidgetHostView
OffScreenRenderWidgetHostView(bool transparent, OffScreenRenderWidgetHostView(bool transparent,
const OnPaintCallback& callback, const OnPaintCallback& callback,
content::RenderWidgetHost* render_widget_host, content::RenderWidgetHost* render_widget_host,
bool is_guest_view_hack, OffScreenRenderWidgetHostView* parent_host_view,
NativeWindow* native_window); NativeWindow* native_window);
~OffScreenRenderWidgetHostView() override; ~OffScreenRenderWidgetHostView() override;
@ -139,6 +141,9 @@ class OffScreenRenderWidgetHostView
void BeginFrameSubscription( void BeginFrameSubscription(
std::unique_ptr<content::RenderWidgetHostViewFrameSubscriber>) override; std::unique_ptr<content::RenderWidgetHostViewFrameSubscriber>) override;
void EndFrameSubscription() override; void EndFrameSubscription() override;
void InitAsGuest(
content::RenderWidgetHostView*,
content::RenderWidgetHostViewGuest*) override;
bool HasAcceleratedSurface(const gfx::Size &) override; bool HasAcceleratedSurface(const gfx::Size &) override;
gfx::Rect GetBoundsInRootWindow(void) override; gfx::Rect GetBoundsInRootWindow(void) override;
void ImeCompositionRangeChanged( void ImeCompositionRangeChanged(
@ -193,7 +198,32 @@ class OffScreenRenderWidgetHostView
void DestroyPlatformWidget(); void DestroyPlatformWidget();
#endif #endif
void CancelWidget();
void AddGuestHostView(OffScreenRenderWidgetHostView* guest_host);
void RemoveGuestHostView(OffScreenRenderWidgetHostView* guest_host);
void RegisterGuestViewFrameSwappedCallback(
content::RenderWidgetHostViewGuest* guest_host_view);
void OnGuestViewFrameSwapped(
content::RenderWidgetHostViewGuest* guest_host_view);
void OnPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap); void OnPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap);
void OnPopupPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap);
bool IsPopupWidget() const {
return popup_type_ != blink::WebPopupTypeNone;
}
void HoldResize();
void ReleaseResize();
void WasResized();
void ProcessKeyboardEvent(
const content::NativeWebKeyboardEvent& event) override;
void ProcessMouseEvent(const blink::WebMouseEvent& event,
const ui::LatencyInfo& latency) override;
void ProcessMouseWheelEvent(const blink::WebMouseWheelEvent& event,
const ui::LatencyInfo& latency) override;
void SetPainting(bool painting); void SetPainting(bool painting);
bool IsPainting() const; bool IsPainting() const;
@ -206,6 +236,7 @@ class OffScreenRenderWidgetHostView
content::DelegatedFrameHost* GetDelegatedFrameHost() const; content::DelegatedFrameHost* GetDelegatedFrameHost() const;
void Invalidate(); void Invalidate();
void InvalidateBounds(const gfx::Rect&);
content::RenderWidgetHostImpl* render_widget_host() const content::RenderWidgetHostImpl* render_widget_host() const
{ return render_widget_host_; } { return render_widget_host_; }
@ -213,6 +244,14 @@ class OffScreenRenderWidgetHostView
gfx::Size size() const { return size_; } gfx::Size size() const { return size_; }
float scale_factor() const { return scale_factor_; } float scale_factor() const { return scale_factor_; }
void set_popup_host_view(OffScreenRenderWidgetHostView* popup_view) {
popup_host_view_ = popup_view;
}
void set_child_host_view(OffScreenRenderWidgetHostView* child_view) {
child_host_view_ = child_view;
}
private: private:
void SetupFrameRate(bool force); void SetupFrameRate(bool force);
void ResizeRootLayer(); void ResizeRootLayer();
@ -221,11 +260,19 @@ class OffScreenRenderWidgetHostView
// Weak ptrs. // Weak ptrs.
content::RenderWidgetHostImpl* render_widget_host_; content::RenderWidgetHostImpl* render_widget_host_;
OffScreenRenderWidgetHostView* parent_host_view_;
OffScreenRenderWidgetHostView* popup_host_view_;
std::unique_ptr<SkBitmap> popup_bitmap_;
OffScreenRenderWidgetHostView* child_host_view_;
std::set<OffScreenRenderWidgetHostView*> guest_host_views_;
NativeWindow* native_window_; NativeWindow* native_window_;
OffScreenOutputDevice* software_output_device_; OffScreenOutputDevice* software_output_device_;
const bool transparent_; const bool transparent_;
OnPaintCallback callback_; OnPaintCallback callback_;
OnPaintCallback parent_callback_;
int frame_rate_; int frame_rate_;
int frame_rate_threshold_ms_; int frame_rate_threshold_ms_;
@ -233,10 +280,16 @@ class OffScreenRenderWidgetHostView
base::Time last_time_; base::Time last_time_;
float scale_factor_; float scale_factor_;
bool is_showing_;
gfx::Vector2dF last_scroll_offset_; gfx::Vector2dF last_scroll_offset_;
gfx::Size size_; gfx::Size size_;
bool painting_; bool painting_;
bool is_showing_;
bool is_destroyed_;
gfx::Rect popup_position_;
bool hold_resize_;
bool pending_resize_;
std::unique_ptr<ui::Layer> root_layer_; std::unique_ptr<ui::Layer> root_layer_;
std::unique_ptr<ui::Compositor> compositor_; std::unique_ptr<ui::Compositor> compositor_;

View file

@ -4,7 +4,9 @@
#include "atom/browser/osr/osr_web_contents_view.h" #include "atom/browser/osr/osr_web_contents_view.h"
#include "content/public/browser/render_view_host.h"
#include "third_party/WebKit/public/platform/WebScreenInfo.h" #include "third_party/WebKit/public/platform/WebScreenInfo.h"
#include "ui/display/screen.h"
namespace atom { namespace atom {
@ -31,15 +33,27 @@ void OffScreenWebContentsView::SetWebContents(
#if !defined(OS_MACOSX) #if !defined(OS_MACOSX)
gfx::NativeView OffScreenWebContentsView::GetNativeView() const { gfx::NativeView OffScreenWebContentsView::GetNativeView() const {
return gfx::NativeView(); if (!web_contents_) return gfx::NativeView();
auto relay = NativeWindowRelay::FromWebContents(web_contents_);
if (!relay) return gfx::NativeView();
return relay->window->GetNativeView();
} }
gfx::NativeView OffScreenWebContentsView::GetContentNativeView() const { gfx::NativeView OffScreenWebContentsView::GetContentNativeView() const {
return gfx::NativeView(); if (!web_contents_) return gfx::NativeView();
auto relay = NativeWindowRelay::FromWebContents(web_contents_);
if (!relay) return gfx::NativeView();
return relay->window->GetNativeView();
} }
gfx::NativeWindow OffScreenWebContentsView::GetTopLevelNativeWindow() const { gfx::NativeWindow OffScreenWebContentsView::GetTopLevelNativeWindow() const {
return gfx::NativeWindow(); if (!web_contents_) return gfx::NativeWindow();
auto relay = NativeWindowRelay::FromWebContents(web_contents_);
if (!relay) return gfx::NativeWindow();
return relay->window->GetNativeWindow();
} }
#endif #endif
@ -67,7 +81,7 @@ content::DropData* OffScreenWebContentsView::GetDropData() const {
} }
gfx::Rect OffScreenWebContentsView::GetViewBounds() const { gfx::Rect OffScreenWebContentsView::GetViewBounds() const {
return view_ ? view_->GetViewBounds() : gfx::Rect(); return GetView() ? GetView()->GetViewBounds() : gfx::Rect();
} }
void OffScreenWebContentsView::CreateView(const gfx::Size& initial_size, void OffScreenWebContentsView::CreateView(const gfx::Size& initial_size,
@ -76,21 +90,55 @@ void OffScreenWebContentsView::CreateView(const gfx::Size& initial_size,
content::RenderWidgetHostViewBase* content::RenderWidgetHostViewBase*
OffScreenWebContentsView::CreateViewForWidget( OffScreenWebContentsView::CreateViewForWidget(
content::RenderWidgetHost* render_widget_host, bool is_guest_view_hack) { content::RenderWidgetHost* render_widget_host, bool is_guest_view_hack) {
if (render_widget_host->GetView()) {
return static_cast<content::RenderWidgetHostViewBase*>(
render_widget_host->GetView());
}
auto relay = NativeWindowRelay::FromWebContents(web_contents_); auto relay = NativeWindowRelay::FromWebContents(web_contents_);
view_ = new OffScreenRenderWidgetHostView( return new OffScreenRenderWidgetHostView(
transparent_, callback_, render_widget_host, transparent_,
is_guest_view_hack, relay->window.get()); callback_,
return view_; render_widget_host,
nullptr,
relay->window.get());
}
content::RenderWidgetHostViewBase*
OffScreenWebContentsView::CreateViewForWidget(
content::RenderWidgetHost* render_widget_host,
content::RenderWidgetHost* embedder_render_widget_host) {
if (render_widget_host->GetView()) {
return static_cast<content::RenderWidgetHostViewBase*>(
render_widget_host->GetView());
}
OffScreenRenderWidgetHostView* embedder_host_view = nullptr;
if (embedder_render_widget_host) {
embedder_host_view = static_cast<OffScreenRenderWidgetHostView*>(
embedder_render_widget_host->GetView());
}
auto relay = NativeWindowRelay::FromWebContents(web_contents_);
return new OffScreenRenderWidgetHostView(
transparent_,
callback_,
render_widget_host,
embedder_host_view,
relay->window.get());
} }
content::RenderWidgetHostViewBase* content::RenderWidgetHostViewBase*
OffScreenWebContentsView::CreateViewForPopupWidget( OffScreenWebContentsView::CreateViewForPopupWidget(
content::RenderWidgetHost* render_widget_host) { content::RenderWidgetHost* render_widget_host) {
auto relay = NativeWindowRelay::FromWebContents(web_contents_); auto relay = NativeWindowRelay::FromWebContents(web_contents_);
view_ = new OffScreenRenderWidgetHostView( return new OffScreenRenderWidgetHostView(
transparent_, callback_, render_widget_host, false, relay->window.get()); transparent_,
return view_; callback_,
render_widget_host,
GetView(),
relay->window.get());
} }
void OffScreenWebContentsView::SetPageTitle(const base::string16& title) { void OffScreenWebContentsView::SetPageTitle(const base::string16& title) {
@ -98,8 +146,8 @@ void OffScreenWebContentsView::SetPageTitle(const base::string16& title) {
void OffScreenWebContentsView::RenderViewCreated( void OffScreenWebContentsView::RenderViewCreated(
content::RenderViewHost* host) { content::RenderViewHost* host) {
if (view_) if (GetView())
view_->InstallTransparency(); GetView()->InstallTransparency();
} }
void OffScreenWebContentsView::RenderViewSwappedIn( void OffScreenWebContentsView::RenderViewSwappedIn(
@ -111,14 +159,23 @@ void OffScreenWebContentsView::SetOverscrollControllerEnabled(bool enabled) {
void OffScreenWebContentsView::GetScreenInfo( void OffScreenWebContentsView::GetScreenInfo(
content::ScreenInfo* screen_info) const { content::ScreenInfo* screen_info) const {
screen_info->rect = gfx::Rect(view_->size());
screen_info->available_rect = gfx::Rect(view_->size());
screen_info->depth = 24; screen_info->depth = 24;
screen_info->depth_per_component = 8; screen_info->depth_per_component = 8;
screen_info->device_scale_factor = view_->scale_factor();
screen_info->orientation_angle = 0; screen_info->orientation_angle = 0;
screen_info->orientation_type = screen_info->orientation_type =
content::SCREEN_ORIENTATION_VALUES_LANDSCAPE_PRIMARY; content::SCREEN_ORIENTATION_VALUES_LANDSCAPE_PRIMARY;
if (GetView()) {
screen_info->rect = gfx::Rect(GetView()->size());
screen_info->available_rect = gfx::Rect(GetView()->size());
screen_info->device_scale_factor = GetView()->scale_factor();
} else {
const display::Display display =
display::Screen::GetScreen()->GetPrimaryDisplay();
screen_info->rect = display.bounds();
screen_info->available_rect = display.work_area();
screen_info->device_scale_factor = display.device_scale_factor();
}
} }
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
@ -152,4 +209,12 @@ void OffScreenWebContentsView::UpdateDragCursor(
blink::WebDragOperation operation) { blink::WebDragOperation operation) {
} }
OffScreenRenderWidgetHostView* OffScreenWebContentsView::GetView() const {
if (web_contents_) {
return static_cast<OffScreenRenderWidgetHostView*>(
web_contents_->GetRenderViewHost()->GetWidget()->GetView());
}
return nullptr;
}
} // namespace atom } // namespace atom

View file

@ -45,6 +45,9 @@ class OffScreenWebContentsView : public content::WebContentsView,
content::RenderWidgetHostViewBase* CreateViewForWidget( content::RenderWidgetHostViewBase* CreateViewForWidget(
content::RenderWidgetHost* render_widget_host, content::RenderWidgetHost* render_widget_host,
bool is_guest_view_hack) override; bool is_guest_view_hack) override;
content::RenderWidgetHostViewBase* CreateViewForWidget(
content::RenderWidgetHost* render_widget_host,
content::RenderWidgetHost* embedder_render_widget_host) override;
content::RenderWidgetHostViewBase* CreateViewForPopupWidget( content::RenderWidgetHostViewBase* CreateViewForPopupWidget(
content::RenderWidgetHost* render_widget_host) override; content::RenderWidgetHost* render_widget_host) override;
void SetPageTitle(const base::string16& title) override; void SetPageTitle(const base::string16& title) override;
@ -75,11 +78,12 @@ class OffScreenWebContentsView : public content::WebContentsView,
void PlatformDestroy(); void PlatformDestroy();
#endif #endif
OffScreenRenderWidgetHostView* GetView() const;
const bool transparent_; const bool transparent_;
OnPaintCallback callback_; OnPaintCallback callback_;
// Weak refs. // Weak refs.
OffScreenRenderWidgetHostView* view_;
content::WebContents* web_contents_; content::WebContents* web_contents_;
#if defined(OS_MACOSX) #if defined(OS_MACOSX)