Chromium Code Reviews| Index: android_webview/browser/test/fake_view_root_impl.cc |
| diff --git a/android_webview/browser/test/fake_view_root_impl.cc b/android_webview/browser/test/fake_view_root_impl.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..20725803a5f173e6cf8387195075e2ebc300e5cd |
| --- /dev/null |
| +++ b/android_webview/browser/test/fake_view_root_impl.cc |
| @@ -0,0 +1,215 @@ |
| +// Copyright 2014 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 "android_webview/browser/test/fake_view_root_impl.h" |
| + |
| +#include "android_webview/browser/browser_view_renderer.h" |
| +#include "android_webview/public/browser/draw_gl.h" |
| +#include "base/message_loop/message_loop_proxy.h" |
| +#include "base/synchronization/waitable_event.h" |
| +#include "base/threading/thread.h" |
| +#include "ui/gl/gl_bindings.h" |
| + |
| +namespace android_webview { |
| + |
| +class FakeViewRootImpl::ScopedMakeCurrent { |
| + public: |
| + ScopedMakeCurrent(FakeViewRootImpl* view_root) : view_root_(view_root) { |
| + DCHECK(!view_root_->context_current_); |
| + view_root_->context_current_ = true; |
| + bool result = view_root_->context_->MakeCurrent(view_root_->surface_.get()); |
| + DCHECK(result); |
| + }; |
| + |
| + ~ScopedMakeCurrent() { |
| + DCHECK(view_root_->context_current_); |
| + view_root_->context_current_ = false; |
| + |
| + // Release the underlying EGLContext. This is required because the real |
| + // GLContextEGL may no longer be current here and to satisfy DCHECK in |
| + // GLContextEGL::IsCurrent. |
| + eglMakeCurrent(view_root_->surface_->GetDisplay(), EGL_NO_SURFACE, |
| + EGL_NO_SURFACE, EGL_NO_CONTEXT); |
| + view_root_->context_->ReleaseCurrent(view_root_->surface_.get()); |
| + } |
| + |
| + private: |
| + FakeViewRootImpl* view_root_; |
| +}; |
| + |
| +FakeViewRootImpl::FakeViewRootImpl(BrowserViewRenderer* view, |
| + ViewRootHooks* hooks, |
| + gfx::Rect location) |
| + : view_(view), |
| + hooks_(hooks), |
| + surface_size_(100, 100), |
| + location_(location), |
| + on_draw_hardware_pending_(false), |
| + functor_(nullptr), |
| + context_current_(false), |
| + weak_ptr_factory_(this) { |
| + DCHECK(view_); |
| + view_->OnAttachedToWindow(location_.width(), location_.height()); |
| +} |
| + |
| +FakeViewRootImpl::~FakeViewRootImpl() { |
| +} |
| + |
| +void FakeViewRootImpl::Detach() { |
| + view_->OnDetachedFromWindow(); |
| + |
| + if (render_thread_loop_) { |
| + base::WaitableEvent completion(true, false); |
| + render_thread_loop_->PostTask( |
| + FROM_HERE, base::Bind(&FakeViewRootImpl::DestroyOnRT, |
| + base::Unretained(this), &completion)); |
| + completion.Wait(); |
| + } |
| + |
| + render_thread_.reset(); |
| + functor_ = nullptr; |
| +} |
| + |
| +void FakeViewRootImpl::RequestDrawGL(bool wait_for_completion) { |
| + base::WaitableEvent completion(true, false); |
| + render_thread_loop_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&FakeViewRootImpl::ProcessFunctorOnRT, base::Unretained(this), |
| + wait_for_completion ? &completion : nullptr)); |
| + if (wait_for_completion) |
| + completion.Wait(); |
| +} |
| + |
| +void FakeViewRootImpl::ProcessFunctorOnRT(base::WaitableEvent* sync) { |
| + AwDrawGLInfo process_info; |
| + process_info.version = kAwDrawGLInfoVersion; |
| + process_info.mode = AwDrawGLInfo::kModeProcess; |
| + |
| + hooks_->WillProcessOnRT(functor_); |
| + { |
| + ScopedMakeCurrent make_current(this); |
| + functor_->DrawGL(&process_info); |
| + } |
| + hooks_->DidProcessOnRT(functor_); |
| + |
| + if (sync) |
| + sync->Signal(); |
| +} |
| + |
| +void FakeViewRootImpl::PostInvalidate() { |
| + if (on_draw_hardware_pending_) |
| + return; |
| + on_draw_hardware_pending_ = true; |
|
hush (inactive)
2014/12/10 20:07:58
could there be a race condition with line 111?
Pos
boliu
2014/12/10 21:30:32
PostInvalidate and OnDrawHardware are both called
|
| + base::MessageLoopProxy::current()->PostTask( |
| + FROM_HERE, base::Bind(&FakeViewRootImpl::OnDrawHardware, |
| + weak_ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void FakeViewRootImpl::OnDrawHardware() { |
| + DCHECK(on_draw_hardware_pending_); |
| + on_draw_hardware_pending_ = false; |
| + |
| + bool success = view_->OnDrawHardware(); |
| + if (success) { |
| + CheckRenderThread(); |
| + |
| + base::WaitableEvent completion(true, false); |
| + render_thread_loop_->PostTask( |
| + FROM_HERE, base::Bind(&FakeViewRootImpl::DrawFunctorOnRT, |
| + base::Unretained(this), &completion)); |
| + completion.Wait(); |
| + } |
| +} |
| + |
| +void FakeViewRootImpl::DrawFunctorOnRT(base::WaitableEvent* sync) { |
| + // Ok to access UI functions until sync is signalled. |
| + gfx::Rect location = location_; |
| + { |
|
hush (inactive)
2014/12/10 20:07:58
why is this in its own block?
boliu
2014/12/10 21:30:32
So AwDrawGLInfo can't be reused for the kModeDraw
|
| + AwDrawGLInfo process_info; |
| + process_info.version = kAwDrawGLInfoVersion; |
| + process_info.mode = AwDrawGLInfo::kModeSync; |
| + |
| + hooks_->WillSyncOnRT(functor_); |
| + functor_->DrawGL(&process_info); |
| + hooks_->DidSyncOnRT(functor_); |
| + } |
| + sync->Signal(); |
| + |
| + AwDrawGLInfo draw_info; |
| + draw_info.version = kAwDrawGLInfoVersion; |
| + draw_info.mode = AwDrawGLInfo::kModeDraw; |
| + draw_info.clip_left = location.x(); |
|
hush (inactive)
2014/12/10 20:07:58
just use location_ in this function?
boliu
2014/12/10 21:30:32
I imagined location_ to be UI only.
|
| + draw_info.clip_top = location.y(); |
| + draw_info.clip_right = location.x() + location.width(); |
| + draw_info.clip_bottom = location.y() + location.height(); |
| + draw_info.width = surface_size_.width(); |
| + draw_info.height = surface_size_.height(); |
| + draw_info.is_layer = false; |
| + |
| + draw_info.transform[0] = 1.0; |
| + draw_info.transform[1] = 0.0; |
| + draw_info.transform[2] = 0.0; |
| + draw_info.transform[3] = 0.0; |
| + |
| + draw_info.transform[4] = 0.0; |
| + draw_info.transform[5] = 1.0; |
| + draw_info.transform[6] = 0.0; |
| + draw_info.transform[7] = 0.0; |
| + |
| + draw_info.transform[8] = 0.0; |
| + draw_info.transform[9] = 0.0; |
| + draw_info.transform[10] = 1.0; |
| + draw_info.transform[11] = 0.0; |
| + |
| + draw_info.transform[12] = 0.0; |
| + draw_info.transform[13] = 0.0; |
| + draw_info.transform[14] = 0.0; |
| + draw_info.transform[15] = 1.0; |
| + |
| + hooks_->WillDrawOnRT(functor_); |
| + { |
| + ScopedMakeCurrent make_current(this); |
| + functor_->DrawGL(&draw_info); |
| + } |
| + hooks_->DidDrawOnRT(functor_); |
| +} |
| + |
| +void FakeViewRootImpl::CheckRenderThread() { |
|
hush (inactive)
2014/12/10 20:07:57
this function is basically "InitializeRenderThread
boliu
2014/12/10 21:30:32
sgtm!
|
| + if (functor_) { |
| + DCHECK(render_thread_.get()); |
| + DCHECK(render_thread_loop_.get()); |
| + return; |
| + } |
| + functor_ = view_->GetAwDrawGLViewContext(); |
| + render_thread_.reset(new base::Thread("TestRenderThread")); |
| + render_thread_->Start(); |
| + render_thread_loop_ = render_thread_->task_runner(); |
| + |
| + base::WaitableEvent completion(true, false); |
| + render_thread_loop_->PostTask( |
| + FROM_HERE, base::Bind(&FakeViewRootImpl::InitializeOnRT, |
| + base::Unretained(this), &completion)); |
| + completion.Wait(); |
| +} |
| + |
| +void FakeViewRootImpl::InitializeOnRT(base::WaitableEvent* sync) { |
| + surface_ = gfx::GLSurface::CreateOffscreenGLSurface(surface_size_); |
| + DCHECK(surface_.get()); |
| + DCHECK(surface_->GetHandle()); |
| + context_ = gfx::GLContext::CreateGLContext(nullptr, surface_.get(), |
| + gfx::PreferDiscreteGpu); |
| + DCHECK(context_.get()); |
| + sync->Signal(); |
| +} |
| + |
| +void FakeViewRootImpl::DestroyOnRT(base::WaitableEvent* sync) { |
| + if (context_) { |
| + DCHECK(!context_->IsCurrent(surface_.get())); |
| + context_ = nullptr; |
| + surface_ = nullptr; |
| + } |
| + sync->Signal(); |
| +} |
| + |
| +} // namespace android_webview |