Fix Debug building on Windows
[platform/framework/web/crosswalk-tizen.git] / atom / browser / osr / osr_render_widget_host_view.cc
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.
4
5 #include "atom/browser/osr/osr_render_widget_host_view.h"
6
7 #include <vector>
8
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"
29
30 namespace atom {
31
32 namespace {
33
34 const float kDefaultScaleFactor = 1.0;
35 const int kFrameRetryLimit = 2;
36
37 }  // namespace
38
39 class AtomCopyFrameGenerator {
40  public:
41   AtomCopyFrameGenerator(int frame_rate_threshold_ms,
42                         OffScreenRenderWidgetHostView* view)
43     : frame_rate_threshold_ms_(frame_rate_threshold_ms),
44       view_(view),
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();
50   }
51
52   void GenerateCopyFrame(
53       bool force_frame,
54       const gfx::Rect& damage_rect) {
55     if (force_frame && !frame_pending_)
56       frame_pending_ = true;
57
58     if (!frame_pending_)
59       return;
60
61     if (!damage_rect.IsEmpty())
62       pending_damage_rect_.Union(damage_rect);
63
64     if (frame_in_progress_)
65       return;
66
67     frame_in_progress_ = true;
68
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,
73         FROM_HERE,
74         base::Bind(&AtomCopyFrameGenerator::InternalGenerateCopyFrame,
75                    weak_ptr_factory_.GetWeakPtr()),
76         base::TimeDelta::FromMilliseconds(
77             frame_rate_threshold_ms_ - frame_rate_delta));
78       return;
79     }
80
81     InternalGenerateCopyFrame();
82   }
83
84   bool frame_pending() const { return frame_pending_; }
85
86   void set_frame_rate_threshold_ms(int frame_rate_threshold_ms) {
87     frame_rate_threshold_ms_ = frame_rate_threshold_ms;
88   }
89
90  private:
91   void InternalGenerateCopyFrame() {
92     frame_pending_ = false;
93     frame_start_time_ = base::TimeTicks::Now();
94
95     if (!view_->render_widget_host())
96       return;
97
98     const gfx::Rect damage_rect = pending_damage_rect_;
99     pending_damage_rect_.SetRect(0, 0, 0, 0);
100
101     std::unique_ptr<cc::CopyOutputRequest> request =
102         cc::CopyOutputRequest::CreateRequest(base::Bind(
103             &AtomCopyFrameGenerator::CopyFromCompositingSurfaceHasResult,
104             weak_ptr_factory_.GetWeakPtr(),
105             damage_rect));
106
107     request->set_area(gfx::Rect(view_->GetPhysicalBackingSize()));
108     view_->GetRootLayer()->RequestCopyOfOutput(std::move(request));
109   }
110
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);
117       return;
118     }
119
120     if (result->HasTexture()) {
121       PrepareTextureCopyOutputResult(damage_rect, std::move(result));
122       return;
123     }
124
125     DCHECK(result->HasBitmap());
126     PrepareBitmapCopyOutputResult(damage_rect, std::move(result));
127   }
128
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(),
136                    damage_rect));
137
138     const gfx::Size& result_size = result->size();
139     SkIRect bitmap_size;
140     if (bitmap_)
141       bitmap_->getBounds(&bitmap_size);
142
143     if (!bitmap_ ||
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(),
149                               true);
150       if (bitmap_->drawsNothing())
151         return;
152     }
153
154     content::ImageTransportFactory* factory =
155         content::ImageTransportFactory::GetInstance();
156     display_compositor::GLHelper* gl_helper = factory->GetGLHelper();
157     if (!gl_helper)
158       return;
159
160     std::unique_ptr<SkAutoLockPixels> bitmap_pixels_lock(
161         new SkAutoLockPixels(*bitmap_));
162     uint8_t* pixels = static_cast<uint8_t*>(bitmap_->getPixels());
163
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())
169       return;
170
171     ignore_result(scoped_callback_runner.Release());
172
173     gl_helper->CropScaleReadbackAndCleanMailbox(
174         texture_mailbox.mailbox(),
175         texture_mailbox.sync_token(),
176         result_size,
177         gfx::Rect(result_size),
178         result_size,
179         pixels,
180         kN32_SkColorType,
181         base::Bind(
182             &AtomCopyFrameGenerator::CopyFromCompositingSurfaceFinishedProxy,
183             weak_ptr_factory_.GetWeakPtr(),
184             base::Passed(&release_callback),
185             damage_rect,
186             base::Passed(&bitmap_),
187             base::Passed(&bitmap_pixels_lock)),
188         display_compositor::GLHelper::SCALER_QUALITY_FAST);
189   }
190
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,
197       bool result) {
198     gpu::SyncToken sync_token;
199     if (result) {
200       display_compositor::GLHelper* gl_helper =
201           content::ImageTransportFactory::GetInstance()->GetGLHelper();
202       if (gl_helper)
203         gl_helper->GenerateSyncToken(&sync_token);
204     }
205     const bool lost_resource = !sync_token.HasData();
206     release_callback->Run(sync_token, lost_resource);
207
208     if (generator) {
209       generator->CopyFromCompositingSurfaceFinished(
210           damage_rect, std::move(bitmap), std::move(bitmap_pixels_lock),
211           result);
212     } else {
213       bitmap_pixels_lock.reset();
214       bitmap.reset();
215     }
216   }
217
218   void CopyFromCompositingSurfaceFinished(
219       const gfx::Rect& damage_rect,
220       std::unique_ptr<SkBitmap> bitmap,
221       std::unique_ptr<SkAutoLockPixels> bitmap_pixels_lock,
222       bool result) {
223     DCHECK(!bitmap_);
224     bitmap_ = std::move(bitmap);
225
226     if (result) {
227       OnCopyFrameCaptureSuccess(damage_rect, *bitmap_,
228                                 std::move(bitmap_pixels_lock));
229     } else {
230       bitmap_pixels_lock.reset();
231       OnCopyFrameCaptureFailure(damage_rect);
232     }
233   }
234
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();
240     DCHECK(source);
241     if (source) {
242       std::unique_ptr<SkAutoLockPixels> bitmap_pixels_lock(
243           new SkAutoLockPixels(*source));
244       OnCopyFrameCaptureSuccess(damage_rect, *source,
245                                 std::move(bitmap_pixels_lock));
246     } else {
247       OnCopyFrameCaptureFailure(damage_rect);
248     }
249   }
250
251   void OnCopyFrameCaptureFailure(
252       const gfx::Rect& damage_rect) {
253     pending_damage_rect_.Union(damage_rect);
254
255     const bool force_frame = (++frame_retry_count_ <= kFrameRetryLimit);
256     OnCopyFrameCaptureCompletion(force_frame);
257   }
258
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);
264
265     if (frame_retry_count_ > 0)
266       frame_retry_count_ = 0;
267
268     OnCopyFrameCaptureCompletion(false);
269   }
270
271   void OnCopyFrameCaptureCompletion(bool force_frame) {
272     frame_in_progress_ = false;
273
274     if (frame_pending_) {
275       content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
276         base::Bind(&AtomCopyFrameGenerator::GenerateCopyFrame,
277                    weak_ptr_factory_.GetWeakPtr(),
278                    force_frame,
279                    gfx::Rect()));
280     }
281   }
282
283   int frame_rate_threshold_ms_;
284   OffScreenRenderWidgetHostView* view_;
285
286   base::Time last_time_;
287
288   base::TimeTicks frame_start_time_;
289   bool frame_pending_;
290   bool frame_in_progress_;
291   int frame_retry_count_;
292   std::unique_ptr<SkBitmap> bitmap_;
293   gfx::Rect pending_damage_rect_;
294
295   base::WeakPtrFactory<AtomCopyFrameGenerator> weak_ptr_factory_;
296
297   DISALLOW_COPY_AND_ASSIGN(AtomCopyFrameGenerator);
298 };
299
300 class AtomBeginFrameTimer : public cc::DelayBasedTimeSourceClient {
301  public:
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);
309   }
310
311   void SetActive(bool active) {
312     time_source_->SetActive(active);
313   }
314
315   bool IsActive() const {
316     return time_source_->Active();
317   }
318
319   void SetFrameRateThresholdMs(int frame_rate_threshold_ms) {
320     time_source_->SetTimebaseAndInterval(
321         base::TimeTicks::Now(),
322         base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms));
323   }
324
325  private:
326   void OnTimerTick() override {
327     callback_.Run();
328   }
329
330   const base::Closure callback_;
331   std::unique_ptr<cc::DelayBasedTimeSource> time_source_;
332
333   DISALLOW_COPY_AND_ASSIGN(AtomBeginFrameTimer);
334 };
335
336 OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
337     bool transparent,
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),
345       callback_(callback),
346       frame_rate_(60),
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()),
352       painting_(true),
353       weak_ptr_factory_(this) {
354   DCHECK(render_widget_host_);
355   render_widget_host_->SetView(this);
356
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);
362
363   root_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
364 #endif
365
366 #if defined(OS_MACOSX)
367   CreatePlatformWidget();
368 #else
369   compositor_.reset(
370       new ui::Compositor(content::GetContextFactory(),
371                          base::ThreadTaskRunnerHandle::Get()));
372   compositor_->SetAcceleratedWidget(native_window_->GetAcceleratedWidget());
373   compositor_->SetRootLayer(root_layer_.get());
374 #endif
375   GetCompositor()->SetDelegate(this);
376
377   native_window_->AddObserver(this);
378
379   ResizeRootLayer();
380 }
381
382 OffScreenRenderWidgetHostView::~OffScreenRenderWidgetHostView() {
383   if (native_window_)
384     native_window_->RemoveObserver(this);
385
386 #if defined(OS_MACOSX)
387   if (is_showing_)
388     browser_compositor_->SetRenderWidgetHostIsHidden(true);
389 #else
390   // Marking the DelegatedFrameHost as removed from the window hierarchy is
391   // necessary to remove all connections to its old ui::Compositor.
392   if (is_showing_)
393     delegated_frame_host_->WasHidden();
394   delegated_frame_host_->ResetCompositor();
395 #endif
396
397 #if defined(OS_MACOSX)
398   DestroyPlatformWidget();
399 #endif
400 }
401
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);
407 }
408
409 void OffScreenRenderWidgetHostView::SendBeginFrame(
410     base::TimeTicks frame_time, base::TimeDelta vsync_period) {
411   base::TimeTicks display_time = frame_time + vsync_period;
412
413   base::TimeDelta estimated_browser_composite_time =
414       base::TimeDelta::FromMicroseconds(
415           (1.0f * base::Time::kMicrosecondsPerSecond) / (3.0f * 60));
416
417   base::TimeTicks deadline = display_time - estimated_browser_composite_time;
418
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)));
423 }
424
425 bool OffScreenRenderWidgetHostView::OnMessageReceived(
426     const IPC::Message& message) {
427   bool handled = true;
428   IPC_BEGIN_MESSAGE_MAP(OffScreenRenderWidgetHostView, message)
429     IPC_MESSAGE_HANDLER(ViewHostMsg_SetNeedsBeginFrames,
430                         SetNeedsBeginFrames)
431     IPC_MESSAGE_UNHANDLED(handled = false)
432   IPC_END_MESSAGE_MAP()
433
434   if (!handled)
435     return content::RenderWidgetHostViewBase::OnMessageReceived(message);
436   return handled;
437 }
438
439 void OffScreenRenderWidgetHostView::InitAsChild(gfx::NativeView) {
440 }
441
442 content::RenderWidgetHost* OffScreenRenderWidgetHostView::GetRenderWidgetHost()
443     const {
444   return render_widget_host_;
445 }
446
447 void OffScreenRenderWidgetHostView::SetSize(const gfx::Size& size) {
448   size_ = size;
449
450   ResizeRootLayer();
451   if (render_widget_host_)
452     render_widget_host_->WasResized();
453   GetDelegatedFrameHost()->WasResized();
454 }
455
456 void OffScreenRenderWidgetHostView::SetBounds(const gfx::Rect& new_bounds) {
457 }
458
459 gfx::Vector2dF OffScreenRenderWidgetHostView::GetLastScrollOffset() const {
460   return last_scroll_offset_;
461 }
462
463 gfx::NativeView OffScreenRenderWidgetHostView::GetNativeView() const {
464   return gfx::NativeView();
465 }
466
467 gfx::NativeViewAccessible
468 OffScreenRenderWidgetHostView::GetNativeViewAccessible() {
469   return gfx::NativeViewAccessible();
470 }
471
472 ui::TextInputClient* OffScreenRenderWidgetHostView::GetTextInputClient() {
473   return nullptr;
474 }
475
476 void OffScreenRenderWidgetHostView::Focus() {
477 }
478
479 bool OffScreenRenderWidgetHostView::HasFocus() const {
480   return false;
481 }
482
483 bool OffScreenRenderWidgetHostView::IsSurfaceAvailableForCopy() const {
484   return GetDelegatedFrameHost()->CanCopyToBitmap();
485 }
486
487 void OffScreenRenderWidgetHostView::Show() {
488   if (is_showing_)
489     return;
490
491   is_showing_ = true;
492
493 #if defined(OS_MACOSX)
494   browser_compositor_->SetRenderWidgetHostIsHidden(false);
495 #else
496   delegated_frame_host_->SetCompositor(compositor_.get());
497   delegated_frame_host_->WasShown(ui::LatencyInfo());
498 #endif
499
500   if (render_widget_host_)
501     render_widget_host_->WasShown(ui::LatencyInfo());
502 }
503
504 void OffScreenRenderWidgetHostView::Hide() {
505   if (!is_showing_)
506     return;
507
508   if (render_widget_host_)
509     render_widget_host_->WasHidden();
510
511 #if defined(OS_MACOSX)
512   browser_compositor_->SetRenderWidgetHostIsHidden(true);
513 #else
514   GetDelegatedFrameHost()->WasHidden();
515   GetDelegatedFrameHost()->ResetCompositor();
516 #endif
517
518   is_showing_ = false;
519 }
520
521 bool OffScreenRenderWidgetHostView::IsShowing() {
522   return is_showing_;
523 }
524
525 gfx::Rect OffScreenRenderWidgetHostView::GetViewBounds() const {
526   return gfx::Rect(size_);
527 }
528
529 void OffScreenRenderWidgetHostView::SetBackgroundColor(SkColor color) {
530   if (transparent_)
531     color = SkColorSetARGB(SK_AlphaTRANSPARENT, 0, 0, 0);
532
533   content::RenderWidgetHostViewBase::SetBackgroundColor(color);
534
535   const bool opaque = !transparent_ && GetBackgroundOpaque();
536   if (render_widget_host_)
537     render_widget_host_->SetBackgroundOpaque(opaque);
538 }
539
540 gfx::Size OffScreenRenderWidgetHostView::GetVisibleViewportSize() const {
541   return size_;
542 }
543
544 void OffScreenRenderWidgetHostView::SetInsets(const gfx::Insets& insets) {
545 }
546
547 bool OffScreenRenderWidgetHostView::LockMouse() {
548   return false;
549 }
550
551 void OffScreenRenderWidgetHostView::UnlockMouse() {
552 }
553
554 void OffScreenRenderWidgetHostView::OnSwapCompositorFrame(
555   uint32_t output_surface_id,
556   cc::CompositorFrame frame) {
557   TRACE_EVENT0("electron",
558     "OffScreenRenderWidgetHostView::OnSwapCompositorFrame");
559
560   if (frame.metadata.root_scroll_offset != last_scroll_offset_) {
561     last_scroll_offset_ = frame.metadata.root_scroll_offset;
562   }
563
564   if (frame.delegated_frame_data) {
565     if (software_output_device_) {
566       if (!begin_frame_timer_.get()) {
567         software_output_device_->SetActive(painting_);
568       }
569
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,
574                                                std::move(frame));
575 #else
576       delegated_frame_host_->SwapDelegatedFrame(output_surface_id,
577                                                 std::move(frame));
578 #endif
579     } else {
580       if (!copy_frame_generator_.get()) {
581         copy_frame_generator_.reset(
582             new AtomCopyFrameGenerator(frame_rate_threshold_ms_, this));
583       }
584
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));
593
594 #if defined(OS_MACOSX)
595       browser_compositor_->SwapCompositorFrame(output_surface_id,
596                                                std::move(frame));
597 #else
598       delegated_frame_host_->SwapDelegatedFrame(output_surface_id,
599                                                 std::move(frame));
600 #endif
601
602       // Request a copy of the last compositor frame which will eventually call
603       // OnPaint asynchronously.
604       copy_frame_generator_->GenerateCopyFrame(true, damage_rect);
605     }
606   }
607 }
608
609 void OffScreenRenderWidgetHostView::ClearCompositorFrame() {
610   GetDelegatedFrameHost()->ClearDelegatedFrame();
611 }
612
613 void OffScreenRenderWidgetHostView::InitAsPopup(
614     content::RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
615 }
616
617 void OffScreenRenderWidgetHostView::InitAsFullscreen(
618   content::RenderWidgetHostView *) {
619 }
620
621 void OffScreenRenderWidgetHostView::UpdateCursor(const content::WebCursor &) {
622 }
623
624 void OffScreenRenderWidgetHostView::SetIsLoading(bool loading) {
625 }
626
627 void OffScreenRenderWidgetHostView::TextInputStateChanged(
628   const content::TextInputState& params) {
629 }
630
631 void OffScreenRenderWidgetHostView::ImeCancelComposition() {
632 }
633
634 void OffScreenRenderWidgetHostView::RenderProcessGone(base::TerminationStatus,
635     int) {
636   Destroy();
637 }
638
639 void OffScreenRenderWidgetHostView::Destroy() {
640   delete this;
641 }
642
643 void OffScreenRenderWidgetHostView::SetTooltipText(const base::string16 &) {
644 }
645
646 void OffScreenRenderWidgetHostView::SelectionBoundsChanged(
647   const ViewHostMsg_SelectionBounds_Params &) {
648 }
649
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);
657 }
658
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);
665 }
666
667 bool OffScreenRenderWidgetHostView::CanCopyToVideoFrame() const {
668   return GetDelegatedFrameHost()->CanCopyToVideoFrame();
669 }
670
671 void OffScreenRenderWidgetHostView::BeginFrameSubscription(
672   std::unique_ptr<content::RenderWidgetHostViewFrameSubscriber> subscriber) {
673   GetDelegatedFrameHost()->BeginFrameSubscription(std::move(subscriber));
674 }
675
676 void OffScreenRenderWidgetHostView::EndFrameSubscription() {
677   GetDelegatedFrameHost()->EndFrameSubscription();
678 }
679
680 bool OffScreenRenderWidgetHostView::HasAcceleratedSurface(const gfx::Size &) {
681   return false;
682 }
683
684 gfx::Rect OffScreenRenderWidgetHostView::GetBoundsInRootWindow() {
685   return gfx::Rect(size_);
686 }
687
688 void OffScreenRenderWidgetHostView::LockCompositingSurface() {
689 }
690
691 void OffScreenRenderWidgetHostView::UnlockCompositingSurface() {
692 }
693
694 void OffScreenRenderWidgetHostView::ImeCompositionRangeChanged(
695   const gfx::Range &, const std::vector<gfx::Rect>&) {
696 }
697
698 gfx::Size OffScreenRenderWidgetHostView::GetPhysicalBackingSize() const {
699   return size_;
700 }
701
702 gfx::Size OffScreenRenderWidgetHostView::GetRequestedRendererSize() const {
703   return size_;
704 }
705
706 #if !defined(OS_MACOSX)
707 ui::Layer* OffScreenRenderWidgetHostView::DelegatedFrameHostGetLayer() const {
708   return const_cast<ui::Layer*>(root_layer_.get());
709 }
710
711 bool OffScreenRenderWidgetHostView::DelegatedFrameHostIsVisible() const {
712   return !render_widget_host_->is_hidden();
713 }
714
715 SkColor OffScreenRenderWidgetHostView::DelegatedFrameHostGetGutterColor(
716     SkColor color) const {
717   return color;
718 }
719
720 gfx::Size OffScreenRenderWidgetHostView::DelegatedFrameHostDesiredSizeInDIP()
721   const {
722   return size_;
723 }
724
725 bool OffScreenRenderWidgetHostView::DelegatedFrameCanCreateResizeLock() const {
726   return false;
727 }
728
729 std::unique_ptr<content::ResizeLock>
730   OffScreenRenderWidgetHostView::DelegatedFrameHostCreateResizeLock(
731       bool defer_compositor_lock) {
732   return nullptr;
733 }
734
735 void OffScreenRenderWidgetHostView::DelegatedFrameHostResizeLockWasReleased() {
736   return render_widget_host_->WasResized();
737 }
738
739 void
740 OffScreenRenderWidgetHostView::DelegatedFrameHostSendReclaimCompositorResources(
741     int output_surface_id,
742     bool is_swap_ack,
743     const cc::ReturnedResourceArray& resources) {
744   render_widget_host_->Send(new ViewMsg_ReclaimCompositorResources(
745       render_widget_host_->GetRoutingID(), output_surface_id, is_swap_ack,
746       resources));
747 }
748
749 void OffScreenRenderWidgetHostView::SetBeginFrameSource(
750     cc::BeginFrameSource* source) {
751 }
752
753 #endif  // !defined(OS_MACOSX)
754
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_);
761
762   software_output_device_ = new OffScreenOutputDevice(
763       transparent_,
764       base::Bind(&OffScreenRenderWidgetHostView::OnPaint,
765                  weak_ptr_factory_.GetWeakPtr()));
766   return base::WrapUnique(software_output_device_);
767 }
768
769 bool OffScreenRenderWidgetHostView::InstallTransparency() {
770   if (transparent_) {
771     SetBackgroundColor(SkColor());
772 #if defined(OS_MACOSX)
773     browser_compositor_->SetHasTransparentBackground(true);
774 #else
775     compositor_->SetHostHasTransparentBackground(true);
776 #endif
777     return true;
778   }
779   return false;
780 }
781
782 bool OffScreenRenderWidgetHostView::IsAutoResizeEnabled() const {
783   return false;
784 }
785
786 void OffScreenRenderWidgetHostView::SetNeedsBeginFrames(
787     bool needs_begin_frames) {
788   SetupFrameRate(false);
789
790   begin_frame_timer_->SetActive(needs_begin_frames);
791
792   if (software_output_device_) {
793     software_output_device_->SetActive(needs_begin_frames && painting_);
794   }
795 }
796
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);
801 }
802
803 void OffScreenRenderWidgetHostView::SetPainting(bool painting) {
804   painting_ = painting;
805
806   if (software_output_device_) {
807     software_output_device_->SetActive(painting_);
808   }
809 }
810
811 bool OffScreenRenderWidgetHostView::IsPainting() const {
812   return painting_;
813 }
814
815 void OffScreenRenderWidgetHostView::SetFrameRate(int frame_rate) {
816   if (frame_rate <= 0)
817     frame_rate = 1;
818   if (frame_rate > 60)
819     frame_rate = 60;
820
821   frame_rate_ = frame_rate;
822
823   SetupFrameRate(true);
824 }
825
826 int OffScreenRenderWidgetHostView::GetFrameRate() const {
827   return frame_rate_;
828 }
829
830 #if !defined(OS_MACOSX)
831 ui::Compositor* OffScreenRenderWidgetHostView::GetCompositor() const {
832   return compositor_.get();
833 }
834
835 ui::Layer* OffScreenRenderWidgetHostView::GetRootLayer() const {
836   return root_layer_.get();
837 }
838
839 content::DelegatedFrameHost*
840 OffScreenRenderWidgetHostView::GetDelegatedFrameHost() const {
841   return delegated_frame_host_.get();
842 }
843 #endif
844
845 void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) {
846   if (!force && frame_rate_threshold_ms_ != 0)
847     return;
848
849   frame_rate_threshold_ms_ = 1000 / frame_rate_;
850
851   GetCompositor()->vsync_manager()->SetAuthoritativeVSyncInterval(
852       base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms_));
853
854   if (copy_frame_generator_.get()) {
855     copy_frame_generator_->set_frame_rate_threshold_ms(
856         frame_rate_threshold_ms_);
857   }
858
859   if (begin_frame_timer_.get()) {
860     begin_frame_timer_->SetFrameRateThresholdMs(frame_rate_threshold_ms_);
861   } else {
862     begin_frame_timer_.reset(new AtomBeginFrameTimer(
863         frame_rate_threshold_ms_,
864         base::Bind(&OffScreenRenderWidgetHostView::OnBeginFrameTimerTick,
865                    weak_ptr_factory_.GetWeakPtr())));
866   }
867 }
868
869 void OffScreenRenderWidgetHostView::Invalidate() {
870   const gfx::Rect& bounds_in_pixels = GetViewBounds();
871
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);
876   }
877 }
878
879 void OffScreenRenderWidgetHostView::ResizeRootLayer() {
880   SetupFrameRate(false);
881
882   const float orgScaleFactor = scale_factor_;
883   const bool scaleFactorDidChange = (orgScaleFactor != scale_factor_);
884
885   gfx::Size size = GetViewBounds().size();
886
887   if (!scaleFactorDidChange && size == GetRootLayer()->bounds().size())
888     return;
889
890   const gfx::Size& size_in_pixels =
891       gfx::ConvertSizeToPixel(scale_factor_, size);
892
893   GetRootLayer()->SetBounds(gfx::Rect(size));
894   GetCompositor()->SetScaleAndSize(scale_factor_, size_in_pixels);
895 }
896
897 void OffScreenRenderWidgetHostView::OnWindowResize() {
898   // In offscreen mode call RenderWidgetHostView's SetSize explicitly
899   auto size = native_window_->GetSize();
900   SetSize(size);
901 }
902
903 void OffScreenRenderWidgetHostView::OnWindowClosed() {
904   native_window_->RemoveObserver(this);
905   native_window_ = nullptr;
906 }
907
908 }  // namespace atom