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 "cc/input/layer_scroll_offset_delegate.h"
11 #include "content/browser/android/in_process/synchronous_compositor_factory_impl.h"
12 #include "content/browser/android/in_process/synchronous_input_event_filter.h"
13 #include "content/browser/renderer_host/render_widget_host_view_android.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 DCHECK(contents);
71 }
72
~SynchronousCompositorImpl()73 SynchronousCompositorImpl::~SynchronousCompositorImpl() {
74 if (compositor_client_)
75 compositor_client_->DidDestroyCompositor(this);
76 SetInputHandler(NULL);
77 }
78
SetClient(SynchronousCompositorClient * compositor_client)79 void SynchronousCompositorImpl::SetClient(
80 SynchronousCompositorClient* compositor_client) {
81 DCHECK(CalledOnValidThread());
82 compositor_client_ = compositor_client;
83 }
84
85 // static
SetGpuService(scoped_refptr<gpu::InProcessCommandBuffer::Service> service)86 void SynchronousCompositor::SetGpuService(
87 scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
88 g_factory.Get().SetDeferredGpuService(service);
89 }
90
InitializeHwDraw(scoped_refptr<gfx::GLSurface> surface)91 bool SynchronousCompositorImpl::InitializeHwDraw(
92 scoped_refptr<gfx::GLSurface> surface) {
93 DCHECK(CalledOnValidThread());
94 DCHECK(output_surface_);
95
96 // Create contexts in this order so that the share group gets passed
97 // along correctly.
98 scoped_refptr<cc::ContextProvider> offscreen_context =
99 g_factory.Get().GetOffscreenContextProviderForCompositorThread();
100 scoped_refptr<cc::ContextProvider> onscreen_context =
101 g_factory.Get().CreateOnscreenContextProviderForCompositorThread(surface);
102
103 bool success =
104 output_surface_->InitializeHwDraw(onscreen_context, offscreen_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
DemandDrawHw(gfx::Size surface_size,const gfx::Transform & transform,gfx::Rect viewport,gfx::Rect clip,bool stencil_enabled)118 bool SynchronousCompositorImpl::DemandDrawHw(
119 gfx::Size surface_size,
120 const gfx::Transform& transform,
121 gfx::Rect viewport,
122 gfx::Rect clip,
123 bool stencil_enabled) {
124 DCHECK(CalledOnValidThread());
125 DCHECK(output_surface_);
126
127 return output_surface_->DemandDrawHw(
128 surface_size, transform, viewport, clip, stencil_enabled);
129 }
130
DemandDrawSw(SkCanvas * canvas)131 bool SynchronousCompositorImpl::DemandDrawSw(SkCanvas* canvas) {
132 DCHECK(CalledOnValidThread());
133 DCHECK(output_surface_);
134
135 return output_surface_->DemandDrawSw(canvas);
136 }
137
SetMemoryPolicy(const SynchronousCompositorMemoryPolicy & policy)138 void SynchronousCompositorImpl::SetMemoryPolicy(
139 const SynchronousCompositorMemoryPolicy& policy) {
140 DCHECK(CalledOnValidThread());
141 DCHECK(output_surface_);
142
143 return output_surface_->SetMemoryPolicy(policy);
144 }
145
DidChangeRootLayerScrollOffset()146 void SynchronousCompositorImpl::DidChangeRootLayerScrollOffset() {
147 if (input_handler_)
148 input_handler_->OnRootLayerDelegatedScrollOffsetChanged();
149 }
150
DidBindOutputSurface(SynchronousCompositorOutputSurface * output_surface)151 void SynchronousCompositorImpl::DidBindOutputSurface(
152 SynchronousCompositorOutputSurface* output_surface) {
153 DCHECK(CalledOnValidThread());
154 output_surface_ = output_surface;
155 if (compositor_client_)
156 compositor_client_->DidInitializeCompositor(this);
157 }
158
DidDestroySynchronousOutputSurface(SynchronousCompositorOutputSurface * output_surface)159 void SynchronousCompositorImpl::DidDestroySynchronousOutputSurface(
160 SynchronousCompositorOutputSurface* output_surface) {
161 DCHECK(CalledOnValidThread());
162
163 // Allow for transient hand-over when two output surfaces may refer to
164 // a single delegate.
165 if (output_surface_ == output_surface) {
166 output_surface_ = NULL;
167 if (compositor_client_)
168 compositor_client_->DidDestroyCompositor(this);
169 compositor_client_ = NULL;
170 }
171 }
172
SetInputHandler(cc::InputHandler * input_handler)173 void SynchronousCompositorImpl::SetInputHandler(
174 cc::InputHandler* input_handler) {
175 DCHECK(CalledOnValidThread());
176
177 if (input_handler_)
178 input_handler_->SetRootLayerScrollOffsetDelegate(NULL);
179
180 input_handler_ = input_handler;
181
182 if (input_handler_)
183 input_handler_->SetRootLayerScrollOffsetDelegate(this);
184 }
185
DidOverscroll(const cc::DidOverscrollParams & params)186 void SynchronousCompositorImpl::DidOverscroll(
187 const cc::DidOverscrollParams& params) {
188 if (compositor_client_) {
189 compositor_client_->DidOverscroll(params.accumulated_overscroll,
190 params.latest_overscroll_delta,
191 params.current_fling_velocity);
192 }
193 }
194
SetContinuousInvalidate(bool enable)195 void SynchronousCompositorImpl::SetContinuousInvalidate(bool enable) {
196 DCHECK(CalledOnValidThread());
197 if (compositor_client_)
198 compositor_client_->SetContinuousInvalidate(enable);
199 }
200
HandleInputEvent(const blink::WebInputEvent & input_event)201 InputEventAckState SynchronousCompositorImpl::HandleInputEvent(
202 const blink::WebInputEvent& input_event) {
203 DCHECK(CalledOnValidThread());
204 return g_factory.Get().synchronous_input_event_filter()->HandleInputEvent(
205 contents_->GetRoutingID(), input_event);
206 }
207
UpdateFrameMetaData(const cc::CompositorFrameMetadata & frame_metadata)208 void SynchronousCompositorImpl::UpdateFrameMetaData(
209 const cc::CompositorFrameMetadata& frame_metadata) {
210 RenderWidgetHostViewAndroid* rwhv = static_cast<RenderWidgetHostViewAndroid*>(
211 contents_->GetRenderWidgetHostView());
212 if (rwhv)
213 rwhv->SynchronousFrameMetadata(frame_metadata);
214 }
215
DidActivatePendingTree()216 void SynchronousCompositorImpl::DidActivatePendingTree() {
217 if (compositor_client_)
218 compositor_client_->DidUpdateContent();
219 }
220
SetMaxScrollOffset(gfx::Vector2dF max_scroll_offset)221 void SynchronousCompositorImpl::SetMaxScrollOffset(
222 gfx::Vector2dF max_scroll_offset) {
223 DCHECK(CalledOnValidThread());
224 if (compositor_client_)
225 compositor_client_->SetMaxRootLayerScrollOffset(max_scroll_offset);
226 }
227
SetTotalScrollOffset(gfx::Vector2dF new_value)228 void SynchronousCompositorImpl::SetTotalScrollOffset(gfx::Vector2dF new_value) {
229 DCHECK(CalledOnValidThread());
230 if (compositor_client_)
231 compositor_client_->SetTotalRootLayerScrollOffset(new_value);
232 }
233
GetTotalScrollOffset()234 gfx::Vector2dF SynchronousCompositorImpl::GetTotalScrollOffset() {
235 DCHECK(CalledOnValidThread());
236 if (compositor_client_)
237 return compositor_client_->GetTotalRootLayerScrollOffset();
238 return gfx::Vector2dF();
239 }
240
IsExternalFlingActive() const241 bool SynchronousCompositorImpl::IsExternalFlingActive() const {
242 DCHECK(CalledOnValidThread());
243 if (compositor_client_)
244 return compositor_client_->IsExternalFlingActive();
245 return false;
246 }
247
SetTotalPageScaleFactor(float page_scale_factor)248 void SynchronousCompositorImpl::SetTotalPageScaleFactor(
249 float page_scale_factor) {
250 DCHECK(CalledOnValidThread());
251 if (compositor_client_)
252 compositor_client_->SetRootLayerPageScaleFactor(page_scale_factor);
253 }
254
SetScrollableSize(gfx::SizeF scrollable_size)255 void SynchronousCompositorImpl::SetScrollableSize(gfx::SizeF scrollable_size) {
256 DCHECK(CalledOnValidThread());
257 if (compositor_client_)
258 compositor_client_->SetRootLayerScrollableSize(scrollable_size);
259 }
260
261 // Not using base::NonThreadSafe as we want to enforce a more exacting threading
262 // requirement: SynchronousCompositorImpl() must only be used on the UI thread.
CalledOnValidThread() const263 bool SynchronousCompositorImpl::CalledOnValidThread() const {
264 return BrowserThread::CurrentlyOn(BrowserThread::UI);
265 }
266
267 // static
SetClientForWebContents(WebContents * contents,SynchronousCompositorClient * client)268 void SynchronousCompositor::SetClientForWebContents(
269 WebContents* contents,
270 SynchronousCompositorClient* client) {
271 DCHECK(contents);
272 if (client) {
273 g_factory.Get(); // Ensure it's initialized.
274 SynchronousCompositorImpl::CreateForWebContents(contents);
275 }
276 if (SynchronousCompositorImpl* instance =
277 SynchronousCompositorImpl::FromWebContents(contents)) {
278 instance->SetClient(client);
279 }
280 }
281
282 } // namespace content
283