Chromium Code Reviews| Index: components/exo/surface.cc | 
| diff --git a/components/exo/surface.cc b/components/exo/surface.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..87e0f28c9ab1414833447fb6b1b33b819a45e984 | 
| --- /dev/null | 
| +++ b/components/exo/surface.cc | 
| @@ -0,0 +1,163 @@ | 
| +// Copyright 2015 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "components/exo/surface.h" | 
| + | 
| +#include "base/callback_helpers.h" | 
| +#include "base/logging.h" | 
| +#include "base/trace_event/trace_event.h" | 
| +#include "base/trace_event/trace_event_argument.h" | 
| +#include "cc/resources/single_release_callback.h" | 
| +#include "components/exo/buffer.h" | 
| +#include "components/exo/surface_delegate.h" | 
| +#include "ui/compositor/layer.h" | 
| +#include "ui/gfx/buffer_format_util.h" | 
| +#include "ui/gfx/gpu_memory_buffer.h" | 
| + | 
| +namespace exo { | 
| + | 
| +//////////////////////////////////////////////////////////////////////////////// | 
| +// Surface, public: | 
| + | 
| +Surface::Surface() : delegate_(nullptr) { | 
| + SetLayer(new ui::Layer(ui::LAYER_SOLID_COLOR)); | 
| + set_owned_by_client(); | 
| +} | 
| + | 
| +Surface::~Surface() { | 
| + if (delegate_) | 
| + delegate_->OnSurfaceDestroying(); | 
| + | 
| + if (pending_mailbox_release_callback_) | 
| + pending_mailbox_release_callback_->Run(gpu::SyncToken(), false); | 
| + | 
| + layer()->SetShowSolidColorContent(); | 
| + | 
| + // If we are observing the compositor for frame callbacks, stop now. | 
| + if (!frame_callbacks_.empty() || !active_frame_callbacks_.empty()) | 
| + layer()->GetCompositor()->RemoveObserver(this); | 
| +} | 
| + | 
| +void Surface::Attach(Buffer* buffer, const gfx::Point& point) { | 
| + TRACE_EVENT2("exo", "Surface::Attach", "buffer", buffer->AsTracedValue(), | 
| + "point", point.ToString()); | 
| + | 
| + // If Attach() is called twice without calling Commit(), run the release | 
| + // callback for the previous buffer now. | 
| + if (pending_mailbox_release_callback_) { | 
| + pending_mailbox_release_callback_->Run(gpu::SyncToken(), false); | 
| + pending_mailbox_release_callback_ = nullptr; | 
| + } | 
| + | 
| + // If |buffer| is null, the following Commit() call will remove the surface | 
| + // content. | 
| + if (buffer) { | 
| + pending_mailbox_release_callback_ = | 
| + buffer->GetTextureMailbox(&pending_mailbox_); | 
| + } | 
| +} | 
| + | 
| +void Surface::Damage(const gfx::Rect& damage) { | 
| + TRACE_EVENT1("exo", "Surface::Damage", "damage", damage.ToString()); | 
| + | 
| + pending_damage_.Union(damage); | 
| +} | 
| + | 
| +void Surface::RequestFrameCallback(const FrameCallback& callback) { | 
| + TRACE_EVENT0("exo", "Surface::RequestFrameCallback"); | 
| + | 
| + pending_frame_callbacks_.push_back(callback); | 
| +} | 
| + | 
| +void Surface::SetOpaqueRegion(const cc::Region& region) { | 
| + TRACE_EVENT1("exo", "Surface::SetOpaqueRegion", "region", region.ToString()); | 
| + | 
| + pending_opaque_region_ = region; | 
| +} | 
| + | 
| +void Surface::Commit() { | 
| + TRACE_EVENT0("exo", "Surface::Commit"); | 
| + | 
| + if (delegate_) | 
| + delegate_->OnSurfaceCommit(); | 
| + | 
| + if (pending_mailbox_release_callback_) { | 
| + // Update layer with the new contents. | 
| + layer()->SetTextureMailbox(pending_mailbox_, | 
| + pending_mailbox_release_callback_.Pass(), | 
| + pending_mailbox_.size_in_pixels()); | 
| + layer()->SetTextureFlipped(false); | 
| + layer()->SetBounds(gfx::Rect(layer()->bounds().origin(), | 
| + pending_mailbox_.size_in_pixels())); | 
| + layer()->SetFillsBoundsOpaquely(pending_opaque_region_.Contains( | 
| + gfx::Rect(pending_mailbox_.size_in_pixels()))); | 
| + } else { | 
| + // Show solid color content if there is no pending buffer. | 
| + layer()->SetShowSolidColorContent(); | 
| + } | 
| + | 
| + // Schedule redraw of the damage region. | 
| + layer()->SchedulePaint(pending_damage_); | 
| + pending_damage_ = gfx::Rect(); | 
| + | 
| + ui::Compositor* compositor = layer()->GetCompositor(); | 
| + if (compositor) { | 
| + // Start observing the compositor for frame callbacks. | 
| + if (frame_callbacks_.empty() && active_frame_callbacks_.empty()) | 
| 
 
lpique
2015/11/05 21:25:00
Shouldn't you also check "&& !frame_callbacks_.emp
 
 | 
| + compositor->AddObserver(this); | 
| + | 
| + // Move pending frame callbacks to the end of |frame_callbacks_|. | 
| + frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_); | 
| 
 
lpique
2015/11/05 21:25:00
Under the calling sequence:
  Surface::RequestFra
 
 | 
| + } | 
| +} | 
| + | 
| +void Surface::SetSurfaceDelegate(SurfaceDelegate* delegate) { | 
| + DCHECK(!delegate_ || !delegate); | 
| + delegate_ = delegate; | 
| +} | 
| + | 
| +scoped_refptr<base::trace_event::TracedValue> Surface::AsTracedValue() const { | 
| + scoped_refptr<base::trace_event::TracedValue> value = | 
| + new base::trace_event::TracedValue; | 
| + value->SetString("name", layer()->name()); | 
| + return value; | 
| +} | 
| + | 
| +//////////////////////////////////////////////////////////////////////////////// | 
| +// views::Views overrides: | 
| + | 
| +gfx::Size Surface::GetPreferredSize() const { | 
| + return pending_mailbox_release_callback_ ? pending_mailbox_.size_in_pixels() | 
| + : layer()->size(); | 
| +} | 
| + | 
| +//////////////////////////////////////////////////////////////////////////////// | 
| +// ui::CompositorObserver overrides: | 
| + | 
| +void Surface::OnCompositingDidCommit(ui::Compositor* compositor) { | 
| + // Move frame callbacks to the end of |active_frame_callbacks_|. | 
| + active_frame_callbacks_.splice(active_frame_callbacks_.end(), | 
| + frame_callbacks_); | 
| +} | 
| + | 
| +void Surface::OnCompositingStarted(ui::Compositor* compositor, | 
| + base::TimeTicks start_time) { | 
| + // Run all frame callbacks associated with the compositor's active tree. | 
| + while (!active_frame_callbacks_.empty()) { | 
| + active_frame_callbacks_.front().Run(start_time); | 
| + active_frame_callbacks_.pop_front(); | 
| + } | 
| + | 
| + // Stop observing the compositor if we have processed all frame callbacks. | 
| + if (frame_callbacks_.empty()) | 
| + compositor->RemoveObserver(this); | 
| +} | 
| + | 
| +void Surface::OnCompositingShuttingDown(ui::Compositor* compositor) { | 
| + compositor->RemoveObserver(this); | 
| + active_frame_callbacks_.clear(); | 
| + frame_callbacks_.clear(); | 
| +} | 
| + | 
| +} // namespace exo |