view_element.cc 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // Copyright 2017 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. #include "components/ui_devtools/views/view_element.h"
  5. #include <algorithm>
  6. #include "base/strings/string_split.h"
  7. #include "base/strings/string_util.h"
  8. #include "base/strings/utf_string_conversions.h"
  9. #include "components/ui_devtools/protocol.h"
  10. #include "components/ui_devtools/ui_element_delegate.h"
  11. #include "components/ui_devtools/views/devtools_event_util.h"
  12. #include "components/ui_devtools/views/element_utility.h"
  13. #include "ui/base/interaction/element_tracker.h"
  14. #include "ui/base/metadata/metadata_types.h"
  15. #include "ui/gfx/color_utils.h"
  16. #include "ui/views/controls/textfield/textfield.h"
  17. #include "ui/views/interaction/element_tracker_views.h"
  18. #include "ui/views/view_utils.h"
  19. #include "ui/views/widget/widget.h"
  20. namespace ui_devtools {
  21. namespace {
  22. ui::EventType GetMouseEventType(const std::string& type) {
  23. if (type == protocol::DOM::MouseEvent::TypeEnum::MousePressed)
  24. return ui::ET_MOUSE_PRESSED;
  25. if (type == protocol::DOM::MouseEvent::TypeEnum::MouseDragged)
  26. return ui::ET_MOUSE_DRAGGED;
  27. if (type == protocol::DOM::MouseEvent::TypeEnum::MouseReleased)
  28. return ui::ET_MOUSE_RELEASED;
  29. if (type == protocol::DOM::MouseEvent::TypeEnum::MouseMoved)
  30. return ui::ET_MOUSE_MOVED;
  31. if (type == protocol::DOM::MouseEvent::TypeEnum::MouseEntered)
  32. return ui::ET_MOUSE_ENTERED;
  33. if (type == protocol::DOM::MouseEvent::TypeEnum::MouseExited)
  34. return ui::ET_MOUSE_EXITED;
  35. if (type == protocol::DOM::MouseEvent::TypeEnum::MouseWheel)
  36. return ui::ET_MOUSEWHEEL;
  37. return ui::ET_UNKNOWN;
  38. }
  39. int GetButtonFlags(const std::string& button) {
  40. if (button == protocol::DOM::MouseEvent::ButtonEnum::Left)
  41. return ui::EF_LEFT_MOUSE_BUTTON;
  42. if (button == protocol::DOM::MouseEvent::ButtonEnum::Right)
  43. return ui::EF_RIGHT_MOUSE_BUTTON;
  44. if (button == protocol::DOM::MouseEvent::ButtonEnum::Middle)
  45. return ui::EF_MIDDLE_MOUSE_BUTTON;
  46. if (button == protocol::DOM::MouseEvent::ButtonEnum::Back)
  47. return ui::EF_BACK_MOUSE_BUTTON;
  48. if (button == protocol::DOM::MouseEvent::ButtonEnum::Forward)
  49. return ui::EF_FORWARD_MOUSE_BUTTON;
  50. return ui::EF_NONE;
  51. }
  52. int GetMouseWheelXOffset(const std::string& mouse_wheel_direction) {
  53. if (mouse_wheel_direction ==
  54. protocol::DOM::MouseEvent::WheelDirectionEnum::Left)
  55. return ui::MouseWheelEvent::kWheelDelta;
  56. if (mouse_wheel_direction ==
  57. protocol::DOM::MouseEvent::WheelDirectionEnum::Right)
  58. return -ui::MouseWheelEvent::kWheelDelta;
  59. return 0;
  60. }
  61. int GetMouseWheelYOffset(const std::string& mouse_wheel_direction) {
  62. if (mouse_wheel_direction ==
  63. protocol::DOM::MouseEvent::WheelDirectionEnum::Up)
  64. return ui::MouseWheelEvent::kWheelDelta;
  65. if (mouse_wheel_direction ==
  66. protocol::DOM::MouseEvent::WheelDirectionEnum::Down)
  67. return -ui::MouseWheelEvent::kWheelDelta;
  68. return 0;
  69. }
  70. } // namespace
  71. ViewElement::ViewElement(views::View* view,
  72. UIElementDelegate* ui_element_delegate,
  73. UIElement* parent)
  74. : UIElementWithMetaData(UIElementType::VIEW, ui_element_delegate, parent),
  75. view_(view) {
  76. observer_.Observe(view_);
  77. }
  78. ViewElement::~ViewElement() = default;
  79. void ViewElement::OnChildViewRemoved(views::View* parent, views::View* view) {
  80. DCHECK_EQ(parent, view_);
  81. auto iter = std::find_if(
  82. children().begin(), children().end(), [view](UIElement* child) {
  83. return view ==
  84. UIElement::GetBackingElement<views::View, ViewElement>(child);
  85. });
  86. if (iter == children().end()) {
  87. RebuildTree();
  88. return;
  89. }
  90. UIElement* child_element = *iter;
  91. RemoveChild(child_element);
  92. delete child_element;
  93. }
  94. void ViewElement::OnChildViewAdded(views::View* parent, views::View* view) {
  95. DCHECK_EQ(parent, view_);
  96. auto iter = std::find_if(
  97. children().begin(), children().end(), [view](UIElement* child) {
  98. return view ==
  99. UIElement::GetBackingElement<views::View, ViewElement>(child);
  100. });
  101. if (iter != children().end()) {
  102. RebuildTree();
  103. return;
  104. }
  105. AddChild(new ViewElement(view, delegate(), this));
  106. }
  107. void ViewElement::OnChildViewReordered(views::View* parent, views::View* view) {
  108. DCHECK_EQ(parent, view_);
  109. auto iter = std::find_if(
  110. children().begin(), children().end(), [view](UIElement* child) {
  111. return view ==
  112. UIElement::GetBackingElement<views::View, ViewElement>(child);
  113. });
  114. if (iter == children().end() ||
  115. children().size() != view_->children().size()) {
  116. RebuildTree();
  117. return;
  118. }
  119. UIElement* child_element = *iter;
  120. ReorderChild(child_element, parent->GetIndexOf(view).value());
  121. }
  122. void ViewElement::OnViewBoundsChanged(views::View* view) {
  123. DCHECK_EQ(view_, view);
  124. delegate()->OnUIElementBoundsChanged(this);
  125. }
  126. void ViewElement::GetBounds(gfx::Rect* bounds) const {
  127. *bounds = view_->bounds();
  128. }
  129. void ViewElement::SetBounds(const gfx::Rect& bounds) {
  130. view_->SetBoundsRect(bounds);
  131. }
  132. std::vector<std::string> ViewElement::GetAttributes() const {
  133. // TODO(lgrey): Change name to class after updating tests.
  134. return {"name", view_->GetClassName()};
  135. }
  136. std::pair<gfx::NativeWindow, gfx::Rect>
  137. ViewElement::GetNodeWindowAndScreenBounds() const {
  138. return std::make_pair(view_->GetWidget()->GetNativeWindow(),
  139. view_->GetBoundsInScreen());
  140. }
  141. // static
  142. views::View* ViewElement::From(const UIElement* element) {
  143. DCHECK_EQ(UIElementType::VIEW, element->type());
  144. return static_cast<const ViewElement*>(element)->view_;
  145. }
  146. template <>
  147. int UIElement::FindUIElementIdForBackendElement<views::View>(
  148. views::View* element) const {
  149. if (type_ == UIElementType::VIEW &&
  150. UIElement::GetBackingElement<views::View, ViewElement>(this) == element) {
  151. return node_id_;
  152. }
  153. for (auto* child : children_) {
  154. int ui_element_id = child->FindUIElementIdForBackendElement(element);
  155. if (ui_element_id)
  156. return ui_element_id;
  157. }
  158. return 0;
  159. }
  160. void ViewElement::PaintRect() const {
  161. view()->SchedulePaint();
  162. }
  163. bool ViewElement::FindMatchByElementID(
  164. const ui::ElementIdentifier& identifier) {
  165. auto result = views::ElementTrackerViews::GetInstance()
  166. ->GetAllMatchingViewsInAnyContext(identifier);
  167. return std::find(result.begin(), result.end(), view_) != result.end();
  168. }
  169. bool ViewElement::DispatchMouseEvent(protocol::DOM::MouseEvent* event) {
  170. ui::EventType event_type = GetMouseEventType(event->getType());
  171. int button_flags = GetButtonFlags(event->getButton());
  172. if (event_type == ui::ET_UNKNOWN)
  173. return false;
  174. gfx::Point location(event->getX(), event->getY());
  175. if (event_type == ui::ET_MOUSEWHEEL) {
  176. int x_offset = GetMouseWheelXOffset(event->getWheelDirection());
  177. int y_offset = GetMouseWheelYOffset(event->getWheelDirection());
  178. ui::MouseWheelEvent mouse_wheel_event(
  179. gfx::Vector2d(x_offset, y_offset), location, location,
  180. ui::EventTimeForNow(), button_flags, button_flags);
  181. view_->OnMouseWheel(mouse_wheel_event);
  182. } else {
  183. ui::MouseEvent mouse_event(event_type, location, location,
  184. ui::EventTimeForNow(), button_flags,
  185. button_flags);
  186. view_->OnMouseEvent(&mouse_event);
  187. }
  188. return true;
  189. }
  190. bool ViewElement::DispatchKeyEvent(protocol::DOM::KeyEvent* event) {
  191. ui::KeyEvent key_event = ConvertToUIKeyEvent(event);
  192. // Key events are processed differently based on classes. Character events are
  193. // routed to the text input client while key stroke events are propragated
  194. // through the normal event flow. The IME flow is bypassed.
  195. if (key_event.is_char()) {
  196. // Since the IME flow is bypassed, we need to manually add ui components
  197. // we want to receive character events here.
  198. if (views::IsViewClass<views::Textfield>(view_)) {
  199. static_cast<views::Textfield*>(view_)->InsertChar(key_event);
  200. } else {
  201. return false;
  202. }
  203. } else {
  204. view_->OnKeyEvent(&key_event);
  205. }
  206. return true;
  207. }
  208. ui::metadata::ClassMetaData* ViewElement::GetClassMetaData() const {
  209. return view_->GetClassMetaData();
  210. }
  211. void* ViewElement::GetClassInstance() const {
  212. return view_;
  213. }
  214. ui::Layer* ViewElement::GetLayer() const {
  215. return view_->layer();
  216. }
  217. void ViewElement::RebuildTree() {
  218. ClearChildren();
  219. for (auto* child : view_->children()) {
  220. AddChild(new ViewElement(child, delegate(), this));
  221. }
  222. }
  223. } // namespace ui_devtools