Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / compositor / delegated_frame_host.cc
index 4f1d43a..70b93ae 100644 (file)
 #include "cc/resources/texture_mailbox.h"
 #include "cc/surfaces/surface_factory.h"
 #include "content/browser/compositor/resize_lock.h"
+#include "content/browser/gpu/compositor_util.h"
 #include "content/common/gpu/client/gl_helper.h"
 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
 #include "content/public/common/content_switches.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
 #include "skia/ext/image_operations.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/effects/SkLumaColorFilter.h"
 #include "ui/gfx/frame_time.h"
 
 namespace content {
@@ -50,8 +54,7 @@ void DelegatedFrameHostClient::RequestCopyOfOutput(
 
 DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client)
     : client_(client),
-      use_surfaces_(base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kUseSurfaces)),
+      use_surfaces_(UseSurfacesEnabled()),
       last_output_surface_id_(0),
       pending_delegated_ack_count_(0),
       skipped_frames_(false),
@@ -63,7 +66,7 @@ DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client)
 void DelegatedFrameHost::WasShown(const ui::LatencyInfo& latency_info) {
   delegated_frame_evictor_->SetVisible(true);
 
-  if (surface_id_.is_null() && !frame_provider_ &&
+  if (surface_id_.is_null() && !frame_provider_.get() &&
       !released_front_lock_.get()) {
     ui::Compositor* compositor = client_->GetCompositor();
     if (compositor)
@@ -127,16 +130,24 @@ bool DelegatedFrameHost::ShouldCreateResizeLock() {
 
 void DelegatedFrameHost::RequestCopyOfOutput(
     scoped_ptr<cc::CopyOutputRequest> request) {
-  client_->GetLayer()->RequestCopyOfOutput(request.Pass());
+  if (use_surfaces_) {
+    if (surface_factory_ && !surface_id_.is_null())
+      surface_factory_->RequestCopyOfSurface(surface_id_, request.Pass());
+    else
+      request->SendEmptyResult();
+  } else {
+    client_->GetLayer()->RequestCopyOfOutput(request.Pass());
+  }
 }
 
 void DelegatedFrameHost::CopyFromCompositingSurface(
     const gfx::Rect& src_subrect,
     const gfx::Size& output_size,
-    const base::Callback<void(bool, const SkBitmap&)>& callback,
+    CopyFromCompositingSurfaceCallback& callback,
     const SkColorType color_type) {
   // Only ARGB888 and RGB565 supported as of now.
-  bool format_support = ((color_type == kRGB_565_SkColorType) ||
+  bool format_support = ((color_type == kAlpha_8_SkColorType) ||
+                         (color_type == kRGB_565_SkColorType) ||
                          (color_type == kN32_SkColorType));
   DCHECK(format_support);
   if (!CanCopyToBitmap()) {
@@ -350,9 +361,12 @@ void DelegatedFrameHost::SwapDelegatedFrame(
     }
     last_output_surface_id_ = output_surface_id;
   }
+  bool modified_layers = false;
+  ui::Compositor* compositor = client_->GetCompositor();
   if (frame_size.IsEmpty()) {
     DCHECK(frame_data->resource_list.empty());
     EvictDelegatedFrame();
+    modified_layers = true;
   } else {
     if (use_surfaces_) {
       if (!surface_factory_) {
@@ -364,19 +378,36 @@ void DelegatedFrameHost::SwapDelegatedFrame(
       }
       if (surface_id_.is_null() || frame_size != current_surface_size_ ||
           frame_size_in_dip != current_frame_size_in_dip_) {
+        // TODO(jbauman): Wait to destroy this surface until the parent has
+        // finished using it.
         if (!surface_id_.is_null())
           surface_factory_->Destroy(surface_id_);
         surface_id_ = id_allocator_->GenerateId();
         surface_factory_->Create(surface_id_, frame_size);
         client_->GetLayer()->SetShowSurface(surface_id_, frame_size_in_dip);
         current_surface_size_ = frame_size;
+        modified_layers = true;
       }
       scoped_ptr<cc::CompositorFrame> compositor_frame =
           make_scoped_ptr(new cc::CompositorFrame());
       compositor_frame->delegated_frame_data = frame_data.Pass();
-      surface_factory_->SubmitFrame(surface_id_, compositor_frame.Pass());
+
+      compositor_frame->metadata.latency_info.swap(skipped_latency_info_list_);
+      compositor_frame->metadata.latency_info.insert(
+          compositor_frame->metadata.latency_info.end(),
+          latency_info.begin(),
+          latency_info.end());
+
+      base::Closure ack_callback;
+      if (compositor) {
+        ack_callback = base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck,
+                                  AsWeakPtr(),
+                                  output_surface_id);
+      }
+      surface_factory_->SubmitFrame(
+          surface_id_, compositor_frame.Pass(), ack_callback);
     } else {
-      if (!resource_collection_) {
+      if (!resource_collection_.get()) {
         resource_collection_ = new cc::DelegatedFrameResourceCollection;
         resource_collection_->SetClient(this);
       }
@@ -395,20 +426,24 @@ void DelegatedFrameHost::SwapDelegatedFrame(
       } else {
         frame_provider_->SetFrameData(frame_data.Pass());
       }
+      modified_layers = true;
     }
   }
   released_front_lock_ = NULL;
   current_frame_size_in_dip_ = frame_size_in_dip;
   CheckResizeLock();
 
-  client_->SchedulePaintInRect(damage_rect_in_dip);
+  if (modified_layers && !damage_rect_in_dip.IsEmpty()) {
+    // TODO(jbauman): Need to always tell the window observer about the
+    // damage.
+    client_->GetLayer()->OnDelegatedFrameDamage(damage_rect_in_dip);
+  }
 
   pending_delegated_ack_count_++;
 
-  ui::Compositor* compositor = client_->GetCompositor();
   if (!compositor) {
     SendDelegatedFrameAck(output_surface_id);
-  } else {
+  } else if (!use_surfaces_) {
     std::vector<ui::LatencyInfo>::const_iterator it;
     for (it = latency_info.begin(); it != latency_info.end(); ++it)
       compositor->SetLatencyInfo(*it);
@@ -434,7 +469,7 @@ void DelegatedFrameHost::SendDelegatedFrameAck(uint32 output_surface_id) {
   cc::CompositorFrameAck ack;
   if (!surface_returned_resources_.empty())
     ack.resources.swap(surface_returned_resources_);
-  if (resource_collection_)
+  if (resource_collection_.get())
     resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
   RenderWidgetHostImpl::SendSwapCompositorFrameAck(host->GetRoutingID(),
                                                    output_surface_id,
@@ -459,7 +494,7 @@ void DelegatedFrameHost::SendReturnedDelegatedResources(
   if (!surface_returned_resources_.empty()) {
     ack.resources.swap(surface_returned_resources_);
   } else {
-    DCHECK(resource_collection_);
+    DCHECK(resource_collection_.get());
     resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources);
   }
   DCHECK(!ack.resources.empty());
@@ -504,6 +539,7 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
   }
 
   if (result->HasTexture()) {
+    // GPU-accelerated path
     PrepareTextureCopyOutputResult(dst_size_in_pixel, color_type,
                                    callback,
                                    result.Pass());
@@ -511,6 +547,7 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult(
   }
 
   DCHECK(result->HasBitmap());
+  // Software path
   PrepareBitmapCopyOutputResult(dst_size_in_pixel, color_type, callback,
                                 result.Pass());
 }
@@ -544,11 +581,14 @@ void DelegatedFrameHost::PrepareTextureCopyOutputResult(
   base::ScopedClosureRunner scoped_callback_runner(
       base::Bind(callback, false, SkBitmap()));
 
+  // TODO(sikugu): We should be able to validate the format here using
+  // GLHelper::IsReadbackConfigSupported before we processs the result.
+  // See crbug.com/415682.
   scoped_ptr<SkBitmap> bitmap(new SkBitmap);
-  if (!bitmap->allocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
-                                             dst_size_in_pixel.height(),
-                                             color_type,
-                                             kOpaque_SkAlphaType)))
+  if (!bitmap->tryAllocPixels(SkImageInfo::Make(dst_size_in_pixel.width(),
+                                                dst_size_in_pixel.height(),
+                                                color_type,
+                                                kOpaque_SkAlphaType)))
     return;
 
   ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
@@ -589,7 +629,7 @@ void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
     const SkColorType color_type,
     const base::Callback<void(bool, const SkBitmap&)>& callback,
     scoped_ptr<cc::CopyOutputResult> result) {
-  if (color_type != kN32_SkColorType) {
+  if (color_type != kN32_SkColorType && color_type != kAlpha_8_SkColorType) {
     NOTIMPLEMENTED();
     callback.Run(false, SkBitmap());
     return;
@@ -597,12 +637,41 @@ void DelegatedFrameHost::PrepareBitmapCopyOutputResult(
   DCHECK(result->HasBitmap());
   scoped_ptr<SkBitmap> source = result->TakeBitmap();
   DCHECK(source);
-  SkBitmap bitmap = skia::ImageOperations::Resize(
-      *source,
-      skia::ImageOperations::RESIZE_BEST,
-      dst_size_in_pixel.width(),
-      dst_size_in_pixel.height());
-  callback.Run(true, bitmap);
+  SkBitmap scaled_bitmap;
+  if (source->width() != dst_size_in_pixel.width() ||
+      source->height() != dst_size_in_pixel.height()) {
+    scaled_bitmap =
+        skia::ImageOperations::Resize(*source,
+                                      skia::ImageOperations::RESIZE_BEST,
+                                      dst_size_in_pixel.width(),
+                                      dst_size_in_pixel.height());
+  } else {
+    scaled_bitmap = *source;
+  }
+  if (color_type == kN32_SkColorType) {
+    DCHECK_EQ(scaled_bitmap.colorType(), kN32_SkColorType);
+    callback.Run(true, scaled_bitmap);
+    return;
+  }
+  DCHECK_EQ(color_type, kAlpha_8_SkColorType);
+  // The software path currently always returns N32 bitmap regardless of the
+  // |color_type| we ask for.
+  DCHECK_EQ(scaled_bitmap.colorType(), kN32_SkColorType);
+  // Paint |scaledBitmap| to alpha-only |grayscale_bitmap|.
+  SkBitmap grayscale_bitmap;
+  bool success = grayscale_bitmap.tryAllocPixels(
+      SkImageInfo::MakeA8(scaled_bitmap.width(), scaled_bitmap.height()));
+  if (!success) {
+    callback.Run(false, SkBitmap());
+    return;
+  }
+  SkCanvas canvas(grayscale_bitmap);
+  SkPaint paint;
+  skia::RefPtr<SkColorFilter> filter =
+      skia::AdoptRef(SkLumaColorFilter::Create());
+  paint.setColorFilter(filter.get());
+  canvas.drawBitmap(scaled_bitmap, SkIntToScalar(0), SkIntToScalar(0), &paint);
+  callback.Run(true, grayscale_bitmap);
 }
 
 // static
@@ -621,6 +690,7 @@ void DelegatedFrameHost::ReturnSubscriberTexture(
     dfh->idle_frame_subscriber_textures_.push_back(subscriber_texture);
 }
 
+// static
 void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
     base::WeakPtr<DelegatedFrameHost> dfh,
     const base::Callback<void(bool)>& callback,
@@ -637,7 +707,7 @@ void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
   if (release_callback) {
     // A release callback means the texture came from the compositor, so there
     // should be no |subscriber_texture|.
-    DCHECK(!subscriber_texture);
+    DCHECK(!subscriber_texture.get());
     bool lost_resource = sync_point == 0;
     release_callback->Run(sync_point, lost_resource);
   }
@@ -848,7 +918,7 @@ DelegatedFrameHost::~DelegatedFrameHost() {
   if (resource_collection_.get())
     resource_collection_->SetClient(NULL);
 
-  DCHECK(!vsync_manager_);
+  DCHECK(!vsync_manager_.get());
 }
 
 void DelegatedFrameHost::RunOnCommitCallbacks() {
@@ -875,7 +945,7 @@ void DelegatedFrameHost::AddOnCommitCallbackAndDisableLocks(
 void DelegatedFrameHost::AddedToWindow() {
   ui::Compositor* compositor = client_->GetCompositor();
   if (compositor) {
-    DCHECK(!vsync_manager_);
+    DCHECK(!vsync_manager_.get());
     vsync_manager_ = compositor->vsync_manager();
     vsync_manager_->AddObserver(this);
   }
@@ -889,19 +959,19 @@ void DelegatedFrameHost::RemovingFromWindow() {
   if (compositor && compositor->HasObserver(this))
     compositor->RemoveObserver(this);
 
-  if (vsync_manager_) {
+  if (vsync_manager_.get()) {
     vsync_manager_->RemoveObserver(this);
     vsync_manager_ = NULL;
   }
 }
 
 void DelegatedFrameHost::LockResources() {
-  DCHECK(frame_provider_ || !surface_id_.is_null());
+  DCHECK(frame_provider_.get() || !surface_id_.is_null());
   delegated_frame_evictor_->LockFrame();
 }
 
 void DelegatedFrameHost::UnlockResources() {
-  DCHECK(frame_provider_ || !surface_id_.is_null());
+  DCHECK(frame_provider_.get() || !surface_id_.is_null());
   delegated_frame_evictor_->UnlockFrame();
 }