910e62b5创建于 1月15日历史提交
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_VIEWS_ACCESSIBILITY_AX_VIRTUAL_VIEW_H_
#define UI_VIEWS_ACCESSIBILITY_AX_VIRTUAL_VIEW_H_

#include <stdint.h>

#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
#include "ui/accessibility/platform/ax_unique_id.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/native_ui_types.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/views_export.h"

#if defined(USE_AURA)
#include "ui/views/accessibility/ax_virtual_view_wrapper.h"
#endif

namespace ui {

struct AXActionData;

}  // namespace ui

namespace views {

class AXAuraObjCache;
class AXVirtualViewWrapper;
class View;
class ViewAXPlatformNodeDelegate;

namespace test {
class AXVirtualViewTest;
}  // namespace test

// Implements a virtual view that is used only for accessibility.
//
// Some composite widgets such as tree and table views may utilize lightweight
// UI objects instead of actual views for displaying and managing their
// contents. We need a corresponding virtual accessibility view to expose
// information about these lightweight Ui objects to accessibility. An
// AXVirtualView is owned by its parent, which could either be a
// ViewAccessibility or an AXVirtualView.
class VIEWS_EXPORT AXVirtualView : public ViewAccessibility,
                                   public ui::AXPlatformNodeDelegate {
 public:
  using AXVirtualViews = std::vector<std::unique_ptr<AXVirtualView>>;

  static AXVirtualView* GetFromId(int32_t id);

  AXVirtualView();
  AXVirtualView(const AXVirtualView&) = delete;
  AXVirtualView& operator=(const AXVirtualView&) = delete;
  ~AXVirtualView() override;

  //
  // Methods for managing parent - child relationships.
  //

  // Adds |view| as a child of this virtual view, optionally at |index|.
  // We take ownership of our children.
  void AddChildView(std::unique_ptr<AXVirtualView> view);
  void AddChildViewAt(std::unique_ptr<AXVirtualView> view, size_t index);

  // Moves |view| to the specified |index|. A too-large value for |index| moves
  // |view| to the end.
  void ReorderChildView(AXVirtualView* view, size_t index);

  // Removes this virtual view from its parent, which could either be a virtual
  // or a real view. Hands ownership of this view back to the caller.
  std::unique_ptr<AXVirtualView> RemoveFromParentView();

  // Removes |view| from this virtual view. The view's parent will change to
  // nullptr. Hands ownership back to the caller.
  std::unique_ptr<AXVirtualView> RemoveChildView(AXVirtualView* view);

  // Removes all the children from this virtual view.
  // The virtual views are deleted.
  void RemoveAllChildViews();

  const AXVirtualViews& children() const { return children_; }

  // Returns the parent ViewAccessibility if the parent is a real View and not
  // an AXVirtualView. Returns nullptr otherwise.
  const ViewAccessibility* parent_view() const { return parent_view_; }
  ViewAccessibility* parent_view() { return parent_view_; }

  // Returns the parent view if the parent is an AXVirtualView and not a real
  // View. Returns nullptr otherwise.
  const AXVirtualView* virtual_parent_view() const {
    return virtual_parent_view_;
  }
  AXVirtualView* virtual_parent_view() { return virtual_parent_view_; }

  ui::AXPlatformNode* ax_platform_node() { return ax_platform_node_.get(); }

  // Returns true if |view| is contained within the hierarchy of this
  // AXVirtualView, even as an indirect descendant. Will return true if |view|
  // is also this AXVirtualView.
  bool Contains(const AXVirtualView* view) const;

  // Returns the index of |view|, or nullopt if |view| is not a child of this
  // virtual view.
  std::optional<size_t> GetIndexOf(const AXVirtualView* view) const;

  //
  // Other methods.
  //

  const char* GetViewClassName() const;
  gfx::NativeViewAccessible GetNativeObject() const override;

  Widget* GetWidget() const override;
  // TODO(crbug.com/40672441): Rename to GetParent once ViewsAX is completed and
  // AXVirtualView no longer needs to extend AXPlatformNodeDelegate.
  ViewAccessibility* GetViewAccessibilityParent() const override;

  std::string GetDebugString() const override;

  // ui::AXPlatformNodeDelegate. Note that
  // - Some of these functions have Mac-specific implementations in
  //   ax_virtual_view_mac.mm.
  // - GetChildCount(), ChildAtIndex(), and GetParent() are used by assistive
  //   technologies to access the unignored accessibility tree, which doesn't
  //   necessarily reflect the internal descendant tree. (An ignored node means
  //   that the node should not be exposed to the platform.)
  const ui::AXNodeData& GetData() const override;
  size_t GetChildCount() const override;
  gfx::NativeViewAccessible ChildAtIndex(size_t index) const override;
  gfx::NativeViewAccessible GetNSWindow() override;
  gfx::NativeViewAccessible GetNativeViewAccessible() override;
  gfx::NativeViewAccessible GetParent() const override;
  using AXPlatformNodeDelegate::GetBoundsRect;
  gfx::Rect GetBoundsRect(
      const ui::AXCoordinateSystem coordinate_system,
      const ui::AXClippingBehavior clipping_behavior,
      ui::AXOffscreenResult* offscreen_result) const override;
  gfx::NativeViewAccessible HitTestSync(
      int screen_physical_pixel_x,
      int screen_physical_pixel_y) const override;
  gfx::NativeViewAccessible GetFocus() const override;
  ui::AXPlatformNode* GetFromNodeID(int32_t id) override;
  bool AccessibilityPerformAction(const ui::AXActionData& data) override;
  bool ShouldIgnoreHoveredStateForTesting() override;
  bool IsOffscreen() const override;
  ui::AXPlatformNodeId GetUniqueId() const override;
  gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override;
  std::vector<int32_t> GetColHeaderNodeIds() const override;
  std::vector<int32_t> GetColHeaderNodeIds(int col_index) const override;
  std::optional<int32_t> GetCellId(int row_index, int col_index) const override;

  // Gets the real View that owns our shallowest virtual ancestor,, if any.
  View* GetOwnerView() const;

  // Gets the delegate for our owning View; if we are on a platform that exposes
  // Views directly to platform APIs instead of serializing them into an AXTree.
  // Otherwise, returns nullptr.
  ViewAXPlatformNodeDelegate* GetDelegate() const;

  // Gets or creates a wrapper suitable for use with tree sources.
  AXVirtualViewWrapper* GetOrCreateWrapper(views::AXAuraObjCache* cache);

  // Handle a request from assistive technology to perform an action on this
  // virtual view. Returns true on success, but note that the success/failure is
  // not propagated to the client that requested the action, since the
  // request is sometimes asynchronous. The right way to send a response is
  // via NotifyAccessibilityEventDeprecated().
  virtual bool HandleAccessibleAction(const ui::AXActionData& action_data);

  // Prune/Unprune all descendant virtual views from the tree. As of right now,
  // these should only be called by their ViewAccessibility counterparts. This
  // is for a scenario such as the following: ViewAccessibility A has a child
  // AXVirtualView B, which has a child AXVirtualView C:
  // A
  //  B
  //   C
  // A->SetIsLeaf(true) is called. B and C then should be pruned from the tree
  // and marked as ignored.
  void PruneVirtualSubtree();
  void UnpruneVirtualSubtree();

  // Warning: This method will overwrite the focusable state. In most
  // cases, we compute the focusable state automatically in
  // `UpdateFocusableState`, however, AXVirtualViews are not Views, so we need
  // to provide a way to set their focusable state manually, similar to
  // the `FocusBehavior` in Views.
  void ForceSetIsFocusable(bool focusable);
  void ResetIsFocusable();

  // This is also called by `ViewAccessibility::OnViewHasNewAncestor`, to update
  // the relevant attributes on its AXVirtualView subtree.
  void OnViewHasNewAncestor(bool ancestor_focusable);

  void OnViewHasNewAncestor(const AXVirtualView* new_ancestor);

  // `ViewAccessibility` overrides.
  void NotifyEvent(ax::mojom::Event event_type,
                   bool send_native_event) override;
  void NotifyDataChanged() override;
  void UpdateFocusableState() override;
  void UpdateInvisibleState() override;
  void OnWidgetClosing(Widget* widget) override;
  void OnWidgetDestroyed(Widget* widget) override;
  void OnWidgetUpdated(Widget* widget, Widget* old_widget) override;
  void UpdateReadyToNotifyEvents() override;
  void UpdateIgnoredState() override;
  void SetIsEnabled(bool enabled) override;
  void SetShowContextMenu(bool show_context_menu) override;

  bool parent_view_is_drawn() const { return parent_view_is_drawn_; }

 protected:
  // Forwards a request from assistive technology to perform an action on this
  // virtual view to the owner view's accessible action handler.
  bool HandleAccessibleActionInOwnerView(const ui::AXActionData& action_data);

 private:
  // Needed in order to access set_cache(), so that AXAuraObjCache can
  // track when an AXVirtualViewWrapper is deleted.
  friend class AXAuraObjCache;
  friend class AXVirtualViewWrapper;
  friend class views::test::AXVirtualViewTest;

  // Internal class name.
  static const char kViewClassName[];

  // The AXAuraObjCache associated with our wrapper, if any. This is
  // called by friend classes AXAuraObjCache and AXVirtualViewWrapper.
  void set_cache(AXAuraObjCache* cache);

  // Sets the parent ViewAccessibility if the parent is a real View and not an
  // AXVirtualView. It is invalid to set both |parent_view_| and
  // |virtual_parent_view_|.
  void set_parent_view(ViewAccessibility* view_accessibility) {
    DCHECK(!virtual_parent_view_);
    parent_view_ = view_accessibility;
  }

  // AXVirtualViews should be marked as disabled if their
  // owner View is disabled.
  void SetIsEnabledRecursive(bool enabled);

  void SetShowContextMenuRecursive(bool show_context_menu);

  void UpdateParentViewIsDrawnRecursive(const views::View* initial_view,
                                        bool parent_view_is_drawn);

  ui::AXPlatformNode::Pointer ax_platform_node_;

  // Weak. Owns us if not nullptr.
  // Either |parent_view_| or |virtual_parent_view_| should be set but not both.
  raw_ptr<ViewAccessibility> parent_view_ = nullptr;

  // Weak. Owns us if not nullptr.
  // Either |parent_view_| or |virtual_parent_view_| should be set but not both.
  raw_ptr<AXVirtualView> virtual_parent_view_ = nullptr;

  // We own our children.
  AXVirtualViews children_;

  // The AXAuraObjCache that owns the AXVirtualViewWrapper associated with
  // this object, if any.
  raw_ptr<AXAuraObjCache> ax_aura_obj_cache_ = nullptr;

  std::optional<bool> should_be_focusable_ = std::nullopt;

  bool parent_view_is_drawn_ = true;

  friend class ViewAccessibility;
};

}  // namespace views

#endif  // UI_VIEWS_ACCESSIBILITY_AX_VIRTUAL_VIEW_H_