diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index fedb5af844fa..1d4ac80498b9 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -49,6 +49,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" @@ -316,6 +317,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_); @@ -340,7 +344,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); @@ -390,7 +405,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()); @@ -1404,18 +1419,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)) { @@ -1424,13 +1437,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->ProcessMouseWheelEvent(mouse_wheel_event, ui::LatencyInfo()); return; } } @@ -1567,9 +1580,7 @@ bool WebContents::IsOffScreen() const { } void WebContents::OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap) { - mate::Handle image = - NativeImage::Create(isolate(), gfx::Image::CreateFrom1xBitmap(bitmap)); - Emit("paint", dirty_rect, image); + Emit("paint", dirty_rect, gfx::Image::CreateFrom1xBitmap(bitmap)); } void WebContents::StartPainting() { 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_mac.h b/atom/browser/native_window_mac.h index af0f157ecaef..69bf3afef65a 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -89,6 +89,7 @@ class NativeWindowMac : public NativeWindow, void SetContentProtection(bool enable) override; void SetBrowserView(NativeBrowserView* browser_view) override; void SetParentWindow(NativeWindow* parent) override; + gfx::NativeView GetNativeView() override; gfx::NativeWindow GetNativeWindow() override; gfx::AcceleratedWidget GetAcceleratedWidget() override; void SetProgressBar(double progress, const ProgressState state) override; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 330d48226dc4..755e46c4f326 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -1314,6 +1314,10 @@ void NativeWindowMac::SetParentWindow(NativeWindow* parent) { [parent->GetNativeWindow() addChildWindow:window_ ordered:NSWindowAbove]; } +gfx::NativeView NativeWindowMac::GetNativeView() { + return inspectable_web_contents()->GetView()->GetNativeView(); +} + gfx::NativeWindow NativeWindowMac::GetNativeWindow() { return window_; } 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_output_device.cc b/atom/browser/osr/osr_output_device.cc index 49c4191e21ef..c35e364236f6 100644 --- a/atom/browser/osr/osr_output_device.cc +++ b/atom/browser/osr/osr_output_device.cc @@ -4,6 +4,8 @@ #include "atom/browser/osr/osr_output_device.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/src/core/SkDevice.h" #include "ui/gfx/skia_util.h" @@ -36,8 +38,11 @@ void OffScreenOutputDevice::Resize( return; } - if (transparent_) - bitmap_->eraseARGB(0, 0, 0, 0); + if (transparent_) { + bitmap_->eraseColor(SK_ColorTRANSPARENT); + } else { + bitmap_->eraseColor(SK_ColorWHITE); + } canvas_.reset(new SkCanvas(*bitmap_)); } @@ -47,6 +52,17 @@ SkCanvas* OffScreenOutputDevice::BeginPaint(const gfx::Rect& damage_rect) { DCHECK(bitmap_.get()); damage_rect_ = damage_rect; + SkIRect damage = SkIRect::MakeXYWH( + damage_rect_.x(), + damage_rect_.y(), + damage_rect_.width(), + damage_rect_.height()); + + if (transparent_) { + bitmap_->erase(SK_ColorTRANSPARENT, damage); + } else { + bitmap_->erase(SK_ColorWHITE, damage); + } return canvas_.get(); } diff --git a/atom/browser/osr/osr_render_widget_host_view.cc b/atom/browser/osr/osr_render_widget_host_view.cc index c41a6805c068..77002358154f 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" @@ -27,6 +28,7 @@ #include "ui/events/latency_info.h" #include "ui/gfx/geometry/dip_util.h" #include "ui/gfx/native_widget_types.h" +#include "ui/gfx/skbitmap_operations.h" namespace atom { @@ -35,72 +37,87 @@ 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 { public: - AtomCopyFrameGenerator(int frame_rate_threshold_ms, - OffScreenRenderWidgetHostView* view) - : frame_rate_threshold_ms_(frame_rate_threshold_ms), - view_(view), - frame_pending_(false), - frame_in_progress_(false), + AtomCopyFrameGenerator(OffScreenRenderWidgetHostView* view, + int frame_rate_threshold_us) + : view_(view), frame_retry_count_(0), + next_frame_time_(base::TimeTicks::Now()), + frame_duration_(base::TimeDelta::FromMicroseconds( + frame_rate_threshold_us)), weak_ptr_factory_(this) { last_time_ = base::Time::Now(); } - void GenerateCopyFrame( - bool force_frame, - const gfx::Rect& damage_rect) { - if (force_frame && !frame_pending_) - frame_pending_ = true; - - if (!frame_pending_) - return; - - if (!damage_rect.IsEmpty()) - pending_damage_rect_.Union(damage_rect); - - if (frame_in_progress_) - return; - - frame_in_progress_ = true; - - const int64_t frame_rate_delta = - (base::TimeTicks::Now() - frame_start_time_).InMilliseconds(); - if (frame_rate_delta < frame_rate_threshold_ms_) { - content::BrowserThread::PostDelayedTask(content::BrowserThread::UI, - FROM_HERE, - base::Bind(&AtomCopyFrameGenerator::InternalGenerateCopyFrame, - weak_ptr_factory_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds( - frame_rate_threshold_ms_ - frame_rate_delta)); - return; - } - - InternalGenerateCopyFrame(); - } - - bool frame_pending() const { return frame_pending_; } - - void set_frame_rate_threshold_ms(int frame_rate_threshold_ms) { - frame_rate_threshold_ms_ = frame_rate_threshold_ms; - } - - private: - void InternalGenerateCopyFrame() { - frame_pending_ = false; - frame_start_time_ = base::TimeTicks::Now(); - + void GenerateCopyFrame(const gfx::Rect& damage_rect) { if (!view_->render_widget_host()) return; - const gfx::Rect damage_rect = pending_damage_rect_; - pending_damage_rect_.SetRect(0, 0, 0, 0); - std::unique_ptr request = - cc::CopyOutputRequest::CreateRequest(base::Bind( + cc::CopyOutputRequest::CreateBitmapRequest(base::Bind( &AtomCopyFrameGenerator::CopyFromCompositingSurfaceHasResult, weak_ptr_factory_.GetWeakPtr(), damage_rect)); @@ -109,6 +126,12 @@ class AtomCopyFrameGenerator { view_->GetRootLayer()->RequestCopyOfOutput(std::move(request)); } + void set_frame_rate_threshold_us(int frame_rate_threshold_us) { + frame_duration_ = base::TimeDelta::FromMicroseconds( + frame_rate_threshold_us); + } + + private: void CopyFromCompositingSurfaceHasResult( const gfx::Rect& damage_rect, std::unique_ptr result) { @@ -118,180 +141,62 @@ class AtomCopyFrameGenerator { return; } - if (result->HasTexture()) { - PrepareTextureCopyOutputResult(damage_rect, std::move(result)); - return; - } - - DCHECK(result->HasBitmap()); - PrepareBitmapCopyOutputResult(damage_rect, std::move(result)); - } - - void PrepareTextureCopyOutputResult( - const gfx::Rect& damage_rect, - std::unique_ptr result) { - DCHECK(result->HasTexture()); - base::ScopedClosureRunner scoped_callback_runner( - base::Bind(&AtomCopyFrameGenerator::OnCopyFrameCaptureFailure, - weak_ptr_factory_.GetWeakPtr(), - damage_rect)); - - 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()) { - bitmap_.reset(new SkBitmap); - bitmap_->allocN32Pixels(result_size.width(), - result_size.height(), - true); - if (bitmap_->drawsNothing()) - return; - } - - content::ImageTransportFactory* factory = - content::ImageTransportFactory::GetInstance(); - display_compositor::GLHelper* gl_helper = factory->GetGLHelper(); - if (!gl_helper) - return; - - std::unique_ptr bitmap_pixels_lock( - new SkAutoLockPixels(*bitmap_)); - uint8_t* pixels = static_cast(bitmap_->getPixels()); - - cc::TextureMailbox texture_mailbox; - std::unique_ptr 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_token(), - result_size, - gfx::Rect(result_size), - result_size, - pixels, - kN32_SkColorType, - base::Bind( - &AtomCopyFrameGenerator::CopyFromCompositingSurfaceFinishedProxy, - weak_ptr_factory_.GetWeakPtr(), - base::Passed(&release_callback), - damage_rect, - base::Passed(&bitmap_), - base::Passed(&bitmap_pixels_lock)), - display_compositor::GLHelper::SCALER_QUALITY_FAST); - } - - static void CopyFromCompositingSurfaceFinishedProxy( - base::WeakPtr generator, - std::unique_ptr release_callback, - const gfx::Rect& damage_rect, - std::unique_ptr bitmap, - std::unique_ptr bitmap_pixels_lock, - bool result) { - gpu::SyncToken sync_token; - if (result) { - display_compositor::GLHelper* gl_helper = - content::ImageTransportFactory::GetInstance()->GetGLHelper(); - if (gl_helper) - gl_helper->GenerateSyncToken(&sync_token); - } - const bool lost_resource = !sync_token.HasData(); - release_callback->Run(sync_token, lost_resource); - - if (generator) { - generator->CopyFromCompositingSurfaceFinished( - damage_rect, std::move(bitmap), std::move(bitmap_pixels_lock), - result); - } else { - bitmap_pixels_lock.reset(); - bitmap.reset(); - } - } - - void CopyFromCompositingSurfaceFinished( - const gfx::Rect& damage_rect, - std::unique_ptr bitmap, - std::unique_ptr bitmap_pixels_lock, - bool result) { - DCHECK(!bitmap_); - bitmap_ = std::move(bitmap); - - if (result) { - OnCopyFrameCaptureSuccess(damage_rect, *bitmap_, - std::move(bitmap_pixels_lock)); - } else { - bitmap_pixels_lock.reset(); - OnCopyFrameCaptureFailure(damage_rect); - } - } - - void PrepareBitmapCopyOutputResult( - const gfx::Rect& damage_rect, - std::unique_ptr result) { DCHECK(result->HasBitmap()); std::unique_ptr source = result->TakeBitmap(); DCHECK(source); if (source) { - std::unique_ptr bitmap_pixels_lock( - new SkAutoLockPixels(*source)); - OnCopyFrameCaptureSuccess(damage_rect, *source, - std::move(bitmap_pixels_lock)); + base::AutoLock autolock(lock_); + std::shared_ptr bitmap(source.release()); + + base::TimeTicks now = base::TimeTicks::Now(); + base::TimeDelta next_frame_in = next_frame_time_ - now; + if (next_frame_in > frame_duration_ / 4) { + next_frame_time_ += frame_duration_; + content::BrowserThread::PostDelayedTask(content::BrowserThread::UI, + FROM_HERE, + base::Bind(&AtomCopyFrameGenerator::OnCopyFrameCaptureSuccess, + weak_ptr_factory_.GetWeakPtr(), + damage_rect, + bitmap), + next_frame_in); + } else { + next_frame_time_ = now + frame_duration_; + OnCopyFrameCaptureSuccess(damage_rect, bitmap); + } + + frame_retry_count_ = 0; } else { OnCopyFrameCaptureFailure(damage_rect); } } - void OnCopyFrameCaptureFailure( - const gfx::Rect& damage_rect) { - pending_damage_rect_.Union(damage_rect); - + void OnCopyFrameCaptureFailure(const gfx::Rect& damage_rect) { const bool force_frame = (++frame_retry_count_ <= kFrameRetryLimit); - OnCopyFrameCaptureCompletion(force_frame); + if (force_frame) { + // Retry with the same |damage_rect|. + content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, + base::Bind(&AtomCopyFrameGenerator::GenerateCopyFrame, + weak_ptr_factory_.GetWeakPtr(), + damage_rect)); + } } void OnCopyFrameCaptureSuccess( const gfx::Rect& damage_rect, - const SkBitmap& bitmap, - std::unique_ptr bitmap_pixels_lock) { - view_->OnPaint(damage_rect, bitmap); - - if (frame_retry_count_ > 0) - frame_retry_count_ = 0; - - OnCopyFrameCaptureCompletion(false); + std::shared_ptr bitmap) { + base::AutoLock lock(onPaintLock_); + view_->OnPaint(damage_rect, *bitmap); } - void OnCopyFrameCaptureCompletion(bool force_frame) { - frame_in_progress_ = false; - - if (frame_pending_) { - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&AtomCopyFrameGenerator::GenerateCopyFrame, - weak_ptr_factory_.GetWeakPtr(), - force_frame, - gfx::Rect())); - } - } - - int frame_rate_threshold_ms_; + base::Lock lock_; + base::Lock onPaintLock_; OffScreenRenderWidgetHostView* view_; base::Time last_time_; - base::TimeTicks frame_start_time_; - bool frame_pending_; - bool frame_in_progress_; int frame_retry_count_; - std::unique_ptr bitmap_; - gfx::Rect pending_damage_rect_; + base::TimeTicks next_frame_time_; + base::TimeDelta frame_duration_; base::WeakPtrFactory weak_ptr_factory_; @@ -300,12 +205,15 @@ class AtomCopyFrameGenerator { class AtomBeginFrameTimer : public cc::DelayBasedTimeSourceClient { public: - AtomBeginFrameTimer(int frame_rate_threshold_ms, + AtomBeginFrameTimer(int frame_rate_threshold_us, const base::Closure& callback) : callback_(callback) { time_source_.reset(new cc::DelayBasedTimeSource( content::BrowserThread::GetTaskRunnerForThread( content::BrowserThread::UI).get())); + time_source_->SetTimebaseAndInterval( + base::TimeTicks(), + base::TimeDelta::FromMicroseconds(frame_rate_threshold_us)); time_source_->SetClient(this); } @@ -317,10 +225,10 @@ class AtomBeginFrameTimer : public cc::DelayBasedTimeSourceClient { return time_source_->Active(); } - void SetFrameRateThresholdMs(int frame_rate_threshold_ms) { + void SetFrameRateThresholdUs(int frame_rate_threshold_us) { time_source_->SetTimebaseAndInterval( base::TimeTicks::Now(), - base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms)); + base::TimeDelta::FromMicroseconds(frame_rate_threshold_us)); } private: @@ -338,24 +246,31 @@ 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), + frame_rate_threshold_us_(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), weak_ptr_factory_(this) { DCHECK(render_widget_host_); - render_widget_host_->SetView(this); - + bool is_guest_view_hack = parent_host_view_ != nullptr; #if !defined(OS_MACOSX) delegated_frame_host_ = base::MakeUnique( AllocateFrameSinkId(is_guest_view_hack), this); @@ -383,6 +298,8 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView( native_window_->AddObserver(this); ResizeRootLayer(); + render_widget_host_->SetView(this); + InstallTransparency(); } OffScreenRenderWidgetHostView::~OffScreenRenderWidgetHostView() { @@ -400,8 +317,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 } @@ -419,7 +343,7 @@ void OffScreenRenderWidgetHostView::OnWindowClosed() { void OffScreenRenderWidgetHostView::OnBeginFrameTimerTick() { const base::TimeTicks frame_time = base::TimeTicks::Now(); const base::TimeDelta vsync_period = - base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms_); + base::TimeDelta::FromMicroseconds(frame_rate_threshold_us_); SendBeginFrame(frame_time, vsync_period); } @@ -461,6 +385,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 +405,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 +479,9 @@ bool OffScreenRenderWidgetHostView::IsShowing() { } gfx::Rect OffScreenRenderWidgetHostView::GetViewBounds() const { + if (IsPopupWidget()) + return popup_position_; + return gfx::Rect(size_); } @@ -587,7 +522,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_); } @@ -601,7 +536,7 @@ void OffScreenRenderWidgetHostView::OnSwapCompositorFrame( } else { if (!copy_frame_generator_.get()) { copy_frame_generator_.reset( - new AtomCopyFrameGenerator(frame_rate_threshold_ms_, this)); + new AtomCopyFrameGenerator(this, frame_rate_threshold_us_)); } // Determine the damage rectangle for the current frame. This is the same @@ -620,7 +555,7 @@ void OffScreenRenderWidgetHostView::OnSwapCompositorFrame( // Request a copy of the last compositor frame which will eventually call // OnPaint asynchronously. - copy_frame_generator_->GenerateCopyFrame(true, damage_rect); + copy_frame_generator_->GenerateCopyFrame(damage_rect); } } } @@ -631,10 +566,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 +606,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 +659,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 +679,35 @@ 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(); +} + +content::RenderWidgetHostViewBase* + OffScreenRenderWidgetHostView::CreateViewForWidget( + content::RenderWidgetHost* render_widget_host, + content::RenderWidgetHost* embedder_render_widget_host, + content::WebContentsView* web_contents_view) { + 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()); + } + + return new OffScreenRenderWidgetHostView( + transparent_, + callback_, + render_widget_host, + embedder_host_view, + native_window_); } #if !defined(OS_MACOSX) @@ -723,22 +721,29 @@ bool OffScreenRenderWidgetHostView::DelegatedFrameHostIsVisible() const { SkColor OffScreenRenderWidgetHostView::DelegatedFrameHostGetGutterColor( SkColor color) const { + if (render_widget_host_->delegate() && + render_widget_host_->delegate()->IsFullscreenForCurrentTab()) { + return SK_ColorWHITE; + } 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 +800,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 +879,7 @@ bool OffScreenRenderWidgetHostView::InstallTransparency() { } bool OffScreenRenderWidgetHostView::IsAutoResizeEnabled() const { - return false; + return render_widget_host_->auto_resize_enabled(); } void OffScreenRenderWidgetHostView::SetNeedsBeginFrames( @@ -837,10 +893,147 @@ 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, + pos.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_; + gfx::Rect damage(damage_rect); + damage.Union(pos); + + SkBitmap copy = SkBitmapOperations::CreateTiledBitmap(bitmap, + pos.x(), pos.y(), pos.width(), pos.height()); + + CopyBitmapTo(bitmap, *popup_bitmap_, pos); + callback_.Run(damage, 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()); + InvalidateBounds(popup_host_view_->popup_position_); +} + +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 +1049,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); } @@ -886,36 +1089,38 @@ OffScreenRenderWidgetHostView::GetDelegatedFrameHost() const { #endif void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) { - if (!force && frame_rate_threshold_ms_ != 0) + if (!force && frame_rate_threshold_us_ != 0) return; - frame_rate_threshold_ms_ = 1000 / frame_rate_; + frame_rate_threshold_us_ = 1000000 / frame_rate_; GetCompositor()->vsync_manager()->SetAuthoritativeVSyncInterval( - base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms_)); + base::TimeDelta::FromMicroseconds(frame_rate_threshold_us_)); - if (copy_frame_generator_) { - copy_frame_generator_->set_frame_rate_threshold_ms( - frame_rate_threshold_ms_); + if (copy_frame_generator_.get()) { + copy_frame_generator_->set_frame_rate_threshold_us( + frame_rate_threshold_us_); } - if (begin_frame_timer_) { - begin_frame_timer_->SetFrameRateThresholdMs(frame_rate_threshold_ms_); + if (begin_frame_timer_.get()) { + begin_frame_timer_->SetFrameRateThresholdUs(frame_rate_threshold_us_); } else { begin_frame_timer_.reset(new AtomBeginFrameTimer( - frame_rate_threshold_ms_, + frame_rate_threshold_us_, base::Bind(&OffScreenRenderWidgetHostView::OnBeginFrameTimerTick, weak_ptr_factory_.GetWeakPtr()))); } } 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); + software_output_device_->OnPaint(bounds); } else if (copy_frame_generator_) { - copy_frame_generator_->GenerateCopyFrame(true, bounds_in_pixels); + copy_frame_generator_->GenerateCopyFrame(bounds); } } @@ -925,7 +1130,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..1f8558db1f9e 100644 --- a/atom/browser/osr/osr_render_widget_host_view.h +++ b/atom/browser/osr/osr_render_widget_host_view.h @@ -5,6 +5,7 @@ #ifndef ATOM_BROWSER_OSR_OSR_RENDER_WIDGET_HOST_VIEW_H_ #define ATOM_BROWSER_OSR_OSR_RENDER_WIDGET_HOST_VIEW_H_ +#include #include #include @@ -20,10 +21,13 @@ #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 "content/browser/web_contents/web_contents_view.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 +73,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 +143,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( @@ -146,6 +153,11 @@ class OffScreenRenderWidgetHostView gfx::Size GetPhysicalBackingSize() const override; gfx::Size GetRequestedRendererSize() const override; + content::RenderWidgetHostViewBase* CreateViewForWidget( + content::RenderWidgetHost*, + content::RenderWidgetHost*, + content::WebContentsView*) override; + #if !defined(OS_MACOSX) // content::DelegatedFrameHostClient: int DelegatedFrameHostGetGpuMemoryBufferClientId(void) const; @@ -193,7 +205,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 +243,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 +251,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,23 +267,37 @@ 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_; + int frame_rate_threshold_us_; 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_; std::unique_ptr delegated_frame_host_; diff --git a/atom/browser/osr/osr_web_contents_view.cc b/atom/browser/osr/osr_web_contents_view.cc index 8d95017b0e64..0e10abf6a034 100644 --- a/atom/browser/osr/osr_web_contents_view.cc +++ b/atom/browser/osr/osr_web_contents_view.cc @@ -4,7 +4,11 @@ #include "atom/browser/osr/osr_web_contents_view.h" +#include "atom/common/api/api_messages.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/render_view_host.h" #include "third_party/WebKit/public/platform/WebScreenInfo.h" +#include "ui/display/screen.h" namespace atom { @@ -27,19 +31,33 @@ OffScreenWebContentsView::~OffScreenWebContentsView() { void OffScreenWebContentsView::SetWebContents( content::WebContents* web_contents) { web_contents_ = web_contents; + + RenderViewCreated(web_contents_->GetRenderViewHost()); } #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 +85,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, @@ -77,20 +95,40 @@ void OffScreenWebContentsView::CreateView(const gfx::Size& initial_size, content::RenderWidgetHostViewBase* OffScreenWebContentsView::CreateViewForWidget( 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::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_; + + content::WebContentsImpl *web_contents_impl = + static_cast(web_contents_); + + OffScreenRenderWidgetHostView *view = + static_cast( + web_contents_impl->GetOuterWebContents() + ? web_contents_impl->GetOuterWebContents()->GetRenderWidgetHostView() + : web_contents_impl->GetRenderWidgetHostView()); + + return new OffScreenRenderWidgetHostView( + transparent_, + callback_, + render_widget_host, + view, + relay->window.get()); } void OffScreenWebContentsView::SetPageTitle(const base::string16& title) { @@ -98,8 +136,12 @@ void OffScreenWebContentsView::SetPageTitle(const base::string16& title) { void OffScreenWebContentsView::RenderViewCreated( content::RenderViewHost* host) { - if (view_) - view_->InstallTransparency(); + if (GetView()) + GetView()->InstallTransparency(); + +#if defined(OS_MACOSX) + host->Send(new AtomViewMsg_Offscreen(host->GetRoutingID())); +#endif } void OffScreenWebContentsView::RenderViewSwappedIn( @@ -111,14 +153,22 @@ 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->device_scale_factor = 1.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()); + } else { + const display::Display display = + display::Screen::GetScreen()->GetPrimaryDisplay(); + screen_info->rect = display.bounds(); + screen_info->available_rect = display.work_area(); + } } #if defined(OS_MACOSX) @@ -152,4 +202,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..ffb3b38619c4 100644 --- a/atom/browser/osr/osr_web_contents_view.h +++ b/atom/browser/osr/osr_web_contents_view.h @@ -75,11 +75,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) diff --git a/atom/common/api/api_messages.h b/atom/common/api/api_messages.h index ef945d9eebe9..e25089b869a9 100644 --- a/atom/common/api/api_messages.h +++ b/atom/common/api/api_messages.h @@ -35,6 +35,8 @@ IPC_MESSAGE_ROUTED3(AtomViewMsg_Message, base::string16 /* channel */, base::ListValue /* arguments */) +IPC_MESSAGE_ROUTED0(AtomViewMsg_Offscreen) + // Sent by the renderer when the draggable regions are updated. IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions, std::vector /* regions */) diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 6811ab919303..c15e47407b64 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -202,6 +202,11 @@ void Noop(char*, void*) { NativeImage::NativeImage(v8::Isolate* isolate, const gfx::Image& image) : image_(image) { Init(isolate); + if (image_.HasRepresentation(gfx::Image::kImageRepSkia)) { + isolate->AdjustAmountOfExternalAllocatedMemory( + image_.ToImageSkia()->bitmap()->computeSize64()); + } + MarkHighMemoryUsage(); } #if defined(OS_WIN) @@ -212,10 +217,20 @@ NativeImage::NativeImage(v8::Isolate* isolate, const base::FilePath& hicon_path) ReadImageSkiaFromICO(&image_skia, GetHICON(256)); image_ = gfx::Image(image_skia); Init(isolate); + if (image_.HasRepresentation(gfx::Image::kImageRepSkia)) { + isolate->AdjustAmountOfExternalAllocatedMemory( + image_.ToImageSkia()->bitmap()->computeSize64()); + } + MarkHighMemoryUsage(); } #endif -NativeImage::~NativeImage() {} +NativeImage::~NativeImage() { + if (image_.HasRepresentation(gfx::Image::kImageRepSkia)) { + isolate()->AdjustAmountOfExternalAllocatedMemory( + - image_.ToImageSkia()->bitmap()->computeSize64()); + } +} #if defined(OS_WIN) HICON NativeImage::GetHICON(int size) { diff --git a/atom/renderer/atom_render_view_observer.cc b/atom/renderer/atom_render_view_observer.cc index a68238ba4ced..6aa26cccaf01 100644 --- a/atom/renderer/atom_render_view_observer.cc +++ b/atom/renderer/atom_render_view_observer.cc @@ -136,6 +136,7 @@ bool AtomRenderViewObserver::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(AtomRenderViewObserver, message) IPC_MESSAGE_HANDLER(AtomViewMsg_Message, OnBrowserMessage) + IPC_MESSAGE_HANDLER(AtomViewMsg_Offscreen, OnOffscreen) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -169,4 +170,8 @@ void AtomRenderViewObserver::OnBrowserMessage(bool send_to_all, } } +void AtomRenderViewObserver::OnOffscreen() { + blink::WebView::setUseExternalPopupMenus(false); +} + } // namespace atom diff --git a/atom/renderer/atom_render_view_observer.h b/atom/renderer/atom_render_view_observer.h index e642bbe94224..4751db2d8c6c 100644 --- a/atom/renderer/atom_render_view_observer.h +++ b/atom/renderer/atom_render_view_observer.h @@ -40,6 +40,8 @@ class AtomRenderViewObserver : public content::RenderViewObserver { const base::string16& channel, const base::ListValue& args); + void OnOffscreen(); + AtomRendererClient* renderer_client_; // Whether the document object has been created. diff --git a/vendor/native_mate b/vendor/native_mate index fd0e7dc4ab77..7d9c1a80f025 160000 --- a/vendor/native_mate +++ b/vendor/native_mate @@ -1 +1 @@ -Subproject commit fd0e7dc4ab778f0d1ccda6c9640464ea06ee771e +Subproject commit 7d9c1a80f025f4c46f7da8ea73246fe0f1968579