ui: Move compositor/ directory out of gfx/, up to ui/.

BUG=104040
[email protected],[email protected]
[email protected]

Review URL: https://chromiumcodereview.appspot.com/10365007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@135560 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
new file mode 100644
index 0000000..8c9b1bda
--- /dev/null
+++ b/ui/compositor/compositor.cc
@@ -0,0 +1,354 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/compositor/compositor.h"
+
+#include "base/command_line.h"
+#include "base/threading/thread_restrictions.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositor.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebFloatPoint.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/images/SkImageEncoder.h"
+#include "ui/compositor/compositor_observer.h"
+#include "ui/compositor/compositor_switches.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/test_web_graphics_context_3d.h"
+#include "ui/gfx/gl/gl_context.h"
+#include "ui/gfx/gl/gl_implementation.h"
+#include "ui/gfx/gl/gl_surface.h"
+#include "webkit/glue/webthread_impl.h"
+#include "webkit/gpu/webgraphicscontext3d_in_process_impl.h"
+
+namespace {
+
+const double kDefaultRefreshRate = 60.0;
+const double kTestRefreshRate = 100.0;
+
+webkit_glue::WebThreadImpl* g_compositor_thread = NULL;
+
+bool test_compositor_enabled = false;
+
+ui::ContextFactory* g_context_factory = NULL;
+
+}  // anonymous namespace
+
+namespace ui {
+
+// static
+ContextFactory* ContextFactory::GetInstance() {
+  // We leak the shared resources so that we don't race with
+  // the tear down of the gl_bindings.
+  if (!g_context_factory) {
+    DVLOG(1) << "Using DefaultSharedResource";
+    scoped_ptr<DefaultContextFactory> instance(
+        new DefaultContextFactory());
+    if (instance->Initialize())
+      g_context_factory = instance.release();
+  }
+  return g_context_factory;
+}
+
+// static
+void ContextFactory::SetInstance(ContextFactory* instance) {
+  g_context_factory = instance;
+}
+
+DefaultContextFactory::DefaultContextFactory() {
+}
+
+DefaultContextFactory::~DefaultContextFactory() {
+}
+
+bool DefaultContextFactory::Initialize() {
+  // The following line of code exists soley to disable IO restrictions
+  // on this thread long enough to perform the GL bindings.
+  // TODO(wjmaclean) Remove this when GL initialisation cleaned up.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  if (!gfx::GLSurface::InitializeOneOff() ||
+      gfx::GetGLImplementation() == gfx::kGLImplementationNone) {
+    LOG(ERROR) << "Could not load the GL bindings";
+    return false;
+  }
+  return true;
+}
+
+WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateContext(
+    Compositor* compositor) {
+  return CreateContextCommon(compositor, false);
+}
+
+WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateOffscreenContext(
+    Compositor* compositor) {
+  return CreateContextCommon(compositor, true);
+}
+
+void DefaultContextFactory::RemoveCompositor(Compositor* compositor) {
+}
+
+WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateContextCommon(
+    Compositor* compositor,
+    bool offscreen) {
+  WebKit::WebGraphicsContext3D::Attributes attrs;
+  attrs.shareResources = true;
+  WebKit::WebGraphicsContext3D* context =
+      offscreen ?
+      webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWebView(
+          attrs, false) :
+      webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWindow(
+          attrs, compositor->widget(), share_group_.get());
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (!command_line->HasSwitch(switches::kDisableUIVsync)) {
+    context->makeContextCurrent();
+    gfx::GLContext* gl_context = gfx::GLContext::GetCurrent();
+    gl_context->SetSwapInterval(1);
+    gl_context->ReleaseCurrent(NULL);
+  }
+  return context;
+}
+
+Texture::Texture(bool flipped, const gfx::Size& size)
+    : texture_id_(0),
+      flipped_(flipped),
+      size_(size) {
+}
+
+Texture::~Texture() {
+}
+
+Compositor::Compositor(CompositorDelegate* delegate,
+                       gfx::AcceleratedWidget widget,
+                       const gfx::Size& size)
+    : delegate_(delegate),
+      size_(size),
+      root_layer_(NULL),
+      widget_(widget),
+      root_web_layer_(WebKit::WebLayer::create()),
+      swap_posted_(false) {
+  WebKit::WebLayerTreeView::Settings settings;
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  settings.showFPSCounter =
+      command_line->HasSwitch(switches::kUIShowFPSCounter);
+  settings.showPlatformLayerTree =
+      command_line->HasSwitch(switches::kUIShowLayerTree);
+  settings.refreshRate = test_compositor_enabled ?
+      kTestRefreshRate : kDefaultRefreshRate;
+  settings.partialSwapEnabled =
+      command_line->HasSwitch(switches::kUIEnablePartialSwap);
+  settings.perTilePainting =
+    command_line->HasSwitch(switches::kUIEnablePerTilePainting);
+
+  host_.initialize(this, root_web_layer_, settings);
+  root_web_layer_.setAnchorPoint(WebKit::WebFloatPoint(0.f, 0.f));
+  WidgetSizeChanged(size_);
+}
+
+Compositor::~Compositor() {
+  // There's a cycle between |root_web_layer_| and |host_|, which results in
+  // leaking and/or crashing. Explicitly set the root layer to NULL so the cycle
+  // is broken.
+  host_.setRootLayer(NULL);
+  if (root_layer_)
+    root_layer_->SetCompositor(NULL);
+  if (!test_compositor_enabled)
+    ContextFactory::GetInstance()->RemoveCompositor(this);
+}
+
+void Compositor::Initialize(bool use_thread) {
+  if (use_thread)
+    g_compositor_thread = new webkit_glue::WebThreadImpl("Browser Compositor");
+  WebKit::WebCompositor::initialize(g_compositor_thread);
+}
+
+void Compositor::Terminate() {
+  WebKit::WebCompositor::shutdown();
+  if (g_compositor_thread) {
+    delete g_compositor_thread;
+    g_compositor_thread = NULL;
+  }
+}
+
+void Compositor::ScheduleDraw() {
+  if (g_compositor_thread) {
+    // TODO(nduca): Temporary while compositor calls
+    // compositeImmediately() directly.
+    layout();
+    host_.composite();
+  } else {
+    delegate_->ScheduleDraw();
+  }
+}
+
+void Compositor::SetRootLayer(Layer* root_layer) {
+  if (root_layer_ == root_layer)
+    return;
+  if (root_layer_)
+    root_layer_->SetCompositor(NULL);
+  root_layer_ = root_layer;
+  if (root_layer_ && !root_layer_->GetCompositor())
+    root_layer_->SetCompositor(this);
+  root_web_layer_.removeAllChildren();
+  if (root_layer_)
+    root_web_layer_.addChild(root_layer_->web_layer());
+}
+
+void Compositor::Draw(bool force_clear) {
+  if (!root_layer_)
+    return;
+
+  // TODO(nduca): Temporary while compositor calls
+  // compositeImmediately() directly.
+  layout();
+  host_.composite();
+  if (!g_compositor_thread && !swap_posted_)
+    NotifyEnd();
+}
+
+void Compositor::ScheduleFullDraw() {
+  host_.setNeedsRedraw();
+}
+
+bool Compositor::ReadPixels(SkBitmap* bitmap, const gfx::Rect& bounds) {
+  if (bounds.right() > size().width() || bounds.bottom() > size().height())
+    return false;
+  // Convert to OpenGL coordinates.
+  gfx::Point new_origin(bounds.x(),
+                        size().height() - bounds.height() - bounds.y());
+
+  bitmap->setConfig(SkBitmap::kARGB_8888_Config,
+                    bounds.width(), bounds.height());
+  bitmap->allocPixels();
+  SkAutoLockPixels lock_image(*bitmap);
+  unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels());
+  if (host_.compositeAndReadback(pixels,
+                                 gfx::Rect(new_origin, bounds.size()))) {
+    SwizzleRGBAToBGRAAndFlip(pixels, bounds.size());
+    return true;
+  }
+  return false;
+}
+
+void Compositor::WidgetSizeChanged(const gfx::Size& size) {
+  if (size.IsEmpty())
+    return;
+  size_ = size;
+  host_.setViewportSize(size_);
+  root_web_layer_.setBounds(size_);
+}
+
+void Compositor::AddObserver(CompositorObserver* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void Compositor::RemoveObserver(CompositorObserver* observer) {
+  observer_list_.RemoveObserver(observer);
+}
+
+bool Compositor::HasObserver(CompositorObserver* observer) {
+  return observer_list_.HasObserver(observer);
+}
+
+void Compositor::OnSwapBuffersPosted() {
+  swap_posted_ = true;
+}
+
+void Compositor::OnSwapBuffersComplete() {
+  DCHECK(swap_posted_);
+  swap_posted_ = false;
+  NotifyEnd();
+}
+
+void Compositor::OnSwapBuffersAborted() {
+  if (swap_posted_) {
+    swap_posted_ = false;
+    NotifyEnd();
+  }
+}
+
+void Compositor::updateAnimations(double frameBeginTime) {
+}
+
+void Compositor::layout() {
+  if (root_layer_)
+    root_layer_->SendDamagedRects();
+}
+
+void Compositor::applyScrollAndScale(const WebKit::WebSize& scrollDelta,
+                                     float scaleFactor) {
+}
+
+WebKit::WebGraphicsContext3D* Compositor::createContext3D() {
+  if (test_compositor_enabled) {
+    ui::TestWebGraphicsContext3D* test_context =
+      new ui::TestWebGraphicsContext3D();
+   test_context->Initialize();
+   return test_context;
+  } else {
+    return ContextFactory::GetInstance()->CreateContext(this);
+  }
+}
+
+void Compositor::didRebindGraphicsContext(bool success) {
+}
+
+void Compositor::didCommitAndDrawFrame() {
+  FOR_EACH_OBSERVER(CompositorObserver,
+                    observer_list_,
+                    OnCompositingStarted(this));
+}
+
+void Compositor::didCompleteSwapBuffers() {
+  NotifyEnd();
+}
+
+void Compositor::scheduleComposite() {
+  ScheduleDraw();
+}
+
+void Compositor::SwizzleRGBAToBGRAAndFlip(unsigned char* pixels,
+                                          const gfx::Size& image_size) {
+  // Swizzle from RGBA to BGRA
+  size_t bitmap_size = 4 * image_size.width() * image_size.height();
+  for(size_t i = 0; i < bitmap_size; i += 4)
+    std::swap(pixels[i], pixels[i + 2]);
+
+  // Vertical flip to transform from GL co-ords
+  size_t row_size = 4 * image_size.width();
+  scoped_array<unsigned char> tmp_row(new unsigned char[row_size]);
+  for(int row = 0; row < image_size.height() / 2; row++) {
+    memcpy(tmp_row.get(),
+           &pixels[row * row_size],
+           row_size);
+    memcpy(&pixels[row * row_size],
+           &pixels[bitmap_size - (row + 1) * row_size],
+           row_size);
+    memcpy(&pixels[bitmap_size - (row + 1) * row_size],
+           tmp_row.get(),
+           row_size);
+  }
+}
+
+void Compositor::NotifyEnd() {
+  FOR_EACH_OBSERVER(CompositorObserver,
+                    observer_list_,
+                    OnCompositingEnded(this));
+}
+
+COMPOSITOR_EXPORT void SetupTestCompositor() {
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kDisableTestCompositor)) {
+    test_compositor_enabled = true;
+  }
+}
+
+COMPOSITOR_EXPORT void DisableTestCompositor() {
+  test_compositor_enabled = false;
+}
+
+COMPOSITOR_EXPORT bool IsTestCompositorEnabled() {
+  return test_compositor_enabled;
+}
+
+}  // namespace ui