1 // Copyright (c) 2016 GitHub, Inc.
2 // Use of this source code is governed by the MIT license that can be
3 // found in the LICENSE file.
5 #include "atom/browser/osr/osr_render_widget_host_view.h"
9 #include "base/callback_helpers.h"
10 #include "base/location.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/time/time.h"
14 #include "cc/output/copy_output_request.h"
15 #include "cc/scheduler/delay_based_time_source.h"
16 #include "components/display_compositor/gl_helper.h"
17 #include "content/browser/renderer_host/render_widget_host_delegate.h"
18 #include "content/browser/renderer_host/render_widget_host_impl.h"
19 #include "content/common/view_messages.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/context_factory.h"
22 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
23 #include "ui/compositor/compositor.h"
24 #include "ui/compositor/layer.h"
25 #include "ui/compositor/layer_type.h"
26 #include "ui/events/latency_info.h"
27 #include "ui/gfx/geometry/dip_util.h"
28 #include "ui/gfx/native_widget_types.h"
34 const float kDefaultScaleFactor = 1.0;
35 const int kFrameRetryLimit = 2;
39 class AtomCopyFrameGenerator {
41 AtomCopyFrameGenerator(int frame_rate_threshold_ms,
42 OffScreenRenderWidgetHostView* view)
43 : frame_rate_threshold_ms_(frame_rate_threshold_ms),
45 frame_pending_(false),
46 frame_in_progress_(false),
47 frame_retry_count_(0),
48 weak_ptr_factory_(this) {
49 last_time_ = base::Time::Now();
52 void GenerateCopyFrame(
54 const gfx::Rect& damage_rect) {
55 if (force_frame && !frame_pending_)
56 frame_pending_ = true;
61 if (!damage_rect.IsEmpty())
62 pending_damage_rect_.Union(damage_rect);
64 if (frame_in_progress_)
67 frame_in_progress_ = true;
69 const int64_t frame_rate_delta =
70 (base::TimeTicks::Now() - frame_start_time_).InMilliseconds();
71 if (frame_rate_delta < frame_rate_threshold_ms_) {
72 content::BrowserThread::PostDelayedTask(content::BrowserThread::UI,
74 base::Bind(&AtomCopyFrameGenerator::InternalGenerateCopyFrame,
75 weak_ptr_factory_.GetWeakPtr()),
76 base::TimeDelta::FromMilliseconds(
77 frame_rate_threshold_ms_ - frame_rate_delta));
81 InternalGenerateCopyFrame();
84 bool frame_pending() const { return frame_pending_; }
86 void set_frame_rate_threshold_ms(int frame_rate_threshold_ms) {
87 frame_rate_threshold_ms_ = frame_rate_threshold_ms;
91 void InternalGenerateCopyFrame() {
92 frame_pending_ = false;
93 frame_start_time_ = base::TimeTicks::Now();
95 if (!view_->render_widget_host())
98 const gfx::Rect damage_rect = pending_damage_rect_;
99 pending_damage_rect_.SetRect(0, 0, 0, 0);
101 std::unique_ptr<cc::CopyOutputRequest> request =
102 cc::CopyOutputRequest::CreateRequest(base::Bind(
103 &AtomCopyFrameGenerator::CopyFromCompositingSurfaceHasResult,
104 weak_ptr_factory_.GetWeakPtr(),
107 request->set_area(gfx::Rect(view_->GetPhysicalBackingSize()));
108 view_->GetRootLayer()->RequestCopyOfOutput(std::move(request));
111 void CopyFromCompositingSurfaceHasResult(
112 const gfx::Rect& damage_rect,
113 std::unique_ptr<cc::CopyOutputResult> result) {
114 if (result->IsEmpty() || result->size().IsEmpty() ||
115 !view_->render_widget_host()) {
116 OnCopyFrameCaptureFailure(damage_rect);
120 if (result->HasTexture()) {
121 PrepareTextureCopyOutputResult(damage_rect, std::move(result));
125 DCHECK(result->HasBitmap());
126 PrepareBitmapCopyOutputResult(damage_rect, std::move(result));
129 void PrepareTextureCopyOutputResult(
130 const gfx::Rect& damage_rect,
131 std::unique_ptr<cc::CopyOutputResult> result) {
132 DCHECK(result->HasTexture());
133 base::ScopedClosureRunner scoped_callback_runner(
134 base::Bind(&AtomCopyFrameGenerator::OnCopyFrameCaptureFailure,
135 weak_ptr_factory_.GetWeakPtr(),
138 const gfx::Size& result_size = result->size();
141 bitmap_->getBounds(&bitmap_size);
144 bitmap_size.width() != result_size.width() ||
145 bitmap_size.height() != result_size.height()) {
146 bitmap_.reset(new SkBitmap);
147 bitmap_->allocN32Pixels(result_size.width(),
148 result_size.height(),
150 if (bitmap_->drawsNothing())
154 content::ImageTransportFactory* factory =
155 content::ImageTransportFactory::GetInstance();
156 display_compositor::GLHelper* gl_helper = factory->GetGLHelper();
160 std::unique_ptr<SkAutoLockPixels> bitmap_pixels_lock(
161 new SkAutoLockPixels(*bitmap_));
162 uint8_t* pixels = static_cast<uint8_t*>(bitmap_->getPixels());
164 cc::TextureMailbox texture_mailbox;
165 std::unique_ptr<cc::SingleReleaseCallback> release_callback;
166 result->TakeTexture(&texture_mailbox, &release_callback);
167 DCHECK(texture_mailbox.IsTexture());
168 if (!texture_mailbox.IsTexture())
171 ignore_result(scoped_callback_runner.Release());
173 gl_helper->CropScaleReadbackAndCleanMailbox(
174 texture_mailbox.mailbox(),
175 texture_mailbox.sync_token(),
177 gfx::Rect(result_size),
182 &AtomCopyFrameGenerator::CopyFromCompositingSurfaceFinishedProxy,
183 weak_ptr_factory_.GetWeakPtr(),
184 base::Passed(&release_callback),
186 base::Passed(&bitmap_),
187 base::Passed(&bitmap_pixels_lock)),
188 display_compositor::GLHelper::SCALER_QUALITY_FAST);
191 static void CopyFromCompositingSurfaceFinishedProxy(
192 base::WeakPtr<AtomCopyFrameGenerator> generator,
193 std::unique_ptr<cc::SingleReleaseCallback> release_callback,
194 const gfx::Rect& damage_rect,
195 std::unique_ptr<SkBitmap> bitmap,
196 std::unique_ptr<SkAutoLockPixels> bitmap_pixels_lock,
198 gpu::SyncToken sync_token;
200 display_compositor::GLHelper* gl_helper =
201 content::ImageTransportFactory::GetInstance()->GetGLHelper();
203 gl_helper->GenerateSyncToken(&sync_token);
205 const bool lost_resource = !sync_token.HasData();
206 release_callback->Run(sync_token, lost_resource);
209 generator->CopyFromCompositingSurfaceFinished(
210 damage_rect, std::move(bitmap), std::move(bitmap_pixels_lock),
213 bitmap_pixels_lock.reset();
218 void CopyFromCompositingSurfaceFinished(
219 const gfx::Rect& damage_rect,
220 std::unique_ptr<SkBitmap> bitmap,
221 std::unique_ptr<SkAutoLockPixels> bitmap_pixels_lock,
224 bitmap_ = std::move(bitmap);
227 OnCopyFrameCaptureSuccess(damage_rect, *bitmap_,
228 std::move(bitmap_pixels_lock));
230 bitmap_pixels_lock.reset();
231 OnCopyFrameCaptureFailure(damage_rect);
235 void PrepareBitmapCopyOutputResult(
236 const gfx::Rect& damage_rect,
237 std::unique_ptr<cc::CopyOutputResult> result) {
238 DCHECK(result->HasBitmap());
239 std::unique_ptr<SkBitmap> source = result->TakeBitmap();
242 std::unique_ptr<SkAutoLockPixels> bitmap_pixels_lock(
243 new SkAutoLockPixels(*source));
244 OnCopyFrameCaptureSuccess(damage_rect, *source,
245 std::move(bitmap_pixels_lock));
247 OnCopyFrameCaptureFailure(damage_rect);
251 void OnCopyFrameCaptureFailure(
252 const gfx::Rect& damage_rect) {
253 pending_damage_rect_.Union(damage_rect);
255 const bool force_frame = (++frame_retry_count_ <= kFrameRetryLimit);
256 OnCopyFrameCaptureCompletion(force_frame);
259 void OnCopyFrameCaptureSuccess(
260 const gfx::Rect& damage_rect,
261 const SkBitmap& bitmap,
262 std::unique_ptr<SkAutoLockPixels> bitmap_pixels_lock) {
263 view_->OnPaint(damage_rect, bitmap);
265 if (frame_retry_count_ > 0)
266 frame_retry_count_ = 0;
268 OnCopyFrameCaptureCompletion(false);
271 void OnCopyFrameCaptureCompletion(bool force_frame) {
272 frame_in_progress_ = false;
274 if (frame_pending_) {
275 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
276 base::Bind(&AtomCopyFrameGenerator::GenerateCopyFrame,
277 weak_ptr_factory_.GetWeakPtr(),
283 int frame_rate_threshold_ms_;
284 OffScreenRenderWidgetHostView* view_;
286 base::Time last_time_;
288 base::TimeTicks frame_start_time_;
290 bool frame_in_progress_;
291 int frame_retry_count_;
292 std::unique_ptr<SkBitmap> bitmap_;
293 gfx::Rect pending_damage_rect_;
295 base::WeakPtrFactory<AtomCopyFrameGenerator> weak_ptr_factory_;
297 DISALLOW_COPY_AND_ASSIGN(AtomCopyFrameGenerator);
300 class AtomBeginFrameTimer : public cc::DelayBasedTimeSourceClient {
302 AtomBeginFrameTimer(int frame_rate_threshold_ms,
303 const base::Closure& callback)
304 : callback_(callback) {
305 time_source_.reset(new cc::DelayBasedTimeSource(
306 content::BrowserThread::GetTaskRunnerForThread(
307 content::BrowserThread::UI).get()));
308 time_source_->SetClient(this);
311 void SetActive(bool active) {
312 time_source_->SetActive(active);
315 bool IsActive() const {
316 return time_source_->Active();
319 void SetFrameRateThresholdMs(int frame_rate_threshold_ms) {
320 time_source_->SetTimebaseAndInterval(
321 base::TimeTicks::Now(),
322 base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms));
326 void OnTimerTick() override {
330 const base::Closure callback_;
331 std::unique_ptr<cc::DelayBasedTimeSource> time_source_;
333 DISALLOW_COPY_AND_ASSIGN(AtomBeginFrameTimer);
336 OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
338 const OnPaintCallback& callback,
339 content::RenderWidgetHost* host,
340 NativeWindow* native_window)
341 : render_widget_host_(content::RenderWidgetHostImpl::From(host)),
342 native_window_(native_window),
343 software_output_device_(nullptr),
344 transparent_(transparent),
347 frame_rate_threshold_ms_(0),
348 last_time_(base::Time::Now()),
349 scale_factor_(kDefaultScaleFactor),
350 is_showing_(!render_widget_host_->is_hidden()),
351 size_(native_window->GetSize()),
353 weak_ptr_factory_(this) {
354 DCHECK(render_widget_host_);
355 render_widget_host_->SetView(this);
357 #if !defined(OS_MACOSX)
358 content::ImageTransportFactory* factory =
359 content::ImageTransportFactory::GetInstance();
360 delegated_frame_host_ = base::MakeUnique<content::DelegatedFrameHost>(
361 factory->GetContextFactory()->AllocateFrameSinkId(), this);
363 root_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
366 #if defined(OS_MACOSX)
367 CreatePlatformWidget();
370 new ui::Compositor(content::GetContextFactory(),
371 base::ThreadTaskRunnerHandle::Get()));
372 compositor_->SetAcceleratedWidget(native_window_->GetAcceleratedWidget());
373 compositor_->SetRootLayer(root_layer_.get());
375 GetCompositor()->SetDelegate(this);
377 native_window_->AddObserver(this);
382 OffScreenRenderWidgetHostView::~OffScreenRenderWidgetHostView() {
384 native_window_->RemoveObserver(this);
386 #if defined(OS_MACOSX)
388 browser_compositor_->SetRenderWidgetHostIsHidden(true);
390 // Marking the DelegatedFrameHost as removed from the window hierarchy is
391 // necessary to remove all connections to its old ui::Compositor.
393 delegated_frame_host_->WasHidden();
394 delegated_frame_host_->ResetCompositor();
397 #if defined(OS_MACOSX)
398 DestroyPlatformWidget();
402 void OffScreenRenderWidgetHostView::OnBeginFrameTimerTick() {
403 const base::TimeTicks frame_time = base::TimeTicks::Now();
404 const base::TimeDelta vsync_period =
405 base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms_);
406 SendBeginFrame(frame_time, vsync_period);
409 void OffScreenRenderWidgetHostView::SendBeginFrame(
410 base::TimeTicks frame_time, base::TimeDelta vsync_period) {
411 base::TimeTicks display_time = frame_time + vsync_period;
413 base::TimeDelta estimated_browser_composite_time =
414 base::TimeDelta::FromMicroseconds(
415 (1.0f * base::Time::kMicrosecondsPerSecond) / (3.0f * 60));
417 base::TimeTicks deadline = display_time - estimated_browser_composite_time;
419 render_widget_host_->Send(new ViewMsg_BeginFrame(
420 render_widget_host_->GetRoutingID(),
421 cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
422 vsync_period, cc::BeginFrameArgs::NORMAL)));
425 bool OffScreenRenderWidgetHostView::OnMessageReceived(
426 const IPC::Message& message) {
428 IPC_BEGIN_MESSAGE_MAP(OffScreenRenderWidgetHostView, message)
429 IPC_MESSAGE_HANDLER(ViewHostMsg_SetNeedsBeginFrames,
431 IPC_MESSAGE_UNHANDLED(handled = false)
432 IPC_END_MESSAGE_MAP()
435 return content::RenderWidgetHostViewBase::OnMessageReceived(message);
439 void OffScreenRenderWidgetHostView::InitAsChild(gfx::NativeView) {
442 content::RenderWidgetHost* OffScreenRenderWidgetHostView::GetRenderWidgetHost()
444 return render_widget_host_;
447 void OffScreenRenderWidgetHostView::SetSize(const gfx::Size& size) {
451 if (render_widget_host_)
452 render_widget_host_->WasResized();
453 GetDelegatedFrameHost()->WasResized();
456 void OffScreenRenderWidgetHostView::SetBounds(const gfx::Rect& new_bounds) {
459 gfx::Vector2dF OffScreenRenderWidgetHostView::GetLastScrollOffset() const {
460 return last_scroll_offset_;
463 gfx::NativeView OffScreenRenderWidgetHostView::GetNativeView() const {
464 return gfx::NativeView();
467 gfx::NativeViewAccessible
468 OffScreenRenderWidgetHostView::GetNativeViewAccessible() {
469 return gfx::NativeViewAccessible();
472 ui::TextInputClient* OffScreenRenderWidgetHostView::GetTextInputClient() {
476 void OffScreenRenderWidgetHostView::Focus() {
479 bool OffScreenRenderWidgetHostView::HasFocus() const {
483 bool OffScreenRenderWidgetHostView::IsSurfaceAvailableForCopy() const {
484 return GetDelegatedFrameHost()->CanCopyToBitmap();
487 void OffScreenRenderWidgetHostView::Show() {
493 #if defined(OS_MACOSX)
494 browser_compositor_->SetRenderWidgetHostIsHidden(false);
496 delegated_frame_host_->SetCompositor(compositor_.get());
497 delegated_frame_host_->WasShown(ui::LatencyInfo());
500 if (render_widget_host_)
501 render_widget_host_->WasShown(ui::LatencyInfo());
504 void OffScreenRenderWidgetHostView::Hide() {
508 if (render_widget_host_)
509 render_widget_host_->WasHidden();
511 #if defined(OS_MACOSX)
512 browser_compositor_->SetRenderWidgetHostIsHidden(true);
514 GetDelegatedFrameHost()->WasHidden();
515 GetDelegatedFrameHost()->ResetCompositor();
521 bool OffScreenRenderWidgetHostView::IsShowing() {
525 gfx::Rect OffScreenRenderWidgetHostView::GetViewBounds() const {
526 return gfx::Rect(size_);
529 void OffScreenRenderWidgetHostView::SetBackgroundColor(SkColor color) {
531 color = SkColorSetARGB(SK_AlphaTRANSPARENT, 0, 0, 0);
533 content::RenderWidgetHostViewBase::SetBackgroundColor(color);
535 const bool opaque = !transparent_ && GetBackgroundOpaque();
536 if (render_widget_host_)
537 render_widget_host_->SetBackgroundOpaque(opaque);
540 gfx::Size OffScreenRenderWidgetHostView::GetVisibleViewportSize() const {
544 void OffScreenRenderWidgetHostView::SetInsets(const gfx::Insets& insets) {
547 bool OffScreenRenderWidgetHostView::LockMouse() {
551 void OffScreenRenderWidgetHostView::UnlockMouse() {
554 void OffScreenRenderWidgetHostView::OnSwapCompositorFrame(
555 uint32_t output_surface_id,
556 cc::CompositorFrame frame) {
557 TRACE_EVENT0("electron",
558 "OffScreenRenderWidgetHostView::OnSwapCompositorFrame");
560 if (frame.metadata.root_scroll_offset != last_scroll_offset_) {
561 last_scroll_offset_ = frame.metadata.root_scroll_offset;
564 if (frame.delegated_frame_data) {
565 if (software_output_device_) {
566 if (!begin_frame_timer_.get()) {
567 software_output_device_->SetActive(painting_);
570 // The compositor will draw directly to the SoftwareOutputDevice which
571 // then calls OnPaint.
572 #if defined(OS_MACOSX)
573 browser_compositor_->SwapCompositorFrame(output_surface_id,
576 delegated_frame_host_->SwapDelegatedFrame(output_surface_id,
580 if (!copy_frame_generator_.get()) {
581 copy_frame_generator_.reset(
582 new AtomCopyFrameGenerator(frame_rate_threshold_ms_, this));
585 // Determine the damage rectangle for the current frame. This is the same
586 // calculation that SwapDelegatedFrame uses.
587 cc::RenderPass* root_pass =
588 frame.delegated_frame_data->render_pass_list.back().get();
589 gfx::Size frame_size = root_pass->output_rect.size();
590 gfx::Rect damage_rect =
591 gfx::ToEnclosingRect(gfx::RectF(root_pass->damage_rect));
592 damage_rect.Intersect(gfx::Rect(frame_size));
594 #if defined(OS_MACOSX)
595 browser_compositor_->SwapCompositorFrame(output_surface_id,
598 delegated_frame_host_->SwapDelegatedFrame(output_surface_id,
602 // Request a copy of the last compositor frame which will eventually call
603 // OnPaint asynchronously.
604 copy_frame_generator_->GenerateCopyFrame(true, damage_rect);
609 void OffScreenRenderWidgetHostView::ClearCompositorFrame() {
610 GetDelegatedFrameHost()->ClearDelegatedFrame();
613 void OffScreenRenderWidgetHostView::InitAsPopup(
614 content::RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
617 void OffScreenRenderWidgetHostView::InitAsFullscreen(
618 content::RenderWidgetHostView *) {
621 void OffScreenRenderWidgetHostView::UpdateCursor(const content::WebCursor &) {
624 void OffScreenRenderWidgetHostView::SetIsLoading(bool loading) {
627 void OffScreenRenderWidgetHostView::TextInputStateChanged(
628 const content::TextInputState& params) {
631 void OffScreenRenderWidgetHostView::ImeCancelComposition() {
634 void OffScreenRenderWidgetHostView::RenderProcessGone(base::TerminationStatus,
639 void OffScreenRenderWidgetHostView::Destroy() {
643 void OffScreenRenderWidgetHostView::SetTooltipText(const base::string16 &) {
646 void OffScreenRenderWidgetHostView::SelectionBoundsChanged(
647 const ViewHostMsg_SelectionBounds_Params &) {
650 void OffScreenRenderWidgetHostView::CopyFromCompositingSurface(
651 const gfx::Rect& src_subrect,
652 const gfx::Size& dst_size,
653 const content::ReadbackRequestCallback& callback,
654 const SkColorType preferred_color_type) {
655 GetDelegatedFrameHost()->CopyFromCompositingSurface(
656 src_subrect, dst_size, callback, preferred_color_type);
659 void OffScreenRenderWidgetHostView::CopyFromCompositingSurfaceToVideoFrame(
660 const gfx::Rect& src_subrect,
661 const scoped_refptr<media::VideoFrame>& target,
662 const base::Callback<void(const gfx::Rect&, bool)>& callback) {
663 GetDelegatedFrameHost()->CopyFromCompositingSurfaceToVideoFrame(
664 src_subrect, target, callback);
667 bool OffScreenRenderWidgetHostView::CanCopyToVideoFrame() const {
668 return GetDelegatedFrameHost()->CanCopyToVideoFrame();
671 void OffScreenRenderWidgetHostView::BeginFrameSubscription(
672 std::unique_ptr<content::RenderWidgetHostViewFrameSubscriber> subscriber) {
673 GetDelegatedFrameHost()->BeginFrameSubscription(std::move(subscriber));
676 void OffScreenRenderWidgetHostView::EndFrameSubscription() {
677 GetDelegatedFrameHost()->EndFrameSubscription();
680 bool OffScreenRenderWidgetHostView::HasAcceleratedSurface(const gfx::Size &) {
684 gfx::Rect OffScreenRenderWidgetHostView::GetBoundsInRootWindow() {
685 return gfx::Rect(size_);
688 void OffScreenRenderWidgetHostView::LockCompositingSurface() {
691 void OffScreenRenderWidgetHostView::UnlockCompositingSurface() {
694 void OffScreenRenderWidgetHostView::ImeCompositionRangeChanged(
695 const gfx::Range &, const std::vector<gfx::Rect>&) {
698 gfx::Size OffScreenRenderWidgetHostView::GetPhysicalBackingSize() const {
702 gfx::Size OffScreenRenderWidgetHostView::GetRequestedRendererSize() const {
706 #if !defined(OS_MACOSX)
707 ui::Layer* OffScreenRenderWidgetHostView::DelegatedFrameHostGetLayer() const {
708 return const_cast<ui::Layer*>(root_layer_.get());
711 bool OffScreenRenderWidgetHostView::DelegatedFrameHostIsVisible() const {
712 return !render_widget_host_->is_hidden();
715 SkColor OffScreenRenderWidgetHostView::DelegatedFrameHostGetGutterColor(
716 SkColor color) const {
720 gfx::Size OffScreenRenderWidgetHostView::DelegatedFrameHostDesiredSizeInDIP()
725 bool OffScreenRenderWidgetHostView::DelegatedFrameCanCreateResizeLock() const {
729 std::unique_ptr<content::ResizeLock>
730 OffScreenRenderWidgetHostView::DelegatedFrameHostCreateResizeLock(
731 bool defer_compositor_lock) {
735 void OffScreenRenderWidgetHostView::DelegatedFrameHostResizeLockWasReleased() {
736 return render_widget_host_->WasResized();
740 OffScreenRenderWidgetHostView::DelegatedFrameHostSendReclaimCompositorResources(
741 int output_surface_id,
743 const cc::ReturnedResourceArray& resources) {
744 render_widget_host_->Send(new ViewMsg_ReclaimCompositorResources(
745 render_widget_host_->GetRoutingID(), output_surface_id, is_swap_ack,
749 void OffScreenRenderWidgetHostView::SetBeginFrameSource(
750 cc::BeginFrameSource* source) {
753 #endif // !defined(OS_MACOSX)
755 std::unique_ptr<cc::SoftwareOutputDevice>
756 OffScreenRenderWidgetHostView::CreateSoftwareOutputDevice(
757 ui::Compositor* compositor) {
758 DCHECK_EQ(GetCompositor(), compositor);
759 DCHECK(!copy_frame_generator_);
760 DCHECK(!software_output_device_);
762 software_output_device_ = new OffScreenOutputDevice(
764 base::Bind(&OffScreenRenderWidgetHostView::OnPaint,
765 weak_ptr_factory_.GetWeakPtr()));
766 return base::WrapUnique(software_output_device_);
769 bool OffScreenRenderWidgetHostView::InstallTransparency() {
771 SetBackgroundColor(SkColor());
772 #if defined(OS_MACOSX)
773 browser_compositor_->SetHasTransparentBackground(true);
775 compositor_->SetHostHasTransparentBackground(true);
782 bool OffScreenRenderWidgetHostView::IsAutoResizeEnabled() const {
786 void OffScreenRenderWidgetHostView::SetNeedsBeginFrames(
787 bool needs_begin_frames) {
788 SetupFrameRate(false);
790 begin_frame_timer_->SetActive(needs_begin_frames);
792 if (software_output_device_) {
793 software_output_device_->SetActive(needs_begin_frames && painting_);
797 void OffScreenRenderWidgetHostView::OnPaint(
798 const gfx::Rect& damage_rect, const SkBitmap& bitmap) {
799 TRACE_EVENT0("electron", "OffScreenRenderWidgetHostView::OnPaint");
800 callback_.Run(damage_rect, bitmap);
803 void OffScreenRenderWidgetHostView::SetPainting(bool painting) {
804 painting_ = painting;
806 if (software_output_device_) {
807 software_output_device_->SetActive(painting_);
811 bool OffScreenRenderWidgetHostView::IsPainting() const {
815 void OffScreenRenderWidgetHostView::SetFrameRate(int frame_rate) {
821 frame_rate_ = frame_rate;
823 SetupFrameRate(true);
826 int OffScreenRenderWidgetHostView::GetFrameRate() const {
830 #if !defined(OS_MACOSX)
831 ui::Compositor* OffScreenRenderWidgetHostView::GetCompositor() const {
832 return compositor_.get();
835 ui::Layer* OffScreenRenderWidgetHostView::GetRootLayer() const {
836 return root_layer_.get();
839 content::DelegatedFrameHost*
840 OffScreenRenderWidgetHostView::GetDelegatedFrameHost() const {
841 return delegated_frame_host_.get();
845 void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) {
846 if (!force && frame_rate_threshold_ms_ != 0)
849 frame_rate_threshold_ms_ = 1000 / frame_rate_;
851 GetCompositor()->vsync_manager()->SetAuthoritativeVSyncInterval(
852 base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms_));
854 if (copy_frame_generator_.get()) {
855 copy_frame_generator_->set_frame_rate_threshold_ms(
856 frame_rate_threshold_ms_);
859 if (begin_frame_timer_.get()) {
860 begin_frame_timer_->SetFrameRateThresholdMs(frame_rate_threshold_ms_);
862 begin_frame_timer_.reset(new AtomBeginFrameTimer(
863 frame_rate_threshold_ms_,
864 base::Bind(&OffScreenRenderWidgetHostView::OnBeginFrameTimerTick,
865 weak_ptr_factory_.GetWeakPtr())));
869 void OffScreenRenderWidgetHostView::Invalidate() {
870 const gfx::Rect& bounds_in_pixels = GetViewBounds();
872 if (software_output_device_) {
873 software_output_device_->OnPaint(bounds_in_pixels);
874 } else if (copy_frame_generator_.get()) {
875 copy_frame_generator_->GenerateCopyFrame(true, bounds_in_pixels);
879 void OffScreenRenderWidgetHostView::ResizeRootLayer() {
880 SetupFrameRate(false);
882 const float orgScaleFactor = scale_factor_;
883 const bool scaleFactorDidChange = (orgScaleFactor != scale_factor_);
885 gfx::Size size = GetViewBounds().size();
887 if (!scaleFactorDidChange && size == GetRootLayer()->bounds().size())
890 const gfx::Size& size_in_pixels =
891 gfx::ConvertSizeToPixel(scale_factor_, size);
893 GetRootLayer()->SetBounds(gfx::Rect(size));
894 GetCompositor()->SetScaleAndSize(scale_factor_, size_in_pixels);
897 void OffScreenRenderWidgetHostView::OnWindowResize() {
898 // In offscreen mode call RenderWidgetHostView's SetSize explicitly
899 auto size = native_window_->GetSize();
903 void OffScreenRenderWidgetHostView::OnWindowClosed() {
904 native_window_->RemoveObserver(this);
905 native_window_ = nullptr;