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

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

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