blob: db17684b416160b38e13884635f538c6683c5f98 [file] [log] [blame]
// Copyright 2016 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/ui_devtools/views/dom_agent_aura.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/stl_util.h"
#include "components/ui_devtools/devtools_server.h"
#include "components/ui_devtools/root_element.h"
#include "components/ui_devtools/ui_element.h"
#include "components/ui_devtools/views/view_element.h"
#include "components/ui_devtools/views/widget_element.h"
#include "components/ui_devtools/views/window_element.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/window_util.h"
namespace ui_devtools {
namespace {
using ui_devtools::protocol::DOM::Node;
using ui_devtools::protocol::Array;
// TODO(mhashmi): Make ids reusable
views::Widget* GetWidgetFromWindow(gfx::NativeWindow window) {
return views::Widget::GetWidgetForNativeView(window);
}
} // namespace
DOMAgentAura* DOMAgentAura::dom_agent_aura_ = nullptr;
DOMAgentAura::DOMAgentAura(aura::Env* env) {
DCHECK(!dom_agent_aura_);
dom_agent_aura_ = this;
RegisterEnv(env);
}
DOMAgentAura::~DOMAgentAura() {
for (aura::Window* window : roots_)
window->RemoveObserver(this);
for (auto* env : envs_)
env->RemoveObserver(this);
dom_agent_aura_ = nullptr;
}
void DOMAgentAura::RegisterEnv(aura::Env* env) {
envs_.push_back(env);
env->AddObserver(this);
}
void DOMAgentAura::RegisterRootWindow(aura::Window* root) {
roots_.push_back(root);
root->AddObserver(this);
}
void DOMAgentAura::OnHostInitialized(aura::WindowTreeHost* host) {
RegisterRootWindow(host->window());
}
void DOMAgentAura::OnWindowDestroying(aura::Window* window) {
base::Erase(roots_, window);
}
std::vector<UIElement*> DOMAgentAura::CreateChildrenForRoot() {
std::vector<UIElement*> children;
for (aura::Window* window : roots_) {
UIElement* window_element = new WindowElement(window, this, element_root());
children.push_back(window_element);
}
return children;
}
std::unique_ptr<Node> DOMAgentAura::BuildTreeForUIElement(
UIElement* ui_element) {
if (ui_element->type() == UIElementType::WINDOW) {
return BuildTreeForWindow(
ui_element,
UIElement::GetBackingElement<aura::Window, WindowElement>(ui_element));
} else if (ui_element->type() == UIElementType::WIDGET) {
return BuildTreeForRootWidget(
ui_element,
UIElement::GetBackingElement<views::Widget, WidgetElement>(ui_element));
} else if (ui_element->type() == UIElementType::VIEW) {
return BuildTreeForView(
ui_element,
UIElement::GetBackingElement<views::View, ViewElement>(ui_element));
}
return nullptr;
}
std::unique_ptr<Node> DOMAgentAura::BuildTreeForWindow(
UIElement* window_element_root,
aura::Window* window) {
std::unique_ptr<Array<Node>> children = Array<Node>::create();
views::Widget* widget = GetWidgetFromWindow(window);
if (widget) {
UIElement* widget_element =
new WidgetElement(widget, this, window_element_root);
children->addItem(BuildTreeForRootWidget(widget_element, widget));
window_element_root->AddChild(widget_element);
}
for (aura::Window* child : window->children()) {
UIElement* window_element =
new WindowElement(child, this, window_element_root);
children->addItem(BuildTreeForWindow(window_element, child));
window_element_root->AddChild(window_element);
}
std::unique_ptr<Node> node =
BuildNode("Window", window_element_root->GetAttributes(),
std::move(children), window_element_root->node_id());
return node;
}
std::unique_ptr<Node> DOMAgentAura::BuildTreeForRootWidget(
UIElement* widget_element,
views::Widget* widget) {
std::unique_ptr<Array<Node>> children = Array<Node>::create();
UIElement* view_element =
new ViewElement(widget->GetRootView(), this, widget_element);
children->addItem(BuildTreeForView(view_element, widget->GetRootView()));
widget_element->AddChild(view_element);
std::unique_ptr<Node> node =
BuildNode("Widget", widget_element->GetAttributes(), std::move(children),
widget_element->node_id());
return node;
}
std::unique_ptr<Node> DOMAgentAura::BuildTreeForView(UIElement* view_element,
views::View* view) {
std::unique_ptr<Array<Node>> children = Array<Node>::create();
for (auto* child : view->GetChildrenInZOrder()) {
// When building the subtree, a particular view could be visited multiple
// times because for each view of the subtree, we would call
// BuildTreeForView(..) on that view which causes the subtree with that view
// as root being visited again. Here we check if we already constructed the
// ViewElement and skip true.
UIElement* view_element_child = nullptr;
auto id =
view_element->FindUIElementIdForBackendElement<views::View>(child);
if (id > 0) {
view_element_child = GetElementFromNodeId(id);
} else {
view_element_child = new ViewElement(child, this, view_element);
view_element->AddChild(view_element_child);
}
children->addItem(BuildTreeForView(view_element_child, child));
}
std::unique_ptr<Node> node =
BuildNode("View", view_element->GetAttributes(), std::move(children),
view_element->node_id());
return node;
}
} // namespace ui_devtools