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

Side by Side Diff: ash/devtools/ash_devtools_dom_agent.cc

Issue 2852733002: Duplicate -Move DevTools out of ash and turn it to a component. (Closed)
Patch Set: move unittest to ui/views Created 3 years, 7 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 unified diff | Download patch
« no previous file with comments | « ash/devtools/ash_devtools_dom_agent.h ('k') | ash/devtools/ash_devtools_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ash/devtools/ash_devtools_dom_agent.h"
6
7 #include "ash/devtools/ui_element.h"
8 #include "ash/devtools/view_element.h"
9 #include "ash/devtools/widget_element.h"
10 #include "ash/devtools/window_element.h"
11 #include "ash/public/cpp/shell_window_ids.h"
12 #include "components/ui_devtools/devtools_server.h"
13 #include "third_party/skia/include/core/SkColor.h"
14 #include "ui/aura/env.h"
15 #include "ui/aura/window.h"
16 #include "ui/aura/window_tree_host.h"
17 #include "ui/display/display.h"
18 #include "ui/display/screen.h"
19 #include "ui/views/background.h"
20 #include "ui/views/border.h"
21 #include "ui/views/view.h"
22 #include "ui/views/widget/widget.h"
23 #include "ui/wm/core/window_util.h"
24
25 namespace ash {
26 namespace devtools {
27 namespace {
28
29 using namespace ui::devtools::protocol;
30 // TODO(mhashmi): Make ids reusable
31
32 std::unique_ptr<DOM::Node> BuildNode(
33 const std::string& name,
34 std::unique_ptr<Array<std::string>> attributes,
35 std::unique_ptr<Array<DOM::Node>> children,
36 int node_ids) {
37 constexpr int kDomElementNodeType = 1;
38 std::unique_ptr<DOM::Node> node = DOM::Node::create()
39 .setNodeId(node_ids)
40 .setNodeName(name)
41 .setNodeType(kDomElementNodeType)
42 .setAttributes(std::move(attributes))
43 .build();
44 node->setChildNodeCount(children->length());
45 node->setChildren(std::move(children));
46 return node;
47 }
48
49 std::unique_ptr<Array<std::string>> GetAttributes(UIElement* ui_element) {
50 std::unique_ptr<Array<std::string>> attributes = Array<std::string>::create();
51 attributes->addItem("name");
52 switch (ui_element->type()) {
53 case UIElementType::WINDOW: {
54 aura::Window* window =
55 UIElement::GetBackingElement<aura::Window, WindowElement>(ui_element);
56 attributes->addItem(window->GetName());
57 attributes->addItem("active");
58 attributes->addItem(::wm::IsActiveWindow(window) ? "true" : "false");
59 break;
60 }
61 case UIElementType::WIDGET: {
62 views::Widget* widget =
63 UIElement::GetBackingElement<views::Widget, WidgetElement>(
64 ui_element);
65 attributes->addItem(widget->GetName());
66 attributes->addItem("active");
67 attributes->addItem(widget->IsActive() ? "true" : "false");
68 break;
69 }
70 case UIElementType::VIEW: {
71 attributes->addItem(
72 UIElement::GetBackingElement<views::View, ViewElement>(ui_element)
73 ->GetClassName());
74 break;
75 }
76 default:
77 DCHECK(false);
78 }
79 return attributes;
80 }
81
82 int MaskColor(int value) {
83 return value & 0xff;
84 }
85
86 SkColor RGBAToSkColor(DOM::RGBA* rgba) {
87 if (!rgba)
88 return SkColorSetARGB(0, 0, 0, 0);
89 // Default alpha value is 0 (not visible) and need to convert alpha decimal
90 // percentage value to hex
91 return SkColorSetARGB(MaskColor(static_cast<int>(rgba->getA(0) * 255)),
92 MaskColor(rgba->getR()), MaskColor(rgba->getG()),
93 MaskColor(rgba->getB()));
94 }
95
96 views::Widget* GetWidgetFromWindow(aura::Window* window) {
97 return views::Widget::GetWidgetForNativeView(window);
98 }
99
100 std::unique_ptr<DOM::Node> BuildDomNodeFromUIElement(UIElement* root) {
101 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create();
102 for (auto* it : root->children())
103 children->addItem(BuildDomNodeFromUIElement(it));
104
105 constexpr int kDomElementNodeType = 1;
106 std::unique_ptr<DOM::Node> node = DOM::Node::create()
107 .setNodeId(root->node_id())
108 .setNodeName(root->GetTypeName())
109 .setNodeType(kDomElementNodeType)
110 .setAttributes(GetAttributes(root))
111 .build();
112 node->setChildNodeCount(children->length());
113 node->setChildren(std::move(children));
114 return node;
115 }
116
117 } // namespace
118
119 AshDevToolsDOMAgent::AshDevToolsDOMAgent() : is_building_tree_(false) {
120 aura::Env::GetInstance()->AddObserver(this);
121 }
122
123 AshDevToolsDOMAgent::~AshDevToolsDOMAgent() {
124 aura::Env::GetInstance()->RemoveObserver(this);
125 Reset();
126 }
127
128 ui::devtools::protocol::Response AshDevToolsDOMAgent::disable() {
129 Reset();
130 return ui::devtools::protocol::Response::OK();
131 }
132
133 ui::devtools::protocol::Response AshDevToolsDOMAgent::getDocument(
134 std::unique_ptr<ui::devtools::protocol::DOM::Node>* out_root) {
135 *out_root = BuildInitialTree();
136 return ui::devtools::protocol::Response::OK();
137 }
138
139 ui::devtools::protocol::Response AshDevToolsDOMAgent::highlightNode(
140 std::unique_ptr<ui::devtools::protocol::DOM::HighlightConfig>
141 highlight_config,
142 ui::devtools::protocol::Maybe<int> node_id) {
143 return HighlightNode(std::move(highlight_config), node_id.fromJust());
144 }
145
146 ui::devtools::protocol::Response AshDevToolsDOMAgent::hideHighlight() {
147 if (widget_for_highlighting_ && widget_for_highlighting_->IsVisible())
148 widget_for_highlighting_->Hide();
149 return ui::devtools::protocol::Response::OK();
150 }
151
152 void AshDevToolsDOMAgent::OnUIElementAdded(UIElement* parent,
153 UIElement* child) {
154 if (!parent) {
155 node_id_to_ui_element_[child->node_id()] = child;
156 return;
157 }
158 // If tree is being built, don't add child to dom tree again.
159 if (is_building_tree_)
160 return;
161 DCHECK(node_id_to_ui_element_.count(parent->node_id()));
162
163 const auto& children = parent->children();
164 auto iter = std::find(children.begin(), children.end(), child);
165 int prev_node_id =
166 (iter == children.end() - 1) ? 0 : (*std::next(iter))->node_id();
167 frontend()->childNodeInserted(parent->node_id(), prev_node_id,
168 BuildTreeForUIElement(child));
169 }
170
171 void AshDevToolsDOMAgent::OnUIElementReordered(UIElement* parent,
172 UIElement* child) {
173 DCHECK(node_id_to_ui_element_.count(parent->node_id()));
174
175 const auto& children = parent->children();
176 auto iter = std::find(children.begin(), children.end(), child);
177 int prev_node_id =
178 (iter == children.begin()) ? 0 : (*std::prev(iter))->node_id();
179 RemoveDomNode(child);
180 frontend()->childNodeInserted(parent->node_id(), prev_node_id,
181 BuildDomNodeFromUIElement(child));
182 }
183
184 void AshDevToolsDOMAgent::OnUIElementRemoved(UIElement* ui_element) {
185 DCHECK(node_id_to_ui_element_.count(ui_element->node_id()));
186
187 RemoveDomNode(ui_element);
188 node_id_to_ui_element_.erase(ui_element->node_id());
189 }
190
191 void AshDevToolsDOMAgent::OnUIElementBoundsChanged(UIElement* ui_element) {
192 for (auto& observer : observers_)
193 observer.OnNodeBoundsChanged(ui_element->node_id());
194 }
195
196 bool AshDevToolsDOMAgent::IsHighlightingWindow(aura::Window* window) {
197 return widget_for_highlighting_ &&
198 GetWidgetFromWindow(window) == widget_for_highlighting_.get();
199 }
200
201 void AshDevToolsDOMAgent::AddObserver(AshDevToolsDOMAgentObserver* observer) {
202 observers_.AddObserver(observer);
203 }
204
205 void AshDevToolsDOMAgent::RemoveObserver(
206 AshDevToolsDOMAgentObserver* observer) {
207 observers_.RemoveObserver(observer);
208 }
209
210 UIElement* AshDevToolsDOMAgent::GetElementFromNodeId(int node_id) {
211 return node_id_to_ui_element_[node_id];
212 }
213
214 void AshDevToolsDOMAgent::OnHostInitialized(aura::WindowTreeHost* host) {
215 root_windows_.push_back(host->window());
216 }
217
218 void AshDevToolsDOMAgent::OnNodeBoundsChanged(int node_id) {
219 for (auto& observer : observers_)
220 observer.OnNodeBoundsChanged(node_id);
221 }
222
223 std::unique_ptr<ui::devtools::protocol::DOM::Node>
224 AshDevToolsDOMAgent::BuildInitialTree() {
225 is_building_tree_ = true;
226 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create();
227
228 // TODO(thanhph): Root of UIElement tree shoudn't be WindowElement
229 // but maybe a new different type.
230 window_element_root_ = new WindowElement(nullptr, this, nullptr);
231
232 for (aura::Window* window : root_windows()) {
233 UIElement* window_element =
234 new WindowElement(window, this, window_element_root_);
235
236 children->addItem(BuildTreeForUIElement(window_element));
237 window_element_root_->AddChild(window_element);
238 }
239 std::unique_ptr<ui::devtools::protocol::DOM::Node> root_node = BuildNode(
240 "root", nullptr, std::move(children), window_element_root_->node_id());
241 is_building_tree_ = false;
242 return root_node;
243 }
244
245 std::unique_ptr<ui::devtools::protocol::DOM::Node>
246 AshDevToolsDOMAgent::BuildTreeForUIElement(UIElement* ui_element) {
247 if (ui_element->type() == UIElementType::WINDOW) {
248 return BuildTreeForWindow(
249 ui_element,
250 UIElement::GetBackingElement<aura::Window, WindowElement>(ui_element));
251 } else if (ui_element->type() == UIElementType::WIDGET) {
252 return BuildTreeForRootWidget(
253 ui_element,
254 UIElement::GetBackingElement<views::Widget, WidgetElement>(ui_element));
255 } else if (ui_element->type() == UIElementType::VIEW) {
256 return BuildTreeForView(
257 ui_element,
258 UIElement::GetBackingElement<views::View, ViewElement>(ui_element));
259 }
260 return nullptr;
261 }
262
263 std::unique_ptr<DOM::Node> AshDevToolsDOMAgent::BuildTreeForWindow(
264 UIElement* window_element_root,
265 aura::Window* window) {
266 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create();
267 views::Widget* widget = GetWidgetFromWindow(window);
268 if (widget) {
269 UIElement* widget_element =
270 new WidgetElement(widget, this, window_element_root);
271
272 children->addItem(BuildTreeForRootWidget(widget_element, widget));
273 window_element_root->AddChild(widget_element);
274 }
275 for (aura::Window* child : window->children()) {
276 UIElement* window_element =
277 new WindowElement(child, this, window_element_root);
278
279 children->addItem(BuildTreeForWindow(window_element, child));
280 window_element_root->AddChild(window_element);
281 }
282 std::unique_ptr<ui::devtools::protocol::DOM::Node> node =
283 BuildNode("Window", GetAttributes(window_element_root),
284 std::move(children), window_element_root->node_id());
285 return node;
286 }
287
288 std::unique_ptr<DOM::Node> AshDevToolsDOMAgent::BuildTreeForRootWidget(
289 UIElement* widget_element,
290 views::Widget* widget) {
291 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create();
292
293 UIElement* view_element =
294 new ViewElement(widget->GetRootView(), this, widget_element);
295
296 children->addItem(BuildTreeForView(view_element, widget->GetRootView()));
297 widget_element->AddChild(view_element);
298
299 std::unique_ptr<ui::devtools::protocol::DOM::Node> node =
300 BuildNode("Widget", GetAttributes(widget_element), std::move(children),
301 widget_element->node_id());
302 return node;
303 }
304
305 std::unique_ptr<DOM::Node> AshDevToolsDOMAgent::BuildTreeForView(
306 UIElement* view_element,
307 views::View* view) {
308 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create();
309
310 for (auto* child : view->GetChildrenInZOrder()) {
311 UIElement* view_element_child = new ViewElement(child, this, view_element);
312
313 children->addItem(BuildTreeForView(view_element_child, child));
314 view_element->AddChild(view_element_child);
315 }
316 std::unique_ptr<ui::devtools::protocol::DOM::Node> node =
317 BuildNode("View", GetAttributes(view_element), std::move(children),
318 view_element->node_id());
319 return node;
320 }
321
322 void AshDevToolsDOMAgent::RemoveDomNode(UIElement* ui_element) {
323 for (auto* child_element : ui_element->children())
324 RemoveDomNode(child_element);
325 frontend()->childNodeRemoved(ui_element->parent()->node_id(),
326 ui_element->node_id());
327 }
328
329 void AshDevToolsDOMAgent::Reset() {
330 is_building_tree_ = false;
331 widget_for_highlighting_.reset();
332 window_element_root_->Destroy();
333 node_id_to_ui_element_.clear();
334 observers_.Clear();
335 }
336
337 void AshDevToolsDOMAgent::InitializeHighlightingWidget() {
338 DCHECK(!widget_for_highlighting_);
339 widget_for_highlighting_.reset(new views::Widget);
340 views::Widget::InitParams params;
341 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
342 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
343 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
344 params.opacity = views::Widget::InitParams::WindowOpacity::TRANSLUCENT_WINDOW;
345 params.name = "HighlightingWidget";
346 params.parent = nullptr;
347 if (!root_windows().empty()) {
348 params.parent =
349 root_windows()[0]->GetChildById(kShellWindowId_OverlayContainer);
350 }
351 params.keep_on_top = true;
352 params.accept_events = false;
353 widget_for_highlighting_->Init(params);
354 }
355
356 void AshDevToolsDOMAgent::UpdateHighlight(
357 const std::pair<aura::Window*, gfx::Rect>& window_and_bounds,
358 SkColor background,
359 SkColor border) {
360 constexpr int kBorderThickness = 1;
361 views::View* root_view = widget_for_highlighting_->GetRootView();
362 root_view->SetBorder(views::CreateSolidBorder(kBorderThickness, border));
363 root_view->set_background(
364 views::Background::CreateSolidBackground(background));
365 display::Display display =
366 display::Screen::GetScreen()->GetDisplayNearestWindow(
367 window_and_bounds.first);
368 widget_for_highlighting_->GetNativeWindow()->SetBoundsInScreen(
369 window_and_bounds.second, display);
370 }
371
372 ui::devtools::protocol::Response AshDevToolsDOMAgent::HighlightNode(
373 std::unique_ptr<ui::devtools::protocol::DOM::HighlightConfig>
374 highlight_config,
375 int node_id) {
376 if (!widget_for_highlighting_)
377 InitializeHighlightingWidget();
378
379 std::pair<aura::Window*, gfx::Rect> window_and_bounds =
380 node_id_to_ui_element_.count(node_id)
381 ? node_id_to_ui_element_[node_id]->GetNodeWindowAndBounds()
382 : std::make_pair<aura::Window*, gfx::Rect>(nullptr, gfx::Rect());
383
384 if (!window_and_bounds.first) {
385 return ui::devtools::protocol::Response::Error(
386 "No node found with that id");
387 }
388 SkColor border_color =
389 RGBAToSkColor(highlight_config->getBorderColor(nullptr));
390 SkColor content_color =
391 RGBAToSkColor(highlight_config->getContentColor(nullptr));
392 UpdateHighlight(window_and_bounds, content_color, border_color);
393
394 if (!widget_for_highlighting_->IsVisible())
395 widget_for_highlighting_->Show();
396
397 return ui::devtools::protocol::Response::OK();
398 }
399
400 } // namespace devtools
401 } // namespace ash
OLDNEW
« no previous file with comments | « ash/devtools/ash_devtools_dom_agent.h ('k') | ash/devtools/ash_devtools_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698