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.
5 #include "content/browser/android/in_process/synchronous_compositor_impl.h"
7 #include "base/auto_reset.h"
9 #include "base/lazy_instance.h"
10 #include "base/message_loop/message_loop.h"
11 #include "cc/input/input_handler.h"
12 #include "content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h"
13 #include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
14 #include "content/browser/android/in_process/synchronous_compositor_registry.h"
15 #include "content/browser/android/in_process/synchronous_input_event_filter.h"
16 #include "content/browser/renderer_host/render_widget_host_view_android.h"
17 #include "content/common/input/did_overscroll_params.h"
18 #include "content/public/browser/android/synchronous_compositor_client.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "ui/gl/gl_surface.h"
28 int GetInProcessRendererId() {
29 content::RenderProcessHost::iterator it
=
30 content::RenderProcessHost::AllHostsIterator();
32 // There should always be one RPH in single process mode.
37 int id
= it
.GetCurrentValue()->GetID();
39 DCHECK(it
.IsAtEnd()); // Not multiprocess compatible.
43 base::LazyInstance
<SynchronousCompositorFactoryImpl
>::Leaky g_factory
=
44 LAZY_INSTANCE_INITIALIZER
;
48 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl
);
51 SynchronousCompositorImpl
* SynchronousCompositorImpl::FromID(int process_id
,
53 if (g_factory
== NULL
)
55 RenderViewHost
* rvh
= RenderViewHost::FromID(process_id
, routing_id
);
58 WebContents
* contents
= WebContents::FromRenderViewHost(rvh
);
61 return FromWebContents(contents
);
64 SynchronousCompositorImpl
* SynchronousCompositorImpl::FromRoutingID(
66 return FromID(GetInProcessRendererId(), routing_id
);
69 SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents
* contents
)
70 : compositor_client_(NULL
),
71 output_surface_(NULL
),
72 begin_frame_source_(nullptr),
74 routing_id_(contents
->GetRoutingID()),
77 renderer_needs_begin_frames_(false),
78 weak_ptr_factory_(this) {
80 DCHECK_NE(routing_id_
, MSG_ROUTING_NONE
);
81 SynchronousCompositorRegistry::GetInstance()->RegisterCompositor(routing_id_
,
85 SynchronousCompositorImpl::~SynchronousCompositorImpl() {
86 SynchronousCompositorRegistry::GetInstance()->UnregisterCompositor(
88 SetInputHandler(NULL
);
90 DCHECK(!output_surface_
);
91 DCHECK(!begin_frame_source_
);
94 void SynchronousCompositorImpl::SetClient(
95 SynchronousCompositorClient
* compositor_client
) {
96 DCHECK(CalledOnValidThread());
97 compositor_client_
= compositor_client
;
101 void SynchronousCompositor::SetGpuService(
102 scoped_refptr
<gpu::InProcessCommandBuffer::Service
> service
) {
103 g_factory
.Get().SetDeferredGpuService(service
);
107 void SynchronousCompositor::SetRecordFullDocument(bool record_full_document
) {
108 g_factory
.Get().SetRecordFullDocument(record_full_document
);
111 void SynchronousCompositorImpl::DidInitializeRendererObjects(
112 SynchronousCompositorOutputSurface
* output_surface
,
113 SynchronousCompositorExternalBeginFrameSource
* begin_frame_source
) {
114 DCHECK(!output_surface_
);
115 DCHECK(!begin_frame_source_
);
116 DCHECK(output_surface
);
117 DCHECK(begin_frame_source
);
118 DCHECK(compositor_client_
);
120 output_surface_
= output_surface
;
121 begin_frame_source_
= begin_frame_source
;
123 begin_frame_source_
->SetCompositor(this);
124 output_surface_
->SetCompositor(this);
126 output_surface_
->SetTreeActivationCallback(
127 base::Bind(&SynchronousCompositorImpl::DidActivatePendingTree
,
128 weak_ptr_factory_
.GetWeakPtr()));
130 OnNeedsBeginFramesChange(begin_frame_source_
->NeedsBeginFrames());
132 compositor_client_
->DidInitializeCompositor(this);
135 void SynchronousCompositorImpl::DidDestroyRendererObjects() {
136 DCHECK(output_surface_
);
137 DCHECK(begin_frame_source_
);
139 begin_frame_source_
->SetCompositor(nullptr);
140 output_surface_
->SetCompositor(nullptr);
141 if (compositor_client_
)
142 compositor_client_
->DidDestroyCompositor(this);
143 compositor_client_
= nullptr;
144 output_surface_
= nullptr;
145 begin_frame_source_
= nullptr;
148 void SynchronousCompositorImpl::NotifyDidDestroyCompositorToClient() {
149 if (compositor_client_
)
150 compositor_client_
->DidDestroyCompositor(this);
151 compositor_client_
= nullptr;
154 bool SynchronousCompositorImpl::InitializeHwDraw() {
155 DCHECK(CalledOnValidThread());
156 DCHECK(output_surface_
);
158 scoped_refptr
<cc::ContextProvider
> onscreen_context
=
159 g_factory
.Get().CreateContextProviderForCompositor();
161 scoped_refptr
<cc::ContextProvider
> worker_context
=
162 g_factory
.Get().CreateContextProviderForCompositor();
165 output_surface_
->InitializeHwDraw(onscreen_context
, worker_context
);
168 g_factory
.Get().CompositorInitializedHardwareDraw();
172 void SynchronousCompositorImpl::ReleaseHwDraw() {
173 DCHECK(CalledOnValidThread());
174 DCHECK(output_surface_
);
175 output_surface_
->ReleaseHwDraw();
176 g_factory
.Get().CompositorReleasedHardwareDraw();
179 scoped_ptr
<cc::CompositorFrame
> SynchronousCompositorImpl::DemandDrawHw(
180 gfx::Size surface_size
,
181 const gfx::Transform
& transform
,
184 gfx::Rect viewport_rect_for_tile_priority
,
185 const gfx::Transform
& transform_for_tile_priority
) {
186 DCHECK(CalledOnValidThread());
187 DCHECK(output_surface_
);
188 DCHECK(compositor_client_
);
189 DCHECK(begin_frame_source_
);
191 scoped_ptr
<cc::CompositorFrame
> frame
=
192 output_surface_
->DemandDrawHw(surface_size
,
196 viewport_rect_for_tile_priority
,
197 transform_for_tile_priority
);
200 UpdateFrameMetaData(frame
->metadata
);
205 void SynchronousCompositorImpl::ReturnResources(
206 const cc::CompositorFrameAck
& frame_ack
) {
207 DCHECK(CalledOnValidThread());
208 output_surface_
->ReturnResources(frame_ack
);
211 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas
* canvas
) {
212 DCHECK(CalledOnValidThread());
213 DCHECK(output_surface_
);
214 DCHECK(compositor_client_
);
215 DCHECK(begin_frame_source_
);
217 scoped_ptr
<cc::CompositorFrame
> frame
=
218 output_surface_
->DemandDrawSw(canvas
);
221 UpdateFrameMetaData(frame
->metadata
);
223 return !!frame
.get();
226 void SynchronousCompositorImpl::UpdateFrameMetaData(
227 const cc::CompositorFrameMetadata
& frame_metadata
) {
228 RenderWidgetHostViewAndroid
* rwhv
= static_cast<RenderWidgetHostViewAndroid
*>(
229 contents_
->GetRenderWidgetHostView());
231 rwhv
->SynchronousFrameMetadata(frame_metadata
);
235 void SynchronousCompositorImpl::SetMemoryPolicy(size_t bytes_limit
) {
236 DCHECK(CalledOnValidThread());
237 DCHECK(output_surface_
);
239 output_surface_
->SetMemoryPolicy(bytes_limit
);
242 void SynchronousCompositorImpl::PostInvalidate() {
243 DCHECK(CalledOnValidThread());
244 DCHECK(compositor_client_
);
245 compositor_client_
->PostInvalidate();
248 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
250 input_handler_
->OnRootLayerDelegatedScrollOffsetChanged();
253 void SynchronousCompositorImpl::SetIsActive(bool is_active
) {
254 TRACE_EVENT1("cc", "SynchronousCompositorImpl::SetIsActive", "is_active",
256 is_active_
= is_active
;
257 UpdateNeedsBeginFrames();
260 void SynchronousCompositorImpl::OnNeedsBeginFramesChange(
261 bool needs_begin_frames
) {
262 renderer_needs_begin_frames_
= needs_begin_frames
;
263 UpdateNeedsBeginFrames();
266 void SynchronousCompositorImpl::BeginFrame(const cc::BeginFrameArgs
& args
) {
267 if (begin_frame_source_
)
268 begin_frame_source_
->BeginFrame(args
);
271 void SynchronousCompositorImpl::UpdateNeedsBeginFrames() {
272 RenderWidgetHostViewAndroid
* rwhv
= static_cast<RenderWidgetHostViewAndroid
*>(
273 contents_
->GetRenderWidgetHostView());
275 rwhv
->OnSetNeedsBeginFrames(is_active_
&& renderer_needs_begin_frames_
);
278 void SynchronousCompositorImpl::SetInputHandler(
279 cc::InputHandler
* input_handler
) {
280 DCHECK(CalledOnValidThread());
283 input_handler_
->SetRootLayerScrollOffsetDelegate(NULL
);
285 input_handler_
= input_handler
;
288 input_handler_
->SetRootLayerScrollOffsetDelegate(this);
291 void SynchronousCompositorImpl::DidOverscroll(
292 const DidOverscrollParams
& params
) {
293 if (compositor_client_
) {
294 compositor_client_
->DidOverscroll(params
.accumulated_overscroll
,
295 params
.latest_overscroll_delta
,
296 params
.current_fling_velocity
);
300 void SynchronousCompositorImpl::DidStopFlinging() {
301 RenderWidgetHostViewAndroid
* rwhv
= static_cast<RenderWidgetHostViewAndroid
*>(
302 contents_
->GetRenderWidgetHostView());
304 rwhv
->DidStopFlinging();
307 InputEventAckState
SynchronousCompositorImpl::HandleInputEvent(
308 const blink::WebInputEvent
& input_event
) {
309 DCHECK(CalledOnValidThread());
310 return g_factory
.Get().synchronous_input_event_filter()->HandleInputEvent(
311 contents_
->GetRoutingID(), input_event
);
314 void SynchronousCompositorImpl::DeliverMessages() {
315 ScopedVector
<IPC::Message
> messages
;
316 output_surface_
->GetMessagesToDeliver(&messages
);
317 RenderProcessHost
* rph
= contents_
->GetRenderProcessHost();
318 for (ScopedVector
<IPC::Message
>::const_iterator i
= messages
.begin();
321 rph
->OnMessageReceived(**i
);
325 void SynchronousCompositorImpl::DidActivatePendingTree() {
326 if (compositor_client_
)
327 compositor_client_
->DidUpdateContent();
330 gfx::ScrollOffset
SynchronousCompositorImpl::GetTotalScrollOffset() {
331 DCHECK(CalledOnValidThread());
332 if (compositor_client_
) {
333 // TODO(miletus): Make GetTotalRootLayerScrollOffset return
334 // ScrollOffset. crbug.com/414283.
335 return gfx::ScrollOffset(
336 compositor_client_
->GetTotalRootLayerScrollOffset());
338 return gfx::ScrollOffset();
341 bool SynchronousCompositorImpl::IsExternalFlingActive() const {
342 DCHECK(CalledOnValidThread());
343 if (compositor_client_
)
344 return compositor_client_
->IsExternalFlingActive();
348 void SynchronousCompositorImpl::UpdateRootLayerState(
349 const gfx::ScrollOffset
& total_scroll_offset
,
350 const gfx::ScrollOffset
& max_scroll_offset
,
351 const gfx::SizeF
& scrollable_size
,
352 float page_scale_factor
,
353 float min_page_scale_factor
,
354 float max_page_scale_factor
) {
355 DCHECK(CalledOnValidThread());
356 if (!compositor_client_
)
359 // TODO(miletus): Pass in ScrollOffset. crbug.com/414283.
360 compositor_client_
->UpdateRootLayerState(
361 gfx::ScrollOffsetToVector2dF(total_scroll_offset
),
362 gfx::ScrollOffsetToVector2dF(max_scroll_offset
),
365 min_page_scale_factor
,
366 max_page_scale_factor
);
369 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
370 // requirement: SynchronousCompositorImpl() must only be used on the UI thread.
371 bool SynchronousCompositorImpl::CalledOnValidThread() const {
372 return BrowserThread::CurrentlyOn(BrowserThread::UI
);
376 void SynchronousCompositor::SetClientForWebContents(
377 WebContents
* contents
,
378 SynchronousCompositorClient
* client
) {
381 g_factory
.Get(); // Ensure it's initialized.
382 SynchronousCompositorImpl::CreateForWebContents(contents
);
384 SynchronousCompositorImpl
* instance
=
385 SynchronousCompositorImpl::FromWebContents(contents
);
387 instance
->SetClient(client
);
390 } // namespace content