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

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

Issue 2542243002: Add hovering feature to AshDevToolsDOMAgent (Closed)
Patch Set: Update highlighting widget name Created 4 years 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
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ash/common/devtools/ash_devtools_dom_agent.h" 5 #include "ash/common/devtools/ash_devtools_dom_agent.h"
6 6
7 #include "ash/common/wm_lookup.h" 7 #include "ash/common/wm_lookup.h"
8 #include "ash/common/wm_root_window_controller.h"
8 #include "ash/common/wm_window.h" 9 #include "ash/common/wm_window.h"
10 #include "ash/public/cpp/shell_window_ids.h"
9 #include "components/ui_devtools/devtools_server.h" 11 #include "components/ui_devtools/devtools_server.h"
12 #include "third_party/skia/include/core/SkColor.h"
13 #include "ui/display/display.h"
14 #include "ui/views/background.h"
15 #include "ui/views/border.h"
10 16
11 namespace ash { 17 namespace ash {
12 namespace devtools { 18 namespace devtools {
13 19
14 namespace { 20 namespace {
15 using namespace ui::devtools::protocol; 21 using namespace ui::devtools::protocol;
16 // TODO(mhashmi): Make ids reusable 22 // TODO(mhashmi): Make ids reusable
17 DOM::NodeId node_ids = 1; 23 DOM::NodeId node_ids = 1;
18 24
19 std::unique_ptr<DOM::Node> BuildNode( 25 std::unique_ptr<DOM::Node> BuildNode(
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 for (int i = 0, count = parent->child_count(); i < count; i++) { 78 for (int i = 0, count = parent->child_count(); i < count; i++) {
73 if (view == parent->child_at(i)) { 79 if (view == parent->child_at(i)) {
74 view_index = i; 80 view_index = i;
75 break; 81 break;
76 } 82 }
77 } 83 }
78 DCHECK_GE(view_index, 0); 84 DCHECK_GE(view_index, 0);
79 return view_index == 0 ? nullptr : parent->child_at(view_index - 1); 85 return view_index == 0 ? nullptr : parent->child_at(view_index - 1);
80 } 86 }
81 87
88 SkColor RGBAToSkColor(DOM::RGBA* rgba) {
89 if (!rgba)
90 return SkColorSetARGB(0, 0, 0, 0);
91 // Default alpha value is 0 (not visibile) and need to convert alpha decimal
92 // percentage value to hex
93 return SkColorSetARGB(rgba->getA(0) * 255, rgba->getR(), rgba->getG(),
94 rgba->getB());
sadrul 2016/12/06 20:48:58 Should we sanity check these values?
Sarmad Hashmi 2016/12/06 22:54:34 Done.
95 }
96
82 } // namespace 97 } // namespace
83 98 AshDevToolsDOMAgent::AshDevToolsDOMAgent(
84 AshDevToolsDOMAgent::AshDevToolsDOMAgent(ash::WmShell* shell) : shell_(shell) { 99 ash::WmShell* shell,
100 scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
101 : main_thread_task_runner_(main_thread_task_runner), shell_(shell) {
85 DCHECK(shell_); 102 DCHECK(shell_);
103 DCHECK(main_thread_task_runner_);
86 } 104 }
87 105
88 AshDevToolsDOMAgent::~AshDevToolsDOMAgent() { 106 AshDevToolsDOMAgent::~AshDevToolsDOMAgent() {
89 RemoveObservers(); 107 RemoveObservers();
90 } 108 }
91 109
92 ui::devtools::protocol::Response AshDevToolsDOMAgent::disable() { 110 ui::devtools::protocol::Response AshDevToolsDOMAgent::disable() {
93 Reset(); 111 Reset();
94 return ui::devtools::protocol::Response::OK(); 112 return ui::devtools::protocol::Response::OK();
95 } 113 }
96 114
97 ui::devtools::protocol::Response AshDevToolsDOMAgent::getDocument( 115 ui::devtools::protocol::Response AshDevToolsDOMAgent::getDocument(
98 std::unique_ptr<ui::devtools::protocol::DOM::Node>* out_root) { 116 std::unique_ptr<ui::devtools::protocol::DOM::Node>* out_root) {
99 *out_root = BuildInitialTree(); 117 *out_root = BuildInitialTree();
100 return ui::devtools::protocol::Response::OK(); 118 return ui::devtools::protocol::Response::OK();
101 } 119 }
102 120
121 ui::devtools::protocol::Response AshDevToolsDOMAgent::highlightNode(
122 std::unique_ptr<ui::devtools::protocol::DOM::HighlightConfig>
123 highlight_config,
124 ui::devtools::protocol::Maybe<int> node_id) {
125 main_thread_task_runner_->PostTask(
sadrul 2016/12/06 20:48:59 Why do you need to PostTask()?
Sarmad Hashmi 2016/12/06 22:54:34 Removed, as discussed.
126 FROM_HERE,
127 base::Bind(&AshDevToolsDOMAgent::HighlightNode, base::Unretained(this),
128 base::Passed(std::move(highlight_config)),
129 node_id.fromJust()));
130 return ui::devtools::protocol::Response::OK();
131 }
132
133 ui::devtools::protocol::Response AshDevToolsDOMAgent::hideHighlight() {
134 if (widget_for_highlighting_ && widget_for_highlighting_->IsVisible()) {
135 main_thread_task_runner_->PostTask(
136 FROM_HERE,
137 base::Bind(&views::Widget::Hide,
138 base::Unretained(widget_for_highlighting_.get())));
139 }
140 return ui::devtools::protocol::Response::OK();
141 }
142
103 // Handles removing windows. 143 // Handles removing windows.
104 void AshDevToolsDOMAgent::OnWindowTreeChanging(WmWindow* window, 144 void AshDevToolsDOMAgent::OnWindowTreeChanging(WmWindow* window,
105 const TreeChangeParams& params) { 145 const TreeChangeParams& params) {
106 // Only trigger this when window == params.old_parent. 146 // Only trigger this when window == params.old_parent.
107 // Only removals are handled here. Removing a node can occur as a result of 147 // Only removals are handled here. Removing a node can occur as a result of
108 // reorganizing a window or just destroying it. OnWindowTreeChanged 148 // reorganizing a window or just destroying it. OnWindowTreeChanged
109 // is only called if there is a new_parent. The only case this method isn't 149 // is only called if there is a new_parent. The only case this method isn't
110 // called is when adding a node because old_parent is then null. 150 // called is when adding a node because old_parent is then null.
111 // Finally, We only trigger this 0 or 1 times as an old_parent will 151 // Finally, We only trigger this 0 or 1 times as an old_parent will
112 // either exist and only call this callback once, or not at all. 152 // either exist and only call this callback once, or not at all.
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 return BuildNode("root", nullptr, std::move(children)); 256 return BuildNode("root", nullptr, std::move(children));
217 } 257 }
218 258
219 std::unique_ptr<DOM::Node> AshDevToolsDOMAgent::BuildTreeForWindow( 259 std::unique_ptr<DOM::Node> AshDevToolsDOMAgent::BuildTreeForWindow(
220 ash::WmWindow* window) { 260 ash::WmWindow* window) {
221 DCHECK(!window_to_node_id_map_.count(window)); 261 DCHECK(!window_to_node_id_map_.count(window));
222 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create(); 262 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create();
223 views::Widget* widget = window->GetInternalWidget(); 263 views::Widget* widget = window->GetInternalWidget();
224 if (widget) 264 if (widget)
225 children->addItem(BuildTreeForRootWidget(widget)); 265 children->addItem(BuildTreeForRootWidget(widget));
226 for (ash::WmWindow* child : window->GetChildren()) 266 for (ash::WmWindow* child : window->GetChildren()) {
227 children->addItem(BuildTreeForWindow(child)); 267 if (!IsHighlightingWindow(child))
268 children->addItem(BuildTreeForWindow(child));
269 }
228 270
229 std::unique_ptr<ui::devtools::protocol::DOM::Node> node = 271 std::unique_ptr<ui::devtools::protocol::DOM::Node> node =
230 BuildNode("Window", GetAttributes(window), std::move(children)); 272 BuildNode("Window", GetAttributes(window), std::move(children));
231 if (!window->HasObserver(this)) 273 if (!window->HasObserver(this))
232 window->AddObserver(this); 274 window->AddObserver(this);
233 window_to_node_id_map_[window] = node->getNodeId(); 275 window_to_node_id_map_[window] = node->getNodeId();
234 node_id_to_window_map_[node->getNodeId()] = window; 276 node_id_to_window_map_[node->getNodeId()] = window;
235 return node; 277 return node;
236 } 278 }
237 279
(...skipping 20 matching lines...) Expand all
258 std::unique_ptr<ui::devtools::protocol::DOM::Node> node = 300 std::unique_ptr<ui::devtools::protocol::DOM::Node> node =
259 BuildNode("View", GetAttributes(view), std::move(children)); 301 BuildNode("View", GetAttributes(view), std::move(children));
260 if (!view->HasObserver(this)) 302 if (!view->HasObserver(this))
261 view->AddObserver(this); 303 view->AddObserver(this);
262 view_to_node_id_map_[view] = node->getNodeId(); 304 view_to_node_id_map_[view] = node->getNodeId();
263 node_id_to_view_map_[node->getNodeId()] = view; 305 node_id_to_view_map_[node->getNodeId()] = view;
264 return node; 306 return node;
265 } 307 }
266 308
267 void AshDevToolsDOMAgent::AddWindowTree(WmWindow* window) { 309 void AshDevToolsDOMAgent::AddWindowTree(WmWindow* window) {
310 if (IsHighlightingWindow(window))
311 return;
312
268 DCHECK(window_to_node_id_map_.count(window->GetParent())); 313 DCHECK(window_to_node_id_map_.count(window->GetParent()));
269 WmWindow* prev_sibling = FindPreviousSibling(window); 314 WmWindow* prev_sibling = FindPreviousSibling(window);
270 frontend()->childNodeInserted( 315 frontend()->childNodeInserted(
271 window_to_node_id_map_[window->GetParent()], 316 window_to_node_id_map_[window->GetParent()],
272 prev_sibling ? window_to_node_id_map_[prev_sibling] : 0, 317 prev_sibling ? window_to_node_id_map_[prev_sibling] : 0,
273 BuildTreeForWindow(window)); 318 BuildTreeForWindow(window));
274 } 319 }
275 320
276 void AshDevToolsDOMAgent::RemoveWindowTree(WmWindow* window, 321 void AshDevToolsDOMAgent::RemoveWindowTree(WmWindow* window,
277 bool remove_observer) { 322 bool remove_observer) {
278 DCHECK(window); 323 DCHECK(window);
324 if (IsHighlightingWindow(window))
325 return;
326
279 if (window->GetInternalWidget()) 327 if (window->GetInternalWidget())
280 RemoveWidgetTree(window->GetInternalWidget(), remove_observer); 328 RemoveWidgetTree(window->GetInternalWidget(), remove_observer);
281 329
282 for (ash::WmWindow* child : window->GetChildren()) 330 for (ash::WmWindow* child : window->GetChildren())
283 RemoveWindowTree(child, remove_observer); 331 RemoveWindowTree(child, remove_observer);
284 332
285 RemoveWindowNode(window, remove_observer); 333 RemoveWindowNode(window, remove_observer);
286 } 334 }
287 335
288 void AshDevToolsDOMAgent::RemoveWindowNode(WmWindow* window, 336 void AshDevToolsDOMAgent::RemoveWindowNode(WmWindow* window,
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 421
374 NodeIdToViewMap::iterator node_id_to_view_it = 422 NodeIdToViewMap::iterator node_id_to_view_it =
375 node_id_to_view_map_.find(node_id); 423 node_id_to_view_map_.find(node_id);
376 DCHECK(node_id_to_view_it != node_id_to_view_map_.end()); 424 DCHECK(node_id_to_view_it != node_id_to_view_map_.end());
377 425
378 view_to_node_id_map_.erase(view_to_node_id_it); 426 view_to_node_id_map_.erase(view_to_node_id_it);
379 node_id_to_view_map_.erase(node_id_to_view_it); 427 node_id_to_view_map_.erase(node_id_to_view_it);
380 frontend()->childNodeRemoved(parent_id, node_id); 428 frontend()->childNodeRemoved(parent_id, node_id);
381 } 429 }
382 430
431 void AshDevToolsDOMAgent::DestroyHighlightingWidget() {
432 DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
433 widget_for_highlighting_.reset();
434 }
435
383 void AshDevToolsDOMAgent::RemoveObservers() { 436 void AshDevToolsDOMAgent::RemoveObservers() {
384 for (auto& pair : window_to_node_id_map_) 437 for (auto& pair : window_to_node_id_map_)
385 pair.first->RemoveObserver(this); 438 pair.first->RemoveObserver(this);
386 for (auto& pair : widget_to_node_id_map_) 439 for (auto& pair : widget_to_node_id_map_)
387 pair.first->RemoveRemovalsObserver(this); 440 pair.first->RemoveRemovalsObserver(this);
388 for (auto& pair : view_to_node_id_map_) 441 for (auto& pair : view_to_node_id_map_)
389 pair.first->RemoveObserver(this); 442 pair.first->RemoveObserver(this);
390 } 443 }
391 444
392 void AshDevToolsDOMAgent::Reset() { 445 void AshDevToolsDOMAgent::Reset() {
393 RemoveObservers(); 446 RemoveObservers();
447 main_thread_task_runner_->PostTask(
448 FROM_HERE, base::Bind(&AshDevToolsDOMAgent::DestroyHighlightingWidget,
449 base::Unretained(this)));
394 window_to_node_id_map_.clear(); 450 window_to_node_id_map_.clear();
395 widget_to_node_id_map_.clear(); 451 widget_to_node_id_map_.clear();
396 view_to_node_id_map_.clear(); 452 view_to_node_id_map_.clear();
397 node_id_to_window_map_.clear(); 453 node_id_to_window_map_.clear();
398 node_id_to_widget_map_.clear(); 454 node_id_to_widget_map_.clear();
399 node_id_to_view_map_.clear(); 455 node_id_to_view_map_.clear();
400 node_ids = 1; 456 node_ids = 1;
401 } 457 }
402 458
459 AshDevToolsDOMAgent::WindowAndBoundsPair
460 AshDevToolsDOMAgent::GetNodeWindowAndBounds(int node_id) {
461 WmWindow* window = GetWindowFromNodeId(node_id);
462 if (window)
463 return std::make_pair(window, window->GetBoundsInScreen());
464
465 views::Widget* widget = GetWidgetFromNodeId(node_id);
466 if (widget) {
467 return std::make_pair(WmLookup::Get()->GetWindowForWidget(widget),
468 widget->GetWindowBoundsInScreen());
469 }
470
471 views::View* view = GetViewFromNodeId(node_id);
472 if (view) {
473 gfx::Rect bounds = view->GetBoundsInScreen();
474 while (view->parent() != nullptr)
475 view = view->parent();
sadrul 2016/12/06 20:48:58 Why is this needed?
Sarmad Hashmi 2016/12/06 22:54:34 Sorry, thought an earlier bug I was encountering w
476 return std::make_pair(
477 WmLookup::Get()->GetWindowForWidget(view->GetWidget()), bounds);
478 }
479
480 return std::make_pair(nullptr, gfx::Rect());
481 }
482
483 void AshDevToolsDOMAgent::InitializeHighlightingWidget() {
484 DCHECK(!widget_for_highlighting_);
485 widget_for_highlighting_.reset(new views::Widget);
486 views::Widget::InitParams params;
487 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
488 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
489 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
490 params.opacity = views::Widget::InitParams::WindowOpacity::TRANSLUCENT_WINDOW;
491 params.name = "HighlightingWidget";
492 shell_->GetPrimaryRootWindowController()
493 ->ConfigureWidgetInitParamsForContainer(widget_for_highlighting_.get(),
494 kShellWindowId_OverlayContainer,
495 &params);
496 params.keep_on_top = true;
497 params.accept_events = false;
498 widget_for_highlighting_->Init(params);
499 }
500
501 void AshDevToolsDOMAgent::UpdateHighlight(WindowAndBoundsPair window_and_bounds,
502 SkColor background,
503 SkColor border) {
504 constexpr int kBorderThickness = 1;
505 views::View* root_view = widget_for_highlighting_->GetRootView();
506 root_view->SetBorder(views::CreateSolidBorder(kBorderThickness, border));
507 root_view->set_background(
508 views::Background::CreateSolidBackground(background));
509 WmLookup::Get()
510 ->GetWindowForWidget(widget_for_highlighting_.get())
511 ->SetBoundsInScreen(window_and_bounds.second,
512 window_and_bounds.first->GetDisplayNearestWindow());
sadrul 2016/12/06 20:48:59 Can you just SetBounds() on |widget_for_highlighti
Sarmad Hashmi 2016/12/06 22:54:34 We need to do SetBoundsInScreen so that we can han
513 }
514
515 void AshDevToolsDOMAgent::HighlightNode(
516 std::unique_ptr<ui::devtools::protocol::DOM::HighlightConfig>
517 highlight_config,
518 int node_id) {
519 DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
520 if (!widget_for_highlighting_)
521 InitializeHighlightingWidget();
522
523 WindowAndBoundsPair window_and_bounds(GetNodeWindowAndBounds(node_id));
524 // Invalid node id provided
525 if (!window_and_bounds.first)
526 return;
527
528 SkColor border_color =
529 RGBAToSkColor(highlight_config->getBorderColor(nullptr));
530 SkColor content_color =
531 RGBAToSkColor(highlight_config->getContentColor(nullptr));
532 UpdateHighlight(window_and_bounds, content_color, border_color);
533
534 if (!widget_for_highlighting_->IsVisible())
535 widget_for_highlighting_->Show();
536 }
537
538 bool AshDevToolsDOMAgent::IsHighlightingWindow(WmWindow* window) {
539 return widget_for_highlighting_ &&
540 window->GetInternalWidget() == widget_for_highlighting_.get();
541 }
542
403 } // namespace devtools 543 } // namespace devtools
404 } // namespace ash 544 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698