compositor.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/compositor/compositor.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <deque>
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/singleton.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/message_loop.h"
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/string_util.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread_restrictions.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "cc/base/switches.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "cc/base/thread_impl.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "cc/input/input_handler.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "cc/layers/layer.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "cc/output/context_provider.h"
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "cc/output/output_surface.h"
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "cc/trees/layer_tree_host.h"
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/compositor/compositor_observer.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/compositor/compositor_switches.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/compositor/dip_util.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/compositor/layer.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/compositor/test_web_graphics_context_3d.h"
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/gl/gl_context.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gl/gl_implementation.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gl/gl_surface.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gl/gl_switches.h"
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "webkit/gpu/grcontext_for_webgraphicscontext3d.h"
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "webkit/gpu/webgraphicscontext3d_in_process_impl.h"
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_CHROMEOS)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/chromeos/chromeos_version.h"
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const double kDefaultRefreshRate = 60.0;
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const double kTestRefreshRate = 100.0;
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccienum SwapType {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DRAW_SWAP,
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  READPIXELS_SWAP,
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::Thread* g_compositor_thread = NULL;
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool g_test_compositor_enabled = false;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ui::ContextFactory* g_implicit_factory = NULL;
56ui::ContextFactory* g_context_factory = NULL;
57
58const int kCompositorLockTimeoutMs = 67;
59
60class PendingSwap {
61 public:
62  PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps);
63  ~PendingSwap();
64
65  SwapType type() const { return type_; }
66  bool posted() const { return posted_; }
67
68 private:
69  friend class ui::PostedSwapQueue;
70
71  SwapType type_;
72  bool posted_;
73  ui::PostedSwapQueue* posted_swaps_;
74
75  DISALLOW_COPY_AND_ASSIGN(PendingSwap);
76};
77
78void SetupImplicitFactory() {
79  // We leak the implicit factory so that we don't race with the tear down of
80  // the gl_bindings.
81  DCHECK(!g_context_factory);
82  DCHECK(!g_implicit_factory);
83  if (g_test_compositor_enabled) {
84    g_implicit_factory = new ui::TestContextFactory;
85  } else {
86    DVLOG(1) << "Using DefaultContextFactory";
87    scoped_ptr<ui::DefaultContextFactory> instance(
88        new ui::DefaultContextFactory());
89    if (instance->Initialize())
90      g_implicit_factory = instance.release();
91  }
92  g_context_factory = g_implicit_factory;
93}
94
95void ResetImplicitFactory() {
96  if (!g_implicit_factory || g_context_factory != g_implicit_factory)
97    return;
98  delete g_implicit_factory;
99  g_implicit_factory = NULL;
100  g_context_factory = NULL;
101}
102
103}  // namespace
104
105namespace ui {
106
107// static
108ContextFactory* ContextFactory::GetInstance() {
109  if (!g_context_factory)
110    SetupImplicitFactory();
111  return g_context_factory;
112}
113
114// static
115void ContextFactory::SetInstance(ContextFactory* instance) {
116  g_context_factory = instance;
117}
118
119class ContextProviderFromContextFactory : public cc::ContextProvider {
120 public:
121  static scoped_refptr<ContextProviderFromContextFactory> Create(
122      ContextFactory* factory) {
123    scoped_refptr<ContextProviderFromContextFactory> provider =
124        new ContextProviderFromContextFactory(factory);
125    if (!provider->InitializeOnMainThread())
126      return NULL;
127    return provider;
128  }
129
130  virtual bool BindToCurrentThread() OVERRIDE {
131    DCHECK(context3d_);
132
133    return context3d_->makeContextCurrent();
134  }
135
136  virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
137    DCHECK(context3d_);
138
139    return context3d_.get();
140  }
141
142  virtual class GrContext* GrContext() OVERRIDE {
143    DCHECK(context3d_);
144
145    if (!gr_context_) {
146      gr_context_.reset(
147          new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
148    }
149    return gr_context_->get();
150  }
151
152  virtual void VerifyContexts() OVERRIDE {
153    DCHECK(context3d_);
154
155    if (context3d_->isContextLost()) {
156      base::AutoLock lock(destroyed_lock_);
157      destroyed_ = true;
158    }
159  }
160
161  virtual bool DestroyedOnMainThread() OVERRIDE {
162    base::AutoLock lock(destroyed_lock_);
163    return destroyed_;
164  }
165
166 protected:
167  explicit ContextProviderFromContextFactory(ContextFactory* factory)
168      : factory_(factory),
169        destroyed_(false) {}
170  virtual ~ContextProviderFromContextFactory() {}
171
172  bool InitializeOnMainThread() {
173    if (context3d_)
174      return true;
175    context3d_.reset(factory_->CreateOffscreenContext());
176    return !!context3d_;
177  }
178
179 private:
180  ContextFactory* factory_;
181  base::Lock destroyed_lock_;
182  bool destroyed_;
183  scoped_ptr<WebKit::WebGraphicsContext3D> context3d_;
184  scoped_ptr<webkit::gpu::GrContextForWebGraphicsContext3D> gr_context_;
185};
186
187DefaultContextFactory::DefaultContextFactory() {
188}
189
190DefaultContextFactory::~DefaultContextFactory() {
191}
192
193bool DefaultContextFactory::Initialize() {
194  if (!gfx::GLSurface::InitializeOneOff() ||
195      gfx::GetGLImplementation() == gfx::kGLImplementationNone) {
196    LOG(ERROR) << "Could not load the GL bindings";
197    return false;
198  }
199  return true;
200}
201
202cc::OutputSurface* DefaultContextFactory::CreateOutputSurface(
203    Compositor* compositor) {
204  return new cc::OutputSurface(
205      make_scoped_ptr(CreateContextCommon(compositor, false)));
206}
207
208WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateOffscreenContext() {
209  return CreateContextCommon(NULL, true);
210}
211
212scoped_refptr<cc::ContextProvider>
213DefaultContextFactory::OffscreenContextProviderForMainThread() {
214  if (!offscreen_contexts_main_thread_ ||
215      !offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
216    offscreen_contexts_main_thread_ =
217        ContextProviderFromContextFactory::Create(this);
218    if (offscreen_contexts_main_thread_ &&
219        !offscreen_contexts_main_thread_->BindToCurrentThread())
220      offscreen_contexts_main_thread_ = NULL;
221  }
222  return offscreen_contexts_main_thread_;
223}
224
225scoped_refptr<cc::ContextProvider>
226DefaultContextFactory::OffscreenContextProviderForCompositorThread() {
227  if (!offscreen_contexts_compositor_thread_ ||
228      !offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
229    offscreen_contexts_compositor_thread_ =
230        ContextProviderFromContextFactory::Create(this);
231  }
232  return offscreen_contexts_compositor_thread_;
233}
234
235void DefaultContextFactory::RemoveCompositor(Compositor* compositor) {
236}
237
238WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateContextCommon(
239    Compositor* compositor,
240    bool offscreen) {
241  DCHECK(offscreen || compositor);
242  WebKit::WebGraphicsContext3D::Attributes attrs;
243  attrs.depth = false;
244  attrs.stencil = false;
245  attrs.antialias = false;
246  attrs.shareResources = true;
247  WebKit::WebGraphicsContext3D* context =
248      offscreen ?
249      webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWebView(
250          attrs, false) :
251      webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWindow(
252          attrs, compositor->widget(), NULL);
253  if (!context)
254    return NULL;
255
256  CommandLine* command_line = CommandLine::ForCurrentProcess();
257  if (!offscreen) {
258    context->makeContextCurrent();
259    gfx::GLContext* gl_context = gfx::GLContext::GetCurrent();
260    bool vsync = !command_line->HasSwitch(switches::kDisableGpuVsync);
261    gl_context->SetSwapInterval(vsync ? 1 : 0);
262    gl_context->ReleaseCurrent(NULL);
263  }
264  return context;
265}
266
267TestContextFactory::TestContextFactory() {}
268
269TestContextFactory::~TestContextFactory() {}
270
271cc::OutputSurface* TestContextFactory::CreateOutputSurface(
272    Compositor* compositor) {
273  return new cc::OutputSurface(make_scoped_ptr(CreateOffscreenContext()));
274}
275
276WebKit::WebGraphicsContext3D* TestContextFactory::CreateOffscreenContext() {
277  ui::TestWebGraphicsContext3D* context = new ui::TestWebGraphicsContext3D;
278  context->Initialize();
279  return context;
280}
281
282scoped_refptr<cc::ContextProvider>
283TestContextFactory::OffscreenContextProviderForMainThread() {
284  if (!offscreen_contexts_main_thread_ ||
285      offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
286    offscreen_contexts_main_thread_ =
287        ContextProviderFromContextFactory::Create(this);
288    CHECK(offscreen_contexts_main_thread_->BindToCurrentThread());
289  }
290  return offscreen_contexts_main_thread_;
291}
292
293scoped_refptr<cc::ContextProvider>
294TestContextFactory::OffscreenContextProviderForCompositorThread() {
295  if (!offscreen_contexts_compositor_thread_ ||
296      offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
297    offscreen_contexts_compositor_thread_ =
298        ContextProviderFromContextFactory::Create(this);
299  }
300  return offscreen_contexts_compositor_thread_;
301}
302
303void TestContextFactory::RemoveCompositor(Compositor* compositor) {
304}
305
306Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor)
307    : size_(size),
308      flipped_(flipped),
309      device_scale_factor_(device_scale_factor) {
310}
311
312Texture::~Texture() {
313}
314
315std::string Texture::Produce() {
316  return EmptyString();
317}
318
319CompositorLock::CompositorLock(Compositor* compositor)
320    : compositor_(compositor) {
321  MessageLoop::current()->PostDelayedTask(
322      FROM_HERE,
323      base::Bind(&CompositorLock::CancelLock, AsWeakPtr()),
324      base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs));
325}
326
327CompositorLock::~CompositorLock() {
328  CancelLock();
329}
330
331void CompositorLock::CancelLock() {
332  if (!compositor_)
333    return;
334  compositor_->UnlockCompositor();
335  compositor_ = NULL;
336}
337
338class PostedSwapQueue {
339 public:
340  PostedSwapQueue() : pending_swap_(NULL) {
341  }
342
343  ~PostedSwapQueue() {
344    DCHECK(!pending_swap_);
345  }
346
347  SwapType NextPostedSwap() const {
348    return queue_.front();
349  }
350
351  bool AreSwapsPosted() const {
352    return !queue_.empty();
353  }
354
355  int NumSwapsPosted(SwapType type) const {
356    int count = 0;
357    for (std::deque<SwapType>::const_iterator it = queue_.begin();
358         it != queue_.end(); ++it) {
359      if (*it == type)
360        count++;
361    }
362    return count;
363  }
364
365  void PostSwap() {
366    DCHECK(pending_swap_);
367    queue_.push_back(pending_swap_->type());
368    pending_swap_->posted_ = true;
369  }
370
371  void EndSwap() {
372    queue_.pop_front();
373  }
374
375 private:
376  friend class ::PendingSwap;
377
378  PendingSwap* pending_swap_;
379  std::deque<SwapType> queue_;
380
381  DISALLOW_COPY_AND_ASSIGN(PostedSwapQueue);
382};
383
384}  // namespace ui
385
386namespace {
387
388PendingSwap::PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps)
389    : type_(type), posted_(false), posted_swaps_(posted_swaps) {
390  // Only one pending swap in flight.
391  DCHECK_EQ(static_cast<PendingSwap*>(NULL), posted_swaps_->pending_swap_);
392  posted_swaps_->pending_swap_ = this;
393}
394
395PendingSwap::~PendingSwap() {
396  DCHECK_EQ(this, posted_swaps_->pending_swap_);
397  posted_swaps_->pending_swap_ = NULL;
398}
399
400}  // namespace
401
402namespace ui {
403
404Compositor::Compositor(CompositorDelegate* delegate,
405                       gfx::AcceleratedWidget widget)
406    : delegate_(delegate),
407      root_layer_(NULL),
408      widget_(widget),
409      posted_swaps_(new PostedSwapQueue()),
410      device_scale_factor_(0.0f),
411      last_started_frame_(0),
412      last_ended_frame_(0),
413      disable_schedule_composite_(false),
414      compositor_lock_(NULL) {
415  root_web_layer_ = cc::Layer::Create();
416  root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f));
417
418  CommandLine* command_line = CommandLine::ForCurrentProcess();
419
420  cc::LayerTreeSettings settings;
421  settings.refresh_rate =
422      g_test_compositor_enabled ? kTestRefreshRate : kDefaultRefreshRate;
423  settings.partial_swap_enabled =
424      command_line->HasSwitch(cc::switches::kUIEnablePartialSwap);
425  settings.per_tile_painting_enabled =
426      command_line->HasSwitch(cc::switches::kUIEnablePerTilePainting);
427
428  // These flags should be mirrored by renderer versions in content/renderer/.
429  settings.initial_debug_state.show_debug_borders =
430      command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders);
431  settings.initial_debug_state.show_fps_counter =
432      command_line->HasSwitch(cc::switches::kUIShowFPSCounter);
433  settings.initial_debug_state.show_paint_rects =
434      command_line->HasSwitch(switches::kUIShowPaintRects);
435  settings.initial_debug_state.show_platform_layer_tree =
436      command_line->HasSwitch(cc::switches::kUIShowCompositedLayerTree);
437  settings.initial_debug_state.show_property_changed_rects =
438      command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects);
439  settings.initial_debug_state.show_surface_damage_rects =
440      command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects);
441  settings.initial_debug_state.show_screen_space_rects =
442      command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects);
443  settings.initial_debug_state.show_replica_screen_space_rects =
444      command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects);
445  settings.initial_debug_state.show_occluding_rects =
446      command_line->HasSwitch(cc::switches::kUIShowOccludingRects);
447  settings.initial_debug_state.show_non_occluding_rects =
448      command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects);
449
450  scoped_ptr<cc::Thread> thread;
451  if (g_compositor_thread) {
452    thread = cc::ThreadImpl::CreateForDifferentThread(
453        g_compositor_thread->message_loop_proxy());
454  }
455
456  host_ = cc::LayerTreeHost::Create(this, settings, thread.Pass());
457  host_->SetRootLayer(root_web_layer_);
458  host_->SetSurfaceReady();
459}
460
461Compositor::~Compositor() {
462  CancelCompositorLock();
463  DCHECK(!compositor_lock_);
464
465  // Don't call |CompositorDelegate::ScheduleDraw| from this point.
466  delegate_ = NULL;
467  if (root_layer_)
468    root_layer_->SetCompositor(NULL);
469
470  // Stop all outstanding draws before telling the ContextFactory to tear
471  // down any contexts that the |host_| may rely upon.
472  host_.reset();
473
474  ContextFactory::GetInstance()->RemoveCompositor(this);
475}
476
477void Compositor::Initialize(bool use_thread) {
478  if (use_thread) {
479    g_compositor_thread = new base::Thread("Browser Compositor");
480    g_compositor_thread->Start();
481  }
482}
483
484void Compositor::Terminate() {
485  if (g_compositor_thread) {
486    g_compositor_thread->Stop();
487    delete g_compositor_thread;
488    g_compositor_thread = NULL;
489  }
490}
491
492void Compositor::ScheduleDraw() {
493  if (g_compositor_thread)
494    host_->Composite(base::TimeTicks::Now());
495  else if (delegate_)
496    delegate_->ScheduleDraw();
497}
498
499void Compositor::SetRootLayer(Layer* root_layer) {
500  if (root_layer_ == root_layer)
501    return;
502  if (root_layer_)
503    root_layer_->SetCompositor(NULL);
504  root_layer_ = root_layer;
505  if (root_layer_ && !root_layer_->GetCompositor())
506    root_layer_->SetCompositor(this);
507  root_web_layer_->RemoveAllChildren();
508  if (root_layer_)
509    root_web_layer_->AddChild(root_layer_->cc_layer());
510}
511
512void Compositor::SetHostHasTransparentBackground(
513    bool host_has_transparent_background) {
514  host_->set_has_transparent_background(host_has_transparent_background);
515}
516
517void Compositor::Draw(bool force_clear) {
518  DCHECK(!g_compositor_thread);
519
520  if (!root_layer_)
521    return;
522
523  last_started_frame_++;
524  PendingSwap pending_swap(DRAW_SWAP, posted_swaps_.get());
525  if (!IsLocked()) {
526    // TODO(nduca): Temporary while compositor calls
527    // compositeImmediately() directly.
528    Layout();
529    host_->Composite(base::TimeTicks::Now());
530  }
531  if (!pending_swap.posted())
532    NotifyEnd();
533}
534
535void Compositor::ScheduleFullDraw() {
536  host_->SetNeedsRedraw();
537}
538
539bool Compositor::ReadPixels(SkBitmap* bitmap,
540                            const gfx::Rect& bounds_in_pixel) {
541  if (bounds_in_pixel.right() > size().width() ||
542      bounds_in_pixel.bottom() > size().height())
543    return false;
544  bitmap->setConfig(SkBitmap::kARGB_8888_Config,
545                    bounds_in_pixel.width(), bounds_in_pixel.height());
546  bitmap->allocPixels();
547  SkAutoLockPixels lock_image(*bitmap);
548  unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels());
549  CancelCompositorLock();
550  PendingSwap pending_swap(READPIXELS_SWAP, posted_swaps_.get());
551  return host_->CompositeAndReadback(pixels, bounds_in_pixel);
552}
553
554void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) {
555  DCHECK_GT(scale, 0);
556  if (!size_in_pixel.IsEmpty()) {
557    size_ = size_in_pixel;
558    host_->SetViewportSize(size_in_pixel, size_in_pixel);
559    root_web_layer_->SetBounds(size_in_pixel);
560  }
561  if (device_scale_factor_ != scale) {
562    device_scale_factor_ = scale;
563    if (root_layer_)
564      root_layer_->OnDeviceScaleFactorChanged(scale);
565  }
566}
567
568void Compositor::AddObserver(CompositorObserver* observer) {
569  observer_list_.AddObserver(observer);
570}
571
572void Compositor::RemoveObserver(CompositorObserver* observer) {
573  observer_list_.RemoveObserver(observer);
574}
575
576bool Compositor::HasObserver(CompositorObserver* observer) {
577  return observer_list_.HasObserver(observer);
578}
579
580void Compositor::OnSwapBuffersPosted() {
581  DCHECK(!g_compositor_thread);
582  posted_swaps_->PostSwap();
583}
584
585void Compositor::OnSwapBuffersComplete() {
586  DCHECK(!g_compositor_thread);
587  DCHECK(posted_swaps_->AreSwapsPosted());
588  DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
589  if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
590    NotifyEnd();
591  posted_swaps_->EndSwap();
592}
593
594void Compositor::OnSwapBuffersAborted() {
595  DCHECK(!g_compositor_thread);
596  DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
597
598  // We've just lost the context, so unwind all posted_swaps.
599  while (posted_swaps_->AreSwapsPosted()) {
600    if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
601      NotifyEnd();
602    posted_swaps_->EndSwap();
603  }
604
605  FOR_EACH_OBSERVER(CompositorObserver,
606                    observer_list_,
607                    OnCompositingAborted(this));
608}
609
610void Compositor::OnUpdateVSyncParameters(base::TimeTicks timebase,
611                                         base::TimeDelta interval) {
612  FOR_EACH_OBSERVER(CompositorObserver,
613                    observer_list_,
614                    OnUpdateVSyncParameters(this, timebase, interval));
615}
616
617void Compositor::Layout() {
618  // We're sending damage that will be addressed during this composite
619  // cycle, so we don't need to schedule another composite to address it.
620  disable_schedule_composite_ = true;
621  if (root_layer_)
622    root_layer_->SendDamagedRects();
623  disable_schedule_composite_ = false;
624}
625
626scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface() {
627  return make_scoped_ptr(
628      ContextFactory::GetInstance()->CreateOutputSurface(this));
629}
630
631scoped_ptr<cc::InputHandler> Compositor::CreateInputHandler() {
632  return scoped_ptr<cc::InputHandler>();
633}
634
635void Compositor::DidCommit() {
636  DCHECK(!IsLocked());
637  FOR_EACH_OBSERVER(CompositorObserver,
638                    observer_list_,
639                    OnCompositingDidCommit(this));
640}
641
642void Compositor::DidCommitAndDrawFrame() {
643  base::TimeTicks start_time = base::TimeTicks::Now();
644  FOR_EACH_OBSERVER(CompositorObserver,
645                    observer_list_,
646                    OnCompositingStarted(this, start_time));
647}
648
649void Compositor::DidCompleteSwapBuffers() {
650  DCHECK(g_compositor_thread);
651  NotifyEnd();
652}
653
654void Compositor::ScheduleComposite() {
655  if (!disable_schedule_composite_)
656    ScheduleDraw();
657}
658
659scoped_refptr<cc::ContextProvider>
660Compositor::OffscreenContextProviderForMainThread() {
661  return ContextFactory::GetInstance()->OffscreenContextProviderForMainThread();
662}
663
664scoped_refptr<cc::ContextProvider>
665Compositor::OffscreenContextProviderForCompositorThread() {
666  return ContextFactory::GetInstance()->
667      OffscreenContextProviderForCompositorThread();
668}
669
670scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
671  if (!compositor_lock_) {
672    compositor_lock_ = new CompositorLock(this);
673    if (g_compositor_thread)
674      host_->SetDeferCommits(true);
675    FOR_EACH_OBSERVER(CompositorObserver,
676                      observer_list_,
677                      OnCompositingLockStateChanged(this));
678  }
679  return compositor_lock_;
680}
681
682void Compositor::UnlockCompositor() {
683  DCHECK(compositor_lock_);
684  compositor_lock_ = NULL;
685  if (g_compositor_thread)
686    host_->SetDeferCommits(false);
687  FOR_EACH_OBSERVER(CompositorObserver,
688                    observer_list_,
689                    OnCompositingLockStateChanged(this));
690}
691
692void Compositor::CancelCompositorLock() {
693  if (compositor_lock_)
694    compositor_lock_->CancelLock();
695}
696
697void Compositor::NotifyEnd() {
698  last_ended_frame_++;
699  FOR_EACH_OBSERVER(CompositorObserver,
700                    observer_list_,
701                    OnCompositingEnded(this));
702}
703
704COMPOSITOR_EXPORT void SetupTestCompositor() {
705  if (!CommandLine::ForCurrentProcess()->HasSwitch(
706      switches::kDisableTestCompositor)) {
707    g_test_compositor_enabled = true;
708  }
709#if defined(OS_CHROMEOS)
710  // If the test is running on the chromeos envrionment (such as
711  // device or vm bots), use the real compositor.
712  if (base::chromeos::IsRunningOnChromeOS())
713    g_test_compositor_enabled = false;
714#endif
715  ResetImplicitFactory();
716}
717
718COMPOSITOR_EXPORT void DisableTestCompositor() {
719  ResetImplicitFactory();
720  g_test_compositor_enabled = false;
721}
722
723COMPOSITOR_EXPORT bool IsTestCompositorEnabled() {
724  return g_test_compositor_enabled;
725}
726
727}  // namespace ui
728