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/common/input_messages.h"
19 #include "content/public/browser/android/synchronous_compositor_client.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "ui/gl/gl_surface.h"
29 int GetInProcessRendererId() {
30 content::RenderProcessHost::iterator it
=
31 content::RenderProcessHost::AllHostsIterator();
33 // There should always be one RPH in single process mode.
38 int id
= it
.GetCurrentValue()->GetID();
40 DCHECK(it
.IsAtEnd()); // Not multiprocess compatible.
44 base::LazyInstance
<SynchronousCompositorFactoryImpl
>::Leaky g_factory
=
45 LAZY_INSTANCE_INITIALIZER
;
49 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SynchronousCompositorImpl
);
52 SynchronousCompositorImpl
* SynchronousCompositorImpl::FromID(int process_id
,
54 if (g_factory
== NULL
)
56 RenderViewHost
* rvh
= RenderViewHost::FromID(process_id
, routing_id
);
59 WebContents
* contents
= WebContents::FromRenderViewHost(rvh
);
62 return FromWebContents(contents
);
65 SynchronousCompositorImpl
* SynchronousCompositorImpl::FromRoutingID(
67 return FromID(GetInProcessRendererId(), routing_id
);
70 SynchronousCompositorImpl::SynchronousCompositorImpl(WebContents
* contents
)
71 : compositor_client_(NULL
),
72 output_surface_(NULL
),
73 begin_frame_source_(nullptr),
75 routing_id_(contents
->GetRoutingID()),
78 renderer_needs_begin_frames_(false),
79 weak_ptr_factory_(this) {
81 DCHECK_NE(routing_id_
, MSG_ROUTING_NONE
);
84 SynchronousCompositorImpl::~SynchronousCompositorImpl() {
85 DCHECK(!output_surface_
);
86 DCHECK(!begin_frame_source_
);
87 DCHECK(!input_handler_
);
90 void SynchronousCompositorImpl::SetClient(
91 SynchronousCompositorClient
* compositor_client
) {
92 DCHECK(CalledOnValidThread());
93 DCHECK_IMPLIES(compositor_client
, !compositor_client_
);
94 DCHECK_IMPLIES(!compositor_client
, compositor_client_
);
96 if (!compositor_client
) {
97 SynchronousCompositorRegistry::GetInstance()->UnregisterCompositor(
101 compositor_client_
= compositor_client
;
103 // SetClient is essentially the constructor and destructor of
104 // SynchronousCompositorImpl.
105 if (compositor_client_
) {
106 SynchronousCompositorRegistry::GetInstance()->RegisterCompositor(
112 void SynchronousCompositor::SetGpuService(
113 scoped_refptr
<gpu::InProcessCommandBuffer::Service
> service
) {
114 g_factory
.Get().SetDeferredGpuService(service
);
118 void SynchronousCompositor::SetRecordFullDocument(bool record_full_document
) {
119 g_factory
.Get().SetRecordFullDocument(record_full_document
);
122 void SynchronousCompositorImpl::DidInitializeRendererObjects(
123 SynchronousCompositorOutputSurface
* output_surface
,
124 SynchronousCompositorExternalBeginFrameSource
* begin_frame_source
,
125 cc::InputHandler
* input_handler
) {
126 DCHECK(!output_surface_
);
127 DCHECK(!begin_frame_source_
);
128 DCHECK(output_surface
);
129 DCHECK(begin_frame_source
);
130 DCHECK(compositor_client_
);
131 DCHECK(input_handler
);
133 output_surface_
= output_surface
;
134 begin_frame_source_
= begin_frame_source
;
136 begin_frame_source_
->SetCompositor(this);
137 output_surface_
->SetCompositor(this);
139 output_surface_
->SetTreeActivationCallback(
140 base::Bind(&SynchronousCompositorImpl::DidActivatePendingTree
,
141 weak_ptr_factory_
.GetWeakPtr()));
143 OnNeedsBeginFramesChange(begin_frame_source_
->NeedsBeginFrames());
145 compositor_client_
->DidInitializeCompositor(this);
147 SetInputHandler(input_handler
);
150 void SynchronousCompositorImpl::DidDestroyRendererObjects() {
151 DCHECK(output_surface_
);
152 DCHECK(begin_frame_source_
);
153 DCHECK(compositor_client_
);
155 begin_frame_source_
->SetCompositor(nullptr);
156 output_surface_
->SetCompositor(nullptr);
157 SetInputHandler(nullptr);
158 compositor_client_
->DidDestroyCompositor(this);
159 output_surface_
= nullptr;
160 begin_frame_source_
= nullptr;
163 scoped_ptr
<cc::CompositorFrame
> SynchronousCompositorImpl::DemandDrawHw(
164 gfx::Size surface_size
,
165 const gfx::Transform
& transform
,
168 gfx::Rect viewport_rect_for_tile_priority
,
169 const gfx::Transform
& transform_for_tile_priority
) {
170 DCHECK(CalledOnValidThread());
171 DCHECK(output_surface_
);
172 DCHECK(compositor_client_
);
173 DCHECK(begin_frame_source_
);
175 scoped_ptr
<cc::CompositorFrame
> frame
=
176 output_surface_
->DemandDrawHw(surface_size
,
180 viewport_rect_for_tile_priority
,
181 transform_for_tile_priority
);
184 UpdateFrameMetaData(frame
->metadata
);
189 void SynchronousCompositorImpl::ReturnResources(
190 const cc::CompositorFrameAck
& frame_ack
) {
191 DCHECK(CalledOnValidThread());
192 output_surface_
->ReturnResources(frame_ack
);
195 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas
* canvas
) {
196 DCHECK(CalledOnValidThread());
197 DCHECK(output_surface_
);
198 DCHECK(compositor_client_
);
199 DCHECK(begin_frame_source_
);
201 scoped_ptr
<cc::CompositorFrame
> frame
=
202 output_surface_
->DemandDrawSw(canvas
);
205 UpdateFrameMetaData(frame
->metadata
);
207 return !!frame
.get();
210 void SynchronousCompositorImpl::UpdateFrameMetaData(
211 const cc::CompositorFrameMetadata
& frame_metadata
) {
212 RenderWidgetHostViewAndroid
* rwhv
= static_cast<RenderWidgetHostViewAndroid
*>(
213 contents_
->GetRenderWidgetHostView());
215 rwhv
->SynchronousFrameMetadata(frame_metadata
);
219 void SynchronousCompositorImpl::SetMemoryPolicy(size_t bytes_limit
) {
220 DCHECK(CalledOnValidThread());
221 DCHECK(output_surface_
);
223 size_t current_bytes_limit
= output_surface_
->GetMemoryPolicy();
224 output_surface_
->SetMemoryPolicy(bytes_limit
);
226 if (bytes_limit
&& !current_bytes_limit
) {
227 g_factory
.Get().CompositorInitializedHardwareDraw();
228 } else if (!bytes_limit
&& current_bytes_limit
) {
229 g_factory
.Get().CompositorReleasedHardwareDraw();
233 void SynchronousCompositorImpl::PostInvalidate() {
234 DCHECK(CalledOnValidThread());
235 DCHECK(compositor_client_
);
236 compositor_client_
->PostInvalidate();
239 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
241 input_handler_
->OnRootLayerDelegatedScrollOffsetChanged();
244 void SynchronousCompositorImpl::SetIsActive(bool is_active
) {
245 TRACE_EVENT1("cc", "SynchronousCompositorImpl::SetIsActive", "is_active",
247 is_active_
= is_active
;
248 UpdateNeedsBeginFrames();
251 void SynchronousCompositorImpl::OnNeedsBeginFramesChange(
252 bool needs_begin_frames
) {
253 renderer_needs_begin_frames_
= needs_begin_frames
;
254 UpdateNeedsBeginFrames();
257 void SynchronousCompositorImpl::BeginFrame(const cc::BeginFrameArgs
& args
) {
258 if (begin_frame_source_
)
259 begin_frame_source_
->BeginFrame(args
);
262 void SynchronousCompositorImpl::UpdateNeedsBeginFrames() {
263 RenderWidgetHostViewAndroid
* rwhv
= static_cast<RenderWidgetHostViewAndroid
*>(
264 contents_
->GetRenderWidgetHostView());
266 rwhv
->OnSetNeedsBeginFrames(is_active_
&& renderer_needs_begin_frames_
);
269 void SynchronousCompositorImpl::SetInputHandler(
270 cc::InputHandler
* input_handler
) {
271 DCHECK(CalledOnValidThread());
274 input_handler_
->SetRootLayerScrollOffsetDelegate(NULL
);
276 input_handler_
= input_handler
;
279 input_handler_
->SetRootLayerScrollOffsetDelegate(this);
282 void SynchronousCompositorImpl::DidOverscroll(
283 const DidOverscrollParams
& params
) {
284 DCHECK(compositor_client_
);
285 compositor_client_
->DidOverscroll(params
.accumulated_overscroll
,
286 params
.latest_overscroll_delta
,
287 params
.current_fling_velocity
);
290 void SynchronousCompositorImpl::DidStopFlinging() {
291 // It's important that the fling-end notification follow the same path as it
292 // takes on other platforms (using an IPC). This ensures consistent
293 // bookkeeping at all stages of the input pipeline.
294 contents_
->GetRenderProcessHost()->OnMessageReceived(
295 InputHostMsg_DidStopFlinging(routing_id_
));
298 InputEventAckState
SynchronousCompositorImpl::HandleInputEvent(
299 const blink::WebInputEvent
& input_event
) {
300 DCHECK(CalledOnValidThread());
301 return g_factory
.Get().synchronous_input_event_filter()->HandleInputEvent(
302 contents_
->GetRoutingID(), input_event
);
305 void SynchronousCompositorImpl::DeliverMessages() {
306 ScopedVector
<IPC::Message
> messages
;
307 output_surface_
->GetMessagesToDeliver(&messages
);
308 RenderProcessHost
* rph
= contents_
->GetRenderProcessHost();
309 for (ScopedVector
<IPC::Message
>::const_iterator i
= messages
.begin();
312 rph
->OnMessageReceived(**i
);
316 void SynchronousCompositorImpl::DidActivatePendingTree() {
317 DCHECK(compositor_client_
);
318 compositor_client_
->DidUpdateContent();
322 gfx::ScrollOffset
SynchronousCompositorImpl::GetTotalScrollOffset() {
323 DCHECK(CalledOnValidThread());
324 DCHECK(compositor_client_
);
325 // TODO(miletus): Make GetTotalRootLayerScrollOffset return
326 // ScrollOffset. crbug.com/414283.
327 return gfx::ScrollOffset(
328 compositor_client_
->GetTotalRootLayerScrollOffset());
331 bool SynchronousCompositorImpl::IsExternalFlingActive() const {
332 DCHECK(CalledOnValidThread());
333 DCHECK(compositor_client_
);
334 return compositor_client_
->IsExternalFlingActive();
337 void SynchronousCompositorImpl::UpdateRootLayerState(
338 const gfx::ScrollOffset
& total_scroll_offset
,
339 const gfx::ScrollOffset
& max_scroll_offset
,
340 const gfx::SizeF
& scrollable_size
,
341 float page_scale_factor
,
342 float min_page_scale_factor
,
343 float max_page_scale_factor
) {
344 DCHECK(CalledOnValidThread());
345 DCHECK(compositor_client_
);
347 // TODO(miletus): Pass in ScrollOffset. crbug.com/414283.
348 compositor_client_
->UpdateRootLayerState(
349 gfx::ScrollOffsetToVector2dF(total_scroll_offset
),
350 gfx::ScrollOffsetToVector2dF(max_scroll_offset
),
353 min_page_scale_factor
,
354 max_page_scale_factor
);
357 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
358 // requirement: SynchronousCompositorImpl() must only be used on the UI thread.
359 bool SynchronousCompositorImpl::CalledOnValidThread() const {
360 return BrowserThread::CurrentlyOn(BrowserThread::UI
);
364 void SynchronousCompositor::SetClientForWebContents(
365 WebContents
* contents
,
366 SynchronousCompositorClient
* client
) {
369 g_factory
.Get(); // Ensure it's initialized.
370 SynchronousCompositorImpl::CreateForWebContents(contents
);
372 SynchronousCompositorImpl
* instance
=
373 SynchronousCompositorImpl::FromWebContents(contents
);
375 instance
->SetClient(client
);
378 } // namespace content