1 // Copyright 2013 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 "content/browser/android/in_process/synchronous_compositor_impl.h" 6 7 #include "base/lazy_instance.h" 8 #include "base/message_loop/message_loop.h" 9 #include "cc/input/input_handler.h" 10 #include "content/browser/android/in_process/synchronous_compositor_factory_impl.h" 11 #include "content/browser/android/in_process/synchronous_input_event_filter.h" 12 #include "content/browser/renderer_host/render_widget_host_view_android.h" 13 #include "content/common/input/did_overscroll_params.h" 14 #include "content/public/browser/android/synchronous_compositor_client.h" 15 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/render_process_host.h" 17 #include "content/public/browser/render_view_host.h" 18 #include "ui/gl/gl_surface.h" 19 20 namespace content { 21 22 namespace { 23 24 int GetInProcessRendererId() { 25 content::RenderProcessHost::iterator it = 26 content::RenderProcessHost::AllHostsIterator(); 27 if (it.IsAtEnd()) { 28 // There should always be one RPH in single process mode. 29 NOTREACHED(); 30 return 0; 31 } 32 33 int id = it.GetCurrentValue()->GetID(); 34 it.Advance(); 35 DCHECK(it.IsAtEnd()); // Not multiprocess compatible. 36 return id; 37 } 38 39 base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory = 40 LAZY_INSTANCE_INITIALIZER; 41 42 } // namespace 43 44 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl); 45 46 // static 47 SynchronousCompositorImpl* SynchronousCompositorImpl::FromID(int process_id, 48 int routing_id) { 49 if (g_factory == NULL) 50 return NULL; 51 RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id); 52 if (!rvh) 53 return NULL; 54 WebContents* contents = WebContents::FromRenderViewHost(rvh); 55 if (!contents) 56 return NULL; 57 return FromWebContents(contents); 58 } 59 60 SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID( 61 int routing_id) { 62 return FromID(GetInProcessRendererId(), routing_id); 63 } 64 65 SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents* contents) 66 : compositor_client_(NULL), 67 output_surface_(NULL), 68 contents_(contents), 69 input_handler_(NULL), 70 weak_ptr_factory_(this) { 71 DCHECK(contents); 72 } 73 74 SynchronousCompositorImpl::~SynchronousCompositorImpl() { 75 if (compositor_client_) 76 compositor_client_->DidDestroyCompositor(this); 77 SetInputHandler(NULL); 78 } 79 80 void SynchronousCompositorImpl::SetClient( 81 SynchronousCompositorClient* compositor_client) { 82 DCHECK(CalledOnValidThread()); 83 compositor_client_ = compositor_client; 84 } 85 86 // static 87 void SynchronousCompositor::SetGpuService( 88 scoped_refptr<gpu::InProcessCommandBuffer::Service> service) { 89 g_factory.Get().SetDeferredGpuService(service); 90 } 91 92 // static 93 void SynchronousCompositor::SetRecordFullDocument(bool record_full_document) { 94 g_factory.Get().SetRecordFullDocument(record_full_document); 95 } 96 97 bool SynchronousCompositorImpl::InitializeHwDraw() { 98 DCHECK(CalledOnValidThread()); 99 DCHECK(output_surface_); 100 101 scoped_refptr<cc::ContextProvider> onscreen_context = 102 g_factory.Get().CreateOnscreenContextProviderForCompositorThread(); 103 104 bool success = output_surface_->InitializeHwDraw(onscreen_context); 105 106 if (success) 107 g_factory.Get().CompositorInitializedHardwareDraw(); 108 return success; 109 } 110 111 void SynchronousCompositorImpl::ReleaseHwDraw() { 112 DCHECK(CalledOnValidThread()); 113 DCHECK(output_surface_); 114 output_surface_->ReleaseHwDraw(); 115 g_factory.Get().CompositorReleasedHardwareDraw(); 116 } 117 118 scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw( 119 gfx::Size surface_size, 120 const gfx::Transform& transform, 121 gfx::Rect viewport, 122 gfx::Rect clip, 123 gfx::Rect viewport_rect_for_tile_priority, 124 const gfx::Transform& transform_for_tile_priority) { 125 DCHECK(CalledOnValidThread()); 126 DCHECK(output_surface_); 127 128 scoped_ptr<cc::CompositorFrame> frame = 129 output_surface_->DemandDrawHw(surface_size, 130 transform, 131 viewport, 132 clip, 133 viewport_rect_for_tile_priority, 134 transform_for_tile_priority); 135 if (frame.get()) 136 UpdateFrameMetaData(frame->metadata); 137 138 return frame.Pass(); 139 } 140 141 void SynchronousCompositorImpl::ReturnResources( 142 const cc::CompositorFrameAck& frame_ack) { 143 DCHECK(CalledOnValidThread()); 144 output_surface_->ReturnResources(frame_ack); 145 } 146 147 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) { 148 DCHECK(CalledOnValidThread()); 149 DCHECK(output_surface_); 150 151 scoped_ptr<cc::CompositorFrame> frame = output_surface_->DemandDrawSw(canvas); 152 if (frame.get()) 153 UpdateFrameMetaData(frame->metadata); 154 return !!frame.get(); 155 } 156 157 void SynchronousCompositorImpl::UpdateFrameMetaData( 158 const cc::CompositorFrameMetadata& frame_metadata) { 159 RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>( 160 contents_->GetRenderWidgetHostView()); 161 if (rwhv) 162 rwhv->SynchronousFrameMetadata(frame_metadata); 163 DeliverMessages(); 164 } 165 166 void SynchronousCompositorImpl::SetMemoryPolicy( 167 const SynchronousCompositorMemoryPolicy& policy) { 168 DCHECK(CalledOnValidThread()); 169 DCHECK(output_surface_); 170 171 output_surface_->SetMemoryPolicy(policy); 172 } 173 174 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() { 175 if (input_handler_) 176 input_handler_->OnRootLayerDelegatedScrollOffsetChanged(); 177 } 178 179 void SynchronousCompositorImpl::DidBindOutputSurface( 180 SynchronousCompositorOutputSurface* output_surface) { 181 DCHECK(CalledOnValidThread()); 182 output_surface_ = output_surface; 183 if (compositor_client_) 184 compositor_client_->DidInitializeCompositor(this); 185 } 186 187 void SynchronousCompositorImpl::DidDestroySynchronousOutputSurface( 188 SynchronousCompositorOutputSurface* output_surface) { 189 DCHECK(CalledOnValidThread()); 190 191 // Allow for transient hand-over when two output surfaces may refer to 192 // a single delegate. 193 if (output_surface_ == output_surface) { 194 output_surface_ = NULL; 195 if (compositor_client_) 196 compositor_client_->DidDestroyCompositor(this); 197 compositor_client_ = NULL; 198 } 199 } 200 201 void SynchronousCompositorImpl::SetInputHandler( 202 cc::InputHandler* input_handler) { 203 DCHECK(CalledOnValidThread()); 204 205 if (input_handler_) 206 input_handler_->SetRootLayerScrollOffsetDelegate(NULL); 207 208 input_handler_ = input_handler; 209 210 if (input_handler_) 211 input_handler_->SetRootLayerScrollOffsetDelegate(this); 212 } 213 214 void SynchronousCompositorImpl::DidOverscroll( 215 const DidOverscrollParams& params) { 216 if (compositor_client_) { 217 compositor_client_->DidOverscroll(params.accumulated_overscroll, 218 params.latest_overscroll_delta, 219 params.current_fling_velocity); 220 } 221 } 222 223 void SynchronousCompositorImpl::DidStopFlinging() { 224 RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>( 225 contents_->GetRenderWidgetHostView()); 226 if (rwhv) 227 rwhv->DidStopFlinging(); 228 } 229 230 void SynchronousCompositorImpl::SetContinuousInvalidate(bool enable) { 231 DCHECK(CalledOnValidThread()); 232 if (compositor_client_) 233 compositor_client_->SetContinuousInvalidate(enable); 234 } 235 236 InputEventAckState SynchronousCompositorImpl::HandleInputEvent( 237 const blink::WebInputEvent& input_event) { 238 DCHECK(CalledOnValidThread()); 239 return g_factory.Get().synchronous_input_event_filter()->HandleInputEvent( 240 contents_->GetRoutingID(), input_event); 241 } 242 243 void SynchronousCompositorImpl::DeliverMessages() { 244 ScopedVector<IPC::Message> messages; 245 output_surface_->GetMessagesToDeliver(&messages); 246 RenderProcessHost* rph = contents_->GetRenderProcessHost(); 247 for (ScopedVector<IPC::Message>::const_iterator i = messages.begin(); 248 i != messages.end(); 249 ++i) { 250 rph->OnMessageReceived(**i); 251 } 252 } 253 254 void SynchronousCompositorImpl::DidActivatePendingTree() { 255 if (compositor_client_) 256 compositor_client_->DidUpdateContent(); 257 } 258 259 gfx::Vector2dF SynchronousCompositorImpl::GetTotalScrollOffset() { 260 DCHECK(CalledOnValidThread()); 261 if (compositor_client_) 262 return compositor_client_->GetTotalRootLayerScrollOffset(); 263 return gfx::Vector2dF(); 264 } 265 266 bool SynchronousCompositorImpl::IsExternalFlingActive() const { 267 DCHECK(CalledOnValidThread()); 268 if (compositor_client_) 269 return compositor_client_->IsExternalFlingActive(); 270 return false; 271 } 272 273 void SynchronousCompositorImpl::UpdateRootLayerState( 274 const gfx::Vector2dF& total_scroll_offset, 275 const gfx::Vector2dF& max_scroll_offset, 276 const gfx::SizeF& scrollable_size, 277 float page_scale_factor, 278 float min_page_scale_factor, 279 float max_page_scale_factor) { 280 DCHECK(CalledOnValidThread()); 281 if (!compositor_client_) 282 return; 283 284 compositor_client_->UpdateRootLayerState(total_scroll_offset, 285 max_scroll_offset, 286 scrollable_size, 287 page_scale_factor, 288 min_page_scale_factor, 289 max_page_scale_factor); 290 } 291 292 // Not using base::NonThreadSafe as we want to enforce a more exacting threading 293 // requirement: SynchronousCompositorImpl() must only be used on the UI thread. 294 bool SynchronousCompositorImpl::CalledOnValidThread() const { 295 return BrowserThread::CurrentlyOn(BrowserThread::UI); 296 } 297 298 // static 299 void SynchronousCompositor::SetClientForWebContents( 300 WebContents* contents, 301 SynchronousCompositorClient* client) { 302 DCHECK(contents); 303 if (client) { 304 g_factory.Get(); // Ensure it's initialized. 305 SynchronousCompositorImpl::CreateForWebContents(contents); 306 } 307 if (SynchronousCompositorImpl* instance = 308 SynchronousCompositorImpl::FromWebContents(contents)) { 309 instance->SetClient(client); 310 } 311 } 312 313 } // namespace content 314