| OLD | NEW |
| (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/public/cpp/shell_window_ids.h" | |
| 8 #include "ash/root_window_controller.h" | |
| 9 #include "ash/wm_window.h" | |
| 10 #include "components/ui_devtools/devtools_server.h" | |
| 11 #include "third_party/skia/include/core/SkColor.h" | |
| 12 #include "ui/display/display.h" | |
| 13 #include "ui/views/background.h" | |
| 14 #include "ui/views/border.h" | |
| 15 | |
| 16 namespace ash { | |
| 17 namespace devtools { | |
| 18 | |
| 19 namespace { | |
| 20 using namespace ui::devtools::protocol; | |
| 21 // TODO(mhashmi): Make ids reusable | |
| 22 DOM::NodeId node_ids = 1; | |
| 23 | |
| 24 std::unique_ptr<DOM::Node> BuildNode( | |
| 25 const std::string& name, | |
| 26 std::unique_ptr<Array<std::string>> attributes, | |
| 27 std::unique_ptr<Array<DOM::Node>> children) { | |
| 28 constexpr int kDomElementNodeType = 1; | |
| 29 std::unique_ptr<DOM::Node> node = DOM::Node::create() | |
| 30 .setNodeId(node_ids++) | |
| 31 .setNodeName(name) | |
| 32 .setNodeType(kDomElementNodeType) | |
| 33 .setAttributes(std::move(attributes)) | |
| 34 .build(); | |
| 35 node->setChildNodeCount(children->length()); | |
| 36 node->setChildren(std::move(children)); | |
| 37 return node; | |
| 38 } | |
| 39 | |
| 40 std::unique_ptr<Array<std::string>> GetAttributes(const ash::WmWindow* window) { | |
| 41 std::unique_ptr<Array<std::string>> attributes = Array<std::string>::create(); | |
| 42 attributes->addItem("name"); | |
| 43 attributes->addItem(window->GetName()); | |
| 44 attributes->addItem("active"); | |
| 45 attributes->addItem(window->IsActive() ? "true" : "false"); | |
| 46 return attributes; | |
| 47 } | |
| 48 | |
| 49 std::unique_ptr<Array<std::string>> GetAttributes(const views::Widget* widget) { | |
| 50 std::unique_ptr<Array<std::string>> attributes = Array<std::string>::create(); | |
| 51 attributes->addItem("name"); | |
| 52 attributes->addItem(widget->GetName()); | |
| 53 attributes->addItem("active"); | |
| 54 attributes->addItem(widget->IsActive() ? "true" : "false"); | |
| 55 return attributes; | |
| 56 } | |
| 57 | |
| 58 std::unique_ptr<Array<std::string>> GetAttributes(const views::View* view) { | |
| 59 std::unique_ptr<Array<std::string>> attributes = Array<std::string>::create(); | |
| 60 attributes->addItem("name"); | |
| 61 attributes->addItem(view->GetClassName()); | |
| 62 return attributes; | |
| 63 } | |
| 64 | |
| 65 WmWindow* FindPreviousSibling(WmWindow* window) { | |
| 66 std::vector<WmWindow*> siblings = window->GetParent()->GetChildren(); | |
| 67 std::vector<WmWindow*>::iterator it = | |
| 68 std::find(siblings.begin(), siblings.end(), window); | |
| 69 DCHECK(it != siblings.end()); | |
| 70 // If this is the first child of its parent, the previous sibling is null | |
| 71 return it == siblings.begin() ? nullptr : *std::prev(it); | |
| 72 } | |
| 73 | |
| 74 views::View* FindPreviousSibling(views::View* view) { | |
| 75 views::View* parent = view->parent(); | |
| 76 int view_index = -1; | |
| 77 for (int i = 0, count = parent->child_count(); i < count; i++) { | |
| 78 if (view == parent->child_at(i)) { | |
| 79 view_index = i; | |
| 80 break; | |
| 81 } | |
| 82 } | |
| 83 DCHECK_GE(view_index, 0); | |
| 84 return view_index == 0 ? nullptr : parent->child_at(view_index - 1); | |
| 85 } | |
| 86 | |
| 87 int MaskColor(int value) { | |
| 88 return value & 0xff; | |
| 89 } | |
| 90 | |
| 91 SkColor RGBAToSkColor(DOM::RGBA* rgba) { | |
| 92 if (!rgba) | |
| 93 return SkColorSetARGB(0, 0, 0, 0); | |
| 94 // Default alpha value is 0 (not visible) and need to convert alpha decimal | |
| 95 // percentage value to hex | |
| 96 return SkColorSetARGB(MaskColor(static_cast<int>(rgba->getA(0) * 255)), | |
| 97 MaskColor(rgba->getR()), MaskColor(rgba->getG()), | |
| 98 MaskColor(rgba->getB())); | |
| 99 } | |
| 100 | |
| 101 views::Widget* GetWidgetFromWmWindow(WmWindow* window) { | |
| 102 return views::Widget::GetWidgetForNativeView(window->aura_window()); | |
| 103 } | |
| 104 | |
| 105 } // namespace | |
| 106 | |
| 107 AshDevToolsDOMAgent::AshDevToolsDOMAgent(ash::WmShell* shell) : shell_(shell) { | |
| 108 DCHECK(shell_); | |
| 109 } | |
| 110 | |
| 111 AshDevToolsDOMAgent::~AshDevToolsDOMAgent() { | |
| 112 RemoveObservers(); | |
| 113 } | |
| 114 | |
| 115 ui::devtools::protocol::Response AshDevToolsDOMAgent::disable() { | |
| 116 Reset(); | |
| 117 return ui::devtools::protocol::Response::OK(); | |
| 118 } | |
| 119 | |
| 120 ui::devtools::protocol::Response AshDevToolsDOMAgent::getDocument( | |
| 121 std::unique_ptr<ui::devtools::protocol::DOM::Node>* out_root) { | |
| 122 *out_root = BuildInitialTree(); | |
| 123 return ui::devtools::protocol::Response::OK(); | |
| 124 } | |
| 125 | |
| 126 ui::devtools::protocol::Response AshDevToolsDOMAgent::highlightNode( | |
| 127 std::unique_ptr<ui::devtools::protocol::DOM::HighlightConfig> | |
| 128 highlight_config, | |
| 129 ui::devtools::protocol::Maybe<int> node_id) { | |
| 130 return HighlightNode(std::move(highlight_config), node_id.fromJust()); | |
| 131 } | |
| 132 | |
| 133 ui::devtools::protocol::Response AshDevToolsDOMAgent::hideHighlight() { | |
| 134 if (widget_for_highlighting_ && widget_for_highlighting_->IsVisible()) | |
| 135 widget_for_highlighting_->Hide(); | |
| 136 return ui::devtools::protocol::Response::OK(); | |
| 137 } | |
| 138 | |
| 139 // Handles removing windows. | |
| 140 void AshDevToolsDOMAgent::OnWindowHierarchyChanging( | |
| 141 const HierarchyChangeParams& params) { | |
| 142 // Only trigger this when params.receiver == params.old_parent. | |
| 143 // Only removals are handled here. Removing a node can occur as a result of | |
| 144 // reorganizing a window or just destroying it. OnWindowHierarchyChanged | |
| 145 // is only called if there is a new_parent. The only case this method isn't | |
| 146 // called is when adding a node because old_parent is then null. | |
| 147 // Finally, We only trigger this 0 or 1 times as an old_parent will | |
| 148 // either exist and only call this callback once, or not at all. | |
| 149 if (params.receiver == params.old_parent) | |
| 150 RemoveWindowTree(WmWindow::Get(params.target), true); | |
| 151 } | |
| 152 | |
| 153 // Handles adding windows. | |
| 154 void AshDevToolsDOMAgent::OnWindowHierarchyChanged( | |
| 155 const HierarchyChangeParams& params) { | |
| 156 // Only trigger this when params.receiver == params.new_parent. | |
| 157 // If there is an old_parent + new_parent, then this window's node was | |
| 158 // removed in OnWindowHierarchyChanging and will now be added to the | |
| 159 // new_parent. If there is only a new_parent, OnWindowHierarchyChanging is | |
| 160 // never called and the window is only added here. | |
| 161 if (params.receiver == params.new_parent) | |
| 162 AddWindowTree(WmWindow::Get(params.target)); | |
| 163 } | |
| 164 | |
| 165 void AshDevToolsDOMAgent::OnWindowStackingChanged(aura::Window* window) { | |
| 166 RemoveWindowTree(WmWindow::Get(window), false); | |
| 167 AddWindowTree(WmWindow::Get(window)); | |
| 168 } | |
| 169 | |
| 170 void AshDevToolsDOMAgent::OnWindowBoundsChanged(aura::Window* window, | |
| 171 const gfx::Rect& old_bounds, | |
| 172 const gfx::Rect& new_bounds) { | |
| 173 for (auto& observer : observers_) | |
| 174 observer.OnWindowBoundsChanged(WmWindow::Get(window)); | |
| 175 } | |
| 176 | |
| 177 void AshDevToolsDOMAgent::OnWillRemoveView(views::Widget* widget, | |
| 178 views::View* view) { | |
| 179 if (view == widget->GetRootView()) | |
| 180 RemoveViewTree(view, nullptr, true); | |
| 181 } | |
| 182 | |
| 183 void AshDevToolsDOMAgent::OnWidgetBoundsChanged(views::Widget* widget, | |
| 184 const gfx::Rect& new_bounds) { | |
| 185 for (auto& observer : observers_) | |
| 186 observer.OnWidgetBoundsChanged(widget); | |
| 187 } | |
| 188 | |
| 189 void AshDevToolsDOMAgent::OnChildViewRemoved(views::View* view, | |
| 190 views::View* parent) { | |
| 191 RemoveViewTree(view, parent, true); | |
| 192 } | |
| 193 | |
| 194 void AshDevToolsDOMAgent::OnChildViewAdded(views::View* view) { | |
| 195 AddViewTree(view); | |
| 196 } | |
| 197 | |
| 198 void AshDevToolsDOMAgent::OnChildViewReordered(views::View* view) { | |
| 199 RemoveViewTree(view, view->parent(), false); | |
| 200 AddViewTree(view); | |
| 201 } | |
| 202 | |
| 203 void AshDevToolsDOMAgent::OnViewBoundsChanged(views::View* view) { | |
| 204 for (auto& observer : observers_) | |
| 205 observer.OnViewBoundsChanged(view); | |
| 206 } | |
| 207 | |
| 208 WmWindow* AshDevToolsDOMAgent::GetWindowFromNodeId(int nodeId) { | |
| 209 return node_id_to_window_map_.count(nodeId) ? node_id_to_window_map_[nodeId] | |
| 210 : nullptr; | |
| 211 } | |
| 212 | |
| 213 views::Widget* AshDevToolsDOMAgent::GetWidgetFromNodeId(int nodeId) { | |
| 214 return node_id_to_widget_map_.count(nodeId) ? node_id_to_widget_map_[nodeId] | |
| 215 : nullptr; | |
| 216 } | |
| 217 | |
| 218 views::View* AshDevToolsDOMAgent::GetViewFromNodeId(int nodeId) { | |
| 219 return node_id_to_view_map_.count(nodeId) ? node_id_to_view_map_[nodeId] | |
| 220 : nullptr; | |
| 221 } | |
| 222 | |
| 223 int AshDevToolsDOMAgent::GetNodeIdFromWindow(WmWindow* window) { | |
| 224 DCHECK(window_to_node_id_map_.count(window)); | |
| 225 return window_to_node_id_map_[window]; | |
| 226 } | |
| 227 | |
| 228 int AshDevToolsDOMAgent::GetNodeIdFromWidget(views::Widget* widget) { | |
| 229 DCHECK(widget_to_node_id_map_.count(widget)); | |
| 230 return widget_to_node_id_map_[widget]; | |
| 231 } | |
| 232 | |
| 233 int AshDevToolsDOMAgent::GetNodeIdFromView(views::View* view) { | |
| 234 DCHECK(view_to_node_id_map_.count(view)); | |
| 235 return view_to_node_id_map_[view]; | |
| 236 } | |
| 237 | |
| 238 void AshDevToolsDOMAgent::AddObserver(AshDevToolsDOMAgentObserver* observer) { | |
| 239 observers_.AddObserver(observer); | |
| 240 } | |
| 241 | |
| 242 void AshDevToolsDOMAgent::RemoveObserver( | |
| 243 AshDevToolsDOMAgentObserver* observer) { | |
| 244 observers_.RemoveObserver(observer); | |
| 245 } | |
| 246 | |
| 247 std::unique_ptr<ui::devtools::protocol::DOM::Node> | |
| 248 AshDevToolsDOMAgent::BuildInitialTree() { | |
| 249 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create(); | |
| 250 for (ash::WmWindow* window : shell_->GetAllRootWindows()) | |
| 251 children->addItem(BuildTreeForWindow(window)); | |
| 252 return BuildNode("root", nullptr, std::move(children)); | |
| 253 } | |
| 254 | |
| 255 std::unique_ptr<DOM::Node> AshDevToolsDOMAgent::BuildTreeForWindow( | |
| 256 ash::WmWindow* window) { | |
| 257 DCHECK(!window_to_node_id_map_.count(window)); | |
| 258 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create(); | |
| 259 views::Widget* widget = GetWidgetFromWmWindow(window); | |
| 260 if (widget) | |
| 261 children->addItem(BuildTreeForRootWidget(widget)); | |
| 262 for (ash::WmWindow* child : window->GetChildren()) { | |
| 263 if (!IsHighlightingWindow(child)) | |
| 264 children->addItem(BuildTreeForWindow(child)); | |
| 265 } | |
| 266 | |
| 267 std::unique_ptr<ui::devtools::protocol::DOM::Node> node = | |
| 268 BuildNode("Window", GetAttributes(window), std::move(children)); | |
| 269 if (!window->aura_window()->HasObserver(this)) | |
| 270 window->aura_window()->AddObserver(this); | |
| 271 window_to_node_id_map_[window] = node->getNodeId(); | |
| 272 node_id_to_window_map_[node->getNodeId()] = window; | |
| 273 return node; | |
| 274 } | |
| 275 | |
| 276 std::unique_ptr<DOM::Node> AshDevToolsDOMAgent::BuildTreeForRootWidget( | |
| 277 views::Widget* widget) { | |
| 278 DCHECK(!widget_to_node_id_map_.count(widget)); | |
| 279 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create(); | |
| 280 children->addItem(BuildTreeForView(widget->GetRootView())); | |
| 281 std::unique_ptr<ui::devtools::protocol::DOM::Node> node = | |
| 282 BuildNode("Widget", GetAttributes(widget), std::move(children)); | |
| 283 if (!widget->HasRemovalsObserver(this)) | |
| 284 widget->AddRemovalsObserver(this); | |
| 285 widget_to_node_id_map_[widget] = node->getNodeId(); | |
| 286 node_id_to_widget_map_[node->getNodeId()] = widget; | |
| 287 return node; | |
| 288 } | |
| 289 | |
| 290 std::unique_ptr<DOM::Node> AshDevToolsDOMAgent::BuildTreeForView( | |
| 291 views::View* view) { | |
| 292 DCHECK(!view_to_node_id_map_.count(view)); | |
| 293 std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create(); | |
| 294 for (int i = 0, count = view->child_count(); i < count; i++) | |
| 295 children->addItem(BuildTreeForView(view->child_at(i))); | |
| 296 std::unique_ptr<ui::devtools::protocol::DOM::Node> node = | |
| 297 BuildNode("View", GetAttributes(view), std::move(children)); | |
| 298 if (!view->HasObserver(this)) | |
| 299 view->AddObserver(this); | |
| 300 view_to_node_id_map_[view] = node->getNodeId(); | |
| 301 node_id_to_view_map_[node->getNodeId()] = view; | |
| 302 return node; | |
| 303 } | |
| 304 | |
| 305 void AshDevToolsDOMAgent::AddWindowTree(WmWindow* window) { | |
| 306 if (IsHighlightingWindow(window)) | |
| 307 return; | |
| 308 | |
| 309 DCHECK(window_to_node_id_map_.count(window->GetParent())); | |
| 310 WmWindow* prev_sibling = FindPreviousSibling(window); | |
| 311 frontend()->childNodeInserted( | |
| 312 window_to_node_id_map_[window->GetParent()], | |
| 313 prev_sibling ? window_to_node_id_map_[prev_sibling] : 0, | |
| 314 BuildTreeForWindow(window)); | |
| 315 } | |
| 316 | |
| 317 void AshDevToolsDOMAgent::RemoveWindowTree(WmWindow* window, | |
| 318 bool remove_observer) { | |
| 319 DCHECK(window); | |
| 320 if (IsHighlightingWindow(window)) | |
| 321 return; | |
| 322 | |
| 323 if (GetWidgetFromWmWindow(window)) | |
| 324 RemoveWidgetTree(GetWidgetFromWmWindow(window), remove_observer); | |
| 325 | |
| 326 for (ash::WmWindow* child : window->GetChildren()) | |
| 327 RemoveWindowTree(child, remove_observer); | |
| 328 | |
| 329 RemoveWindowNode(window, remove_observer); | |
| 330 } | |
| 331 | |
| 332 void AshDevToolsDOMAgent::RemoveWindowNode(WmWindow* window, | |
| 333 bool remove_observer) { | |
| 334 WindowToNodeIdMap::iterator window_to_node_id_it = | |
| 335 window_to_node_id_map_.find(window); | |
| 336 DCHECK(window_to_node_id_it != window_to_node_id_map_.end()); | |
| 337 | |
| 338 int node_id = window_to_node_id_it->second; | |
| 339 int parent_id = GetNodeIdFromWindow(window->GetParent()); | |
| 340 | |
| 341 NodeIdToWindowMap::iterator node_id_to_window_it = | |
| 342 node_id_to_window_map_.find(node_id); | |
| 343 DCHECK(node_id_to_window_it != node_id_to_window_map_.end()); | |
| 344 | |
| 345 if (remove_observer) | |
| 346 window->aura_window()->RemoveObserver(this); | |
| 347 | |
| 348 node_id_to_window_map_.erase(node_id_to_window_it); | |
| 349 window_to_node_id_map_.erase(window_to_node_id_it); | |
| 350 frontend()->childNodeRemoved(parent_id, node_id); | |
| 351 } | |
| 352 | |
| 353 void AshDevToolsDOMAgent::RemoveWidgetTree(views::Widget* widget, | |
| 354 bool remove_observer) { | |
| 355 DCHECK(widget); | |
| 356 if (widget->GetRootView()) | |
| 357 RemoveViewTree(widget->GetRootView(), nullptr, remove_observer); | |
| 358 RemoveWidgetNode(widget, remove_observer); | |
| 359 } | |
| 360 | |
| 361 void AshDevToolsDOMAgent::RemoveWidgetNode(views::Widget* widget, | |
| 362 bool remove_observer) { | |
| 363 WidgetToNodeIdMap::iterator widget_to_node_id_it = | |
| 364 widget_to_node_id_map_.find(widget); | |
| 365 DCHECK(widget_to_node_id_it != widget_to_node_id_map_.end()); | |
| 366 | |
| 367 int node_id = widget_to_node_id_it->second; | |
| 368 int parent_id = GetNodeIdFromWindow(WmWindow::Get(widget->GetNativeWindow())); | |
| 369 | |
| 370 if (remove_observer) | |
| 371 widget->RemoveRemovalsObserver(this); | |
| 372 | |
| 373 NodeIdToWidgetMap::iterator node_id_to_widget_it = | |
| 374 node_id_to_widget_map_.find(node_id); | |
| 375 DCHECK(node_id_to_widget_it != node_id_to_widget_map_.end()); | |
| 376 | |
| 377 widget_to_node_id_map_.erase(widget_to_node_id_it); | |
| 378 node_id_to_widget_map_.erase(node_id_to_widget_it); | |
| 379 frontend()->childNodeRemoved(parent_id, node_id); | |
| 380 } | |
| 381 | |
| 382 void AshDevToolsDOMAgent::AddViewTree(views::View* view) { | |
| 383 DCHECK(view_to_node_id_map_.count(view->parent())); | |
| 384 views::View* prev_sibling = FindPreviousSibling(view); | |
| 385 frontend()->childNodeInserted( | |
| 386 view_to_node_id_map_[view->parent()], | |
| 387 prev_sibling ? view_to_node_id_map_[prev_sibling] : 0, | |
| 388 BuildTreeForView(view)); | |
| 389 } | |
| 390 | |
| 391 void AshDevToolsDOMAgent::RemoveViewTree(views::View* view, | |
| 392 views::View* parent, | |
| 393 bool remove_observer) { | |
| 394 DCHECK(view); | |
| 395 for (int i = 0, count = view->child_count(); i < count; i++) | |
| 396 RemoveViewTree(view->child_at(i), view, remove_observer); | |
| 397 RemoveViewNode(view, parent, remove_observer); | |
| 398 } | |
| 399 | |
| 400 void AshDevToolsDOMAgent::RemoveViewNode(views::View* view, | |
| 401 views::View* parent, | |
| 402 bool remove_observer) { | |
| 403 ViewToNodeIdMap::iterator view_to_node_id_it = | |
| 404 view_to_node_id_map_.find(view); | |
| 405 DCHECK(view_to_node_id_it != view_to_node_id_map_.end()); | |
| 406 | |
| 407 int node_id = view_to_node_id_it->second; | |
| 408 int parent_id = 0; | |
| 409 if (parent) | |
| 410 parent_id = GetNodeIdFromView(parent); | |
| 411 else // views::RootView | |
| 412 parent_id = GetNodeIdFromWidget(view->GetWidget()); | |
| 413 | |
| 414 if (remove_observer) | |
| 415 view->RemoveObserver(this); | |
| 416 | |
| 417 NodeIdToViewMap::iterator node_id_to_view_it = | |
| 418 node_id_to_view_map_.find(node_id); | |
| 419 DCHECK(node_id_to_view_it != node_id_to_view_map_.end()); | |
| 420 | |
| 421 view_to_node_id_map_.erase(view_to_node_id_it); | |
| 422 node_id_to_view_map_.erase(node_id_to_view_it); | |
| 423 frontend()->childNodeRemoved(parent_id, node_id); | |
| 424 } | |
| 425 | |
| 426 void AshDevToolsDOMAgent::RemoveObservers() { | |
| 427 for (auto& pair : window_to_node_id_map_) | |
| 428 pair.first->aura_window()->RemoveObserver(this); | |
| 429 for (auto& pair : widget_to_node_id_map_) | |
| 430 pair.first->RemoveRemovalsObserver(this); | |
| 431 for (auto& pair : view_to_node_id_map_) | |
| 432 pair.first->RemoveObserver(this); | |
| 433 } | |
| 434 | |
| 435 void AshDevToolsDOMAgent::Reset() { | |
| 436 RemoveObservers(); | |
| 437 widget_for_highlighting_.reset(); | |
| 438 window_to_node_id_map_.clear(); | |
| 439 widget_to_node_id_map_.clear(); | |
| 440 view_to_node_id_map_.clear(); | |
| 441 node_id_to_window_map_.clear(); | |
| 442 node_id_to_widget_map_.clear(); | |
| 443 node_id_to_view_map_.clear(); | |
| 444 node_ids = 1; | |
| 445 } | |
| 446 | |
| 447 AshDevToolsDOMAgent::WindowAndBoundsPair | |
| 448 AshDevToolsDOMAgent::GetNodeWindowAndBounds(int node_id) { | |
| 449 WmWindow* window = GetWindowFromNodeId(node_id); | |
| 450 if (window) | |
| 451 return std::make_pair(window, window->GetBoundsInScreen()); | |
| 452 | |
| 453 views::Widget* widget = GetWidgetFromNodeId(node_id); | |
| 454 if (widget) { | |
| 455 return std::make_pair(WmWindow::Get(widget->GetNativeWindow()), | |
| 456 widget->GetWindowBoundsInScreen()); | |
| 457 } | |
| 458 | |
| 459 views::View* view = GetViewFromNodeId(node_id); | |
| 460 if (view) { | |
| 461 gfx::Rect bounds = view->GetBoundsInScreen(); | |
| 462 return std::make_pair(WmWindow::Get(view->GetWidget()->GetNativeWindow()), | |
| 463 bounds); | |
| 464 } | |
| 465 | |
| 466 return std::make_pair(nullptr, gfx::Rect()); | |
| 467 } | |
| 468 | |
| 469 void AshDevToolsDOMAgent::InitializeHighlightingWidget() { | |
| 470 DCHECK(!widget_for_highlighting_); | |
| 471 widget_for_highlighting_.reset(new views::Widget); | |
| 472 views::Widget::InitParams params; | |
| 473 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; | |
| 474 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; | |
| 475 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
| 476 params.opacity = views::Widget::InitParams::WindowOpacity::TRANSLUCENT_WINDOW; | |
| 477 params.name = "HighlightingWidget"; | |
| 478 shell_->GetPrimaryRootWindowController() | |
| 479 ->ConfigureWidgetInitParamsForContainer(widget_for_highlighting_.get(), | |
| 480 kShellWindowId_OverlayContainer, | |
| 481 ¶ms); | |
| 482 params.keep_on_top = true; | |
| 483 params.accept_events = false; | |
| 484 widget_for_highlighting_->Init(params); | |
| 485 } | |
| 486 | |
| 487 void AshDevToolsDOMAgent::UpdateHighlight( | |
| 488 const WindowAndBoundsPair& window_and_bounds, | |
| 489 SkColor background, | |
| 490 SkColor border) { | |
| 491 constexpr int kBorderThickness = 1; | |
| 492 views::View* root_view = widget_for_highlighting_->GetRootView(); | |
| 493 root_view->SetBorder(views::CreateSolidBorder(kBorderThickness, border)); | |
| 494 root_view->set_background( | |
| 495 views::Background::CreateSolidBackground(background)); | |
| 496 WmWindow::Get(widget_for_highlighting_->GetNativeWindow()) | |
| 497 ->SetBoundsInScreen(window_and_bounds.second, | |
| 498 window_and_bounds.first->GetDisplayNearestWindow()); | |
| 499 } | |
| 500 | |
| 501 ui::devtools::protocol::Response AshDevToolsDOMAgent::HighlightNode( | |
| 502 std::unique_ptr<ui::devtools::protocol::DOM::HighlightConfig> | |
| 503 highlight_config, | |
| 504 int node_id) { | |
| 505 if (!widget_for_highlighting_) | |
| 506 InitializeHighlightingWidget(); | |
| 507 | |
| 508 WindowAndBoundsPair window_and_bounds(GetNodeWindowAndBounds(node_id)); | |
| 509 | |
| 510 if (!window_and_bounds.first) | |
| 511 return ui::devtools::protocol::Response::Error( | |
| 512 "No node found with that id"); | |
| 513 | |
| 514 SkColor border_color = | |
| 515 RGBAToSkColor(highlight_config->getBorderColor(nullptr)); | |
| 516 SkColor content_color = | |
| 517 RGBAToSkColor(highlight_config->getContentColor(nullptr)); | |
| 518 UpdateHighlight(window_and_bounds, content_color, border_color); | |
| 519 | |
| 520 if (!widget_for_highlighting_->IsVisible()) | |
| 521 widget_for_highlighting_->Show(); | |
| 522 | |
| 523 return ui::devtools::protocol::Response::OK(); | |
| 524 } | |
| 525 | |
| 526 bool AshDevToolsDOMAgent::IsHighlightingWindow(WmWindow* window) { | |
| 527 return widget_for_highlighting_ && | |
| 528 GetWidgetFromWmWindow(window) == widget_for_highlighting_.get(); | |
| 529 } | |
| 530 | |
| 531 } // namespace devtools | |
| 532 } // namespace ash | |
| OLD | NEW |