Home | History | Annotate | Download | only in renderer
      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 
     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*
     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*
     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 
     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 
     76 ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {}
     77 
     78 BrowserPluginManager* ChildFrameCompositingHelper::GetBrowserPluginManager() {
     79   if (!browser_plugin_)
     80     return NULL;
     81 
     82   return browser_plugin_->browser_plugin_manager();
     83 }
     84 
     85 blink::WebPluginContainer* ChildFrameCompositingHelper::GetContainer() {
     86   if (!browser_plugin_)
     87     return NULL;
     88 
     89   return browser_plugin_->container();
     90 }
     91 
     92 int ChildFrameCompositingHelper::GetInstanceID() {
     93   if (!browser_plugin_)
     94     return 0;
     95 
     96   return browser_plugin_->guest_instance_id();
     97 }
     98 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    516 void ChildFrameCompositingHelper::UnusedResourcesAreAvailable() {
    517   if (ack_pending_)
    518     return;
    519 
    520   SendReturnedDelegatedResources();
    521 }
    522 
    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 
    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 
    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