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