• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/renderer/child_frame_compositing_helper.h"
6 
7 #include "cc/layers/delegated_frame_provider.h"
8 #include "cc/layers/delegated_frame_resource_collection.h"
9 #include "cc/layers/delegated_renderer_layer.h"
10 #include "cc/layers/solid_color_layer.h"
11 #include "cc/layers/texture_layer.h"
12 #include "cc/output/context_provider.h"
13 #include "cc/output/copy_output_request.h"
14 #include "cc/output/copy_output_result.h"
15 #include "cc/resources/single_release_callback.h"
16 #include "content/common/browser_plugin/browser_plugin_messages.h"
17 #include "content/common/frame_messages.h"
18 #include "content/common/gpu/client/context_provider_command_buffer.h"
19 #include "content/renderer/browser_plugin/browser_plugin.h"
20 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
21 #include "content/renderer/compositor_bindings/web_layer_impl.h"
22 #include "content/renderer/render_frame_impl.h"
23 #include "content/renderer/render_frame_proxy.h"
24 #include "content/renderer/render_thread_impl.h"
25 #include "skia/ext/image_operations.h"
26 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
27 #include "third_party/WebKit/public/web/WebFrame.h"
28 #include "third_party/WebKit/public/web/WebPluginContainer.h"
29 #include "third_party/khronos/GLES2/gl2.h"
30 #include "ui/gfx/size_conversions.h"
31 #include "ui/gfx/skia_util.h"
32 
33 namespace content {
34 
SwapBuffersInfo()35 ChildFrameCompositingHelper::SwapBuffersInfo::SwapBuffersInfo()
36     : route_id(0),
37       output_surface_id(0),
38       host_id(0),
39       software_frame_id(0),
40       shared_memory(NULL) {}
41 
42 ChildFrameCompositingHelper*
CreateCompositingHelperForBrowserPlugin(const base::WeakPtr<BrowserPlugin> & browser_plugin)43 ChildFrameCompositingHelper::CreateCompositingHelperForBrowserPlugin(
44     const base::WeakPtr<BrowserPlugin>& browser_plugin) {
45   return new ChildFrameCompositingHelper(
46       browser_plugin, NULL, NULL, browser_plugin->render_view_routing_id());
47 }
48 
49 ChildFrameCompositingHelper*
CreateCompositingHelperForRenderFrame(blink::WebFrame * frame,RenderFrameProxy * render_frame_proxy,int host_routing_id)50 ChildFrameCompositingHelper::CreateCompositingHelperForRenderFrame(
51     blink::WebFrame* frame,
52     RenderFrameProxy* render_frame_proxy,
53     int host_routing_id) {
54   return new ChildFrameCompositingHelper(
55       base::WeakPtr<BrowserPlugin>(), frame, render_frame_proxy,
56       host_routing_id);
57 }
58 
ChildFrameCompositingHelper(const base::WeakPtr<BrowserPlugin> & browser_plugin,blink::WebFrame * frame,RenderFrameProxy * render_frame_proxy,int host_routing_id)59 ChildFrameCompositingHelper::ChildFrameCompositingHelper(
60     const base::WeakPtr<BrowserPlugin>& browser_plugin,
61     blink::WebFrame* frame,
62     RenderFrameProxy* render_frame_proxy,
63     int host_routing_id)
64     : host_routing_id_(host_routing_id),
65       last_route_id_(0),
66       last_output_surface_id_(0),
67       last_host_id_(0),
68       last_mailbox_valid_(false),
69       ack_pending_(true),
70       software_ack_pending_(false),
71       opaque_(true),
72       browser_plugin_(browser_plugin),
73       render_frame_proxy_(render_frame_proxy),
74       frame_(frame) {}
75 
~ChildFrameCompositingHelper()76 ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {}
77 
GetBrowserPluginManager()78 BrowserPluginManager* ChildFrameCompositingHelper::GetBrowserPluginManager() {
79   if (!browser_plugin_)
80     return NULL;
81 
82   return browser_plugin_->browser_plugin_manager();
83 }
84 
GetContainer()85 blink::WebPluginContainer* ChildFrameCompositingHelper::GetContainer() {
86   if (!browser_plugin_)
87     return NULL;
88 
89   return browser_plugin_->container();
90 }
91 
GetInstanceID()92 int ChildFrameCompositingHelper::GetInstanceID() {
93   if (!browser_plugin_)
94     return 0;
95 
96   return browser_plugin_->guest_instance_id();
97 }
98 
SendCompositorFrameSwappedACKToBrowser(FrameHostMsg_CompositorFrameSwappedACK_Params & params)99 void ChildFrameCompositingHelper::SendCompositorFrameSwappedACKToBrowser(
100     FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
101   // This function will be removed when BrowserPluginManager is removed and
102   // BrowserPlugin is modified to use a RenderFrame.
103   if (GetBrowserPluginManager()) {
104     GetBrowserPluginManager()->Send(
105         new BrowserPluginHostMsg_CompositorFrameSwappedACK(
106             host_routing_id_, GetInstanceID(), params));
107   } else if (render_frame_proxy_) {
108     render_frame_proxy_->Send(
109         new FrameHostMsg_CompositorFrameSwappedACK(host_routing_id_, params));
110   }
111 }
112 
SendBuffersSwappedACKToBrowser(FrameHostMsg_BuffersSwappedACK_Params & params)113 void ChildFrameCompositingHelper::SendBuffersSwappedACKToBrowser(
114     FrameHostMsg_BuffersSwappedACK_Params& params) {
115   // This function will be removed when BrowserPluginManager is removed and
116   // BrowserPlugin is modified to use a RenderFrame.
117   if (GetBrowserPluginManager()) {
118     GetBrowserPluginManager()->Send(new BrowserPluginHostMsg_BuffersSwappedACK(
119         host_routing_id_, params));
120   } else if (render_frame_proxy_) {
121     render_frame_proxy_->Send(
122         new FrameHostMsg_BuffersSwappedACK(host_routing_id_, params));
123   }
124 }
125 
SendReclaimCompositorResourcesToBrowser(FrameHostMsg_ReclaimCompositorResources_Params & params)126 void ChildFrameCompositingHelper::SendReclaimCompositorResourcesToBrowser(
127     FrameHostMsg_ReclaimCompositorResources_Params& params) {
128   // This function will be removed when BrowserPluginManager is removed and
129   // BrowserPlugin is modified to use a RenderFrame.
130   if (GetBrowserPluginManager()) {
131     GetBrowserPluginManager()->Send(
132         new BrowserPluginHostMsg_ReclaimCompositorResources(
133             host_routing_id_, GetInstanceID(), params));
134   } else if (render_frame_proxy_) {
135     render_frame_proxy_->Send(
136         new FrameHostMsg_ReclaimCompositorResources(host_routing_id_, params));
137   }
138 }
139 
CopyFromCompositingSurface(int request_id,gfx::Rect source_rect,gfx::Size dest_size)140 void ChildFrameCompositingHelper::CopyFromCompositingSurface(
141     int request_id,
142     gfx::Rect source_rect,
143     gfx::Size dest_size) {
144   CHECK(background_layer_);
145   scoped_ptr<cc::CopyOutputRequest> request =
146       cc::CopyOutputRequest::CreateBitmapRequest(base::Bind(
147           &ChildFrameCompositingHelper::CopyFromCompositingSurfaceHasResult,
148           this,
149           request_id,
150           dest_size));
151   request->set_area(source_rect);
152   background_layer_->RequestCopyOfOutput(request.Pass());
153 }
154 
DidCommitCompositorFrame()155 void ChildFrameCompositingHelper::DidCommitCompositorFrame() {
156   if (software_ack_pending_) {
157     FrameHostMsg_CompositorFrameSwappedACK_Params params;
158     params.producing_host_id = last_host_id_;
159     params.producing_route_id = last_route_id_;
160     params.output_surface_id = last_output_surface_id_;
161     if (!unacked_software_frames_.empty()) {
162       params.ack.last_software_frame_id = unacked_software_frames_.back();
163       unacked_software_frames_.pop_back();
164     }
165 
166     SendCompositorFrameSwappedACKToBrowser(params);
167 
168     software_ack_pending_ = false;
169   }
170   if (!resource_collection_.get() || !ack_pending_)
171     return;
172 
173   FrameHostMsg_CompositorFrameSwappedACK_Params params;
174   params.producing_host_id = last_host_id_;
175   params.producing_route_id = last_route_id_;
176   params.output_surface_id = last_output_surface_id_;
177   resource_collection_->TakeUnusedResourcesForChildCompositor(
178       &params.ack.resources);
179 
180   SendCompositorFrameSwappedACKToBrowser(params);
181 
182   ack_pending_ = false;
183 }
184 
EnableCompositing(bool enable)185 void ChildFrameCompositingHelper::EnableCompositing(bool enable) {
186   if (enable && !background_layer_.get()) {
187     background_layer_ = cc::SolidColorLayer::Create();
188     background_layer_->SetMasksToBounds(true);
189     background_layer_->SetBackgroundColor(
190         SkColorSetARGBInline(255, 255, 255, 255));
191     web_layer_.reset(new WebLayerImpl(background_layer_));
192   }
193 
194   if (GetContainer()) {
195     GetContainer()->setWebLayer(enable ? web_layer_.get() : NULL);
196   } else if (frame_) {
197     frame_->setRemoteWebLayer(enable ? web_layer_.get() : NULL);
198   }
199 }
200 
CheckSizeAndAdjustLayerProperties(const gfx::Size & new_size,float device_scale_factor,cc::Layer * layer)201 void ChildFrameCompositingHelper::CheckSizeAndAdjustLayerProperties(
202     const gfx::Size& new_size,
203     float device_scale_factor,
204     cc::Layer* layer) {
205   if (buffer_size_ != new_size) {
206     buffer_size_ = new_size;
207     // The container size is in DIP, so is the layer size.
208     // Buffer size is in physical pixels, so we need to adjust
209     // it by the device scale factor.
210     gfx::Size device_scale_adjusted_size = gfx::ToFlooredSize(
211         gfx::ScaleSize(buffer_size_, 1.0f / device_scale_factor));
212     layer->SetBounds(device_scale_adjusted_size);
213   }
214 
215   // Manually manage background layer for transparent webview.
216   if (!opaque_)
217     background_layer_->SetIsDrawable(false);
218 }
219 
MailboxReleased(SwapBuffersInfo mailbox,uint32 sync_point,bool lost_resource)220 void ChildFrameCompositingHelper::MailboxReleased(SwapBuffersInfo mailbox,
221                                                   uint32 sync_point,
222                                                   bool lost_resource) {
223   if (mailbox.type == SOFTWARE_COMPOSITOR_FRAME) {
224     delete mailbox.shared_memory;
225     mailbox.shared_memory = NULL;
226   } else if (lost_resource) {
227     // Reset mailbox's name if the resource was lost.
228     mailbox.name.SetZero();
229   }
230 
231   // This means the GPU process crashed or guest crashed.
232   if (last_host_id_ != mailbox.host_id ||
233       last_output_surface_id_ != mailbox.output_surface_id ||
234       last_route_id_ != mailbox.route_id)
235     return;
236 
237   if (mailbox.type == SOFTWARE_COMPOSITOR_FRAME)
238     unacked_software_frames_.push_back(mailbox.software_frame_id);
239 
240   // We need to send an ACK to for every buffer sent to us.
241   // However, if a buffer is freed up from
242   // the compositor in cases like switching back to SW mode without a new
243   // buffer arriving, no ACK is needed.
244   if (!ack_pending_) {
245     last_mailbox_valid_ = false;
246     return;
247   }
248   ack_pending_ = false;
249   switch (mailbox.type) {
250     case TEXTURE_IMAGE_TRANSPORT: {
251       FrameHostMsg_BuffersSwappedACK_Params params;
252       params.gpu_host_id = mailbox.host_id;
253       params.gpu_route_id = mailbox.route_id;
254       params.mailbox = mailbox.name;
255       params.sync_point = sync_point;
256       SendBuffersSwappedACKToBrowser(params);
257       break;
258     }
259     case GL_COMPOSITOR_FRAME: {
260       FrameHostMsg_CompositorFrameSwappedACK_Params params;
261       params.producing_host_id = mailbox.host_id;
262       params.producing_route_id = mailbox.route_id;
263       params.output_surface_id = mailbox.output_surface_id;
264       params.ack.gl_frame_data.reset(new cc::GLFrameData());
265       params.ack.gl_frame_data->mailbox = mailbox.name;
266       params.ack.gl_frame_data->size = mailbox.size;
267       params.ack.gl_frame_data->sync_point = sync_point;
268       SendCompositorFrameSwappedACKToBrowser(params);
269       break;
270     }
271     case SOFTWARE_COMPOSITOR_FRAME:
272       break;
273   }
274 }
275 
OnContainerDestroy()276 void ChildFrameCompositingHelper::OnContainerDestroy() {
277   if (GetContainer())
278     GetContainer()->setWebLayer(NULL);
279 
280   if (resource_collection_)
281     resource_collection_->SetClient(NULL);
282 
283   ack_pending_ = false;
284   software_ack_pending_ = false;
285   resource_collection_ = NULL;
286   frame_provider_ = NULL;
287   texture_layer_ = NULL;
288   delegated_layer_ = NULL;
289   background_layer_ = NULL;
290   web_layer_.reset();
291 }
292 
ChildFrameGone()293 void ChildFrameCompositingHelper::ChildFrameGone() {
294   background_layer_->SetBackgroundColor(SkColorSetARGBInline(255, 0, 128, 0));
295   background_layer_->RemoveAllChildren();
296   background_layer_->SetIsDrawable(true);
297   background_layer_->SetContentsOpaque(true);
298 }
299 
OnBuffersSwappedPrivate(const SwapBuffersInfo & mailbox,uint32 sync_point,float device_scale_factor)300 void ChildFrameCompositingHelper::OnBuffersSwappedPrivate(
301     const SwapBuffersInfo& mailbox,
302     uint32 sync_point,
303     float device_scale_factor) {
304   DCHECK(!delegated_layer_.get());
305   // If these mismatch, we are either just starting up, GPU process crashed or
306   // guest renderer crashed.
307   // In this case, we are communicating with a new image transport
308   // surface and must ACK with the new ID's and an empty mailbox.
309   if (last_route_id_ != mailbox.route_id ||
310       last_output_surface_id_ != mailbox.output_surface_id ||
311       last_host_id_ != mailbox.host_id)
312     last_mailbox_valid_ = false;
313 
314   last_route_id_ = mailbox.route_id;
315   last_output_surface_id_ = mailbox.output_surface_id;
316   last_host_id_ = mailbox.host_id;
317 
318   ack_pending_ = true;
319   // Browser plugin getting destroyed, do a fast ACK.
320   if (!background_layer_.get()) {
321     MailboxReleased(mailbox, sync_point, false);
322     return;
323   }
324 
325   if (!texture_layer_.get()) {
326     texture_layer_ = cc::TextureLayer::CreateForMailbox(NULL);
327     texture_layer_->SetIsDrawable(true);
328     SetContentsOpaque(opaque_);
329 
330     background_layer_->AddChild(texture_layer_);
331   }
332 
333   // The size of browser plugin container is not always equal to the size
334   // of the buffer that arrives here. This could be for a number of reasons,
335   // including autosize and a resize in progress.
336   // During resize, the container size changes first and then some time
337   // later, a new buffer with updated size will arrive. During this process,
338   // we need to make sure that things are still displayed pixel perfect.
339   // We accomplish this by modifying bounds of the texture layer only
340   // when a new buffer arrives.
341   // Visually, this will either display a smaller part of the buffer
342   // or introduce a gutter around it.
343   CheckSizeAndAdjustLayerProperties(
344       mailbox.size, device_scale_factor, texture_layer_.get());
345 
346   bool is_software_frame = mailbox.type == SOFTWARE_COMPOSITOR_FRAME;
347   bool current_mailbox_valid = is_software_frame ? mailbox.shared_memory != NULL
348                                                  : !mailbox.name.IsZero();
349   if (!is_software_frame && !last_mailbox_valid_) {
350     SwapBuffersInfo empty_info = mailbox;
351     empty_info.name.SetZero();
352     MailboxReleased(empty_info, 0, false);
353     if (!current_mailbox_valid)
354       return;
355   }
356 
357   cc::TextureMailbox texture_mailbox;
358   scoped_ptr<cc::SingleReleaseCallback> release_callback;
359   if (current_mailbox_valid) {
360     release_callback =
361         cc::SingleReleaseCallback::Create(
362             base::Bind(&ChildFrameCompositingHelper::MailboxReleased,
363                        scoped_refptr<ChildFrameCompositingHelper>(this),
364                        mailbox)).Pass();
365     if (is_software_frame) {
366       texture_mailbox = cc::TextureMailbox(mailbox.shared_memory, mailbox.size);
367     } else {
368       texture_mailbox =
369           cc::TextureMailbox(mailbox.name, GL_TEXTURE_2D, sync_point);
370     }
371   }
372 
373   texture_layer_->SetFlipped(!is_software_frame);
374   texture_layer_->SetTextureMailbox(texture_mailbox, release_callback.Pass());
375   texture_layer_->SetNeedsDisplay();
376   last_mailbox_valid_ = current_mailbox_valid;
377 }
378 
OnBuffersSwapped(const gfx::Size & size,const gpu::Mailbox & mailbox,int gpu_route_id,int gpu_host_id,float device_scale_factor)379 void ChildFrameCompositingHelper::OnBuffersSwapped(
380     const gfx::Size& size,
381     const gpu::Mailbox& mailbox,
382     int gpu_route_id,
383     int gpu_host_id,
384     float device_scale_factor) {
385   SwapBuffersInfo swap_info;
386   swap_info.name = mailbox;
387   swap_info.type = TEXTURE_IMAGE_TRANSPORT;
388   swap_info.size = size;
389   swap_info.route_id = gpu_route_id;
390   swap_info.output_surface_id = 0;
391   swap_info.host_id = gpu_host_id;
392   OnBuffersSwappedPrivate(swap_info, 0, device_scale_factor);
393 }
394 
OnCompositorFrameSwapped(scoped_ptr<cc::CompositorFrame> frame,int route_id,uint32 output_surface_id,int host_id,base::SharedMemoryHandle handle)395 void ChildFrameCompositingHelper::OnCompositorFrameSwapped(
396     scoped_ptr<cc::CompositorFrame> frame,
397     int route_id,
398     uint32 output_surface_id,
399     int host_id,
400     base::SharedMemoryHandle handle) {
401 
402   if (frame->gl_frame_data) {
403     SwapBuffersInfo swap_info;
404     swap_info.name = frame->gl_frame_data->mailbox;
405     swap_info.type = GL_COMPOSITOR_FRAME;
406     swap_info.size = frame->gl_frame_data->size;
407     swap_info.route_id = route_id;
408     swap_info.output_surface_id = output_surface_id;
409     swap_info.host_id = host_id;
410     OnBuffersSwappedPrivate(swap_info,
411                             frame->gl_frame_data->sync_point,
412                             frame->metadata.device_scale_factor);
413     return;
414   }
415 
416   if (frame->software_frame_data) {
417     cc::SoftwareFrameData* frame_data = frame->software_frame_data.get();
418 
419     SwapBuffersInfo swap_info;
420     swap_info.type = SOFTWARE_COMPOSITOR_FRAME;
421     swap_info.size = frame_data->size;
422     swap_info.route_id = route_id;
423     swap_info.output_surface_id = output_surface_id;
424     swap_info.host_id = host_id;
425     swap_info.software_frame_id = frame_data->id;
426 
427     scoped_ptr<base::SharedMemory> shared_memory(
428         new base::SharedMemory(handle, true));
429     const size_t size_in_bytes = 4 * frame_data->size.GetArea();
430     if (!shared_memory->Map(size_in_bytes)) {
431       LOG(ERROR) << "Failed to map shared memory of size " << size_in_bytes;
432       // Send ACK right away.
433       software_ack_pending_ = true;
434       MailboxReleased(swap_info, 0, false);
435       DidCommitCompositorFrame();
436       return;
437     }
438 
439     swap_info.shared_memory = shared_memory.release();
440     OnBuffersSwappedPrivate(swap_info, 0, frame->metadata.device_scale_factor);
441     software_ack_pending_ = true;
442     last_route_id_ = route_id;
443     last_output_surface_id_ = output_surface_id;
444     last_host_id_ = host_id;
445     return;
446   }
447 
448   DCHECK(!texture_layer_.get());
449 
450   cc::DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
451   // Do nothing if we are getting destroyed or have no frame data.
452   if (!frame_data || !background_layer_)
453     return;
454 
455   DCHECK(!frame_data->render_pass_list.empty());
456   cc::RenderPass* root_pass = frame_data->render_pass_list.back();
457   gfx::Size frame_size = root_pass->output_rect.size();
458 
459   if (last_route_id_ != route_id ||
460       last_output_surface_id_ != output_surface_id ||
461       last_host_id_ != host_id) {
462     // Resource ids are scoped by the output surface.
463     // If the originating output surface doesn't match the last one, it
464     // indicates the guest's output surface may have been recreated, in which
465     // case we should recreate the DelegatedRendererLayer, to avoid matching
466     // resources from the old one with resources from the new one which would
467     // have the same id.
468     frame_provider_ = NULL;
469 
470     // Drop the cc::DelegatedFrameResourceCollection so that we will not return
471     // any resources from the old output surface with the new output surface id.
472     if (resource_collection_) {
473       resource_collection_->SetClient(NULL);
474 
475       if (resource_collection_->LoseAllResources())
476         SendReturnedDelegatedResources();
477       resource_collection_ = NULL;
478     }
479     last_output_surface_id_ = output_surface_id;
480     last_route_id_ = route_id;
481     last_host_id_ = host_id;
482   }
483   if (!resource_collection_) {
484     resource_collection_ = new cc::DelegatedFrameResourceCollection;
485     resource_collection_->SetClient(this);
486   }
487   if (!frame_provider_.get() || frame_provider_->frame_size() != frame_size) {
488     frame_provider_ = new cc::DelegatedFrameProvider(
489         resource_collection_.get(), frame->delegated_frame_data.Pass());
490     if (delegated_layer_.get())
491       delegated_layer_->RemoveFromParent();
492     delegated_layer_ =
493         cc::DelegatedRendererLayer::Create(frame_provider_.get());
494     delegated_layer_->SetIsDrawable(true);
495     SetContentsOpaque(opaque_);
496     background_layer_->AddChild(delegated_layer_);
497   } else {
498     frame_provider_->SetFrameData(frame->delegated_frame_data.Pass());
499   }
500 
501   CheckSizeAndAdjustLayerProperties(
502       frame_data->render_pass_list.back()->output_rect.size(),
503       frame->metadata.device_scale_factor,
504       delegated_layer_.get());
505 
506   ack_pending_ = true;
507 }
508 
UpdateVisibility(bool visible)509 void ChildFrameCompositingHelper::UpdateVisibility(bool visible) {
510   if (texture_layer_.get())
511     texture_layer_->SetIsDrawable(visible);
512   if (delegated_layer_.get())
513     delegated_layer_->SetIsDrawable(visible);
514 }
515 
UnusedResourcesAreAvailable()516 void ChildFrameCompositingHelper::UnusedResourcesAreAvailable() {
517   if (ack_pending_)
518     return;
519 
520   SendReturnedDelegatedResources();
521 }
522 
SendReturnedDelegatedResources()523 void ChildFrameCompositingHelper::SendReturnedDelegatedResources() {
524   FrameHostMsg_ReclaimCompositorResources_Params params;
525   if (resource_collection_)
526     resource_collection_->TakeUnusedResourcesForChildCompositor(
527         &params.ack.resources);
528   DCHECK(!params.ack.resources.empty());
529 
530   params.route_id = last_route_id_;
531   params.output_surface_id = last_output_surface_id_;
532   params.renderer_host_id = last_host_id_;
533   SendReclaimCompositorResourcesToBrowser(params);
534 }
535 
SetContentsOpaque(bool opaque)536 void ChildFrameCompositingHelper::SetContentsOpaque(bool opaque) {
537   opaque_ = opaque;
538 
539   if (texture_layer_.get())
540     texture_layer_->SetContentsOpaque(opaque_);
541   if (delegated_layer_.get())
542     delegated_layer_->SetContentsOpaque(opaque_);
543 }
544 
CopyFromCompositingSurfaceHasResult(int request_id,gfx::Size dest_size,scoped_ptr<cc::CopyOutputResult> result)545 void ChildFrameCompositingHelper::CopyFromCompositingSurfaceHasResult(
546     int request_id,
547     gfx::Size dest_size,
548     scoped_ptr<cc::CopyOutputResult> result) {
549   scoped_ptr<SkBitmap> bitmap;
550   if (result && result->HasBitmap() && !result->size().IsEmpty())
551     bitmap = result->TakeBitmap();
552 
553   SkBitmap resized_bitmap;
554   if (bitmap) {
555     resized_bitmap =
556         skia::ImageOperations::Resize(*bitmap,
557                                       skia::ImageOperations::RESIZE_BEST,
558                                       dest_size.width(),
559                                       dest_size.height());
560   }
561   if (GetBrowserPluginManager()) {
562     GetBrowserPluginManager()->Send(
563         new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck(
564             host_routing_id_, GetInstanceID(), request_id, resized_bitmap));
565   }
566 }
567 
568 }  // namespace content
569