| Index: components/exo/surface.cc
|
| diff --git a/components/exo/surface.cc b/components/exo/surface.cc
|
| index 6e21edc3b10fe86422022d86413811c2a64b2d0f..3f06238588078c265ef61a1321cc270a55285072 100644
|
| --- a/components/exo/surface.cc
|
| +++ b/components/exo/surface.cc
|
| @@ -11,23 +11,48 @@
|
| #include "cc/resources/single_release_callback.h"
|
| #include "components/exo/buffer.h"
|
| #include "components/exo/surface_delegate.h"
|
| +#include "components/exo/surface_observer.h"
|
| #include "ui/compositor/layer.h"
|
| #include "ui/gfx/buffer_format_util.h"
|
| #include "ui/gfx/gpu_memory_buffer.h"
|
|
|
| namespace exo {
|
| +namespace {
|
| +
|
| +// Helper function that returns an iterator to the first entry in |list|
|
| +// with |key|.
|
| +template <typename T, typename U>
|
| +typename T::iterator FindListEntry(T& list, U key) {
|
| + return std::find_if(list.begin(), list.end(),
|
| + [key](const typename T::value_type& entry) {
|
| + return entry.first == key;
|
| + });
|
| +}
|
| +
|
| +// Helper function that returns true if |list| contains an entry with |key|.
|
| +template <typename T, typename U>
|
| +bool ListContainsEntry(T& list, U key) {
|
| + return FindListEntry(list, key) != list.end();
|
| +}
|
| +
|
| +} // namespace
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| // Surface, public:
|
|
|
| -Surface::Surface() : compositor_(nullptr), delegate_(nullptr) {
|
| +Surface::Surface()
|
| + : needs_commit_surface_hierarchy_(false),
|
| + has_contents_(false),
|
| + compositor_(nullptr),
|
| + delegate_(nullptr) {
|
| SetLayer(new ui::Layer(ui::LAYER_SOLID_COLOR));
|
| set_owned_by_client();
|
| + SetVisible(false);
|
| + SetEnabled(false);
|
| }
|
|
|
| Surface::~Surface() {
|
| - if (delegate_)
|
| - delegate_->OnSurfaceDestroying();
|
| + FOR_EACH_OBSERVER(SurfaceObserver, observers_, OnSurfaceDestroying(this));
|
|
|
| layer()->SetShowSolidColorContent();
|
|
|
| @@ -69,11 +94,108 @@ void Surface::SetOpaqueRegion(const SkRegion& region) {
|
| pending_opaque_region_ = region;
|
| }
|
|
|
| +void Surface::AddSubSurface(Surface* sub_surface) {
|
| + TRACE_EVENT1("exo", "Surface::AddSubSurface", "sub_surface",
|
| + sub_surface->AsTracedValue());
|
| +
|
| + DCHECK(!sub_surface->parent());
|
| + DCHECK(!sub_surface->visible());
|
| + DCHECK(!sub_surface->enabled());
|
| + DCHECK(sub_surface->bounds().origin() == gfx::Point());
|
| + AddChildView(sub_surface);
|
| +
|
| + DCHECK(!ListContainsEntry(pending_sub_surfaces_, sub_surface));
|
| + pending_sub_surfaces_.push_back(std::make_pair(sub_surface, gfx::Point()));
|
| +}
|
| +
|
| +void Surface::RemoveSubSurface(Surface* sub_surface) {
|
| + TRACE_EVENT1("exo", "Surface::AddSubSurface", "sub_surface",
|
| + sub_surface->AsTracedValue());
|
| +
|
| + RemoveChildView(sub_surface);
|
| +
|
| + DCHECK(ListContainsEntry(pending_sub_surfaces_, sub_surface));
|
| + pending_sub_surfaces_.erase(
|
| + FindListEntry(pending_sub_surfaces_, sub_surface));
|
| +}
|
| +
|
| +void Surface::SetSubSurfacePosition(Surface* sub_surface,
|
| + const gfx::Point& position) {
|
| + TRACE_EVENT2("exo", "Surface::SetSubSurfacePosition", "sub_surface",
|
| + sub_surface->AsTracedValue(), "position", position.ToString());
|
| +
|
| + auto it = FindListEntry(pending_sub_surfaces_, sub_surface);
|
| + DCHECK(it != pending_sub_surfaces_.end());
|
| + it->second = position;
|
| +}
|
| +
|
| +void Surface::PlaceSubSurfaceAbove(Surface* sub_surface, Surface* reference) {
|
| + TRACE_EVENT2("exo", "Surface::PlaceSubSurfaceAbove", "sub_surface",
|
| + sub_surface->AsTracedValue(), "reference",
|
| + reference->AsTracedValue());
|
| +
|
| + if (sub_surface == reference) {
|
| + DLOG(WARNING) << "Client tried to place sub-surface above itself";
|
| + return;
|
| + }
|
| +
|
| + auto position_it = pending_sub_surfaces_.begin();
|
| + if (reference != this) {
|
| + position_it = FindListEntry(pending_sub_surfaces_, reference);
|
| + if (position_it == pending_sub_surfaces_.end()) {
|
| + DLOG(WARNING) << "Client tried to place sub-surface above a reference "
|
| + "surface that is neither a parent nor a sibling";
|
| + return;
|
| + }
|
| +
|
| + // Advance iterator to have |position_it| point to the sibling surface
|
| + // above |reference|.
|
| + ++position_it;
|
| + }
|
| +
|
| + DCHECK(ListContainsEntry(pending_sub_surfaces_, sub_surface));
|
| + pending_sub_surfaces_.splice(
|
| + position_it, pending_sub_surfaces_,
|
| + FindListEntry(pending_sub_surfaces_, sub_surface));
|
| +}
|
| +
|
| +void Surface::PlaceSubSurfaceBelow(Surface* sub_surface, Surface* sibling) {
|
| + TRACE_EVENT2("exo", "Surface::PlaceSubSurfaceBelow", "sub_surface",
|
| + sub_surface->AsTracedValue(), "sibling",
|
| + sibling->AsTracedValue());
|
| +
|
| + if (sub_surface == sibling) {
|
| + DLOG(WARNING) << "Client tried to place sub-surface below itself";
|
| + return;
|
| + }
|
| +
|
| + auto sibling_it = FindListEntry(pending_sub_surfaces_, sibling);
|
| + if (sibling_it == pending_sub_surfaces_.end()) {
|
| + DLOG(WARNING) << "Client tried to place sub-surface below a surface that "
|
| + "is not a sibling";
|
| + return;
|
| + }
|
| +
|
| + DCHECK(ListContainsEntry(pending_sub_surfaces_, sub_surface));
|
| + pending_sub_surfaces_.splice(
|
| + sibling_it, pending_sub_surfaces_,
|
| + FindListEntry(pending_sub_surfaces_, sub_surface));
|
| +}
|
| +
|
| void Surface::Commit() {
|
| TRACE_EVENT0("exo", "Surface::Commit");
|
|
|
| + needs_commit_surface_hierarchy_ = true;
|
| +
|
| if (delegate_)
|
| delegate_->OnSurfaceCommit();
|
| + else
|
| + CommitSurfaceHierarchy();
|
| +}
|
| +
|
| +void Surface::CommitSurfaceHierarchy() {
|
| + DCHECK(needs_commit_surface_hierarchy_);
|
| + needs_commit_surface_hierarchy_ = false;
|
|
|
| cc::TextureMailbox texture_mailbox;
|
| scoped_ptr<cc::SingleReleaseCallback> texture_mailbox_release_callback;
|
| @@ -81,9 +203,11 @@ void Surface::Commit() {
|
| texture_mailbox_release_callback =
|
| pending_buffer_->AcquireTextureMailbox(&texture_mailbox);
|
| pending_buffer_.reset();
|
| + has_contents_ = true;
|
| } else {
|
| // Show solid color content if there is no pending buffer.
|
| layer()->SetShowSolidColorContent();
|
| + has_contents_ = false;
|
| }
|
|
|
| if (texture_mailbox_release_callback) {
|
| @@ -113,6 +237,36 @@ void Surface::Commit() {
|
| // Move pending frame callbacks to the end of |frame_callbacks_|.
|
| frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
|
| }
|
| +
|
| + // Synchronize view hierarchy. This will position and update the stacking
|
| + // order of all sub-surfaces after committing all pending state of sub-surface
|
| + // descendants.
|
| + int index = 0;
|
| + for (auto& sub_surface_entry : pending_sub_surfaces_) {
|
| + Surface* sub_surface = sub_surface_entry.first;
|
| +
|
| + // Synchronsouly commit all pending state of the sub-surface and its
|
| + // decendents.
|
| + if (sub_surface->needs_commit_surface_hierarchy())
|
| + sub_surface->CommitSurfaceHierarchy();
|
| +
|
| + // Enable/disable sub-surface based on if it has contents.
|
| + sub_surface->SetVisible(sub_surface->has_contents());
|
| + sub_surface->SetEnabled(sub_surface->has_contents());
|
| +
|
| + // Move sub-surface to its new position in the stack.
|
| + DCHECK_LT(index, child_count());
|
| + ReorderChildView(sub_surface, index);
|
| +
|
| + // Update sub-surface position relative to surface origin.
|
| + sub_surface->SetPosition(sub_surface_entry.second);
|
| +
|
| + ++index;
|
| + }
|
| +}
|
| +
|
| +bool Surface::IsSynchronized() const {
|
| + return delegate_ ? delegate_->IsSurfaceSynchronized() : false;
|
| }
|
|
|
| void Surface::SetSurfaceDelegate(SurfaceDelegate* delegate) {
|
| @@ -120,6 +274,22 @@ void Surface::SetSurfaceDelegate(SurfaceDelegate* delegate) {
|
| delegate_ = delegate;
|
| }
|
|
|
| +bool Surface::HasSurfaceDelegate() const {
|
| + return !!delegate_;
|
| +}
|
| +
|
| +void Surface::AddSurfaceObserver(SurfaceObserver* observer) {
|
| + observers_.AddObserver(observer);
|
| +}
|
| +
|
| +void Surface::RemoveSurfaceObserver(SurfaceObserver* observer) {
|
| + observers_.RemoveObserver(observer);
|
| +}
|
| +
|
| +bool Surface::HasSurfaceObserver(const SurfaceObserver* observer) const {
|
| + return observers_.HasObserver(observer);
|
| +}
|
| +
|
| scoped_refptr<base::trace_event::TracedValue> Surface::AsTracedValue() const {
|
| scoped_refptr<base::trace_event::TracedValue> value =
|
| new base::trace_event::TracedValue;
|
|
|