 Chromium Code Reviews
 Chromium Code Reviews Issue 786533002:
  aw: Rendering test harness and end-to-end smoke test  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 786533002:
  aw: Rendering test harness and end-to-end smoke test  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| 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 |