Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / compositor / delegated_frame_host.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/compositor/delegated_frame_host.h"
6
7 #include "base/callback_helpers.h"
8 #include "base/command_line.h"
9 #include "cc/output/compositor_frame.h"
10 #include "cc/output/compositor_frame_ack.h"
11 #include "cc/output/copy_output_request.h"
12 #include "cc/resources/single_release_callback.h"
13 #include "cc/resources/texture_mailbox.h"
14 #include "cc/surfaces/surface_factory.h"
15 #include "content/browser/compositor/resize_lock.h"
16 #include "content/browser/gpu/compositor_util.h"
17 #include "content/common/gpu/client/gl_helper.h"
18 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
19 #include "content/public/common/content_switches.h"
20 #include "media/base/video_frame.h"
21 #include "media/base/video_util.h"
22 #include "skia/ext/image_operations.h"
23 #include "third_party/skia/include/core/SkCanvas.h"
24 #include "third_party/skia/include/core/SkPaint.h"
25 #include "third_party/skia/include/effects/SkLumaColorFilter.h"
26 #include "ui/gfx/frame_time.h"
27
28 namespace content {
29
30 ////////////////////////////////////////////////////////////////////////////////
31 // DelegatedFrameHostClient
32
33 bool DelegatedFrameHostClient::ShouldCreateResizeLock() {
34   // On Windows and Linux, holding pointer moves will not help throttling
35   // resizes.
36   // TODO(piman): on Windows we need to block (nested message loop?) the
37   // WM_SIZE event. On Linux we need to throttle at the WM level using
38   // _NET_WM_SYNC_REQUEST.
39   // TODO(ccameron): Mac browser window resizing is incompletely implemented.
40 #if !defined(OS_CHROMEOS)
41   return false;
42 #else
43   return GetDelegatedFrameHost()->ShouldCreateResizeLock();
44 #endif
45 }
46
47 void DelegatedFrameHostClient::RequestCopyOfOutput(
48     scoped_ptr<cc::CopyOutputRequest> request) {
49   GetDelegatedFrameHost()->RequestCopyOfOutput(request.Pass());
50 }
51
52 ////////////////////////////////////////////////////////////////////////////////
53 // DelegatedFrameHost
54
55 DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client)
56     : client_(client),
57       use_surfaces_(UseSurfacesEnabled()),
58       last_output_surface_id_(0),
59       pending_delegated_ack_count_(0),
60       skipped_frames_(false),
61       can_lock_compositor_(YES_CAN_LOCK),
62       delegated_frame_evictor_(new DelegatedFrameEvictor(this)) {
63   ImageTransportFactory::GetInstance()->AddObserver(this);
64 }
65
66 void DelegatedFrameHost::WasShown(const ui::LatencyInfo& latency_info) {
67   delegated_frame_evictor_->SetVisible(true);
68
69   if (surface_id_.is_null() && !frame_provider_.get() &&
70       !released_front_lock_.get()) {
71     ui::Compositor* compositor = client_->GetCompositor();
72     if (compositor)
73       released_front_lock_ = compositor->GetCompositorLock();
74   }
75
76   ui::Compositor* compositor = client_->GetCompositor();
77   if (compositor) {
78     compositor->SetLatencyInfo(latency_info);
79   }
80 }
81
82 bool DelegatedFrameHost::HasSavedFrame() {
83   return delegated_frame_evictor_->HasFrame();
84 }
85
86 void DelegatedFrameHost::WasHidden() {
87   delegated_frame_evictor_->SetVisible(false);
88   released_front_lock_ = NULL;
89 }
90
91 void DelegatedFrameHost::MaybeCreateResizeLock() {
92   if (!client_->ShouldCreateResizeLock())
93     return;
94   DCHECK(client_->GetCompositor());
95
96   // Listen to changes in the compositor lock state.
97   ui::Compositor* compositor = client_->GetCompositor();
98   if (!compositor->HasObserver(this))
99     compositor->AddObserver(this);
100
101   bool defer_compositor_lock =
102       can_lock_compositor_ == NO_PENDING_RENDERER_FRAME ||
103       can_lock_compositor_ == NO_PENDING_COMMIT;
104
105   if (can_lock_compositor_ == YES_CAN_LOCK)
106     can_lock_compositor_ = YES_DID_LOCK;
107
108   resize_lock_ = client_->CreateResizeLock(defer_compositor_lock);
109 }
110
111 bool DelegatedFrameHost::ShouldCreateResizeLock() {
112   RenderWidgetHostImpl* host = client_->GetHost();
113
114   if (resize_lock_)
115     return false;
116
117   if (host->should_auto_resize())
118     return false;
119
120   gfx::Size desired_size = client_->DesiredFrameSize();
121   if (desired_size == current_frame_size_in_dip_ || desired_size.IsEmpty())
122     return false;
123
124   ui::Compositor* compositor = client_->GetCompositor();
125   if (!compositor)
126     return false;
127
128   return true;
129 }
130
131 void DelegatedFrameHost::RequestCopyOfOutput(
132     scoped_ptr<cc::CopyOutputRequest> request) {
133   if (use_surfaces_) {
134     if (surface_factory_ && !surface_id_.is_null())
135       surface_factory_->RequestCopyOfSurface(surface_id_, request.Pass());
136     else
137       request->SendEmptyResult();
138   } else {
139     client_->GetLayer()->RequestCopyOfOutput(request.Pass());
140   }
141 }
142
143 void DelegatedFrameHost::CopyFromCompositingSurface(
144     const gfx::Rect& src_subrect,
145     const gfx::Size& output_size,
146     CopyFromCompositingSurfaceCallback& callback,
147     const SkColorType color_type) {
148   // Only ARGB888 and RGB565 supported as of now.
149   bool format_support = ((color_type == kAlpha_8_SkColorType) ||
150                          (color_type == kRGB_565_SkColorType) ||
151                          (color_type == kN32_SkColorType));
152   DCHECK(format_support);
153   if (!CanCopyToBitmap()) {
154     callback.Run(false, SkBitmap());
155     return;
156   }
157
158   scoped_ptr<cc::CopyOutputRequest> request =
159       cc::CopyOutputRequest::CreateRequest(base::Bind(
160           &DelegatedFrameHost::CopyFromCompositingSurfaceHasResult,
161           output_size,
162           color_type,
163           callback));
164   request->set_area(src_subrect);
165   client_->RequestCopyOfOutput(request.Pass());
166 }
167
168 void DelegatedFrameHost::CopyFromCompositingSurfaceToVideoFrame(
169       const gfx::Rect& src_subrect,
170       const scoped_refptr<media::VideoFrame>& target,
171       const base::Callback<void(bool)>& callback) {
172   if (!CanCopyToVideoFrame()) {
173     callback.Run(false);
174     return;
175   }
176
177   // Try get a texture to reuse.
178   scoped_refptr<OwnedMailbox> subscriber_texture;
179   if (frame_subscriber_) {
180     if (!idle_frame_subscriber_textures_.empty()) {
181       subscriber_texture = idle_frame_subscriber_textures_.back();
182       idle_frame_subscriber_textures_.pop_back();
183     } else if (GLHelper* helper =
184                    ImageTransportFactory::GetInstance()->GetGLHelper()) {
185       subscriber_texture = new OwnedMailbox(helper);
186     }
187   }
188
189   scoped_ptr<cc::CopyOutputRequest> request =
190       cc::CopyOutputRequest::CreateRequest(base::Bind(
191           &DelegatedFrameHost::
192                CopyFromCompositingSurfaceHasResultForVideo,
193           AsWeakPtr(),  // For caching the ReadbackYUVInterface on this class.
194           subscriber_texture,
195           target,
196           callback));
197   request->set_area(src_subrect);
198   if (subscriber_texture.get()) {
199     request->SetTextureMailbox(
200         cc::TextureMailbox(subscriber_texture->mailbox(),
201                            subscriber_texture->target(),
202                            subscriber_texture->sync_point()));
203   }
204   client_->RequestCopyOfOutput(request.Pass());
205 }
206
207 bool DelegatedFrameHost::CanCopyToBitmap() const {
208   return client_->GetCompositor() &&
209          client_->GetLayer()->has_external_content();
210 }
211
212 bool DelegatedFrameHost::CanCopyToVideoFrame() const {
213   return client_->GetCompositor() &&
214          client_->GetLayer()->has_external_content();
215 }
216
217 bool DelegatedFrameHost::CanSubscribeFrame() const {
218   return true;
219 }
220
221 void DelegatedFrameHost::BeginFrameSubscription(
222     scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) {
223   frame_subscriber_ = subscriber.Pass();
224 }
225
226 void DelegatedFrameHost::EndFrameSubscription() {
227   idle_frame_subscriber_textures_.clear();
228   frame_subscriber_.reset();
229 }
230
231 bool DelegatedFrameHost::ShouldSkipFrame(gfx::Size size_in_dip) const {
232   // Should skip a frame only when another frame from the renderer is guaranteed
233   // to replace it. Otherwise may cause hangs when the renderer is waiting for
234   // the completion of latency infos (such as when taking a Snapshot.)
235   if (can_lock_compositor_ == NO_PENDING_RENDERER_FRAME ||
236       can_lock_compositor_ == NO_PENDING_COMMIT ||
237       !resize_lock_.get())
238     return false;
239
240   return size_in_dip != resize_lock_->expected_size();
241 }
242
243 void DelegatedFrameHost::WasResized() {
244   if (client_->DesiredFrameSize() != current_frame_size_in_dip_ &&
245       client_->GetHost()->is_hidden())
246     EvictDelegatedFrame();
247   MaybeCreateResizeLock();
248 }
249
250 gfx::Size DelegatedFrameHost::GetRequestedRendererSize() const {
251   if (resize_lock_)
252     return resize_lock_->expected_size();
253   else
254     return client_->DesiredFrameSize();
255 }
256
257 void DelegatedFrameHost::CheckResizeLock() {
258   if (!resize_lock_ ||
259       resize_lock_->expected_size() != current_frame_size_in_dip_)
260     return;
261
262   // Since we got the size we were looking for, unlock the compositor. But delay
263   // the release of the lock until we've kicked a frame with the new texture, to
264   // avoid resizing the UI before we have a chance to draw a "good" frame.
265   resize_lock_->UnlockCompositor();
266   ui::Compositor* compositor = client_->GetCompositor();
267   if (compositor) {
268     if (!compositor->HasObserver(this))
269       compositor->AddObserver(this);
270   }
271 }
272
273 void DelegatedFrameHost::DidReceiveFrameFromRenderer(
274     const gfx::Rect& damage_rect) {
275   if (!frame_subscriber() || !CanCopyToVideoFrame())
276     return;
277
278   const base::TimeTicks now = gfx::FrameTime::Now();
279   base::TimeTicks present_time;
280   if (vsync_timebase_.is_null() || vsync_interval_ <= base::TimeDelta()) {
281     present_time = now;
282   } else {
283     const int64 intervals_elapsed = (now - vsync_timebase_) / vsync_interval_;
284     present_time = vsync_timebase_ + (intervals_elapsed + 1) * vsync_interval_;
285   }
286
287   scoped_refptr<media::VideoFrame> frame;
288   RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
289   if (frame_subscriber()->ShouldCaptureFrame(damage_rect, present_time,
290                                              &frame, &callback)) {
291     CopyFromCompositingSurfaceToVideoFrame(
292         gfx::Rect(current_frame_size_in_dip_),
293         frame,
294         base::Bind(callback, present_time));
295   }
296 }
297
298 void DelegatedFrameHost::SwapDelegatedFrame(
299     uint32 output_surface_id,
300     scoped_ptr<cc::DelegatedFrameData> frame_data,
301     float frame_device_scale_factor,
302     const std::vector<ui::LatencyInfo>& latency_info) {
303   RenderWidgetHostImpl* host = client_->GetHost();
304   DCHECK(!frame_data->render_pass_list.empty());
305
306   cc::RenderPass* root_pass = frame_data->render_pass_list.back();
307
308   gfx::Size frame_size = root_pass->output_rect.size();
309   gfx::Size frame_size_in_dip =
310       ConvertSizeToDIP(frame_device_scale_factor, frame_size);
311
312   gfx::Rect damage_rect = gfx::ToEnclosingRect(root_pass->damage_rect);
313   damage_rect.Intersect(gfx::Rect(frame_size));
314   gfx::Rect damage_rect_in_dip =
315       ConvertRectToDIP(frame_device_scale_factor, damage_rect);
316
317   if (ShouldSkipFrame(frame_size_in_dip)) {
318     cc::CompositorFrameAck ack;
319     cc::TransferableResource::ReturnResources(frame_data->resource_list,
320                                               &ack.resources);
321
322     skipped_latency_info_list_.insert(skipped_latency_info_list_.end(),
323         latency_info.begin(), latency_info.end());
324
325     RenderWidgetHostImpl::SendSwapCompositorFrameAck(
326         host->GetRoutingID(), output_surface_id,
327         host->GetProcess()->GetID(), ack);
328     skipped_frames_ = true;
329     return;
330   }
331
332   if (skipped_frames_) {
333     skipped_frames_ = false;
334     damage_rect = gfx::Rect(frame_size);
335     damage_rect_in_dip = gfx::Rect(frame_size_in_dip);
336
337     // Give the same damage rect to the compositor.
338     cc::RenderPass* root_pass = frame_data->render_pass_list.back();
339     root_pass->damage_rect = damage_rect;
340   }
341
342   if (output_surface_id != last_output_surface_id_) {
343     // Resource ids are scoped by the output surface.
344     // If the originating output surface doesn't match the last one, it
345     // indicates the renderer's output surface may have been recreated, in which
346     // case we should recreate the DelegatedRendererLayer, to avoid matching
347     // resources from the old one with resources from the new one which would
348     // have the same id. Changing the layer to showing painted content destroys
349     // the DelegatedRendererLayer.
350     EvictDelegatedFrame();
351
352     // Drop the cc::DelegatedFrameResourceCollection so that we will not return
353     // any resources from the old output surface with the new output surface id.
354     if (resource_collection_.get()) {
355       resource_collection_->SetClient(NULL);
356
357       if (resource_collection_->LoseAllResources())
358         SendReturnedDelegatedResources(last_output_surface_id_);
359
360       resource_collection_ = NULL;
361     }
362     last_output_surface_id_ = output_surface_id;
363   }
364   bool modified_layers = false;
365   ui::Compositor* compositor = client_->GetCompositor();
366   if (frame_size.IsEmpty()) {
367     DCHECK(frame_data->resource_list.empty());
368     EvictDelegatedFrame();
369     modified_layers = true;
370   } else {
371     if (use_surfaces_) {
372       if (!surface_factory_) {
373         ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
374         cc::SurfaceManager* manager = factory->GetSurfaceManager();
375         id_allocator_ = factory->CreateSurfaceIdAllocator();
376         surface_factory_ =
377             make_scoped_ptr(new cc::SurfaceFactory(manager, this));
378       }
379       if (surface_id_.is_null() || frame_size != current_surface_size_ ||
380           frame_size_in_dip != current_frame_size_in_dip_) {
381         // TODO(jbauman): Wait to destroy this surface until the parent has
382         // finished using it.
383         if (!surface_id_.is_null())
384           surface_factory_->Destroy(surface_id_);
385         surface_id_ = id_allocator_->GenerateId();
386         surface_factory_->Create(surface_id_, frame_size);
387         client_->GetLayer()->SetShowSurface(surface_id_, frame_size_in_dip);
388         current_surface_size_ = frame_size;
389         modified_layers = true;
390       }
391       scoped_ptr<cc::CompositorFrame> compositor_frame =
392           make_scoped_ptr(new cc::CompositorFrame());
393       compositor_frame->delegated_frame_data = frame_data.Pass();
394
395       compositor_frame->metadata.latency_info.swap(skipped_latency_info_list_);
396       compositor_frame->metadata.latency_info.insert(
397           compositor_frame->metadata.latency_info.end(),
398           latency_info.begin(),
399           latency_info.end());
400
401       base::Closure ack_callback;
402       if (compositor) {
403         ack_callback = base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
404                                   AsWeakPtr(),
405                                   output_surface_id);
406       }
407       surface_factory_->SubmitFrame(
408           surface_id_, compositor_frame.Pass(), ack_callback);
409     } else {
410       if (!resource_collection_.get()) {
411         resource_collection_ = new cc::DelegatedFrameResourceCollection;
412         resource_collection_->SetClient(this);
413       }
414       // If the physical frame size changes, we need a new |frame_provider_|. If
415       // the physical frame size is the same, but the size in DIP changed, we
416       // need to adjust the scale at which the frames will be drawn, and we do
417       // this by making a new |frame_provider_| also to ensure the scale change
418       // is presented in sync with the new frame content.
419       if (!frame_provider_.get() ||
420           frame_size != frame_provider_->frame_size() ||
421           frame_size_in_dip != current_frame_size_in_dip_) {
422         frame_provider_ = new cc::DelegatedFrameProvider(
423             resource_collection_.get(), frame_data.Pass());
424         client_->GetLayer()->SetShowDelegatedContent(frame_provider_.get(),
425                                                      frame_size_in_dip);
426       } else {
427         frame_provider_->SetFrameData(frame_data.Pass());
428       }
429       modified_layers = true;
430     }
431   }
432   released_front_lock_ = NULL;
433   current_frame_size_in_dip_ = frame_size_in_dip;
434   CheckResizeLock();
435
436   if (modified_layers && !damage_rect_in_dip.IsEmpty()) {
437     // TODO(jbauman): Need to always tell the window observer about the
438     // damage.
439     client_->GetLayer()->OnDelegatedFrameDamage(damage_rect_in_dip);
440   }
441
442   pending_delegated_ack_count_++;
443
444   if (!compositor) {
445     SendDelegatedFrameAck(output_surface_id);
446   } else if (!use_surfaces_) {
447     std::vector<ui::LatencyInfo>::const_iterator it;
448     for (it = latency_info.begin(); it != latency_info.end(); ++it)
449       compositor->SetLatencyInfo(*it);
450     // If we've previously skipped any latency infos add them.
451     for (it = skipped_latency_info_list_.begin();
452         it != skipped_latency_info_list_.end();
453         ++it)
454       compositor->SetLatencyInfo(*it);
455     skipped_latency_info_list_.clear();
456     AddOnCommitCallbackAndDisableLocks(
457         base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
458                    AsWeakPtr(),
459                    output_surface_id));
460   }
461   DidReceiveFrameFromRenderer(damage_rect);
462   if (frame_provider_.get() || !surface_id_.is_null())
463     delegated_frame_evictor_->SwappedFrame(!host->is_hidden());
464   // Note: the frame may have been evicted immediately.
465 }
466
467 void DelegatedFrameHost::SendDelegatedFrameAck(uint32 output_surface_id) {
468   RenderWidgetHostImpl* host = client_->GetHost();
469   cc::CompositorFrameAck ack;
470   if (!surface_returned_resources_.empty())
471     ack.resources.swap(surface_returned_resources_);
472   if (resource_collection_.get())
473     resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
474   RenderWidgetHostImpl::SendSwapCompositorFrameAck(host->GetRoutingID(),
475                                                    output_surface_id,
476                                                    host->GetProcess()->GetID(),
477                                                    ack);
478   DCHECK_GT(pending_delegated_ack_count_, 0);
479   pending_delegated_ack_count_--;
480 }
481
482 void DelegatedFrameHost::UnusedResourcesAreAvailable() {
483   if (pending_delegated_ack_count_)
484     return;
485
486   SendReturnedDelegatedResources(last_output_surface_id_);
487 }
488
489 void DelegatedFrameHost::SendReturnedDelegatedResources(
490     uint32 output_surface_id) {
491   RenderWidgetHostImpl* host = client_->GetHost();
492
493   cc::CompositorFrameAck ack;
494   if (!surface_returned_resources_.empty()) {
495     ack.resources.swap(surface_returned_resources_);
496   } else {
497     DCHECK(resource_collection_.get());
498     resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
499   }
500   DCHECK(!ack.resources.empty());
501
502   RenderWidgetHostImpl::SendReclaimCompositorResources(
503       host->GetRoutingID(),
504       output_surface_id,
505       host->GetProcess()->GetID(),
506       ack);
507 }
508
509 void DelegatedFrameHost::ReturnResources(
510     const cc::ReturnedResourceArray& resources) {
511   if (resources.empty())
512     return;
513   std::copy(resources.begin(),
514             resources.end(),
515             std::back_inserter(surface_returned_resources_));
516   if (!pending_delegated_ack_count_)
517     SendReturnedDelegatedResources(last_output_surface_id_);
518 }
519
520 void DelegatedFrameHost::EvictDelegatedFrame() {
521   client_->GetLayer()->SetShowPaintedContent();
522   frame_provider_ = NULL;
523   if (!surface_id_.is_null()) {
524     surface_factory_->Destroy(surface_id_);
525     surface_id_ = cc::SurfaceId();
526   }
527   delegated_frame_evictor_->DiscardedFrame();
528 }
529
530 // static
531 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
532     const gfx::Size& dst_size_in_pixel,
533     const SkColorType color_type,
534     const base::Callback<void(bool, const SkBitmap&)>& callback,
535     scoped_ptr<cc::CopyOutputResult> result) {
536   if (result->IsEmpty() || result->size().IsEmpty()) {
537     callback.Run(false, SkBitmap());
538     return;
539   }
540
541   if (result->HasTexture()) {
542     // GPU-accelerated path
543     PrepareTextureCopyOutputResult(dst_size_in_pixel, color_type,
544                                    callback,
545                                    result.Pass());
546     return;
547   }
548
549   DCHECK(result->HasBitmap());
550   // Software path
551   PrepareBitmapCopyOutputResult(dst_size_in_pixel, color_type, callback,
552                                 result.Pass());
553 }
554
555 static void CopyFromCompositingSurfaceFinished(
556     const base::Callback<void(bool, const SkBitmap&)>& callback,
557     scoped_ptr<cc::SingleReleaseCallback> release_callback,
558     scoped_ptr<SkBitmap> bitmap,
559     scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock,
560     bool result) {
561   bitmap_pixels_lock.reset();
562
563   uint32 sync_point = 0;
564   if (result) {
565     GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
566     sync_point = gl_helper->InsertSyncPoint();
567   }
568   bool lost_resource = sync_point == 0;
569   release_callback->Run(sync_point, lost_resource);
570
571   callback.Run(result, *bitmap);
572 }
573
574 // static
575 void DelegatedFrameHost::PrepareTextureCopyOutputResult(
576     const gfx::Size& dst_size_in_pixel,
577     const SkColorType color_type,
578     const base::Callback<void(bool, const SkBitmap&)>& callback,
579     scoped_ptr<cc::CopyOutputResult> result) {
580   DCHECK(result->HasTexture());
581   base::ScopedClosureRunner scoped_callback_runner(
582       base::Bind(callback, false, SkBitmap()));
583
584   // TODO(sikugu): We should be able to validate the format here using
585   // GLHelper::IsReadbackConfigSupported before we processs the result.
586   // See crbug.com/415682.
587   scoped_ptr<SkBitmap> bitmap(new SkBitmap);
588   if (!bitmap->tryAllocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
589                                                 dst_size_in_pixel.height(),
590                                                 color_type,
591                                                 kOpaque_SkAlphaType)))
592     return;
593
594   ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
595   GLHelper* gl_helper = factory->GetGLHelper();
596   if (!gl_helper)
597     return;
598
599   scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock(
600       new SkAutoLockPixels(*bitmap));
601   uint8* pixels = static_cast<uint8*>(bitmap->getPixels());
602
603   cc::TextureMailbox texture_mailbox;
604   scoped_ptr<cc::SingleReleaseCallback> release_callback;
605   result->TakeTexture(&texture_mailbox, &release_callback);
606   DCHECK(texture_mailbox.IsTexture());
607
608   ignore_result(scoped_callback_runner.Release());
609
610   gl_helper->CropScaleReadbackAndCleanMailbox(
611       texture_mailbox.mailbox(),
612       texture_mailbox.sync_point(),
613       result->size(),
614       gfx::Rect(result->size()),
615       dst_size_in_pixel,
616       pixels,
617       color_type,
618       base::Bind(&CopyFromCompositingSurfaceFinished,
619                  callback,
620                  base::Passed(&release_callback),
621                  base::Passed(&bitmap),
622                  base::Passed(&bitmap_pixels_lock)),
623       GLHelper::SCALER_QUALITY_FAST);
624 }
625
626 // static
627 void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
628     const gfx::Size& dst_size_in_pixel,
629     const SkColorType color_type,
630     const base::Callback<void(bool, const SkBitmap&)>& callback,
631     scoped_ptr<cc::CopyOutputResult> result) {
632   if (color_type != kN32_SkColorType && color_type != kAlpha_8_SkColorType) {
633     NOTIMPLEMENTED();
634     callback.Run(false, SkBitmap());
635     return;
636   }
637   DCHECK(result->HasBitmap());
638   scoped_ptr<SkBitmap> source = result->TakeBitmap();
639   DCHECK(source);
640   SkBitmap scaled_bitmap;
641   if (source->width() != dst_size_in_pixel.width() ||
642       source->height() != dst_size_in_pixel.height()) {
643     scaled_bitmap =
644         skia::ImageOperations::Resize(*source,
645                                       skia::ImageOperations::RESIZE_BEST,
646                                       dst_size_in_pixel.width(),
647                                       dst_size_in_pixel.height());
648   } else {
649     scaled_bitmap = *source;
650   }
651   if (color_type == kN32_SkColorType) {
652     DCHECK_EQ(scaled_bitmap.colorType(), kN32_SkColorType);
653     callback.Run(true, scaled_bitmap);
654     return;
655   }
656   DCHECK_EQ(color_type, kAlpha_8_SkColorType);
657   // The software path currently always returns N32 bitmap regardless of the
658   // |color_type| we ask for.
659   DCHECK_EQ(scaled_bitmap.colorType(), kN32_SkColorType);
660   // Paint |scaledBitmap| to alpha-only |grayscale_bitmap|.
661   SkBitmap grayscale_bitmap;
662   bool success = grayscale_bitmap.tryAllocPixels(
663       SkImageInfo::MakeA8(scaled_bitmap.width(), scaled_bitmap.height()));
664   if (!success) {
665     callback.Run(false, SkBitmap());
666     return;
667   }
668   SkCanvas canvas(grayscale_bitmap);
669   SkPaint paint;
670   skia::RefPtr<SkColorFilter> filter =
671       skia::AdoptRef(SkLumaColorFilter::Create());
672   paint.setColorFilter(filter.get());
673   canvas.drawBitmap(scaled_bitmap, SkIntToScalar(0), SkIntToScalar(0), &paint);
674   callback.Run(true, grayscale_bitmap);
675 }
676
677 // static
678 void DelegatedFrameHost::ReturnSubscriberTexture(
679     base::WeakPtr<DelegatedFrameHost> dfh,
680     scoped_refptr<OwnedMailbox> subscriber_texture,
681     uint32 sync_point) {
682   if (!subscriber_texture.get())
683     return;
684   if (!dfh)
685     return;
686
687   subscriber_texture->UpdateSyncPoint(sync_point);
688
689   if (dfh->frame_subscriber_ && subscriber_texture->texture_id())
690     dfh->idle_frame_subscriber_textures_.push_back(subscriber_texture);
691 }
692
693 // static
694 void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
695     base::WeakPtr<DelegatedFrameHost> dfh,
696     const base::Callback<void(bool)>& callback,
697     scoped_refptr<OwnedMailbox> subscriber_texture,
698     scoped_ptr<cc::SingleReleaseCallback> release_callback,
699     bool result) {
700   callback.Run(result);
701
702   uint32 sync_point = 0;
703   if (result) {
704     GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
705     sync_point = gl_helper->InsertSyncPoint();
706   }
707   if (release_callback) {
708     // A release callback means the texture came from the compositor, so there
709     // should be no |subscriber_texture|.
710     DCHECK(!subscriber_texture.get());
711     bool lost_resource = sync_point == 0;
712     release_callback->Run(sync_point, lost_resource);
713   }
714   ReturnSubscriberTexture(dfh, subscriber_texture, sync_point);
715 }
716
717 // static
718 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
719     base::WeakPtr<DelegatedFrameHost> dfh,
720     scoped_refptr<OwnedMailbox> subscriber_texture,
721     scoped_refptr<media::VideoFrame> video_frame,
722     const base::Callback<void(bool)>& callback,
723     scoped_ptr<cc::CopyOutputResult> result) {
724   base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false));
725   base::ScopedClosureRunner scoped_return_subscriber_texture(
726       base::Bind(&ReturnSubscriberTexture, dfh, subscriber_texture, 0));
727
728   if (!dfh)
729     return;
730   if (result->IsEmpty())
731     return;
732   if (result->size().IsEmpty())
733     return;
734
735   // Compute the dest size we want after the letterboxing resize. Make the
736   // coordinates and sizes even because we letterbox in YUV space
737   // (see CopyRGBToVideoFrame). They need to be even for the UV samples to
738   // line up correctly.
739   // The video frame's coded_size() and the result's size() are both physical
740   // pixels.
741   gfx::Rect region_in_frame =
742       media::ComputeLetterboxRegion(gfx::Rect(video_frame->coded_size()),
743                                     result->size());
744   region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
745                               region_in_frame.y() & ~1,
746                               region_in_frame.width() & ~1,
747                               region_in_frame.height() & ~1);
748   if (region_in_frame.IsEmpty())
749     return;
750
751   if (!result->HasTexture()) {
752     DCHECK(result->HasBitmap());
753     scoped_ptr<SkBitmap> bitmap = result->TakeBitmap();
754     // Scale the bitmap to the required size, if necessary.
755     SkBitmap scaled_bitmap;
756     if (result->size().width() != region_in_frame.width() ||
757         result->size().height() != region_in_frame.height()) {
758       skia::ImageOperations::ResizeMethod method =
759           skia::ImageOperations::RESIZE_GOOD;
760       scaled_bitmap = skia::ImageOperations::Resize(*bitmap.get(), method,
761                                                     region_in_frame.width(),
762                                                     region_in_frame.height());
763     } else {
764       scaled_bitmap = *bitmap.get();
765     }
766
767     {
768       SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
769
770       media::CopyRGBToVideoFrame(
771           reinterpret_cast<uint8*>(scaled_bitmap.getPixels()),
772           scaled_bitmap.rowBytes(),
773           region_in_frame,
774           video_frame.get());
775     }
776     ignore_result(scoped_callback_runner.Release());
777     callback.Run(true);
778     return;
779   }
780
781   ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
782   GLHelper* gl_helper = factory->GetGLHelper();
783   if (!gl_helper)
784     return;
785   if (subscriber_texture.get() && !subscriber_texture->texture_id())
786     return;
787
788   cc::TextureMailbox texture_mailbox;
789   scoped_ptr<cc::SingleReleaseCallback> release_callback;
790   result->TakeTexture(&texture_mailbox, &release_callback);
791   DCHECK(texture_mailbox.IsTexture());
792
793   gfx::Rect result_rect(result->size());
794
795   content::ReadbackYUVInterface* yuv_readback_pipeline =
796       dfh->yuv_readback_pipeline_.get();
797   if (yuv_readback_pipeline == NULL ||
798       yuv_readback_pipeline->scaler()->SrcSize() != result_rect.size() ||
799       yuv_readback_pipeline->scaler()->SrcSubrect() != result_rect ||
800       yuv_readback_pipeline->scaler()->DstSize() != region_in_frame.size()) {
801     GLHelper::ScalerQuality quality = GLHelper::SCALER_QUALITY_FAST;
802     std::string quality_switch = switches::kTabCaptureDownscaleQuality;
803     // If we're scaling up, we can use the "best" quality.
804     if (result_rect.size().width() < region_in_frame.size().width() &&
805         result_rect.size().height() < region_in_frame.size().height())
806       quality_switch = switches::kTabCaptureUpscaleQuality;
807
808     std::string switch_value =
809         base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
810             quality_switch);
811     if (switch_value == "fast")
812       quality = GLHelper::SCALER_QUALITY_FAST;
813     else if (switch_value == "good")
814       quality = GLHelper::SCALER_QUALITY_GOOD;
815     else if (switch_value == "best")
816       quality = GLHelper::SCALER_QUALITY_BEST;
817
818     dfh->yuv_readback_pipeline_.reset(
819         gl_helper->CreateReadbackPipelineYUV(quality,
820                                              result_rect.size(),
821                                              result_rect,
822                                              video_frame->coded_size(),
823                                              region_in_frame,
824                                              true,
825                                              true));
826     yuv_readback_pipeline = dfh->yuv_readback_pipeline_.get();
827   }
828
829   ignore_result(scoped_callback_runner.Release());
830   ignore_result(scoped_return_subscriber_texture.Release());
831   base::Callback<void(bool result)> finished_callback = base::Bind(
832       &DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo,
833       dfh->AsWeakPtr(),
834       callback,
835       subscriber_texture,
836       base::Passed(&release_callback));
837   yuv_readback_pipeline->ReadbackYUV(texture_mailbox.mailbox(),
838                                      texture_mailbox.sync_point(),
839                                      video_frame.get(),
840                                      finished_callback);
841 }
842
843 ////////////////////////////////////////////////////////////////////////////////
844 // DelegatedFrameHost, ui::CompositorObserver implementation:
845
846 void DelegatedFrameHost::OnCompositingDidCommit(
847     ui::Compositor* compositor) {
848   RenderWidgetHostImpl* host = client_->GetHost();
849   if (can_lock_compositor_ == NO_PENDING_COMMIT) {
850     can_lock_compositor_ = YES_CAN_LOCK;
851     if (resize_lock_.get() && resize_lock_->GrabDeferredLock())
852       can_lock_compositor_ = YES_DID_LOCK;
853   }
854   RunOnCommitCallbacks();
855   if (resize_lock_ &&
856       resize_lock_->expected_size() == current_frame_size_in_dip_) {
857     resize_lock_.reset();
858     host->WasResized();
859     // We may have had a resize while we had the lock (e.g. if the lock expired,
860     // or if the UI still gave us some resizes), so make sure we grab a new lock
861     // if necessary.
862     MaybeCreateResizeLock();
863   }
864 }
865
866 void DelegatedFrameHost::OnCompositingStarted(
867     ui::Compositor* compositor, base::TimeTicks start_time) {
868   last_draw_ended_ = start_time;
869 }
870
871 void DelegatedFrameHost::OnCompositingEnded(
872     ui::Compositor* compositor) {
873 }
874
875 void DelegatedFrameHost::OnCompositingAborted(ui::Compositor* compositor) {
876 }
877
878 void DelegatedFrameHost::OnCompositingLockStateChanged(
879     ui::Compositor* compositor) {
880   // A compositor lock that is part of a resize lock timed out. We
881   // should display a renderer frame.
882   if (!compositor->IsLocked() && can_lock_compositor_ == YES_DID_LOCK) {
883     can_lock_compositor_ = NO_PENDING_RENDERER_FRAME;
884   }
885 }
886
887 void DelegatedFrameHost::OnUpdateVSyncParameters(
888     base::TimeTicks timebase,
889     base::TimeDelta interval) {
890   vsync_timebase_ = timebase;
891   vsync_interval_ = interval;
892   RenderWidgetHostImpl* host = client_->GetHost();
893   if (client_->IsVisible())
894     host->UpdateVSyncParameters(timebase, interval);
895 }
896
897 ////////////////////////////////////////////////////////////////////////////////
898 // RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation:
899
900 void DelegatedFrameHost::OnLostResources() {
901   RenderWidgetHostImpl* host = client_->GetHost();
902   if (frame_provider_.get() || !surface_id_.is_null())
903     EvictDelegatedFrame();
904   idle_frame_subscriber_textures_.clear();
905   yuv_readback_pipeline_.reset();
906
907   host->ScheduleComposite();
908 }
909
910 ////////////////////////////////////////////////////////////////////////////////
911 // DelegatedFrameHost, private:
912
913 DelegatedFrameHost::~DelegatedFrameHost() {
914   ImageTransportFactory::GetInstance()->RemoveObserver(this);
915
916   if (!surface_id_.is_null())
917     surface_factory_->Destroy(surface_id_);
918   if (resource_collection_.get())
919     resource_collection_->SetClient(NULL);
920
921   DCHECK(!vsync_manager_.get());
922 }
923
924 void DelegatedFrameHost::RunOnCommitCallbacks() {
925   for (std::vector<base::Closure>::const_iterator
926       it = on_compositing_did_commit_callbacks_.begin();
927       it != on_compositing_did_commit_callbacks_.end(); ++it) {
928     it->Run();
929   }
930   on_compositing_did_commit_callbacks_.clear();
931 }
932
933 void DelegatedFrameHost::AddOnCommitCallbackAndDisableLocks(
934     const base::Closure& callback) {
935   ui::Compositor* compositor = client_->GetCompositor();
936   DCHECK(compositor);
937
938   if (!compositor->HasObserver(this))
939     compositor->AddObserver(this);
940
941   can_lock_compositor_ = NO_PENDING_COMMIT;
942   on_compositing_did_commit_callbacks_.push_back(callback);
943 }
944
945 void DelegatedFrameHost::AddedToWindow() {
946   ui::Compositor* compositor = client_->GetCompositor();
947   if (compositor) {
948     DCHECK(!vsync_manager_.get());
949     vsync_manager_ = compositor->vsync_manager();
950     vsync_manager_->AddObserver(this);
951   }
952 }
953
954 void DelegatedFrameHost::RemovingFromWindow() {
955   RunOnCommitCallbacks();
956   resize_lock_.reset();
957   client_->GetHost()->WasResized();
958   ui::Compositor* compositor = client_->GetCompositor();
959   if (compositor && compositor->HasObserver(this))
960     compositor->RemoveObserver(this);
961
962   if (vsync_manager_.get()) {
963     vsync_manager_->RemoveObserver(this);
964     vsync_manager_ = NULL;
965   }
966 }
967
968 void DelegatedFrameHost::LockResources() {
969   DCHECK(frame_provider_.get() || !surface_id_.is_null());
970   delegated_frame_evictor_->LockFrame();
971 }
972
973 void DelegatedFrameHost::UnlockResources() {
974   DCHECK(frame_provider_.get() || !surface_id_.is_null());
975   delegated_frame_evictor_->UnlockFrame();
976 }
977
978 ////////////////////////////////////////////////////////////////////////////////
979 // DelegatedFrameHost, ui::LayerOwnerDelegate implementation:
980
981 void DelegatedFrameHost::OnLayerRecreated(ui::Layer* old_layer,
982                                                 ui::Layer* new_layer) {
983   // The new_layer is the one that will be used by our Window, so that's the one
984   // that should keep our frame. old_layer will be returned to the
985   // RecreateLayer caller, and should have a copy.
986   if (frame_provider_.get()) {
987     new_layer->SetShowDelegatedContent(frame_provider_.get(),
988                                        current_frame_size_in_dip_);
989   }
990   if (!surface_id_.is_null()) {
991     new_layer->SetShowSurface(surface_id_, current_frame_size_in_dip_);
992   }
993 }
994
995 }  // namespace content