123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- // Copyright 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/ui_devtools/views/view_element.h"
- #include <algorithm>
- #include "base/strings/string_split.h"
- #include "base/strings/string_util.h"
- #include "base/strings/utf_string_conversions.h"
- #include "components/ui_devtools/protocol.h"
- #include "components/ui_devtools/ui_element_delegate.h"
- #include "components/ui_devtools/views/devtools_event_util.h"
- #include "components/ui_devtools/views/element_utility.h"
- #include "ui/base/interaction/element_tracker.h"
- #include "ui/base/metadata/metadata_types.h"
- #include "ui/gfx/color_utils.h"
- #include "ui/views/controls/textfield/textfield.h"
- #include "ui/views/interaction/element_tracker_views.h"
- #include "ui/views/view_utils.h"
- #include "ui/views/widget/widget.h"
- namespace ui_devtools {
- namespace {
- ui::EventType GetMouseEventType(const std::string& type) {
- if (type == protocol::DOM::MouseEvent::TypeEnum::MousePressed)
- return ui::ET_MOUSE_PRESSED;
- if (type == protocol::DOM::MouseEvent::TypeEnum::MouseDragged)
- return ui::ET_MOUSE_DRAGGED;
- if (type == protocol::DOM::MouseEvent::TypeEnum::MouseReleased)
- return ui::ET_MOUSE_RELEASED;
- if (type == protocol::DOM::MouseEvent::TypeEnum::MouseMoved)
- return ui::ET_MOUSE_MOVED;
- if (type == protocol::DOM::MouseEvent::TypeEnum::MouseEntered)
- return ui::ET_MOUSE_ENTERED;
- if (type == protocol::DOM::MouseEvent::TypeEnum::MouseExited)
- return ui::ET_MOUSE_EXITED;
- if (type == protocol::DOM::MouseEvent::TypeEnum::MouseWheel)
- return ui::ET_MOUSEWHEEL;
- return ui::ET_UNKNOWN;
- }
- int GetButtonFlags(const std::string& button) {
- if (button == protocol::DOM::MouseEvent::ButtonEnum::Left)
- return ui::EF_LEFT_MOUSE_BUTTON;
- if (button == protocol::DOM::MouseEvent::ButtonEnum::Right)
- return ui::EF_RIGHT_MOUSE_BUTTON;
- if (button == protocol::DOM::MouseEvent::ButtonEnum::Middle)
- return ui::EF_MIDDLE_MOUSE_BUTTON;
- if (button == protocol::DOM::MouseEvent::ButtonEnum::Back)
- return ui::EF_BACK_MOUSE_BUTTON;
- if (button == protocol::DOM::MouseEvent::ButtonEnum::Forward)
- return ui::EF_FORWARD_MOUSE_BUTTON;
- return ui::EF_NONE;
- }
- int GetMouseWheelXOffset(const std::string& mouse_wheel_direction) {
- if (mouse_wheel_direction ==
- protocol::DOM::MouseEvent::WheelDirectionEnum::Left)
- return ui::MouseWheelEvent::kWheelDelta;
- if (mouse_wheel_direction ==
- protocol::DOM::MouseEvent::WheelDirectionEnum::Right)
- return -ui::MouseWheelEvent::kWheelDelta;
- return 0;
- }
- int GetMouseWheelYOffset(const std::string& mouse_wheel_direction) {
- if (mouse_wheel_direction ==
- protocol::DOM::MouseEvent::WheelDirectionEnum::Up)
- return ui::MouseWheelEvent::kWheelDelta;
- if (mouse_wheel_direction ==
- protocol::DOM::MouseEvent::WheelDirectionEnum::Down)
- return -ui::MouseWheelEvent::kWheelDelta;
- return 0;
- }
- } // namespace
- ViewElement::ViewElement(views::View* view,
- UIElementDelegate* ui_element_delegate,
- UIElement* parent)
- : UIElementWithMetaData(UIElementType::VIEW, ui_element_delegate, parent),
- view_(view) {
- observer_.Observe(view_);
- }
- ViewElement::~ViewElement() = default;
- void ViewElement::OnChildViewRemoved(views::View* parent, views::View* view) {
- DCHECK_EQ(parent, view_);
- auto iter = std::find_if(
- children().begin(), children().end(), [view](UIElement* child) {
- return view ==
- UIElement::GetBackingElement<views::View, ViewElement>(child);
- });
- if (iter == children().end()) {
- RebuildTree();
- return;
- }
- UIElement* child_element = *iter;
- RemoveChild(child_element);
- delete child_element;
- }
- void ViewElement::OnChildViewAdded(views::View* parent, views::View* view) {
- DCHECK_EQ(parent, view_);
- auto iter = std::find_if(
- children().begin(), children().end(), [view](UIElement* child) {
- return view ==
- UIElement::GetBackingElement<views::View, ViewElement>(child);
- });
- if (iter != children().end()) {
- RebuildTree();
- return;
- }
- AddChild(new ViewElement(view, delegate(), this));
- }
- void ViewElement::OnChildViewReordered(views::View* parent, views::View* view) {
- DCHECK_EQ(parent, view_);
- auto iter = std::find_if(
- children().begin(), children().end(), [view](UIElement* child) {
- return view ==
- UIElement::GetBackingElement<views::View, ViewElement>(child);
- });
- if (iter == children().end() ||
- children().size() != view_->children().size()) {
- RebuildTree();
- return;
- }
- UIElement* child_element = *iter;
- ReorderChild(child_element, parent->GetIndexOf(view).value());
- }
- void ViewElement::OnViewBoundsChanged(views::View* view) {
- DCHECK_EQ(view_, view);
- delegate()->OnUIElementBoundsChanged(this);
- }
- void ViewElement::GetBounds(gfx::Rect* bounds) const {
- *bounds = view_->bounds();
- }
- void ViewElement::SetBounds(const gfx::Rect& bounds) {
- view_->SetBoundsRect(bounds);
- }
- std::vector<std::string> ViewElement::GetAttributes() const {
- // TODO(lgrey): Change name to class after updating tests.
- return {"name", view_->GetClassName()};
- }
- std::pair<gfx::NativeWindow, gfx::Rect>
- ViewElement::GetNodeWindowAndScreenBounds() const {
- return std::make_pair(view_->GetWidget()->GetNativeWindow(),
- view_->GetBoundsInScreen());
- }
- // static
- views::View* ViewElement::From(const UIElement* element) {
- DCHECK_EQ(UIElementType::VIEW, element->type());
- return static_cast<const ViewElement*>(element)->view_;
- }
- template <>
- int UIElement::FindUIElementIdForBackendElement<views::View>(
- views::View* element) const {
- if (type_ == UIElementType::VIEW &&
- UIElement::GetBackingElement<views::View, ViewElement>(this) == element) {
- return node_id_;
- }
- for (auto* child : children_) {
- int ui_element_id = child->FindUIElementIdForBackendElement(element);
- if (ui_element_id)
- return ui_element_id;
- }
- return 0;
- }
- void ViewElement::PaintRect() const {
- view()->SchedulePaint();
- }
- bool ViewElement::FindMatchByElementID(
- const ui::ElementIdentifier& identifier) {
- auto result = views::ElementTrackerViews::GetInstance()
- ->GetAllMatchingViewsInAnyContext(identifier);
- return std::find(result.begin(), result.end(), view_) != result.end();
- }
- bool ViewElement::DispatchMouseEvent(protocol::DOM::MouseEvent* event) {
- ui::EventType event_type = GetMouseEventType(event->getType());
- int button_flags = GetButtonFlags(event->getButton());
- if (event_type == ui::ET_UNKNOWN)
- return false;
- gfx::Point location(event->getX(), event->getY());
- if (event_type == ui::ET_MOUSEWHEEL) {
- int x_offset = GetMouseWheelXOffset(event->getWheelDirection());
- int y_offset = GetMouseWheelYOffset(event->getWheelDirection());
- ui::MouseWheelEvent mouse_wheel_event(
- gfx::Vector2d(x_offset, y_offset), location, location,
- ui::EventTimeForNow(), button_flags, button_flags);
- view_->OnMouseWheel(mouse_wheel_event);
- } else {
- ui::MouseEvent mouse_event(event_type, location, location,
- ui::EventTimeForNow(), button_flags,
- button_flags);
- view_->OnMouseEvent(&mouse_event);
- }
- return true;
- }
- bool ViewElement::DispatchKeyEvent(protocol::DOM::KeyEvent* event) {
- ui::KeyEvent key_event = ConvertToUIKeyEvent(event);
- // Key events are processed differently based on classes. Character events are
- // routed to the text input client while key stroke events are propragated
- // through the normal event flow. The IME flow is bypassed.
- if (key_event.is_char()) {
- // Since the IME flow is bypassed, we need to manually add ui components
- // we want to receive character events here.
- if (views::IsViewClass<views::Textfield>(view_)) {
- static_cast<views::Textfield*>(view_)->InsertChar(key_event);
- } else {
- return false;
- }
- } else {
- view_->OnKeyEvent(&key_event);
- }
- return true;
- }
- ui::metadata::ClassMetaData* ViewElement::GetClassMetaData() const {
- return view_->GetClassMetaData();
- }
- void* ViewElement::GetClassInstance() const {
- return view_;
- }
- ui::Layer* ViewElement::GetLayer() const {
- return view_->layer();
- }
- void ViewElement::RebuildTree() {
- ClearChildren();
- for (auto* child : view_->children()) {
- AddChild(new ViewElement(child, delegate(), this));
- }
- }
- } // namespace ui_devtools
|