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/common/devtools/ash_devtools_dom_agent.h" | |
6 | |
7 #include "ash/common/wm_window.h" | |
8 #include "ash/public/cpp/shell_window_ids.h" | |
9 #include "ash/root_window_controller.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 |