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