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(
89 DCHECK(!output_surface_
);
90 DCHECK(!begin_frame_source_
);
91 DCHECK(!input_handler_
);
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 cc::InputHandler
* input_handler
) {
115 DCHECK(!output_surface_
);
116 DCHECK(!begin_frame_source_
);
117 DCHECK(output_surface
);
118 DCHECK(begin_frame_source
);
119 DCHECK(compositor_client_
);
120 DCHECK(input_handler
);
122 output_surface_
= output_surface
;
123 begin_frame_source_
= begin_frame_source
;
125 begin_frame_source_
->SetCompositor(this);
126 output_surface_
->SetCompositor(this);
128 output_surface_
->SetTreeActivationCallback(
129 base::Bind(&SynchronousCompositorImpl::DidActivatePendingTree
,
130 weak_ptr_factory_
.GetWeakPtr()));
132 OnNeedsBeginFramesChange(begin_frame_source_
->NeedsBeginFrames());
134 compositor_client_
->DidInitializeCompositor(this);
136 SetInputHandler(input_handler
);
139 void SynchronousCompositorImpl::DidDestroyRendererObjects() {
140 DCHECK(output_surface_
);
141 DCHECK(begin_frame_source_
);
143 begin_frame_source_
->SetCompositor(nullptr);
144 output_surface_
->SetCompositor(nullptr);
145 if (compositor_client_
)
146 compositor_client_
->DidDestroyCompositor(this);
147 compositor_client_
= nullptr;
148 output_surface_
= nullptr;
149 begin_frame_source_
= nullptr;
150 SetInputHandler(nullptr);
153 void SynchronousCompositorImpl::NotifyDidDestroyCompositorToClient() {
154 if (compositor_client_
)
155 compositor_client_
->DidDestroyCompositor(this);
156 compositor_client_
= nullptr;
159 scoped_ptr
<cc::CompositorFrame
> SynchronousCompositorImpl::DemandDrawHw(
160 gfx::Size surface_size
,
161 const gfx::Transform
& transform
,
164 gfx::Rect viewport_rect_for_tile_priority
,
165 const gfx::Transform
& transform_for_tile_priority
) {
166 DCHECK(CalledOnValidThread());
167 DCHECK(output_surface_
);
168 DCHECK(compositor_client_
);
169 DCHECK(begin_frame_source_
);
171 scoped_ptr
<cc::CompositorFrame
> frame
=
172 output_surface_
->DemandDrawHw(surface_size
,
176 viewport_rect_for_tile_priority
,
177 transform_for_tile_priority
);
180 UpdateFrameMetaData(frame
->metadata
);
185 void SynchronousCompositorImpl::ReturnResources(
186 const cc::CompositorFrameAck
& frame_ack
) {
187 DCHECK(CalledOnValidThread());
188 output_surface_
->ReturnResources(frame_ack
);
191 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas
* canvas
) {
192 DCHECK(CalledOnValidThread());
193 DCHECK(output_surface_
);
194 DCHECK(compositor_client_
);
195 DCHECK(begin_frame_source_
);
197 scoped_ptr
<cc::CompositorFrame
> frame
=
198 output_surface_
->DemandDrawSw(canvas
);
201 UpdateFrameMetaData(frame
->metadata
);
203 return !!frame
.get();
206 void SynchronousCompositorImpl::UpdateFrameMetaData(
207 const cc::CompositorFrameMetadata
& frame_metadata
) {
208 RenderWidgetHostViewAndroid
* rwhv
= static_cast<RenderWidgetHostViewAndroid
*>(
209 contents_
->GetRenderWidgetHostView());
211 rwhv
->SynchronousFrameMetadata(frame_metadata
);
215 void SynchronousCompositorImpl::SetMemoryPolicy(size_t bytes_limit
) {
216 DCHECK(CalledOnValidThread());
217 DCHECK(output_surface_
);
219 size_t current_bytes_limit
= output_surface_
->GetMemoryPolicy();
220 output_surface_
->SetMemoryPolicy(bytes_limit
);
222 if (bytes_limit
&& !current_bytes_limit
) {
223 g_factory
.Get().CompositorInitializedHardwareDraw();
224 } else if (!bytes_limit
&& current_bytes_limit
) {
225 g_factory
.Get().CompositorReleasedHardwareDraw();
229 void SynchronousCompositorImpl::PostInvalidate() {
230 DCHECK(CalledOnValidThread());
231 DCHECK(compositor_client_
);
232 compositor_client_
->PostInvalidate();
235 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
237 input_handler_
->OnRootLayerDelegatedScrollOffsetChanged();
240 void SynchronousCompositorImpl::SetIsActive(bool is_active
) {
241 TRACE_EVENT1("cc", "SynchronousCompositorImpl::SetIsActive", "is_active",
243 is_active_
= is_active
;
244 UpdateNeedsBeginFrames();
247 void SynchronousCompositorImpl::OnNeedsBeginFramesChange(
248 bool needs_begin_frames
) {
249 renderer_needs_begin_frames_
= needs_begin_frames
;
250 UpdateNeedsBeginFrames();
253 void SynchronousCompositorImpl::BeginFrame(const cc::BeginFrameArgs
& args
) {
254 if (begin_frame_source_
)
255 begin_frame_source_
->BeginFrame(args
);
258 void SynchronousCompositorImpl::UpdateNeedsBeginFrames() {
259 RenderWidgetHostViewAndroid
* rwhv
= static_cast<RenderWidgetHostViewAndroid
*>(
260 contents_
->GetRenderWidgetHostView());
262 rwhv
->OnSetNeedsBeginFrames(is_active_
&& renderer_needs_begin_frames_
);
265 void SynchronousCompositorImpl::SetInputHandler(
266 cc::InputHandler
* input_handler
) {
267 DCHECK(CalledOnValidThread());
270 input_handler_
->SetRootLayerScrollOffsetDelegate(NULL
);
272 input_handler_
= input_handler
;
275 input_handler_
->SetRootLayerScrollOffsetDelegate(this);
278 void SynchronousCompositorImpl::DidOverscroll(
279 const DidOverscrollParams
& params
) {
280 if (compositor_client_
) {
281 compositor_client_
->DidOverscroll(params
.accumulated_overscroll
,
282 params
.latest_overscroll_delta
,
283 params
.current_fling_velocity
);
287 void SynchronousCompositorImpl::DidStopFlinging() {
288 RenderWidgetHostViewAndroid
* rwhv
= static_cast<RenderWidgetHostViewAndroid
*>(
289 contents_
->GetRenderWidgetHostView());
291 rwhv
->DidStopFlinging();
294 InputEventAckState
SynchronousCompositorImpl::HandleInputEvent(
295 const blink::WebInputEvent
& input_event
) {
296 DCHECK(CalledOnValidThread());
297 return g_factory
.Get().synchronous_input_event_filter()->HandleInputEvent(
298 contents_
->GetRoutingID(), input_event
);
301 void SynchronousCompositorImpl::DeliverMessages() {
302 ScopedVector
<IPC::Message
> messages
;
303 output_surface_
->GetMessagesToDeliver(&messages
);
304 RenderProcessHost
* rph
= contents_
->GetRenderProcessHost();
305 for (ScopedVector
<IPC::Message
>::const_iterator i
= messages
.begin();
308 rph
->OnMessageReceived(**i
);
312 void SynchronousCompositorImpl::DidActivatePendingTree() {
313 if (compositor_client_
)
314 compositor_client_
->DidUpdateContent();
317 gfx::ScrollOffset
SynchronousCompositorImpl::GetTotalScrollOffset() {
318 DCHECK(CalledOnValidThread());
319 if (compositor_client_
) {
320 // TODO(miletus): Make GetTotalRootLayerScrollOffset return
321 // ScrollOffset. crbug.com/414283.
322 return gfx::ScrollOffset(
323 compositor_client_
->GetTotalRootLayerScrollOffset());
325 return gfx::ScrollOffset();
328 bool SynchronousCompositorImpl::IsExternalFlingActive() const {
329 DCHECK(CalledOnValidThread());
330 if (compositor_client_
)
331 return compositor_client_
->IsExternalFlingActive();
335 void SynchronousCompositorImpl::UpdateRootLayerState(
336 const gfx::ScrollOffset
& total_scroll_offset
,
337 const gfx::ScrollOffset
& max_scroll_offset
,
338 const gfx::SizeF
& scrollable_size
,
339 float page_scale_factor
,
340 float min_page_scale_factor
,
341 float max_page_scale_factor
) {
342 DCHECK(CalledOnValidThread());
343 if (!compositor_client_
)
346 // TODO(miletus): Pass in ScrollOffset. crbug.com/414283.
347 compositor_client_
->UpdateRootLayerState(
348 gfx::ScrollOffsetToVector2dF(total_scroll_offset
),
349 gfx::ScrollOffsetToVector2dF(max_scroll_offset
),
352 min_page_scale_factor
,
353 max_page_scale_factor
);
356 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
357 // requirement: SynchronousCompositorImpl() must only be used on the UI thread.
358 bool SynchronousCompositorImpl::CalledOnValidThread() const {
359 return BrowserThread::CurrentlyOn(BrowserThread::UI
);
363 void SynchronousCompositor::SetClientForWebContents(
364 WebContents
* contents
,
365 SynchronousCompositorClient
* client
) {
368 g_factory
.Get(); // Ensure it's initialized.
369 SynchronousCompositorImpl::CreateForWebContents(contents
);
371 SynchronousCompositorImpl
* instance
=
372 SynchronousCompositorImpl::FromWebContents(contents
);
374 instance
->SetClient(client
);
377 } // namespace content