Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Unified Diff: examples/ui/tile/tile_view.cc

Issue 1425543002: mozart: Add a simple tiling view manager. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« examples/ui/tile/tile_app.cc ('K') | « examples/ui/tile/tile_view.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: examples/ui/tile/tile_view.cc
diff --git a/examples/ui/tile/tile_view.cc b/examples/ui/tile/tile_view.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6fffdd1cccd108270d99a4b3ee008b91c0787e34
--- /dev/null
+++ b/examples/ui/tile/tile_view.cc
@@ -0,0 +1,264 @@
+// Copyright 2013 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 <algorithm>
+
+#include "examples/ui/tile/tile_view.h"
+#include "mojo/services/surfaces/cpp/surfaces_utils.h"
+#include "mojo/services/surfaces/interfaces/quads.mojom.h"
+
+namespace examples {
+
+TileView::TileView(mojo::ApplicationImpl* app_impl,
+ const std::vector<std::string>& view_urls,
+ const mojo::ui::ViewProvider::CreateViewCallback& callback)
+ : app_impl_(app_impl),
+ view_urls_(view_urls),
+ callback_(callback),
+ binding_(this),
+ surface_id_namespace_(0),
+ frame_pending_(false),
+ weak_ptr_factory_(this) {
+ app_impl_->ConnectToService("mojo:surfaces_service", &surfaces_);
+ app_impl_->ConnectToService("mojo:view_manager_service", &view_manager_);
+
+ surfaces_->GetIdNamespace(base::Bind(&TileView::OnSurfaceIdNamespaceAvailable,
+ base::Unretained(this)));
+}
+
+TileView::~TileView() {}
+
+void TileView::OnSurfaceIdNamespaceAvailable(uint32_t id_namespace) {
+ surface_id_namespace_ = id_namespace;
+ InitView();
+}
+
+void TileView::InitView() {
+ // Register the view.
+ mojo::ui::ViewPtr view;
+ binding_.Bind(mojo::GetProxy(&view));
+ view_manager_->RegisterView(view.Pass(), mojo::GetProxy(&view_host_),
+ callback_);
+
+ // Connect to all child views.
+ for (auto it = view_urls_.begin(); it != view_urls_.end(); it++) {
abarth 2015/10/24 06:51:12 for (const std::string& url : view_urls_) {
+ const std::string& url = *it;
+ const uint32_t key = it - view_urls_.begin();
abarth 2015/10/24 06:51:12 Oh, I see... I probably would have just used the
jeffbrown 2015/10/27 03:13:08 Honestly I just didn't know the for iterator synta
+
+ // Start connecting to the view provider.
+ mojo::ui::ViewProviderPtr provider;
+ app_impl_->ConnectToService(url, &provider);
+ provider.set_connection_error_handler(base::Bind(
+ &TileView::OnChildConnectionError, base::Unretained(this), key, url));
+
+ // Create the view.
+ // We include the provider reference in the callback so that the
+ // binding will be kept alive until the callback completes.
+ LOG(INFO) << "Connecting to view: key=" << key << ", url=" << url;
+ provider->CreateView(
+ mojo::InterfaceRequest<mojo::ServiceProvider>(),
abarth 2015/10/24 06:51:12 there's no implicit conversion from |nullptr| ?
jamesr 2015/10/26 20:31:21 there is. provider->CreateView(nullptr, nullptr, .
jeffbrown 2015/10/27 03:13:08 Done.
+ mojo::ServiceProviderPtr(),
abarth 2015/10/24 06:51:12 ditto
+ base::Bind(&TileView::OnChildCreated, base::Unretained(this), key, url,
+ base::Passed(provider.Pass())));
+ }
+}
+
+void TileView::OnChildConnectionError(uint32_t child_key,
+ const std::string& url) {
+ LOG(ERROR) << "Could not connect to view: key=" << child_key
+ << ", url=" << url;
+}
+
+void TileView::OnChildCreated(uint32_t child_key,
+ const std::string& url,
+ mojo::ui::ViewProviderPtr provider,
+ mojo::ui::ViewTokenPtr token) {
+ DCHECK(views_.find(child_key) == views_.end());
+
+ LOG(INFO) << "View created: key=" << child_key << ", url=" << url;
+ view_host_->AddChild(child_key, token.Pass());
+ views_.emplace(
+ std::make_pair(child_key, std::unique_ptr<ViewData>(new ViewData(url))));
abarth 2015/10/24 06:51:12 We don't have std::make_unique<ViewData>(url) but
jamesr 2015/10/26 20:31:21 there's this: https://github.com/domokit/mojo/blo
jeffbrown 2015/10/27 03:13:08 Hardly seems worth it here. I think I'll just lea
+
+ // Don't need the view provider anymore now that we have created the view
+ // so stop watching for errors.
+ provider.set_connection_error_handler(base::Closure());
+}
+
+void TileView::OnChildUnavailable(uint32_t child_key,
+ const OnChildUnavailableCallback& callback) {
+ auto it = views_.find(child_key);
+ DCHECK(it != views_.end());
+
+ LOG(ERROR) << "View died unexpectedly: key=" << child_key
+ << ", url=" << it->second->url();
+ view_host_->RemoveChild(child_key);
+ views_.erase(it);
+ FinishLayout();
+
+ callback.Run();
+}
+
+void TileView::OnLayout(mojo::ui::ViewLayoutParamsPtr layout_params,
+ mojo::Array<uint32_t> children_needing_layout,
+ const OnLayoutCallback& callback) {
+ // Create a new surface the first time or if the size has changed.
+ mojo::Size new_size;
+ new_size.width = layout_params->constraints->max_width;
+ new_size.height = layout_params->constraints->max_height;
+ if (!surface_id_ || !size_.Equals(new_size)) {
+ if (!surface_id_) {
+ surface_id_ = mojo::SurfaceId::New();
+ surface_id_->id_namespace = surface_id_namespace_;
+ } else {
+ surfaces_->DestroySurface(surface_id_->local);
+ }
+ surface_id_->local++;
+ size_ = new_size;
+ surfaces_->CreateSurface(surface_id_->local);
+ }
abarth 2015/10/24 06:51:12 This stanza has come up several times now...
jeffbrown 2015/10/27 03:13:08 Yup. I find it helpful to be explicit in example
+
+ // Wipe out cached layout information for children needing layout.
+ for (auto it = children_needing_layout.begin();
+ it != children_needing_layout.end(); ++it) {
abarth 2015/10/24 06:51:12 for (uint32_t id : children_needing_layout) {
+ auto view_it = views_.find(*it);
+ if (view_it != views_.end())
+ view_it->second->layout_info.reset();
+ }
+
+ // Layout all children in a row.
+ uint32_t index = 0;
+ for (auto it = views_.begin(); it != views_.end(); ++it, ++index) {
+ ViewData* view_data = it->second.get();
+ DCHECK(!view_data->layout_pending);
+
+ uint32_t child_width = new_size.width / views_.size();
abarth 2015/10/24 06:51:12 If new_size.width doesn't divide evenly by views_.
jeffbrown 2015/10/27 03:13:08 Good point!
+ uint32_t child_height = new_size.height;
+
+ mojo::ui::ViewLayoutParamsPtr params = mojo::ui::ViewLayoutParams::New();
+ params->constraints = mojo::ui::BoxConstraints::New();
+ params->constraints->min_width = child_width;
+ params->constraints->max_width = child_width;
+ params->constraints->min_height = child_height;
+ params->constraints->max_height = child_height;
+ params->device_pixel_ratio = layout_params->device_pixel_ratio;
abarth 2015/10/24 06:51:12 This would be more future-proof if you made |param
jeffbrown 2015/10/27 03:13:08 Discussed in person. I'll see about pushing more
+
+ if (view_data->layout_info.get() && view_data->layout_params.Equals(params))
+ continue; // no work to do
abarth 2015/10/24 06:51:12 This seems dubious. What if one of our grandchild
jeffbrown 2015/10/27 03:13:08 This is just an optimization to avoid an extra rou
+
+ view_data->layout_pending = true;
+ view_data->layout_params = params.Clone();
+ view_data->layout_info.reset();
+ view_data->layout_bounds.x = child_width * index;
+ view_data->layout_bounds.y = 0;
+ view_data->layout_bounds.width = child_width;
+ view_data->layout_bounds.height = child_height;
+
+ view_host_->LayoutChild(it->first, params.Pass(), false /*provide_size*/,
+ base::Bind(&TileView::OnChildLayoutFinished,
+ base::Unretained(this), it->first));
+ }
+
+ // Store the callback until layout of all children is finished.
+ pending_layout_callback_ = callback;
+ FinishLayout();
+}
+
+void TileView::OnChildLayoutFinished(
+ uint32_t child_key,
+ mojo::ui::ViewLayoutInfoPtr child_layout_info) {
+ auto it = views_.find(child_key);
+ if (it != views_.end()) {
+ it->second->layout_pending = false;
+ it->second->layout_info = child_layout_info.Pass();
+ FinishLayout();
+ }
+}
+
+void TileView::FinishLayout() {
+ if (frame_pending_ || pending_layout_callback_.is_null())
+ return;
+
+ // Wait until all children have laid out.
+ // TODO(jeffbrown): There should be a timeout on this.
+ if (std::any_of(views_.begin(), views_.end(),
jamesr 2015/10/26 20:31:21 this scales linearly with views, which might be a
jeffbrown 2015/10/27 03:13:08 True. This is simpler (state can't get out of syn
+ [](const decltype(views_)::value_type& pair) {
jamesr 2015/10/26 20:31:21 this is an odd use of decltype, imo. this isn't ge
jeffbrown 2015/10/27 03:13:08 Hmm. I think the intention is pretty clear. I do
+ return pair.second->layout_pending;
+ }))
+ return;
+
+ // Produce a new frame.
abarth 2015/10/24 06:51:12 This system would be cleaner if the parent allocat
jeffbrown 2015/10/27 03:13:08 It might be. Depends on whether a new surface is
+ mojo::FramePtr frame = mojo::Frame::New();
+ frame->resources.resize(0u);
jamesr 2015/10/26 20:31:21 i *hate* that mojo arrays are nullable - the fact
jeffbrown 2015/10/27 03:13:08 Yup. It's nuts. And if I omit this line then the
+
+ mojo::Rect bounds;
+ bounds.width = size_.width;
+ bounds.height = size_.height;
+ mojo::PassPtr pass = mojo::CreateDefaultPass(1, bounds);
+ pass->shared_quad_states.resize(0u);
+ pass->quads.resize(0u);
+
+ for (auto it = views_.begin(); it != views_.end(); it++) {
jamesr 2015/10/26 20:31:21 'const auto& it' ?
+ const ViewData* view_data = it->second.get();
jamesr 2015/10/26 20:31:21 const ViewData& view_data ? it's not useful to nul
jeffbrown 2015/10/27 03:13:08 Sure, why not.
+
+ mojo::QuadPtr quad = mojo::Quad::New();
+ quad->rect = view_data->layout_bounds.Clone();
+ quad->rect->x = 0;
+ quad->rect->y = 0;
+ quad->opaque_rect = quad->rect.Clone();
+ quad->visible_rect = quad->rect.Clone();
+ quad->shared_quad_state_index = pass->shared_quad_states.size();
+
+ mojo::Size size;
+ size.width = view_data->layout_bounds.width;
+ size.height = view_data->layout_bounds.height;
+
+ mojo::SharedQuadStatePtr quad_state = mojo::CreateDefaultSQS(size);
+ quad_state->content_to_target_transform->matrix[3] =
+ view_data->layout_bounds.x;
+ pass->shared_quad_states.push_back(quad_state.Pass());
+
+ if (it->second->layout_info.get()) {
+ quad->material = mojo::Material::SURFACE_CONTENT;
+ quad->surface_quad_state = mojo::SurfaceQuadState::New();
+ quad->surface_quad_state->surface =
+ view_data->layout_info->surface_id.Clone();
+ } else {
+ quad->material = mojo::Material::SOLID_COLOR;
+ quad->solid_color_quad_state = mojo::SolidColorQuadState::New();
+ quad->solid_color_quad_state->color = mojo::Color::New();
+ quad->solid_color_quad_state->color->rgba = 0xffff00ff;
jamesr 2015/10/26 20:31:21 i think we have some named colors somewhere (not t
+ }
+
+ pass->quads.push_back(quad.Pass());
+ }
+
+ frame->passes.push_back(pass.Pass());
+
+ frame_pending_ = true;
+ surfaces_->SubmitFrame(
+ surface_id_->local, frame.Pass(),
+ base::Bind(&TileView::OnFrameSubmitted, base::Unretained(this)));
+
+ // Submit the new layout information.
+ mojo::ui::ViewLayoutInfoPtr info = mojo::ui::ViewLayoutInfo::New();
+ info->size = size_.Clone();
+ info->surface_id = surface_id_->Clone();
+ pending_layout_callback_.Run(info.Pass());
+ pending_layout_callback_.reset();
+}
+
+void TileView::OnFrameSubmitted() {
+ DCHECK(frame_pending_);
+
+ frame_pending_ = false;
+ FinishLayout();
+}
+
+TileView::ViewData::ViewData(const std::string& url)
+ : layout_pending(false), url_(url) {}
+
+TileView::ViewData::~ViewData() {}
+
+} // namespace examples
« examples/ui/tile/tile_app.cc ('K') | « examples/ui/tile/tile_view.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698