summaryrefslogtreecommitdiffstats
path: root/content/browser/aura/reflector_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser/aura/reflector_impl.cc')
-rw-r--r--content/browser/aura/reflector_impl.cc182
1 files changed, 182 insertions, 0 deletions
diff --git a/content/browser/aura/reflector_impl.cc b/content/browser/aura/reflector_impl.cc
new file mode 100644
index 0000000..6d8e89d
--- /dev/null
+++ b/content/browser/aura/reflector_impl.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2013 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 "content/browser/aura/reflector_impl.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "content/browser/aura/browser_compositor_output_surface.h"
+#include "content/common/gpu/client/gl_helper.h"
+#include "ui/compositor/layer.h"
+
+namespace content {
+
+ReflectorImpl::ReflectorImpl(
+ ui::Compositor* mirrored_compositor,
+ ui::Layer* mirroring_layer,
+ IDMap<BrowserCompositorOutputSurface>* output_surface_map,
+ int surface_id)
+ : texture_id_(0),
+ texture_size_(mirrored_compositor->size()),
+ output_surface_map_(output_surface_map),
+ mirrored_compositor_(mirrored_compositor),
+ mirroring_compositor_(mirroring_layer->GetCompositor()),
+ mirroring_layer_(mirroring_layer),
+ impl_message_loop_(ui::Compositor::GetCompositorMessageLoop()),
+ main_message_loop_(base::MessageLoopProxy::current()),
+ surface_id_(surface_id) {
+ CreateSharedTexture();
+ impl_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&ReflectorImpl::InitOnImplThread, this));
+}
+
+void ReflectorImpl::InitOnImplThread() {
+ // Ignore if the reflector was shutdown before
+ // initialized, or it's already initialized.
+ if (!output_surface_map_ || gl_helper_.get())
+ return;
+
+ BrowserCompositorOutputSurface* source_surface =
+ output_surface_map_->Lookup(surface_id_);
+ // Skip if the source surface isn't ready yet. This will be
+ // initiailze when the source surface becomes ready.
+ if (!source_surface)
+ return;
+
+ AttachToOutputSurface(source_surface);
+ gl_helper_->CopyTextureFullImage(texture_id_, texture_size_);
+ // The shared texture doesn't have the data, so invokes full redraw
+ // now.
+ main_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&ReflectorImpl::FullRedrawContentOnMainThread,
+ scoped_refptr<ReflectorImpl>(this)));
+}
+
+void ReflectorImpl::OnSourceSurfaceReady(int surface_id) {
+ DCHECK_EQ(surface_id_, surface_id);
+ InitOnImplThread();
+}
+
+void ReflectorImpl::Shutdown() {
+ mirroring_compositor_ = NULL;
+ mirroring_layer_ = NULL;
+ shared_texture_ = NULL;
+ impl_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&ReflectorImpl::ShutdownOnImplThread, this));
+}
+
+void ReflectorImpl::ShutdownOnImplThread() {
+ BrowserCompositorOutputSurface* output_surface =
+ output_surface_map_->Lookup(surface_id_);
+ if (output_surface)
+ output_surface->SetReflector(NULL);
+ output_surface_map_ = NULL;
+ gl_helper_.reset();
+ // The instance must be deleted on main thread.
+ main_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&ReflectorImpl::DeleteOnMainThread,
+ scoped_refptr<ReflectorImpl>(this)));
+}
+
+// This must be called on ImplThread, or before the surface is passed to
+// ImplThread.
+void ReflectorImpl::AttachToOutputSurface(
+ BrowserCompositorOutputSurface* output_surface) {
+ gl_helper_.reset(
+ new GLHelper(output_surface->context_provider()->ContextGL(),
+ output_surface->context_provider()->ContextSupport()));
+ output_surface->SetReflector(this);
+}
+
+void ReflectorImpl::OnMirroringCompositorResized() {
+ mirroring_compositor_->ScheduleFullRedraw();
+}
+
+void ReflectorImpl::OnLostResources() {
+ shared_texture_ = NULL;
+ mirroring_layer_->SetShowPaintedContent();
+}
+
+void ReflectorImpl::OnReshape(gfx::Size size) {
+ if (texture_size_ == size)
+ return;
+ texture_size_ = size;
+ DCHECK(texture_id_);
+ gl_helper_->ResizeTexture(texture_id_, size);
+ main_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&ReflectorImpl::UpdateTextureSizeOnMainThread,
+ this->AsWeakPtr(),
+ texture_size_));
+}
+
+void ReflectorImpl::OnSwapBuffers() {
+ DCHECK(texture_id_);
+ gl_helper_->CopyTextureFullImage(texture_id_, texture_size_);
+ main_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&ReflectorImpl::FullRedrawOnMainThread,
+ this->AsWeakPtr(),
+ texture_size_));
+}
+
+void ReflectorImpl::OnPostSubBuffer(gfx::Rect rect) {
+ DCHECK(texture_id_);
+ gl_helper_->CopyTextureSubImage(texture_id_, rect);
+ main_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&ReflectorImpl::UpdateSubBufferOnMainThread,
+ this->AsWeakPtr(),
+ texture_size_,
+ rect));
+}
+
+void ReflectorImpl::CreateSharedTexture() {
+ texture_id_ =
+ ImageTransportFactory::GetInstance()->GetGLHelper()->CreateTexture();
+ shared_texture_ =
+ ImageTransportFactory::GetInstance()->CreateOwnedTexture(
+ texture_size_, 1.0f, texture_id_);
+ mirroring_layer_->SetExternalTexture(shared_texture_.get());
+}
+
+ReflectorImpl::~ReflectorImpl() {
+ // Make sure the reflector is deleted on main thread.
+ DCHECK_EQ(main_message_loop_.get(),
+ base::MessageLoopProxy::current().get());
+}
+
+void ReflectorImpl::UpdateTextureSizeOnMainThread(gfx::Size size) {
+ if (!mirroring_layer_)
+ return;
+ mirroring_layer_->SetBounds(gfx::Rect(size));
+}
+
+void ReflectorImpl::FullRedrawOnMainThread(gfx::Size size) {
+ if (!mirroring_compositor_)
+ return;
+ UpdateTextureSizeOnMainThread(size);
+ mirroring_compositor_->ScheduleFullRedraw();
+}
+
+void ReflectorImpl::UpdateSubBufferOnMainThread(gfx::Size size,
+ gfx::Rect rect) {
+ if (!mirroring_compositor_)
+ return;
+ UpdateTextureSizeOnMainThread(size);
+ // Flip the coordinates to compositor's one.
+ int y = size.height() - rect.y() - rect.height();
+ gfx::Rect new_rect(rect.x(), y, rect.width(), rect.height());
+ mirroring_layer_->SchedulePaint(new_rect);
+}
+
+void ReflectorImpl::FullRedrawContentOnMainThread() {
+ mirrored_compositor_->ScheduleFullRedraw();
+}
+
+} // namespace content