From 20d2ab29ab51cafc1c8b391c19134fbb7f711779 Mon Sep 17 00:00:00 2001 From: Heilig Benedek Date: Sat, 4 Mar 2017 03:09:16 +0100 Subject: [PATCH] Add support for child and popup windows in OSR --- atom/browser/api/atom_api_web_contents.cc | 41 +- atom/browser/api/atom_api_web_contents.h | 1 + atom/browser/native_window.h | 1 + atom/browser/native_window_views.cc | 4 + atom/browser/native_window_views.h | 1 + .../osr/osr_render_widget_host_view.cc | 386 ++++++++++++++++-- .../browser/osr/osr_render_widget_host_view.h | 57 ++- atom/browser/osr/osr_web_contents_view.cc | 99 ++++- atom/browser/osr/osr_web_contents_view.h | 6 +- 9 files changed, 541 insertions(+), 55 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index bedc0976969a..e5f8bfe9d292 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -48,6 +48,7 @@ #include "chrome/browser/ssl/security_state_tab_helper.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_view_base.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/view_messages.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) type_ = OFF_SCREEN; + // Init embedder earlier + options.Get("embedder", &embedder_); + // Whether to 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); guest_delegate_.reset(new WebViewGuestDelegate); 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()) { bool transparent = false; options.Get("transparent", &transparent); @@ -389,7 +404,7 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate, guest_delegate_->Initialize(this); NativeWindow* owner_window = nullptr; - if (options.Get("embedder", &embedder_) && embedder_) { + if (embedder_) { // New WebContents's owner_window is the embedder's owner_window. auto relay = NativeWindowRelay::FromWebContents(embedder_->web_contents()); @@ -1402,18 +1417,16 @@ bool WebContents::SendIPCMessage(bool all_frames, void WebContents::SendInputEvent(v8::Isolate* isolate, v8::Local input_event) { - const auto view = web_contents()->GetRenderWidgetHostView(); + const auto view = static_cast( + web_contents()->GetRenderWidgetHostView()); if (!view) return; - const auto host = view->GetRenderWidgetHost(); - if (!host) - return; int type = mate::GetWebInputEventType(isolate, input_event); if (blink::WebInputEvent::isMouseEventType(type)) { blink::WebMouseEvent mouse_event; if (mate::ConvertFromV8(isolate, input_event, &mouse_event)) { - host->ForwardMouseEvent(mouse_event); + view->ProcessMouseEvent(mouse_event, ui::LatencyInfo()); return; } } else if (blink::WebInputEvent::isKeyboardEventType(type)) { @@ -1422,13 +1435,13 @@ void WebContents::SendInputEvent(v8::Isolate* isolate, blink::WebInputEvent::NoModifiers, ui::EventTimeForNow()); if (mate::ConvertFromV8(isolate, input_event, &keyboard_event)) { - host->ForwardKeyboardEvent(keyboard_event); + view->ProcessKeyboardEvent(keyboard_event); return; } } else if (type == blink::WebInputEvent::MouseWheel) { blink::WebMouseWheelEvent 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; } } @@ -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) { zoom_controller_->SetZoomLevel(level); } diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 1f926dbd7a5a..1916964fa254 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -183,6 +183,7 @@ class WebContents : public mate::TrackableObject, void SetFrameRate(int frame_rate); int GetFrameRate() const; void Invalidate(); + gfx::Size GetSizeForNewRenderView(content::WebContents*) const override; // Methods for zoom handling. void SetZoomLevel(double level); diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index d3f18d8fb95c..b0d25e03f232 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -147,6 +147,7 @@ class NativeWindow : public base::SupportsUserData, virtual void SetMenu(AtomMenuModel* menu); virtual void SetParentWindow(NativeWindow* parent); virtual void SetBrowserView(NativeBrowserView* browser_view) = 0; + virtual gfx::NativeView GetNativeView() = 0; virtual gfx::NativeWindow GetNativeWindow() = 0; virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0; diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index ed524cbdcbc1..00f0befd50fa 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -924,6 +924,10 @@ void NativeWindowViews::SetParentWindow(NativeWindow* parent) { #endif } +gfx::NativeView NativeWindowViews::GetNativeView() { + return window_->GetNativeView(); +} + gfx::NativeWindow NativeWindowViews::GetNativeWindow() { return window_->GetNativeWindow(); } diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index 276cd4adde2d..15bdbad18808 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -106,6 +106,7 @@ class NativeWindowViews : public NativeWindow, void SetMenu(AtomMenuModel* menu_model) override; void SetBrowserView(NativeBrowserView* browser_view) override; void SetParentWindow(NativeWindow* parent) override; + gfx::NativeView GetNativeView() override; gfx::NativeWindow GetNativeWindow() override; void SetOverlayIcon(const gfx::Image& overlay, const std::string& description) override; diff --git a/atom/browser/osr/osr_render_widget_host_view.cc b/atom/browser/osr/osr_render_widget_host_view.cc index c41a6805c068..6719b7b45458 100644 --- a/atom/browser/osr/osr_render_widget_host_view.cc +++ b/atom/browser/osr/osr_render_widget_host_view.cc @@ -17,6 +17,7 @@ #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_view_frame_subscriber.h" +#include "content/browser/renderer_host/resize_lock.h" #include "content/common/view_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/context_factory.h" @@ -25,6 +26,7 @@ #include "ui/compositor/layer.h" #include "ui/compositor/layer_type.h" #include "ui/events/latency_info.h" +#include "ui/gfx/skbitmap_operations.h" #include "ui/gfx/geometry/dip_util.h" #include "ui/gfx/native_widget_types.h" @@ -35,6 +37,66 @@ namespace { const float kDefaultScaleFactor = 1.0; 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 compositor_lock_; + bool cancelled_; + base::WeakPtrFactory weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(AtomResizeLock); +}; + +#endif // !defined(OS_MACOSX) + } // namespace class AtomCopyFrameGenerator { @@ -338,24 +400,30 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView( bool transparent, const OnPaintCallback& callback, content::RenderWidgetHost* host, - bool is_guest_view_hack, + OffScreenRenderWidgetHostView* parent_host_view, NativeWindow* native_window) : 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), software_output_device_(nullptr), transparent_(transparent), callback_(callback), + parent_callback_(nullptr), frame_rate_(60), frame_rate_threshold_ms_(0), last_time_(base::Time::Now()), scale_factor_(kDefaultScaleFactor), - is_showing_(!render_widget_host_->is_hidden()), - size_(native_window->GetSize()), 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) { DCHECK(render_widget_host_); - render_widget_host_->SetView(this); - #if !defined(OS_MACOSX) delegated_frame_host_ = base::MakeUnique( AllocateFrameSinkId(is_guest_view_hack), this); @@ -383,6 +451,8 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView( native_window_->AddObserver(this); ResizeRootLayer(); + render_widget_host_->SetView(this); + InstallTransparency(); } OffScreenRenderWidgetHostView::~OffScreenRenderWidgetHostView() { @@ -400,8 +470,15 @@ OffScreenRenderWidgetHostView::~OffScreenRenderWidgetHostView() { delegated_frame_host_->ResetCompositor(); #endif + if (copy_frame_generator_.get()) + copy_frame_generator_.reset(NULL); + #if defined(OS_MACOSX) DestroyPlatformWidget(); +#else + delegated_frame_host_.reset(NULL); + compositor_.reset(NULL); + root_layer_.reset(NULL); #endif } @@ -461,6 +538,17 @@ bool OffScreenRenderWidgetHostView::OnMessageReceived( } 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() @@ -470,14 +558,11 @@ content::RenderWidgetHost* OffScreenRenderWidgetHostView::GetRenderWidgetHost() void OffScreenRenderWidgetHostView::SetSize(const gfx::Size& size) { size_ = size; - - ResizeRootLayer(); - if (render_widget_host_) - render_widget_host_->WasResized(); - GetDelegatedFrameHost()->WasResized(); + WasResized(); } void OffScreenRenderWidgetHostView::SetBounds(const gfx::Rect& new_bounds) { + SetSize(new_bounds.size()); } gfx::Vector2dF OffScreenRenderWidgetHostView::GetLastScrollOffset() const { @@ -547,6 +632,9 @@ bool OffScreenRenderWidgetHostView::IsShowing() { } gfx::Rect OffScreenRenderWidgetHostView::GetViewBounds() const { + if (IsPopupWidget()) + return popup_position_; + return gfx::Rect(size_); } @@ -587,7 +675,7 @@ void OffScreenRenderWidgetHostView::OnSwapCompositorFrame( if (!frame.render_pass_list.empty()) { if (software_output_device_) { - if (!begin_frame_timer_.get()) { + if (!begin_frame_timer_.get() || IsPopupWidget()) { software_output_device_->SetActive(painting_); } @@ -631,10 +719,25 @@ void OffScreenRenderWidgetHostView::ClearCompositorFrame() { void OffScreenRenderWidgetHostView::InitAsPopup( 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( - content::RenderWidgetHostView *) { + content::RenderWidgetHostView *) { } void OffScreenRenderWidgetHostView::UpdateCursor(const content::WebCursor &) { @@ -656,6 +759,23 @@ void OffScreenRenderWidgetHostView::RenderProcessGone(base::TerminationStatus, } 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; } @@ -692,6 +812,13 @@ void OffScreenRenderWidgetHostView::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 &) { return false; } @@ -705,11 +832,11 @@ void OffScreenRenderWidgetHostView::ImeCompositionRangeChanged( } gfx::Size OffScreenRenderWidgetHostView::GetPhysicalBackingSize() const { - return size_; + return gfx::ConvertSizeToPixel(scale_factor_, GetRequestedRendererSize()); } gfx::Size OffScreenRenderWidgetHostView::GetRequestedRendererSize() const { - return size_; + return GetDelegatedFrameHost()->GetRequestedRendererSize(); } #if !defined(OS_MACOSX) @@ -723,22 +850,29 @@ bool OffScreenRenderWidgetHostView::DelegatedFrameHostIsVisible() const { SkColor OffScreenRenderWidgetHostView::DelegatedFrameHostGetGutterColor( SkColor color) const { + if (render_widget_host_->delegate() && + render_widget_host_->delegate()->IsFullscreenForCurrentTab()) { + return SK_ColorBLACK; + } return color; } gfx::Size OffScreenRenderWidgetHostView::DelegatedFrameHostDesiredSizeInDIP() const { - return size_; + return GetRootLayer()->bounds().size(); } bool OffScreenRenderWidgetHostView::DelegatedFrameCanCreateResizeLock() const { - return false; + return !render_widget_host_->auto_resize_enabled(); } std::unique_ptr OffScreenRenderWidgetHostView::DelegatedFrameHostCreateResizeLock( bool defer_compositor_lock) { - return nullptr; + return std::unique_ptr(new AtomResizeLock( + this, + DelegatedFrameHostDesiredSizeInDIP(), + defer_compositor_lock)); } void OffScreenRenderWidgetHostView::DelegatedFrameHostResizeLockWasReleased() { @@ -795,6 +929,57 @@ bool OffScreenRenderWidgetHostView::TransformPointToCoordSpaceForView( 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::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 OffScreenRenderWidgetHostView::CreateSoftwareOutputDevice( ui::Compositor* compositor) { @@ -823,7 +1008,7 @@ bool OffScreenRenderWidgetHostView::InstallTransparency() { } bool OffScreenRenderWidgetHostView::IsAutoResizeEnabled() const { - return false; + return render_widget_host_->auto_resize_enabled(); } 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(source.getPixels()); + char* dest = static_cast(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( const gfx::Rect& damage_rect, const SkBitmap& bitmap) { 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) { @@ -856,12 +1174,22 @@ bool OffScreenRenderWidgetHostView::IsPainting() const { } void OffScreenRenderWidgetHostView::SetFrameRate(int frame_rate) { - if (frame_rate <= 0) - frame_rate = 1; - if (frame_rate > 60) - frame_rate = 60; + if (parent_host_view_) { + if (parent_host_view_->GetFrameRate() == GetFrameRate()) + return; - 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); } @@ -910,8 +1238,10 @@ void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) { } void OffScreenRenderWidgetHostView::Invalidate() { - const gfx::Rect& bounds_in_pixels = GetViewBounds(); + InvalidateBounds(GetViewBounds()); +} +void OffScreenRenderWidgetHostView::InvalidateBounds(const gfx::Rect& bounds) { if (software_output_device_) { software_output_device_->OnPaint(bounds_in_pixels); } else if (copy_frame_generator_) { @@ -925,7 +1255,11 @@ void OffScreenRenderWidgetHostView::ResizeRootLayer() { const float 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()) return; diff --git a/atom/browser/osr/osr_render_widget_host_view.h b/atom/browser/osr/osr_render_widget_host_view.h index d215d73ab9c4..aa7a0577778c 100644 --- a/atom/browser/osr/osr_render_widget_host_view.h +++ b/atom/browser/osr/osr_render_widget_host_view.h @@ -20,10 +20,12 @@ #include "base/time/time.h" #include "cc/output/compositor_frame.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/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_view_base.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 "ui/base/ime/text_input_client.h" #include "ui/compositor/compositor.h" @@ -69,7 +71,7 @@ class OffScreenRenderWidgetHostView OffScreenRenderWidgetHostView(bool transparent, const OnPaintCallback& callback, content::RenderWidgetHost* render_widget_host, - bool is_guest_view_hack, + OffScreenRenderWidgetHostView* parent_host_view, NativeWindow* native_window); ~OffScreenRenderWidgetHostView() override; @@ -139,6 +141,9 @@ class OffScreenRenderWidgetHostView void BeginFrameSubscription( std::unique_ptr) override; void EndFrameSubscription() override; + void InitAsGuest( + content::RenderWidgetHostView*, + content::RenderWidgetHostViewGuest*) override; bool HasAcceleratedSurface(const gfx::Size &) override; gfx::Rect GetBoundsInRootWindow(void) override; void ImeCompositionRangeChanged( @@ -193,7 +198,32 @@ class OffScreenRenderWidgetHostView void DestroyPlatformWidget(); #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 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); bool IsPainting() const; @@ -206,6 +236,7 @@ class OffScreenRenderWidgetHostView content::DelegatedFrameHost* GetDelegatedFrameHost() const; void Invalidate(); + void InvalidateBounds(const gfx::Rect&); content::RenderWidgetHostImpl* render_widget_host() const { return render_widget_host_; } @@ -213,6 +244,14 @@ class OffScreenRenderWidgetHostView gfx::Size size() const { return size_; } 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: void SetupFrameRate(bool force); void ResizeRootLayer(); @@ -221,11 +260,19 @@ class OffScreenRenderWidgetHostView // Weak ptrs. content::RenderWidgetHostImpl* render_widget_host_; + + OffScreenRenderWidgetHostView* parent_host_view_; + OffScreenRenderWidgetHostView* popup_host_view_; + std::unique_ptr popup_bitmap_; + OffScreenRenderWidgetHostView* child_host_view_; + std::set guest_host_views_; + NativeWindow* native_window_; OffScreenOutputDevice* software_output_device_; const bool transparent_; OnPaintCallback callback_; + OnPaintCallback parent_callback_; int frame_rate_; int frame_rate_threshold_ms_; @@ -233,10 +280,16 @@ class OffScreenRenderWidgetHostView base::Time last_time_; float scale_factor_; - bool is_showing_; gfx::Vector2dF last_scroll_offset_; gfx::Size size_; bool painting_; + + bool is_showing_; + bool is_destroyed_; + gfx::Rect popup_position_; + + bool hold_resize_; + bool pending_resize_; std::unique_ptr root_layer_; std::unique_ptr compositor_; diff --git a/atom/browser/osr/osr_web_contents_view.cc b/atom/browser/osr/osr_web_contents_view.cc index 8d95017b0e64..18b24c1c1ce3 100644 --- a/atom/browser/osr/osr_web_contents_view.cc +++ b/atom/browser/osr/osr_web_contents_view.cc @@ -4,7 +4,9 @@ #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 "ui/display/screen.h" namespace atom { @@ -31,15 +33,27 @@ void OffScreenWebContentsView::SetWebContents( #if !defined(OS_MACOSX) 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 { - 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 { - 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 @@ -67,7 +81,7 @@ content::DropData* OffScreenWebContentsView::GetDropData() 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, @@ -76,21 +90,55 @@ void OffScreenWebContentsView::CreateView(const gfx::Size& initial_size, content::RenderWidgetHostViewBase* 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( + render_widget_host->GetView()); + } + auto relay = NativeWindowRelay::FromWebContents(web_contents_); - view_ = new OffScreenRenderWidgetHostView( - transparent_, callback_, render_widget_host, - is_guest_view_hack, relay->window.get()); - return view_; + return new OffScreenRenderWidgetHostView( + transparent_, + callback_, + 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( + render_widget_host->GetView()); + } + + OffScreenRenderWidgetHostView* embedder_host_view = nullptr; + if (embedder_render_widget_host) { + embedder_host_view = static_cast( + 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* OffScreenWebContentsView::CreateViewForPopupWidget( content::RenderWidgetHost* render_widget_host) { auto relay = NativeWindowRelay::FromWebContents(web_contents_); - view_ = new OffScreenRenderWidgetHostView( - transparent_, callback_, render_widget_host, false, relay->window.get()); - return view_; + return new OffScreenRenderWidgetHostView( + transparent_, + callback_, + render_widget_host, + GetView(), + relay->window.get()); } void OffScreenWebContentsView::SetPageTitle(const base::string16& title) { @@ -98,8 +146,8 @@ void OffScreenWebContentsView::SetPageTitle(const base::string16& title) { void OffScreenWebContentsView::RenderViewCreated( content::RenderViewHost* host) { - if (view_) - view_->InstallTransparency(); + if (GetView()) + GetView()->InstallTransparency(); } void OffScreenWebContentsView::RenderViewSwappedIn( @@ -111,14 +159,23 @@ void OffScreenWebContentsView::SetOverscrollControllerEnabled(bool enabled) { void OffScreenWebContentsView::GetScreenInfo( 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_per_component = 8; - screen_info->device_scale_factor = view_->scale_factor(); screen_info->orientation_angle = 0; screen_info->orientation_type = 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) @@ -152,4 +209,12 @@ void OffScreenWebContentsView::UpdateDragCursor( blink::WebDragOperation operation) { } +OffScreenRenderWidgetHostView* OffScreenWebContentsView::GetView() const { + if (web_contents_) { + return static_cast( + web_contents_->GetRenderViewHost()->GetWidget()->GetView()); + } + return nullptr; +} + } // namespace atom diff --git a/atom/browser/osr/osr_web_contents_view.h b/atom/browser/osr/osr_web_contents_view.h index 8e4e24299473..57aee80d91f9 100644 --- a/atom/browser/osr/osr_web_contents_view.h +++ b/atom/browser/osr/osr_web_contents_view.h @@ -45,6 +45,9 @@ class OffScreenWebContentsView : public content::WebContentsView, content::RenderWidgetHostViewBase* CreateViewForWidget( content::RenderWidgetHost* render_widget_host, 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::RenderWidgetHost* render_widget_host) override; void SetPageTitle(const base::string16& title) override; @@ -75,11 +78,12 @@ class OffScreenWebContentsView : public content::WebContentsView, void PlatformDestroy(); #endif + OffScreenRenderWidgetHostView* GetView() const; + const bool transparent_; OnPaintCallback callback_; // Weak refs. - OffScreenRenderWidgetHostView* view_; content::WebContents* web_contents_; #if defined(OS_MACOSX)