| OLD | NEW |
| 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 Loading... |
| 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 int MaskColor(int value) { |
| 89 return value & 0xff; |
| 90 } |
| 91 |
| 92 SkColor RGBAToSkColor(DOM::RGBA* rgba) { |
| 93 if (!rgba) |
| 94 return SkColorSetARGB(0, 0, 0, 0); |
| 95 // Default alpha value is 0 (not visible) and need to convert alpha decimal |
| 96 // percentage value to hex |
| 97 return SkColorSetARGB(MaskColor(static_cast<int>(rgba->getA(0) * 255)), |
| 98 MaskColor(rgba->getR()), MaskColor(rgba->getG()), |
| 99 MaskColor(rgba->getB())); |
| 100 } |
| 101 |
| 82 } // namespace | 102 } // namespace |
| 83 | 103 |
| 84 AshDevToolsDOMAgent::AshDevToolsDOMAgent(ash::WmShell* shell) : shell_(shell) { | 104 AshDevToolsDOMAgent::AshDevToolsDOMAgent(ash::WmShell* shell) : shell_(shell) { |
| 85 DCHECK(shell_); | 105 DCHECK(shell_); |
| 86 } | 106 } |
| 87 | 107 |
| 88 AshDevToolsDOMAgent::~AshDevToolsDOMAgent() { | 108 AshDevToolsDOMAgent::~AshDevToolsDOMAgent() { |
| 89 RemoveObservers(); | 109 RemoveObservers(); |
| 90 } | 110 } |
| 91 | 111 |
| 92 ui::devtools::protocol::Response AshDevToolsDOMAgent::disable() { | 112 ui::devtools::protocol::Response AshDevToolsDOMAgent::disable() { |
| 93 Reset(); | 113 Reset(); |
| 94 return ui::devtools::protocol::Response::OK(); | 114 return ui::devtools::protocol::Response::OK(); |
| 95 } | 115 } |
| 96 | 116 |
| 97 ui::devtools::protocol::Response AshDevToolsDOMAgent::getDocument( | 117 ui::devtools::protocol::Response AshDevToolsDOMAgent::getDocument( |
| 98 std::unique_ptr<ui::devtools::protocol::DOM::Node>* out_root) { | 118 std::unique_ptr<ui::devtools::protocol::DOM::Node>* out_root) { |
| 99 *out_root = BuildInitialTree(); | 119 *out_root = BuildInitialTree(); |
| 100 return ui::devtools::protocol::Response::OK(); | 120 return ui::devtools::protocol::Response::OK(); |
| 101 } | 121 } |
| 102 | 122 |
| 123 ui::devtools::protocol::Response AshDevToolsDOMAgent::highlightNode( |
| 124 std::unique_ptr<ui::devtools::protocol::DOM::HighlightConfig> |
| 125 highlight_config, |
| 126 ui::devtools::protocol::Maybe<int> node_id) { |
| 127 return HighlightNode(std::move(highlight_config), node_id.fromJust()); |
| 128 } |
| 129 |
| 130 ui::devtools::protocol::Response AshDevToolsDOMAgent::hideHighlight() { |
| 131 if (widget_for_highlighting_ && widget_for_highlighting_->IsVisible()) |
| 132 widget_for_highlighting_->Hide(); |
| 133 return ui::devtools::protocol::Response::OK(); |
| 134 } |
| 135 |
| 103 // Handles removing windows. | 136 // Handles removing windows. |
| 104 void AshDevToolsDOMAgent::OnWindowTreeChanging(WmWindow* window, | 137 void AshDevToolsDOMAgent::OnWindowTreeChanging(WmWindow* window, |
| 105 const TreeChangeParams& params) { | 138 const TreeChangeParams& params) { |
| 106 // Only trigger this when window == params.old_parent. | 139 // Only trigger this when window == params.old_parent. |
| 107 // Only removals are handled here. Removing a node can occur as a result of | 140 // Only removals are handled here. Removing a node can occur as a result of |
| 108 // reorganizing a window or just destroying it. OnWindowTreeChanged | 141 // 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 | 142 // 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. | 143 // 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 | 144 // 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. | 145 // either exist and only call this callback once, or not at all. |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 return BuildNode("root", nullptr, std::move(children)); | 249 return BuildNode("root", nullptr, std::move(children)); |
| 217 } | 250 } |
| 218 | 251 |
| 219 std::unique_ptr<DOM::Node> AshDevToolsDOMAgent::BuildTreeForWindow( | 252 std::unique_ptr<DOM::Node> AshDevToolsDOMAgent::BuildTreeForWindow( |
| 220 ash::WmWindow* window) { | 253 ash::WmWindow* window) { |
| 221 DCHECK(!window_to_node_id_map_.count(window)); | 254 DCHECK(!window_to_node_id_map_.count(window)); |
| 222 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create(); | 255 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create(); |
| 223 views::Widget* widget = window->GetInternalWidget(); | 256 views::Widget* widget = window->GetInternalWidget(); |
| 224 if (widget) | 257 if (widget) |
| 225 children->addItem(BuildTreeForRootWidget(widget)); | 258 children->addItem(BuildTreeForRootWidget(widget)); |
| 226 for (ash::WmWindow* child : window->GetChildren()) | 259 for (ash::WmWindow* child : window->GetChildren()) { |
| 227 children->addItem(BuildTreeForWindow(child)); | 260 if (!IsHighlightingWindow(child)) |
| 261 children->addItem(BuildTreeForWindow(child)); |
| 262 } |
| 228 | 263 |
| 229 std::unique_ptr<ui::devtools::protocol::DOM::Node> node = | 264 std::unique_ptr<ui::devtools::protocol::DOM::Node> node = |
| 230 BuildNode("Window", GetAttributes(window), std::move(children)); | 265 BuildNode("Window", GetAttributes(window), std::move(children)); |
| 231 if (!window->HasObserver(this)) | 266 if (!window->HasObserver(this)) |
| 232 window->AddObserver(this); | 267 window->AddObserver(this); |
| 233 window_to_node_id_map_[window] = node->getNodeId(); | 268 window_to_node_id_map_[window] = node->getNodeId(); |
| 234 node_id_to_window_map_[node->getNodeId()] = window; | 269 node_id_to_window_map_[node->getNodeId()] = window; |
| 235 return node; | 270 return node; |
| 236 } | 271 } |
| 237 | 272 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 258 std::unique_ptr<ui::devtools::protocol::DOM::Node> node = | 293 std::unique_ptr<ui::devtools::protocol::DOM::Node> node = |
| 259 BuildNode("View", GetAttributes(view), std::move(children)); | 294 BuildNode("View", GetAttributes(view), std::move(children)); |
| 260 if (!view->HasObserver(this)) | 295 if (!view->HasObserver(this)) |
| 261 view->AddObserver(this); | 296 view->AddObserver(this); |
| 262 view_to_node_id_map_[view] = node->getNodeId(); | 297 view_to_node_id_map_[view] = node->getNodeId(); |
| 263 node_id_to_view_map_[node->getNodeId()] = view; | 298 node_id_to_view_map_[node->getNodeId()] = view; |
| 264 return node; | 299 return node; |
| 265 } | 300 } |
| 266 | 301 |
| 267 void AshDevToolsDOMAgent::AddWindowTree(WmWindow* window) { | 302 void AshDevToolsDOMAgent::AddWindowTree(WmWindow* window) { |
| 303 if (IsHighlightingWindow(window)) |
| 304 return; |
| 305 |
| 268 DCHECK(window_to_node_id_map_.count(window->GetParent())); | 306 DCHECK(window_to_node_id_map_.count(window->GetParent())); |
| 269 WmWindow* prev_sibling = FindPreviousSibling(window); | 307 WmWindow* prev_sibling = FindPreviousSibling(window); |
| 270 frontend()->childNodeInserted( | 308 frontend()->childNodeInserted( |
| 271 window_to_node_id_map_[window->GetParent()], | 309 window_to_node_id_map_[window->GetParent()], |
| 272 prev_sibling ? window_to_node_id_map_[prev_sibling] : 0, | 310 prev_sibling ? window_to_node_id_map_[prev_sibling] : 0, |
| 273 BuildTreeForWindow(window)); | 311 BuildTreeForWindow(window)); |
| 274 } | 312 } |
| 275 | 313 |
| 276 void AshDevToolsDOMAgent::RemoveWindowTree(WmWindow* window, | 314 void AshDevToolsDOMAgent::RemoveWindowTree(WmWindow* window, |
| 277 bool remove_observer) { | 315 bool remove_observer) { |
| 278 DCHECK(window); | 316 DCHECK(window); |
| 317 if (IsHighlightingWindow(window)) |
| 318 return; |
| 319 |
| 279 if (window->GetInternalWidget()) | 320 if (window->GetInternalWidget()) |
| 280 RemoveWidgetTree(window->GetInternalWidget(), remove_observer); | 321 RemoveWidgetTree(window->GetInternalWidget(), remove_observer); |
| 281 | 322 |
| 282 for (ash::WmWindow* child : window->GetChildren()) | 323 for (ash::WmWindow* child : window->GetChildren()) |
| 283 RemoveWindowTree(child, remove_observer); | 324 RemoveWindowTree(child, remove_observer); |
| 284 | 325 |
| 285 RemoveWindowNode(window, remove_observer); | 326 RemoveWindowNode(window, remove_observer); |
| 286 } | 327 } |
| 287 | 328 |
| 288 void AshDevToolsDOMAgent::RemoveWindowNode(WmWindow* window, | 329 void AshDevToolsDOMAgent::RemoveWindowNode(WmWindow* window, |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 384 for (auto& pair : window_to_node_id_map_) | 425 for (auto& pair : window_to_node_id_map_) |
| 385 pair.first->RemoveObserver(this); | 426 pair.first->RemoveObserver(this); |
| 386 for (auto& pair : widget_to_node_id_map_) | 427 for (auto& pair : widget_to_node_id_map_) |
| 387 pair.first->RemoveRemovalsObserver(this); | 428 pair.first->RemoveRemovalsObserver(this); |
| 388 for (auto& pair : view_to_node_id_map_) | 429 for (auto& pair : view_to_node_id_map_) |
| 389 pair.first->RemoveObserver(this); | 430 pair.first->RemoveObserver(this); |
| 390 } | 431 } |
| 391 | 432 |
| 392 void AshDevToolsDOMAgent::Reset() { | 433 void AshDevToolsDOMAgent::Reset() { |
| 393 RemoveObservers(); | 434 RemoveObservers(); |
| 435 widget_for_highlighting_.reset(); |
| 394 window_to_node_id_map_.clear(); | 436 window_to_node_id_map_.clear(); |
| 395 widget_to_node_id_map_.clear(); | 437 widget_to_node_id_map_.clear(); |
| 396 view_to_node_id_map_.clear(); | 438 view_to_node_id_map_.clear(); |
| 397 node_id_to_window_map_.clear(); | 439 node_id_to_window_map_.clear(); |
| 398 node_id_to_widget_map_.clear(); | 440 node_id_to_widget_map_.clear(); |
| 399 node_id_to_view_map_.clear(); | 441 node_id_to_view_map_.clear(); |
| 400 node_ids = 1; | 442 node_ids = 1; |
| 401 } | 443 } |
| 402 | 444 |
| 445 AshDevToolsDOMAgent::WindowAndBoundsPair |
| 446 AshDevToolsDOMAgent::GetNodeWindowAndBounds(int node_id) { |
| 447 WmWindow* window = GetWindowFromNodeId(node_id); |
| 448 if (window) |
| 449 return std::make_pair(window, window->GetBoundsInScreen()); |
| 450 |
| 451 views::Widget* widget = GetWidgetFromNodeId(node_id); |
| 452 if (widget) { |
| 453 return std::make_pair(WmLookup::Get()->GetWindowForWidget(widget), |
| 454 widget->GetWindowBoundsInScreen()); |
| 455 } |
| 456 |
| 457 views::View* view = GetViewFromNodeId(node_id); |
| 458 if (view) { |
| 459 gfx::Rect bounds = view->GetBoundsInScreen(); |
| 460 return std::make_pair( |
| 461 WmLookup::Get()->GetWindowForWidget(view->GetWidget()), bounds); |
| 462 } |
| 463 |
| 464 return std::make_pair(nullptr, gfx::Rect()); |
| 465 } |
| 466 |
| 467 void AshDevToolsDOMAgent::InitializeHighlightingWidget() { |
| 468 DCHECK(!widget_for_highlighting_); |
| 469 widget_for_highlighting_.reset(new views::Widget); |
| 470 views::Widget::InitParams params; |
| 471 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; |
| 472 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; |
| 473 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| 474 params.opacity = views::Widget::InitParams::WindowOpacity::TRANSLUCENT_WINDOW; |
| 475 params.name = "HighlightingWidget"; |
| 476 shell_->GetPrimaryRootWindowController() |
| 477 ->ConfigureWidgetInitParamsForContainer(widget_for_highlighting_.get(), |
| 478 kShellWindowId_OverlayContainer, |
| 479 ¶ms); |
| 480 params.keep_on_top = true; |
| 481 params.accept_events = false; |
| 482 widget_for_highlighting_->Init(params); |
| 483 } |
| 484 |
| 485 void AshDevToolsDOMAgent::UpdateHighlight( |
| 486 const WindowAndBoundsPair& window_and_bounds, |
| 487 SkColor background, |
| 488 SkColor border) { |
| 489 constexpr int kBorderThickness = 1; |
| 490 views::View* root_view = widget_for_highlighting_->GetRootView(); |
| 491 root_view->SetBorder(views::CreateSolidBorder(kBorderThickness, border)); |
| 492 root_view->set_background( |
| 493 views::Background::CreateSolidBackground(background)); |
| 494 WmLookup::Get() |
| 495 ->GetWindowForWidget(widget_for_highlighting_.get()) |
| 496 ->SetBoundsInScreen(window_and_bounds.second, |
| 497 window_and_bounds.first->GetDisplayNearestWindow()); |
| 498 } |
| 499 |
| 500 ui::devtools::protocol::Response AshDevToolsDOMAgent::HighlightNode( |
| 501 std::unique_ptr<ui::devtools::protocol::DOM::HighlightConfig> |
| 502 highlight_config, |
| 503 int node_id) { |
| 504 if (!widget_for_highlighting_) |
| 505 InitializeHighlightingWidget(); |
| 506 |
| 507 WindowAndBoundsPair window_and_bounds(GetNodeWindowAndBounds(node_id)); |
| 508 |
| 509 if (!window_and_bounds.first) |
| 510 return ui::devtools::protocol::Response::Error( |
| 511 "No node found with that id"); |
| 512 |
| 513 SkColor border_color = |
| 514 RGBAToSkColor(highlight_config->getBorderColor(nullptr)); |
| 515 SkColor content_color = |
| 516 RGBAToSkColor(highlight_config->getContentColor(nullptr)); |
| 517 UpdateHighlight(window_and_bounds, content_color, border_color); |
| 518 |
| 519 if (!widget_for_highlighting_->IsVisible()) |
| 520 widget_for_highlighting_->Show(); |
| 521 |
| 522 return ui::devtools::protocol::Response::OK(); |
| 523 } |
| 524 |
| 525 bool AshDevToolsDOMAgent::IsHighlightingWindow(WmWindow* window) { |
| 526 return widget_for_highlighting_ && |
| 527 window->GetInternalWidget() == widget_for_highlighting_.get(); |
| 528 } |
| 529 |
| 403 } // namespace devtools | 530 } // namespace devtools |
| 404 } // namespace ash | 531 } // namespace ash |
| OLD | NEW |