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
GetInProcessRendererId()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
FromID(int process_id,int routing_id)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
FromRoutingID(int routing_id)60 SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID(
61 int routing_id) {
62 return FromID(GetInProcessRendererId(), routing_id);
63 }
64
SynchronousCompositorImpl(WebContents * contents)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
~SynchronousCompositorImpl()74 SynchronousCompositorImpl::~SynchronousCompositorImpl() {
75 if (compositor_client_)
76 compositor_client_->DidDestroyCompositor(this);
77 SetInputHandler(NULL);
78 }
79
SetClient(SynchronousCompositorClient * compositor_client)80 void SynchronousCompositorImpl::SetClient(
81 SynchronousCompositorClient* compositor_client) {
82 DCHECK(CalledOnValidThread());
83 compositor_client_ = compositor_client;
84 }
85
86 // static
SetGpuService(scoped_refptr<gpu::InProcessCommandBuffer::Service> service)87 void SynchronousCompositor::SetGpuService(
88 scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
89 g_factory.Get().SetDeferredGpuService(service);
90 }
91
92 // static
SetRecordFullDocument(bool record_full_document)93 void SynchronousCompositor::SetRecordFullDocument(bool record_full_document) {
94 g_factory.Get().SetRecordFullDocument(record_full_document);
95 }
96
InitializeHwDraw()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
ReleaseHwDraw()111 void SynchronousCompositorImpl::ReleaseHwDraw() {
112 DCHECK(CalledOnValidThread());
113 DCHECK(output_surface_);
114 output_surface_->ReleaseHwDraw();
115 g_factory.Get().CompositorReleasedHardwareDraw();
116 }
117
GetShareContext()118 gpu::GLInProcessContext* SynchronousCompositorImpl::GetShareContext() {
119 DCHECK(CalledOnValidThread());
120 return g_factory.Get().GetShareContext();
121 }
122
DemandDrawHw(gfx::Size surface_size,const gfx::Transform & transform,gfx::Rect viewport,gfx::Rect clip,gfx::Rect viewport_rect_for_tile_priority,const gfx::Transform & transform_for_tile_priority)123 scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(
124 gfx::Size surface_size,
125 const gfx::Transform& transform,
126 gfx::Rect viewport,
127 gfx::Rect clip,
128 gfx::Rect viewport_rect_for_tile_priority,
129 const gfx::Transform& transform_for_tile_priority) {
130 DCHECK(CalledOnValidThread());
131 DCHECK(output_surface_);
132
133 scoped_ptr<cc::CompositorFrame> frame =
134 output_surface_->DemandDrawHw(surface_size,
135 transform,
136 viewport,
137 clip,
138 viewport_rect_for_tile_priority,
139 transform_for_tile_priority);
140 if (frame.get())
141 UpdateFrameMetaData(frame->metadata);
142 return frame.Pass();
143 }
144
ReturnResources(const cc::CompositorFrameAck & frame_ack)145 void SynchronousCompositorImpl::ReturnResources(
146 const cc::CompositorFrameAck& frame_ack) {
147 DCHECK(CalledOnValidThread());
148 output_surface_->ReturnResources(frame_ack);
149 }
150
DemandDrawSw(SkCanvas * canvas)151 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) {
152 DCHECK(CalledOnValidThread());
153 DCHECK(output_surface_);
154
155 scoped_ptr<cc::CompositorFrame> frame = output_surface_->DemandDrawSw(canvas);
156 if (frame.get())
157 UpdateFrameMetaData(frame->metadata);
158 return !!frame.get();
159 }
160
UpdateFrameMetaData(const cc::CompositorFrameMetadata & frame_metadata)161 void SynchronousCompositorImpl::UpdateFrameMetaData(
162 const cc::CompositorFrameMetadata& frame_metadata) {
163 RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
164 contents_->GetRenderWidgetHostView());
165 if (rwhv)
166 rwhv->SynchronousFrameMetadata(frame_metadata);
167 }
168
SetMemoryPolicy(const SynchronousCompositorMemoryPolicy & policy)169 void SynchronousCompositorImpl::SetMemoryPolicy(
170 const SynchronousCompositorMemoryPolicy& policy) {
171 DCHECK(CalledOnValidThread());
172 DCHECK(output_surface_);
173
174 output_surface_->SetMemoryPolicy(policy);
175 }
176
DidChangeRootLayerScrollOffset()177 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
178 if (input_handler_)
179 input_handler_->OnRootLayerDelegatedScrollOffsetChanged();
180 }
181
DidBindOutputSurface(SynchronousCompositorOutputSurface * output_surface)182 void SynchronousCompositorImpl::DidBindOutputSurface(
183 SynchronousCompositorOutputSurface* output_surface) {
184 DCHECK(CalledOnValidThread());
185 output_surface_ = output_surface;
186 if (compositor_client_)
187 compositor_client_->DidInitializeCompositor(this);
188 }
189
DidDestroySynchronousOutputSurface(SynchronousCompositorOutputSurface * output_surface)190 void SynchronousCompositorImpl::DidDestroySynchronousOutputSurface(
191 SynchronousCompositorOutputSurface* output_surface) {
192 DCHECK(CalledOnValidThread());
193
194 // Allow for transient hand-over when two output surfaces may refer to
195 // a single delegate.
196 if (output_surface_ == output_surface) {
197 output_surface_ = NULL;
198 if (compositor_client_)
199 compositor_client_->DidDestroyCompositor(this);
200 compositor_client_ = NULL;
201 }
202 }
203
SetInputHandler(cc::InputHandler * input_handler)204 void SynchronousCompositorImpl::SetInputHandler(
205 cc::InputHandler* input_handler) {
206 DCHECK(CalledOnValidThread());
207
208 if (input_handler_)
209 input_handler_->SetRootLayerScrollOffsetDelegate(NULL);
210
211 input_handler_ = input_handler;
212
213 if (input_handler_)
214 input_handler_->SetRootLayerScrollOffsetDelegate(this);
215 }
216
DidOverscroll(const DidOverscrollParams & params)217 void SynchronousCompositorImpl::DidOverscroll(
218 const DidOverscrollParams& params) {
219 if (compositor_client_) {
220 compositor_client_->DidOverscroll(params.accumulated_overscroll,
221 params.latest_overscroll_delta,
222 params.current_fling_velocity);
223 }
224 }
225
DidStopFlinging()226 void SynchronousCompositorImpl::DidStopFlinging() {
227 RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
228 contents_->GetRenderWidgetHostView());
229 if (rwhv)
230 rwhv->DidStopFlinging();
231 }
232
SetContinuousInvalidate(bool enable)233 void SynchronousCompositorImpl::SetContinuousInvalidate(bool enable) {
234 DCHECK(CalledOnValidThread());
235 if (compositor_client_)
236 compositor_client_->SetContinuousInvalidate(enable);
237 }
238
HandleInputEvent(const blink::WebInputEvent & input_event)239 InputEventAckState SynchronousCompositorImpl::HandleInputEvent(
240 const blink::WebInputEvent& input_event) {
241 DCHECK(CalledOnValidThread());
242 return g_factory.Get().synchronous_input_event_filter()->HandleInputEvent(
243 contents_->GetRoutingID(), input_event);
244 }
245
DidActivatePendingTree()246 void SynchronousCompositorImpl::DidActivatePendingTree() {
247 if (compositor_client_)
248 compositor_client_->DidUpdateContent();
249 }
250
GetTotalScrollOffset()251 gfx::Vector2dF SynchronousCompositorImpl::GetTotalScrollOffset() {
252 DCHECK(CalledOnValidThread());
253 if (compositor_client_)
254 return compositor_client_->GetTotalRootLayerScrollOffset();
255 return gfx::Vector2dF();
256 }
257
IsExternalFlingActive() const258 bool SynchronousCompositorImpl::IsExternalFlingActive() const {
259 DCHECK(CalledOnValidThread());
260 if (compositor_client_)
261 return compositor_client_->IsExternalFlingActive();
262 return false;
263 }
264
UpdateRootLayerState(const gfx::Vector2dF & total_scroll_offset,const gfx::Vector2dF & max_scroll_offset,const gfx::SizeF & scrollable_size,float page_scale_factor,float min_page_scale_factor,float max_page_scale_factor)265 void SynchronousCompositorImpl::UpdateRootLayerState(
266 const gfx::Vector2dF& total_scroll_offset,
267 const gfx::Vector2dF& max_scroll_offset,
268 const gfx::SizeF& scrollable_size,
269 float page_scale_factor,
270 float min_page_scale_factor,
271 float max_page_scale_factor) {
272 DCHECK(CalledOnValidThread());
273 if (!compositor_client_)
274 return;
275
276 compositor_client_->UpdateRootLayerState(total_scroll_offset,
277 max_scroll_offset,
278 scrollable_size,
279 page_scale_factor,
280 min_page_scale_factor,
281 max_page_scale_factor);
282 }
283
284 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
285 // requirement: SynchronousCompositorImpl() must only be used on the UI thread.
CalledOnValidThread() const286 bool SynchronousCompositorImpl::CalledOnValidThread() const {
287 return BrowserThread::CurrentlyOn(BrowserThread::UI);
288 }
289
290 // static
SetClientForWebContents(WebContents * contents,SynchronousCompositorClient * client)291 void SynchronousCompositor::SetClientForWebContents(
292 WebContents* contents,
293 SynchronousCompositorClient* client) {
294 DCHECK(contents);
295 if (client) {
296 g_factory.Get(); // Ensure it's initialized.
297 SynchronousCompositorImpl::CreateForWebContents(contents);
298 }
299 if (SynchronousCompositorImpl* instance =
300 SynchronousCompositorImpl::FromWebContents(contents)) {
301 instance->SetClient(client);
302 }
303 }
304
305 } // namespace content
306