| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "android_webview/browser/test/fake_window.h" |
| 6 |
| 7 #include "android_webview/browser/browser_view_renderer.h" |
| 8 #include "android_webview/public/browser/draw_gl.h" |
| 9 #include "base/message_loop/message_loop_proxy.h" |
| 10 #include "base/synchronization/waitable_event.h" |
| 11 #include "base/threading/thread.h" |
| 12 #include "ui/gl/gl_bindings.h" |
| 13 |
| 14 namespace android_webview { |
| 15 |
| 16 class FakeWindow::ScopedMakeCurrent { |
| 17 public: |
| 18 ScopedMakeCurrent(FakeWindow* view_root) : view_root_(view_root) { |
| 19 DCHECK(!view_root_->context_current_); |
| 20 view_root_->context_current_ = true; |
| 21 bool result = view_root_->context_->MakeCurrent(view_root_->surface_.get()); |
| 22 DCHECK(result); |
| 23 }; |
| 24 |
| 25 ~ScopedMakeCurrent() { |
| 26 DCHECK(view_root_->context_current_); |
| 27 view_root_->context_current_ = false; |
| 28 |
| 29 // Release the underlying EGLContext. This is required because the real |
| 30 // GLContextEGL may no longer be current here and to satisfy DCHECK in |
| 31 // GLContextEGL::IsCurrent. |
| 32 eglMakeCurrent(view_root_->surface_->GetDisplay(), EGL_NO_SURFACE, |
| 33 EGL_NO_SURFACE, EGL_NO_CONTEXT); |
| 34 view_root_->context_->ReleaseCurrent(view_root_->surface_.get()); |
| 35 } |
| 36 |
| 37 private: |
| 38 FakeWindow* view_root_; |
| 39 }; |
| 40 |
| 41 FakeWindow::FakeWindow(BrowserViewRenderer* view, |
| 42 WindowHooks* hooks, |
| 43 gfx::Rect location) |
| 44 : view_(view), |
| 45 hooks_(hooks), |
| 46 surface_size_(100, 100), |
| 47 location_(location), |
| 48 on_draw_hardware_pending_(false), |
| 49 functor_(nullptr), |
| 50 context_current_(false), |
| 51 weak_ptr_factory_(this) { |
| 52 CheckCurrentlyOnUIThread(); |
| 53 DCHECK(view_); |
| 54 view_->OnAttachedToWindow(location_.width(), location_.height()); |
| 55 } |
| 56 |
| 57 FakeWindow::~FakeWindow() { |
| 58 CheckCurrentlyOnUIThread(); |
| 59 } |
| 60 |
| 61 void FakeWindow::Detach() { |
| 62 CheckCurrentlyOnUIThread(); |
| 63 view_->OnDetachedFromWindow(); |
| 64 |
| 65 if (render_thread_loop_) { |
| 66 base::WaitableEvent completion(true, false); |
| 67 render_thread_loop_->PostTask( |
| 68 FROM_HERE, base::Bind(&FakeWindow::DestroyOnRT, base::Unretained(this), |
| 69 &completion)); |
| 70 completion.Wait(); |
| 71 } |
| 72 |
| 73 render_thread_.reset(); |
| 74 functor_ = nullptr; |
| 75 } |
| 76 |
| 77 void FakeWindow::RequestDrawGL(bool wait_for_completion) { |
| 78 CheckCurrentlyOnUIThread(); |
| 79 base::WaitableEvent completion(true, false); |
| 80 render_thread_loop_->PostTask( |
| 81 FROM_HERE, |
| 82 base::Bind(&FakeWindow::ProcessFunctorOnRT, base::Unretained(this), |
| 83 wait_for_completion ? &completion : nullptr)); |
| 84 if (wait_for_completion) |
| 85 completion.Wait(); |
| 86 } |
| 87 |
| 88 void FakeWindow::ProcessFunctorOnRT(base::WaitableEvent* sync) { |
| 89 CheckCurrentlyOnRT(); |
| 90 AwDrawGLInfo process_info; |
| 91 process_info.version = kAwDrawGLInfoVersion; |
| 92 process_info.mode = AwDrawGLInfo::kModeProcess; |
| 93 |
| 94 hooks_->WillProcessOnRT(functor_); |
| 95 { |
| 96 ScopedMakeCurrent make_current(this); |
| 97 functor_->DrawGL(&process_info); |
| 98 } |
| 99 hooks_->DidProcessOnRT(functor_); |
| 100 |
| 101 if (sync) |
| 102 sync->Signal(); |
| 103 } |
| 104 |
| 105 void FakeWindow::PostInvalidate() { |
| 106 CheckCurrentlyOnUIThread(); |
| 107 if (on_draw_hardware_pending_) |
| 108 return; |
| 109 on_draw_hardware_pending_ = true; |
| 110 base::MessageLoopProxy::current()->PostTask( |
| 111 FROM_HERE, |
| 112 base::Bind(&FakeWindow::OnDrawHardware, weak_ptr_factory_.GetWeakPtr())); |
| 113 } |
| 114 |
| 115 void FakeWindow::OnDrawHardware() { |
| 116 CheckCurrentlyOnUIThread(); |
| 117 DCHECK(on_draw_hardware_pending_); |
| 118 on_draw_hardware_pending_ = false; |
| 119 |
| 120 bool success = view_->OnDrawHardware(); |
| 121 if (success) { |
| 122 CreateRenderThreadIfNeeded(); |
| 123 |
| 124 base::WaitableEvent completion(true, false); |
| 125 render_thread_loop_->PostTask( |
| 126 FROM_HERE, base::Bind(&FakeWindow::DrawFunctorOnRT, |
| 127 base::Unretained(this), &completion)); |
| 128 completion.Wait(); |
| 129 } |
| 130 } |
| 131 |
| 132 void FakeWindow::DrawFunctorOnRT(base::WaitableEvent* sync) { |
| 133 CheckCurrentlyOnRT(); |
| 134 // Ok to access UI functions until sync is signalled. |
| 135 gfx::Rect location = location_; |
| 136 { |
| 137 AwDrawGLInfo process_info; |
| 138 process_info.version = kAwDrawGLInfoVersion; |
| 139 process_info.mode = AwDrawGLInfo::kModeSync; |
| 140 |
| 141 hooks_->WillSyncOnRT(functor_); |
| 142 functor_->DrawGL(&process_info); |
| 143 hooks_->DidSyncOnRT(functor_); |
| 144 } |
| 145 sync->Signal(); |
| 146 |
| 147 AwDrawGLInfo draw_info; |
| 148 draw_info.version = kAwDrawGLInfoVersion; |
| 149 draw_info.mode = AwDrawGLInfo::kModeDraw; |
| 150 draw_info.clip_left = location.x(); |
| 151 draw_info.clip_top = location.y(); |
| 152 draw_info.clip_right = location.x() + location.width(); |
| 153 draw_info.clip_bottom = location.y() + location.height(); |
| 154 draw_info.width = surface_size_.width(); |
| 155 draw_info.height = surface_size_.height(); |
| 156 draw_info.is_layer = false; |
| 157 |
| 158 draw_info.transform[0] = 1.0; |
| 159 draw_info.transform[1] = 0.0; |
| 160 draw_info.transform[2] = 0.0; |
| 161 draw_info.transform[3] = 0.0; |
| 162 |
| 163 draw_info.transform[4] = 0.0; |
| 164 draw_info.transform[5] = 1.0; |
| 165 draw_info.transform[6] = 0.0; |
| 166 draw_info.transform[7] = 0.0; |
| 167 |
| 168 draw_info.transform[8] = 0.0; |
| 169 draw_info.transform[9] = 0.0; |
| 170 draw_info.transform[10] = 1.0; |
| 171 draw_info.transform[11] = 0.0; |
| 172 |
| 173 draw_info.transform[12] = 0.0; |
| 174 draw_info.transform[13] = 0.0; |
| 175 draw_info.transform[14] = 0.0; |
| 176 draw_info.transform[15] = 1.0; |
| 177 |
| 178 hooks_->WillDrawOnRT(functor_); |
| 179 { |
| 180 ScopedMakeCurrent make_current(this); |
| 181 functor_->DrawGL(&draw_info); |
| 182 } |
| 183 hooks_->DidDrawOnRT(functor_); |
| 184 } |
| 185 |
| 186 void FakeWindow::CheckCurrentlyOnUIThread() { |
| 187 DCHECK(ui_checker_.CalledOnValidSequencedThread()); |
| 188 } |
| 189 |
| 190 void FakeWindow::CreateRenderThreadIfNeeded() { |
| 191 CheckCurrentlyOnUIThread(); |
| 192 if (functor_) { |
| 193 DCHECK(render_thread_.get()); |
| 194 DCHECK(render_thread_loop_.get()); |
| 195 return; |
| 196 } |
| 197 functor_ = view_->GetAwDrawGLViewContext(); |
| 198 render_thread_.reset(new base::Thread("TestRenderThread")); |
| 199 render_thread_->Start(); |
| 200 render_thread_loop_ = render_thread_->task_runner(); |
| 201 rt_checker_.DetachFromSequence(); |
| 202 |
| 203 base::WaitableEvent completion(true, false); |
| 204 render_thread_loop_->PostTask( |
| 205 FROM_HERE, base::Bind(&FakeWindow::InitializeOnRT, base::Unretained(this), |
| 206 &completion)); |
| 207 completion.Wait(); |
| 208 } |
| 209 |
| 210 void FakeWindow::InitializeOnRT(base::WaitableEvent* sync) { |
| 211 CheckCurrentlyOnRT(); |
| 212 surface_ = gfx::GLSurface::CreateOffscreenGLSurface(surface_size_); |
| 213 DCHECK(surface_.get()); |
| 214 DCHECK(surface_->GetHandle()); |
| 215 context_ = gfx::GLContext::CreateGLContext(nullptr, surface_.get(), |
| 216 gfx::PreferDiscreteGpu); |
| 217 DCHECK(context_.get()); |
| 218 sync->Signal(); |
| 219 } |
| 220 |
| 221 void FakeWindow::DestroyOnRT(base::WaitableEvent* sync) { |
| 222 CheckCurrentlyOnRT(); |
| 223 if (context_) { |
| 224 DCHECK(!context_->IsCurrent(surface_.get())); |
| 225 context_ = nullptr; |
| 226 surface_ = nullptr; |
| 227 } |
| 228 sync->Signal(); |
| 229 } |
| 230 |
| 231 void FakeWindow::CheckCurrentlyOnRT() { |
| 232 DCHECK(rt_checker_.CalledOnValidSequencedThread()); |
| 233 } |
| 234 |
| 235 } // namespace android_webview |
| OLD | NEW |