IndexedDBFactory now ForceCloses databases.
[chromium-blink-merge.git] / content / renderer / browser_plugin / browser_plugin_compositing_helper.cc
blob89916e2517276bd73ecf3596551f552ed0ef8a2e
1 // Copyright (c) 2013 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.
5 #include "content/renderer/browser_plugin/browser_plugin_compositing_helper.h"
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_manager.h"
20 #include "content/renderer/render_thread_impl.h"
21 #include "skia/ext/image_operations.h"
22 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
23 #include "third_party/WebKit/public/web/WebPluginContainer.h"
24 #include "third_party/khronos/GLES2/gl2.h"
25 #include "ui/gfx/size_conversions.h"
26 #include "ui/gfx/skia_util.h"
27 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
29 namespace content {
31 BrowserPluginCompositingHelper::SwapBuffersInfo::SwapBuffersInfo()
32 : route_id(0),
33 output_surface_id(0),
34 host_id(0),
35 software_frame_id(0),
36 shared_memory(NULL) {
39 BrowserPluginCompositingHelper::BrowserPluginCompositingHelper(
40 blink::WebPluginContainer* container,
41 BrowserPluginManager* manager,
42 int instance_id,
43 int host_routing_id)
44 : instance_id_(instance_id),
45 host_routing_id_(host_routing_id),
46 last_route_id_(0),
47 last_output_surface_id_(0),
48 last_host_id_(0),
49 last_mailbox_valid_(false),
50 ack_pending_(true),
51 software_ack_pending_(false),
52 opaque_(true),
53 container_(container),
54 browser_plugin_manager_(manager) {
57 BrowserPluginCompositingHelper::~BrowserPluginCompositingHelper() {
60 void BrowserPluginCompositingHelper::CopyFromCompositingSurface(
61 int request_id,
62 gfx::Rect source_rect,
63 gfx::Size dest_size) {
64 CHECK(background_layer_);
65 scoped_ptr<cc::CopyOutputRequest> request =
66 cc::CopyOutputRequest::CreateBitmapRequest(base::Bind(
67 &BrowserPluginCompositingHelper::CopyFromCompositingSurfaceHasResult,
68 this,
69 request_id,
70 dest_size));
71 request->set_area(source_rect);
72 background_layer_->RequestCopyOfOutput(request.Pass());
75 void BrowserPluginCompositingHelper::DidCommitCompositorFrame() {
76 if (software_ack_pending_) {
77 FrameHostMsg_CompositorFrameSwappedACK_Params params;
78 params.producing_host_id = last_host_id_;
79 params.producing_route_id = last_route_id_;
80 params.output_surface_id = last_output_surface_id_;
81 if (!unacked_software_frames_.empty()) {
82 params.ack.last_software_frame_id = unacked_software_frames_.back();
83 unacked_software_frames_.pop_back();
86 browser_plugin_manager_->Send(
87 new BrowserPluginHostMsg_CompositorFrameSwappedACK(
88 host_routing_id_,
89 instance_id_,
90 params));
92 software_ack_pending_ = false;
94 if (!resource_collection_.get() || !ack_pending_)
95 return;
97 FrameHostMsg_CompositorFrameSwappedACK_Params params;
98 params.producing_host_id = last_host_id_;
99 params.producing_route_id = last_route_id_;
100 params.output_surface_id = last_output_surface_id_;
101 resource_collection_->TakeUnusedResourcesForChildCompositor(
102 &params.ack.resources);
104 browser_plugin_manager_->Send(
105 new BrowserPluginHostMsg_CompositorFrameSwappedACK(
106 host_routing_id_,
107 instance_id_,
108 params));
110 ack_pending_ = false;
113 void BrowserPluginCompositingHelper::EnableCompositing(bool enable) {
114 if (enable && !background_layer_.get()) {
115 background_layer_ = cc::SolidColorLayer::Create();
116 background_layer_->SetMasksToBounds(true);
117 background_layer_->SetBackgroundColor(
118 SkColorSetARGBInline(255, 255, 255, 255));
119 web_layer_.reset(new webkit::WebLayerImpl(background_layer_));
122 container_->setWebLayer(enable ? web_layer_.get() : NULL);
125 void BrowserPluginCompositingHelper::CheckSizeAndAdjustLayerProperties(
126 const gfx::Size& new_size,
127 float device_scale_factor,
128 cc::Layer* layer) {
129 if (buffer_size_ != new_size) {
130 buffer_size_ = new_size;
131 // The container size is in DIP, so is the layer size.
132 // Buffer size is in physical pixels, so we need to adjust
133 // it by the device scale factor.
134 gfx::Size device_scale_adjusted_size = gfx::ToFlooredSize(
135 gfx::ScaleSize(buffer_size_, 1.0f / device_scale_factor));
136 layer->SetBounds(device_scale_adjusted_size);
139 // Manually manage background layer for transparent webview.
140 if (!opaque_)
141 background_layer_->SetIsDrawable(false);
144 void BrowserPluginCompositingHelper::MailboxReleased(
145 SwapBuffersInfo mailbox,
146 unsigned sync_point,
147 bool lost_resource) {
148 if (mailbox.type == SOFTWARE_COMPOSITOR_FRAME) {
149 delete mailbox.shared_memory;
150 mailbox.shared_memory = NULL;
151 } else if (lost_resource) {
152 // Reset mailbox's name if the resource was lost.
153 mailbox.name.SetZero();
156 // This means the GPU process crashed or guest crashed.
157 if (last_host_id_ != mailbox.host_id ||
158 last_output_surface_id_ != mailbox.output_surface_id ||
159 last_route_id_ != mailbox.route_id)
160 return;
162 if (mailbox.type == SOFTWARE_COMPOSITOR_FRAME)
163 unacked_software_frames_.push_back(mailbox.software_frame_id);
165 // We need to send an ACK to for every buffer sent to us.
166 // However, if a buffer is freed up from
167 // the compositor in cases like switching back to SW mode without a new
168 // buffer arriving, no ACK is needed.
169 if (!ack_pending_) {
170 last_mailbox_valid_ = false;
171 return;
173 ack_pending_ = false;
174 switch (mailbox.type) {
175 case TEXTURE_IMAGE_TRANSPORT: {
176 std::string mailbox_name(reinterpret_cast<const char*>(mailbox.name.name),
177 sizeof(mailbox.name.name));
178 FrameHostMsg_BuffersSwappedACK_Params params;
179 params.gpu_host_id = mailbox.host_id;
180 params.gpu_route_id = mailbox.route_id;
181 params.mailbox_name = mailbox_name;
182 params.sync_point = sync_point;
183 browser_plugin_manager_->Send(
184 new BrowserPluginHostMsg_BuffersSwappedACK(
185 host_routing_id_,
186 instance_id_,
187 params));
188 break;
190 case GL_COMPOSITOR_FRAME: {
191 FrameHostMsg_CompositorFrameSwappedACK_Params params;
192 params.producing_host_id = mailbox.host_id;
193 params.producing_route_id = mailbox.route_id;
194 params.output_surface_id = mailbox.output_surface_id;
195 params.ack.gl_frame_data.reset(new cc::GLFrameData());
196 params.ack.gl_frame_data->mailbox = mailbox.name;
197 params.ack.gl_frame_data->size = mailbox.size;
198 params.ack.gl_frame_data->sync_point = sync_point;
200 browser_plugin_manager_->Send(
201 new BrowserPluginHostMsg_CompositorFrameSwappedACK(
202 host_routing_id_,
203 instance_id_,
204 params));
205 break;
207 case SOFTWARE_COMPOSITOR_FRAME:
208 break;
212 void BrowserPluginCompositingHelper::OnContainerDestroy() {
213 if (container_)
214 container_->setWebLayer(NULL);
215 container_ = NULL;
217 if (resource_collection_)
218 resource_collection_->SetClient(NULL);
220 ack_pending_ = false;
221 software_ack_pending_ = false;
222 resource_collection_ = NULL;
223 frame_provider_ = NULL;
224 texture_layer_ = NULL;
225 delegated_layer_ = NULL;
226 background_layer_ = NULL;
227 web_layer_.reset();
230 void BrowserPluginCompositingHelper::OnBuffersSwappedPrivate(
231 const SwapBuffersInfo& mailbox,
232 unsigned sync_point,
233 float device_scale_factor) {
234 DCHECK(!delegated_layer_.get());
235 // If these mismatch, we are either just starting up, GPU process crashed or
236 // guest renderer crashed.
237 // In this case, we are communicating with a new image transport
238 // surface and must ACK with the new ID's and an empty mailbox.
239 if (last_route_id_ != mailbox.route_id ||
240 last_output_surface_id_ != mailbox.output_surface_id ||
241 last_host_id_ != mailbox.host_id)
242 last_mailbox_valid_ = false;
244 last_route_id_ = mailbox.route_id;
245 last_output_surface_id_ = mailbox.output_surface_id;
246 last_host_id_ = mailbox.host_id;
248 ack_pending_ = true;
249 // Browser plugin getting destroyed, do a fast ACK.
250 if (!background_layer_.get()) {
251 MailboxReleased(mailbox, sync_point, false);
252 return;
255 if (!texture_layer_.get()) {
256 texture_layer_ = cc::TextureLayer::CreateForMailbox(NULL);
257 texture_layer_->SetIsDrawable(true);
258 SetContentsOpaque(opaque_);
260 background_layer_->AddChild(texture_layer_);
263 // The size of browser plugin container is not always equal to the size
264 // of the buffer that arrives here. This could be for a number of reasons,
265 // including autosize and a resize in progress.
266 // During resize, the container size changes first and then some time
267 // later, a new buffer with updated size will arrive. During this process,
268 // we need to make sure that things are still displayed pixel perfect.
269 // We accomplish this by modifying bounds of the texture layer only
270 // when a new buffer arrives.
271 // Visually, this will either display a smaller part of the buffer
272 // or introduce a gutter around it.
273 CheckSizeAndAdjustLayerProperties(mailbox.size,
274 device_scale_factor,
275 texture_layer_.get());
277 bool is_software_frame = mailbox.type == SOFTWARE_COMPOSITOR_FRAME;
278 bool current_mailbox_valid = is_software_frame ?
279 mailbox.shared_memory != NULL : !mailbox.name.IsZero();
280 if (!is_software_frame && !last_mailbox_valid_) {
281 SwapBuffersInfo empty_info = mailbox;
282 empty_info.name.SetZero();
283 MailboxReleased(empty_info, 0, false);
284 if (!current_mailbox_valid)
285 return;
288 cc::TextureMailbox texture_mailbox;
289 scoped_ptr<cc::SingleReleaseCallback> release_callback;
290 if (current_mailbox_valid) {
291 release_callback = cc::SingleReleaseCallback::Create(
292 base::Bind(&BrowserPluginCompositingHelper::MailboxReleased,
293 scoped_refptr<BrowserPluginCompositingHelper>(this),
294 mailbox)).Pass();
295 if (is_software_frame)
296 texture_mailbox = cc::TextureMailbox(mailbox.shared_memory, mailbox.size);
297 else
298 texture_mailbox = cc::TextureMailbox(mailbox.name, sync_point);
301 texture_layer_->SetFlipped(!is_software_frame);
302 texture_layer_->SetTextureMailbox(texture_mailbox, release_callback.Pass());
303 texture_layer_->SetNeedsDisplay();
304 last_mailbox_valid_ = current_mailbox_valid;
307 void BrowserPluginCompositingHelper::OnBuffersSwapped(
308 const gfx::Size& size,
309 const std::string& mailbox_name,
310 int gpu_route_id,
311 int gpu_host_id,
312 float device_scale_factor) {
313 SwapBuffersInfo swap_info;
314 swap_info.name.SetName(reinterpret_cast<const int8*>(mailbox_name.data()));
315 swap_info.type = TEXTURE_IMAGE_TRANSPORT;
316 swap_info.size = size;
317 swap_info.route_id = gpu_route_id;
318 swap_info.output_surface_id = 0;
319 swap_info.host_id = gpu_host_id;
320 OnBuffersSwappedPrivate(swap_info, 0, device_scale_factor);
323 void BrowserPluginCompositingHelper::OnCompositorFrameSwapped(
324 scoped_ptr<cc::CompositorFrame> frame,
325 int route_id,
326 uint32 output_surface_id,
327 int host_id) {
328 if (frame->gl_frame_data) {
329 SwapBuffersInfo swap_info;
330 swap_info.name = frame->gl_frame_data->mailbox;
331 swap_info.type = GL_COMPOSITOR_FRAME;
332 swap_info.size = frame->gl_frame_data->size;
333 swap_info.route_id = route_id;
334 swap_info.output_surface_id = output_surface_id;
335 swap_info.host_id = host_id;
336 OnBuffersSwappedPrivate(swap_info,
337 frame->gl_frame_data->sync_point,
338 frame->metadata.device_scale_factor);
339 return;
342 if (frame->software_frame_data) {
343 cc::SoftwareFrameData* frame_data = frame->software_frame_data.get();
345 SwapBuffersInfo swap_info;
346 swap_info.type = SOFTWARE_COMPOSITOR_FRAME;
347 swap_info.size = frame_data->size;
348 swap_info.route_id = route_id;
349 swap_info.output_surface_id = output_surface_id;
350 swap_info.host_id = host_id;
351 swap_info.software_frame_id = frame_data->id;
353 scoped_ptr<base::SharedMemory> shared_memory(
354 new base::SharedMemory(frame_data->handle, true));
355 const size_t size_in_bytes = 4 * frame_data->size.GetArea();
356 if (!shared_memory->Map(size_in_bytes)) {
357 LOG(ERROR) << "Failed to map shared memory of size "
358 << size_in_bytes;
359 // Send ACK right away.
360 software_ack_pending_ = true;
361 MailboxReleased(swap_info, 0, false);
362 DidCommitCompositorFrame();
363 return;
366 swap_info.shared_memory = shared_memory.release();
367 OnBuffersSwappedPrivate(swap_info, 0,
368 frame->metadata.device_scale_factor);
369 software_ack_pending_ = true;
370 last_route_id_ = route_id;
371 last_output_surface_id_ = output_surface_id;
372 last_host_id_ = host_id;
373 return;
376 DCHECK(!texture_layer_.get());
378 cc::DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
379 // Do nothing if we are getting destroyed or have no frame data.
380 if (!frame_data || !background_layer_)
381 return;
383 DCHECK(!frame_data->render_pass_list.empty());
384 cc::RenderPass* root_pass = frame_data->render_pass_list.back();
385 gfx::Size frame_size = root_pass->output_rect.size();
387 if (last_route_id_ != route_id ||
388 last_output_surface_id_ != output_surface_id ||
389 last_host_id_ != host_id) {
390 // Resource ids are scoped by the output surface.
391 // If the originating output surface doesn't match the last one, it
392 // indicates the guest's output surface may have been recreated, in which
393 // case we should recreate the DelegatedRendererLayer, to avoid matching
394 // resources from the old one with resources from the new one which would
395 // have the same id.
396 frame_provider_ = NULL;
398 // Drop the cc::DelegatedFrameResourceCollection so that we will not return
399 // any resources from the old output surface with the new output surface id.
400 if (resource_collection_) {
401 resource_collection_->SetClient(NULL);
403 if (resource_collection_->LoseAllResources())
404 SendReturnedDelegatedResources();
405 resource_collection_ = NULL;
407 last_output_surface_id_ = output_surface_id;
408 last_route_id_ = route_id;
409 last_host_id_ = host_id;
411 if (!resource_collection_) {
412 resource_collection_ = new cc::DelegatedFrameResourceCollection;
413 resource_collection_->SetClient(this);
415 if (!frame_provider_.get() || frame_provider_->frame_size() != frame_size) {
416 frame_provider_ = new cc::DelegatedFrameProvider(
417 resource_collection_.get(), frame->delegated_frame_data.Pass());
418 if (delegated_layer_.get())
419 delegated_layer_->RemoveFromParent();
420 delegated_layer_ =
421 cc::DelegatedRendererLayer::Create(frame_provider_.get());
422 delegated_layer_->SetIsDrawable(true);
423 SetContentsOpaque(opaque_);
424 background_layer_->AddChild(delegated_layer_);
425 } else {
426 frame_provider_->SetFrameData(frame->delegated_frame_data.Pass());
429 CheckSizeAndAdjustLayerProperties(
430 frame_data->render_pass_list.back()->output_rect.size(),
431 frame->metadata.device_scale_factor,
432 delegated_layer_.get());
434 ack_pending_ = true;
437 void BrowserPluginCompositingHelper::UpdateVisibility(bool visible) {
438 if (texture_layer_.get())
439 texture_layer_->SetIsDrawable(visible);
440 if (delegated_layer_.get())
441 delegated_layer_->SetIsDrawable(visible);
444 void BrowserPluginCompositingHelper::UnusedResourcesAreAvailable() {
445 if (ack_pending_)
446 return;
448 SendReturnedDelegatedResources();
451 void BrowserPluginCompositingHelper::SendReturnedDelegatedResources() {
452 cc::CompositorFrameAck ack;
453 if (resource_collection_)
454 resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
455 DCHECK(!ack.resources.empty());
457 browser_plugin_manager_->Send(
458 new BrowserPluginHostMsg_ReclaimCompositorResources(
459 host_routing_id_,
460 instance_id_,
461 last_route_id_,
462 last_output_surface_id_,
463 last_host_id_,
464 ack));
467 void BrowserPluginCompositingHelper::SetContentsOpaque(bool opaque) {
468 opaque_ = opaque;
470 if (texture_layer_.get())
471 texture_layer_->SetContentsOpaque(opaque_);
472 if (delegated_layer_.get())
473 delegated_layer_->SetContentsOpaque(opaque_);
476 void BrowserPluginCompositingHelper::CopyFromCompositingSurfaceHasResult(
477 int request_id,
478 gfx::Size dest_size,
479 scoped_ptr<cc::CopyOutputResult> result) {
480 scoped_ptr<SkBitmap> bitmap;
481 if (result && result->HasBitmap() && !result->size().IsEmpty())
482 bitmap = result->TakeBitmap();
484 SkBitmap resized_bitmap;
485 if (bitmap) {
486 resized_bitmap = skia::ImageOperations::Resize(*bitmap,
487 skia::ImageOperations::RESIZE_BEST,
488 dest_size.width(),
489 dest_size.height());
491 browser_plugin_manager_->Send(
492 new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck(
493 host_routing_id_, instance_id_, request_id,
494 resized_bitmap));
497 } // namespace content